Staging: Merge branch 'staging-next' into 2.6.38-rc3
authorGreg Kroah-Hartman <gregkh@suse.de>
Wed, 2 Feb 2011 21:35:58 +0000 (13:35 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 2 Feb 2011 21:35:58 +0000 (13:35 -0800)
This was done to resolve conflicts in the following files due
to patches in Linus's tree and in the staging-next tree:
drivers/staging/brcm80211/brcmsmac/wl_mac80211.c
drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c

Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
1563 files changed:
.mailmap
Documentation/ABI/testing/sysfs-platform-at91 [new file with mode: 0644]
Documentation/DocBook/device-drivers.tmpl
Documentation/DocBook/dvb/dvbapi.xml
Documentation/DocBook/media.tmpl
Documentation/DocBook/v4l/dev-rds.xml
Documentation/DocBook/v4l/v4l2.xml
Documentation/feature-removal-schedule.txt
Documentation/filesystems/ntfs.txt
Documentation/kernel-parameters.txt
Documentation/lguest/lguest.c
Documentation/lguest/lguest.txt
Documentation/networking/bonding.txt
Documentation/sound/alsa/soc/codec.txt
Documentation/sound/alsa/soc/machine.txt
Documentation/sound/alsa/soc/platform.txt
Documentation/video4linux/v4l2-controls.txt
MAINTAINERS
Makefile
arch/alpha/Kconfig
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/sp810.h
arch/arm/include/asm/io.h
arch/arm/include/asm/memory.h
arch/arm/kernel/head.S
arch/arm/kernel/smp_twd.c
arch/arm/mach-ep93xx/gpio.c
arch/arm/mach-footbridge/include/mach/debug-macro.S
arch/arm/mach-msm/board-qsd8x50.c
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/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/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/mux.c
arch/arm/mach-omap2/pm24xx.c
arch/arm/mach-omap2/pm34xx.c
arch/arm/mach-omap2/powerdomain2xxx_3xxx.c
arch/arm/mach-omap2/serial.c
arch/arm/mach-omap2/timer-gp.c
arch/arm/mach-realview/Kconfig
arch/arm/mach-realview/platsmp.c
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-shmobile/board-ag5evm.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/intc-sh7372.c
arch/arm/mach-shmobile/intc-sh73a0.c
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/init.c
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/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/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/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/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/microblaze/Kconfig
arch/microblaze/configs/mmu_defconfig
arch/microblaze/configs/nommu_defconfig
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/reg.h
arch/powerpc/include/asm/reg_booke.h
arch/powerpc/include/asm/spu.h
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/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/ras.c
arch/powerpc/sysdev/fsl_rio.c
arch/powerpc/sysdev/mpic.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/kernel/cpu/sh4/setup-sh7750.c
arch/sh/kernel/topology.c
arch/sparc/Kconfig
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/cacheflush.h
arch/x86/include/asm/cpu.h
arch/x86/include/asm/jump_label.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/system_64.h [deleted file]
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/therm_throt.c
arch/x86/kernel/dumpstack_64.c
arch/x86/kernel/process.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/lguest/Kconfig
arch/x86/lguest/boot.c
arch/x86/mm/numa.c
arch/x86/mm/numa_64.c
arch/x86/mm/srat_32.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
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/nvs.c
drivers/acpi/osl.c
drivers/acpi/sleep.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/base/Kconfig
drivers/base/power/runtime.c
drivers/bluetooth/ath3k.c
drivers/char/Kconfig
drivers/char/Makefile
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/tpm/tpm.c
drivers/char/tpm/tpm_tis.c
drivers/char/virtio_console.c [deleted file]
drivers/clocksource/acpi_pm.c
drivers/clocksource/tcb_clksrc.c
drivers/cpufreq/Kconfig
drivers/firewire/Kconfig
drivers/firewire/core-card.c
drivers/firewire/net.c
drivers/firmware/Kconfig
drivers/gpio/langwell_gpio.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/drm_fb_helper.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_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_opregion.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/nouveau/Kconfig
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_drv.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_temp.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/r100.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r420.c
drivers/gpu/drm/radeon/r520.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_reg.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_reg.h
drivers/gpu/drm/radeon/rs400.c
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/vga/Kconfig
drivers/gpu/vga/vgaarb.c
drivers/hid/Kconfig
drivers/hid/usbhid/Kconfig
drivers/hwmon/applesmc.c
drivers/hwmon/asus_atk0110.c
drivers/hwmon/lis3lv02d.c
drivers/ide/Kconfig
drivers/idle/intel_idle.c
drivers/infiniband/hw/mthca/Kconfig
drivers/infiniband/ulp/ipoib/Kconfig
drivers/input/Kconfig
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/mouse/Kconfig
drivers/input/mouse/synaptics.c
drivers/input/serio/Kconfig
drivers/input/serio/ct82c710.c
drivers/input/serio/serport.c
drivers/input/sparse-keymap.c
drivers/input/tablet/wacom_wac.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/bu21013_ts.c
drivers/input/touchscreen/tnetv107x-ts.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/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-raw.c
drivers/media/rc/keymaps/rc-dib0700-nec.c
drivers/media/rc/mceusb.c
drivers/media/rc/rc-main.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/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/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/ubi/build.c
drivers/net/Kconfig
drivers/net/arm/ks8695net.c
drivers/net/bnx2.c
drivers/net/bnx2.h
drivers/net/bnx2x/bnx2x.h
drivers/net/bnx2x/bnx2x_hsi.h
drivers/net/bnx2x/bnx2x_link.c
drivers/net/bnx2x/bnx2x_reg.h
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/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/gianfar.c
drivers/net/irda/sh_irda.c
drivers/net/ns83820.c
drivers/net/pch_gbe/pch_gbe_main.c
drivers/net/tg3.c
drivers/net/tg3.h
drivers/net/usb/cdc_ncm.c
drivers/net/usb/kaweth.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vmxnet3/vmxnet3_ethtool.c
drivers/net/vmxnet3/vmxnet3_int.h
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath9k/ar9002_calib.c
drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/htc.h
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/main.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
drivers/net/wireless/iwmc3200wifi/netdev.c
drivers/net/wireless/rt2x00/rt2x00firmware.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtlwifi/pci.c
drivers/parport/share.c
drivers/pci/pcie/Kconfig
drivers/pcmcia/Kconfig
drivers/platform/x86/intel_scu_ipc.c
drivers/platform/x86/intel_scu_ipcutil.c
drivers/pps/clients/pps-ktimer.c
drivers/pps/clients/pps_parport.c
drivers/pps/generators/pps_gen_parport.c
drivers/rapidio/rio-scan.c
drivers/rtc/Kconfig
drivers/rtc/interface.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.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/ssb/Kconfig
drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c
drivers/staging/brcm80211/brcmsmac/wl_mac80211.c
drivers/staging/brcm80211/brcmsmac/wlc_mac80211.c
drivers/staging/comedi/drivers/ni_labpc.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/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/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/hvc/virtio_console.c [new file with mode: 0644]
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-wdm.c
drivers/usb/core/Kconfig
drivers/usb/core/endpoint.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hub.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/pch_udc.c
drivers/usb/gadget/printer.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-fsl.h
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-mxc.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/fsl-mph-dr-of.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/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_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/spcp8x5.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/usb_debug.c
drivers/usb/storage/unusual_cypress.h
drivers/usb/storage/unusual_devs.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/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/xen/xenfs/xenbus.c
fs/Kconfig
fs/ceph/caps.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/super.c
fs/ceph/xattr.c
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/sess.c
fs/cifs/smbdes.c
fs/cifs/smbencrypt.c
fs/cifs/transport.c
fs/dcache.c
fs/direct-io.c
fs/ext3/super.c
fs/ext4/super.c
fs/gfs2/inode.c
fs/gfs2/inode.h
fs/gfs2/super.c
fs/lockd/host.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/nilfs2/super.c
fs/ntfs/mft.c
fs/ocfs2/super.c
fs/pipe.c
fs/posix_acl.c
fs/proc/Kconfig
fs/proc/consoles.c
fs/quota/dquot.c
fs/quota/quota.c
fs/reiserfs/super.c
fs/squashfs/block.c
fs/squashfs/xz_wrapper.c
fs/squashfs/zlib_wrapper.c
fs/sysfs/Kconfig
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_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/vmlinux.lds.h
include/drm/radeon_drm.h
include/linux/acpi.h
include/linux/acpi_io.h [new file with mode: 0644]
include/linux/console.h
include/linux/gfp.h
include/linux/ieee80211.h
include/linux/input/bu21013.h
include/linux/irqdesc.h
include/linux/kernel.h
include/linux/kmemcheck.h
include/linux/lockdep.h
include/linux/memcontrol.h
include/linux/mm.h
include/linux/mmc/sh_mmcif.h
include/linux/module.h
include/linux/moduleparam.h
include/linux/nfsacl.h
include/linux/posix_acl.h
include/linux/quota.h
include/linux/quotaops.h
include/linux/rtc.h
include/linux/sunrpc/bc_xprt.h
include/linux/sunrpc/svc_xprt.h
include/linux/sysrq.h
include/linux/usb/hcd.h
include/linux/usb/serial.h
include/linux/virtio_config.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/sch_generic.h
include/net/sctp/user.h
init/Kconfig
init/main.c
kernel/irq/Kconfig
kernel/irq/handle.c
kernel/lockdep.c
kernel/params.c
kernel/perf_event.c
kernel/printk.c
kernel/sched.c
kernel/sched_autogroup.c
kernel/sched_autogroup.h
kernel/sched_debug.c
kernel/sched_fair.c
kernel/smp.c
kernel/sys.c
kernel/sysctl.c
kernel/time/tick-sched.c
kernel/trace/trace_irqsoff.c
kernel/workqueue.c
lib/Kconfig.debug
lib/radix-tree.c
lib/rbtree.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/migrate.c
mm/page_alloc.c
mm/pgtable-generic.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/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/l2cap.c
net/bluetooth/rfcomm/core.c
net/caif/cfcnfg.c
net/can/bcm.c
net/can/raw.c
net/core/dev.c
net/core/ethtool.c
net/core/rtnetlink.c
net/core/skbuff.c
net/dcb/dcbnl.c
net/dsa/dsa.c
net/ipv4/arp.c
net/ipv4/inet_diag.c
net/ipv4/inetpeer.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv6/addrconf.c
net/ipv6/route.c
net/ipv6/xfrm6_policy.c
net/mac80211/Kconfig
net/mac80211/agg-rx.c
net/mac80211/main.c
net/mac80211/tx.c
net/netfilter/nf_conntrack_netlink.c
net/netlink/genetlink.c
net/rfkill/Kconfig
net/sched/sch_cbq.c
net/sched/sch_drr.c
net/sched/sch_dsmark.c
net/sched/sch_fifo.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/socket.c
net/sunrpc/svcsock.c
net/wireless/Kconfig
net/xfrm/xfrm_user.c
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/selinux/ss/conditional.c
security/selinux/ss/policydb.c
sound/arm/aaci.c
sound/atmel/ac97c.c
sound/pci/azt3328.c
sound/pci/hda/hda_eld.c
sound/pci/hda/patch_realtek.c
sound/pci/ice1712/delta.c
sound/pci/oxygen/xonar_cs43xx.c
sound/soc/atmel/snd-soc-afeb9260.c
sound/soc/blackfin/Kconfig
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-ssm2602.c
sound/soc/blackfin/bf5xx-tdm.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8995.c
sound/soc/codecs/wm_hubs.c
sound/soc/davinci/davinci-evm.c
sound/soc/pxa/corgi.c
sound/soc/pxa/poodle.c
sound/soc/pxa/spitz.c
sound/soc/pxa/z2.c
sound/soc/samsung/neo1973_gta02_wm8753.c
sound/soc/samsung/neo1973_wm8753.c
sound/soc/samsung/s3c24xx_simtec_hermes.c
sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
sound/soc/samsung/s3c24xx_uda134x.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-top.c
tools/perf/util/event.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
usr/Kconfig

index 581fd39193a26d2932c696d21f0b78c28f4bdc92..1eba28acab64c83c3e6fd1c39cebfbc6ad6d29ac 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 35447e0817367083e2a13d1ec3a1cc389e815d50..36f63d4a0a065368e187822b86a8c4af2feddbe3 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 e3a97fdd62a6b85bf3f705d39de39719a16221dc..ad8678d489169e7d5dc9d8b06a5d42db98d35ad7 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 f11048d4053f01725d762788ee4b9ebe647ced11..a99088aae1aa80e5a0fe872422009d663af65f60 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 360d2737e64946d2ad9a33185ea4a3335962284c..2427f54397e7a28b45d8836befdaee9f8f00d323 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 839e93e875ae2450e8e8e1064bb3b31472f9c492..9288af96de347f6afbb82002869ce4ce0a837f76 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;
index 8c594c45b6a178c5efa49b671473abfde5e98204..b959659c5df46414413530bd213f1e50aa528ee3 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
index 6ef8cf3bc9a33f1083a173143ebcd6fe68947465..933bc66ccff1881470c68f14b350407dae1d1318 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 b72e071a3e5bd1ca958c423df347d7b1ab515573..89835a4766a684468695b430ac8e7e7f1b76dabc 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.
index dc73bc54cc4e4cacb57fcb72289f88f5d99ef7e0..d9da7e148538286d78d6f11236f3a4db89218f45 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 6ccaf8e1a00ed84b51610da92e20cedacdf57981..dad99978a6a8d5439d80662716bc52519a310293 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 5dc638791d975116bf1a1e590fdfc44a6ae5c33c..25d2f4141d27aaa53d297688de68326c85571dcb 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 37ba3a72cb76100ce19771357b752e037be515b7..bce23a4a78750c630becfc9f6cf9e109ed6721c7 100644 (file)
@@ -27,42 +27,38 @@ ASoC Codec driver breakdown
 
 1 - Codec DAI and PCM configuration
 -----------------------------------
-Each codec driver must have a struct snd_soc_codec_dai to define its DAI and
+Each codec driver must have a struct snd_soc_dai_driver to define its DAI and
 PCM capabilities and operations. This struct is exported so that it can be
 registered with the core by your machine driver.
 
 e.g.
 
-struct snd_soc_codec_dai wm8731_dai = {
-       .name = "WM8731",
-       /* playback capabilities */
+static struct snd_soc_dai_ops wm8731_dai_ops = {
+       .prepare        = wm8731_pcm_prepare,
+       .hw_params      = wm8731_hw_params,
+       .shutdown       = wm8731_shutdown,
+       .digital_mute   = wm8731_mute,
+       .set_sysclk     = wm8731_set_dai_sysclk,
+       .set_fmt        = wm8731_set_dai_fmt,
+};
+
+struct snd_soc_dai_driver wm8731_dai = {
+       .name = "wm8731-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
                .channels_max = 2,
                .rates = WM8731_RATES,
                .formats = WM8731_FORMATS,},
-       /* capture capabilities */
        .capture = {
                .stream_name = "Capture",
                .channels_min = 1,
                .channels_max = 2,
                .rates = WM8731_RATES,
                .formats = WM8731_FORMATS,},
-       /* pcm operations - see section 4 below */
-       .ops = {
-               .prepare = wm8731_pcm_prepare,
-               .hw_params = wm8731_hw_params,
-               .shutdown = wm8731_shutdown,
-       },
-       /* DAI operations - see DAI.txt */
-       .dai_ops = {
-               .digital_mute = wm8731_mute,
-               .set_sysclk = wm8731_set_dai_sysclk,
-               .set_fmt = wm8731_set_dai_fmt,
-       }
+       .ops = &wm8731_dai_ops,
+       .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8731_dai);
 
 
 2 - Codec control IO
@@ -186,13 +182,14 @@ when the mute is applied or freed.
 
 i.e.
 
-static int wm8974_mute(struct snd_soc_codec *codec,
-       struct snd_soc_codec_dai *dai, int mute)
+static int wm8974_mute(struct snd_soc_dai *dai, int mute)
 {
-       u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf;
-       if(mute)
-               wm8974_write(codec, WM8974_DAC, mute_reg | 0x40);
+       struct snd_soc_codec *codec = dai->codec;
+       u16 mute_reg = snd_soc_read(codec, WM8974_DAC) & 0xffbf;
+
+       if (mute)
+               snd_soc_write(codec, WM8974_DAC, mute_reg | 0x40);
        else
-               wm8974_write(codec, WM8974_DAC, mute_reg);
+               snd_soc_write(codec, WM8974_DAC, mute_reg);
        return 0;
 }
index 2524c75557df020ad778f92d77e5b9b5a6e01500..3e2ec9cbf3976d0d21c6ee90d7fe075a210a33eb 100644 (file)
@@ -12,6 +12,8 @@ the following struct:-
 struct snd_soc_card {
        char *name;
 
+       ...
+
        int (*probe)(struct platform_device *pdev);
        int (*remove)(struct platform_device *pdev);
 
@@ -22,12 +24,13 @@ struct snd_soc_card {
        int (*resume_pre)(struct platform_device *pdev);
        int (*resume_post)(struct platform_device *pdev);
 
-       /* machine stream operations */
-       struct snd_soc_ops *ops;
+       ...
 
        /* CPU <--> Codec DAI links  */
        struct snd_soc_dai_link *dai_link;
        int num_links;
+
+       ...
 };
 
 probe()/remove()
@@ -42,11 +45,6 @@ of any machine audio tasks that have to be done before or after the codec, DAIs
 and DMA is suspended and resumed. Optional.
 
 
-Machine operations
-------------------
-The machine specific audio operations can be set here. Again this is optional.
-
-
 Machine DAI Configuration
 -------------------------
 The machine DAI configuration glues all the codec and CPU DAIs together. It can
@@ -61,8 +59,10 @@ struct snd_soc_dai_link is used to set up each DAI in your machine. e.g.
 static struct snd_soc_dai_link corgi_dai = {
        .name = "WM8731",
        .stream_name = "WM8731",
-       .cpu_dai = &pxa_i2s_dai,
-       .codec_dai = &wm8731_dai,
+       .cpu_dai_name = "pxa-is2-dai",
+       .codec_dai_name = "wm8731-hifi",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "wm8713-codec.0-001a",
        .init = corgi_wm8731_init,
        .ops = &corgi_ops,
 };
@@ -77,26 +77,6 @@ static struct snd_soc_card snd_soc_corgi = {
 };
 
 
-Machine Audio Subsystem
------------------------
-
-The machine soc device glues the platform, machine and codec driver together.
-Private data can also be set here. e.g.
-
-/* corgi audio private data */
-static struct wm8731_setup_data corgi_wm8731_setup = {
-       .i2c_address = 0x1b,
-};
-
-/* corgi audio subsystem */
-static struct snd_soc_device corgi_snd_devdata = {
-       .machine = &snd_soc_corgi,
-       .platform = &pxa2xx_soc_platform,
-       .codec_dev = &soc_codec_dev_wm8731,
-       .codec_data = &corgi_wm8731_setup,
-};
-
-
 Machine Power Map
 -----------------
 
index 06d835987c6a8f9d4454ca39b57ac13bed978c75..d57efad37e0a5b33606599f6735f180706fd228d 100644 (file)
@@ -20,9 +20,10 @@ struct snd_soc_ops {
        int (*trigger)(struct snd_pcm_substream *, int);
 };
 
-The platform driver exports its DMA functionality via struct snd_soc_platform:-
+The platform driver exports its DMA functionality via struct
+snd_soc_platform_driver:-
 
-struct snd_soc_platform {
+struct snd_soc_platform_driver {
        char *name;
 
        int (*probe)(struct platform_device *pdev);
@@ -34,6 +35,13 @@ struct snd_soc_platform {
        int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, struct snd_pcm *);
        void (*pcm_free)(struct snd_pcm *);
 
+       /*
+        * For platform caused delay reporting.
+        * Optional.
+        */
+       snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
+               struct snd_soc_dai *);
+
        /* platform stream ops */
        struct snd_pcm_ops *pcm_ops;
 };
index 8773778d23fc612a8dc7e514b657df5805961971..881e7f44491b70a6c803fa68f6185cb4f158b87f 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 dd6ca456cde3da2f87a0c47b6ca11b49488c77c7..359e08f0114afb8cc328c397d428d22180516e00 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>
@@ -888,8 +892,8 @@ 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
 
@@ -1256,7 +1260,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 +1416,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>
@@ -1877,7 +1881,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>
@@ -2216,7 +2220,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 +2647,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>
@@ -3135,6 +3139,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 +3156,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 +3333,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 +3359,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>
@@ -3527,7 +3536,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>
@@ -3664,6 +3673,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/
@@ -3671,7 +3702,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/
@@ -5539,7 +5570,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
@@ -5561,7 +5592,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*
 
@@ -5781,14 +5812,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>
@@ -6118,8 +6149,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
@@ -6563,6 +6594,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
@@ -6864,7 +6905,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>
@@ -6910,7 +6951,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 abb49bf8596ea69b383f7fb5e329b4b5e6381ad7..66e7e977ddc00f486fabde85faac0d0cafcef169 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 38
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc3
 NAME = Flesh-Eating Bats with Fangs
 
 # *DOCUMENTATION*
index fc95ee1bcf6fc239f5dbaad783ec33fbb23e4b6a..47f63d480141575adbb11a0ad2fa82e2d5aee22e 100644 (file)
@@ -8,6 +8,9 @@ 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
        help
          The Alpha is a 64-bit general-purpose processor designed and
          marketed by the Digital Equipment Corporation of blessed memory,
@@ -68,22 +71,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 2b9cf56db363d596860e6dd024f719c22db4371a..212ead354a6ba65a142b006e663532236175545c 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 5536c488dd0179e5d58aff28fe1e1dc0d790273d..f0dea52e49c4be569c5c67a00868d564e8c5b61d 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 695e32d4fb58cf73f36852f36d51d4cb82ae68c1..1b1158ae8f821e77e0b5b3ac29f686bd837dac0c 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 3a1ad15a779fbd4bfce447b2eddcbd63a54f12f5..5b54abbeb0b3b0cbd7a94c9b01453a002caf83f9 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 75984cd1e233b4770ba0c156af48c279f5a9e84b..795374d48f817e51cc701f99e7f5cb31b415f101 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 dcfbcf3b6c3e032a97d1880627edb4405124d632..a93ff8da5bab4b39a8afd07153cf58cd02d5b45b 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 f52c64e36d8df802253ee5688b4ebfe35765662b..2ef2c5e8aaeccd6c55c16d84e59f8635cb19eae7 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 310f9a6270be3085190f9bc200e6f7ac764fc789..6c56ad086c7ca8deed6ffa75aeb86925c8e83150 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 4a1fa81ed37d55f26d58cf5e2ddb9e84d5337b35..e53c47563845e641c49d3081ec3dfa164c617c54 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 cdc40c4b8c48f6ff9a36b05033d31c28f6339b73..88ccde058ba494c242d113dade5522f8a28d7f9b 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 2519cc5a5f8f6888fd8d067ba782d62914cb56f0..889922ad229c31e8419c7f211cb5ef481e4d612a 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 9359e1bf32c1b760574a3123d7627ae7a4d3073f..54bf5eec80163e97108a79645f00d8d639f25ee5 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 c3194186920c5409c32a8add1dfd8e748f9231fe..14559dbb4c2c04fb4d0e12bcfeeeee2aaeca614a 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 7b62be1561ea91d17c5f837826e7636217960e5c..d52ded350a1229fbcc119c9b5547cd327b70e13c 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 d7db34f79702b2cbff980228f3879d47e0717c90..60a21e01eb700512221244e00c70f9481b8432a7 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 6d6689cdf398f93fc3701bc9a52c8926482caf8c..8e97b2f7ceec571dbcf494b42cf22d526ecbcef8 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 1691dea582fea8e3249da868d03cbd8c6ba31e58..d68ac67c201c37db932a810ef9f67dfdbb522d58 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 c4eeb6d1cbf03d77eaec269eac6d01f3684ca065..227a477346edb44a2a83ba49a0f9b7cd2b165ec0 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 4f925ead2617d013b8d19da7b0adfe0692bb71fc..038518ab39a84ec7ef98a3c07737bb8350bddde5 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 e11c7eab8ed051291aecf67d15beb2e09ad2baf7..840fced7529fbde24511879b08dec957943a2538 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 ac336f10000c429156c6aed858c38cf880df5a4f..37903e3f0efc9a4c876d0559346ecd71986048d1 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 ade55c8c408b6ad7b6d3fb4bc63cf1b52c114e01..176ec22af0342f215b59a2778144d69ef0f4c806 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 9083246845498f4eb318b78b6fda01fe6fb28179..8405aded97a358987135ee179377449ddfcb7690 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 7fc056a8569cacb53e5f396b5e76a1d634c968d5..688717612e919b9beaf1d828f39aed69729a9ef9 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 5c5023934001a9f01bc66a91fdc2b494128283e2..063e2ab2c8f185f6a153358d9b792e79b7c37f57 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 e1eaff7f5536c456b3b840419a7d6768b86068e6..1ba752b2dc6ddbb0a74cf8d9b6267c158122851e 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 20caaaba4a047b52f297f599bd316eba49f5fd67..5a48f171204ca7f02bba7676441cdbeac0359a1e 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 1efcce97b4a75207db340256b39a1cd2f4efea52..22d0631de009434dcdde73f6dba719a153dc786e 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 af805e8fd03d4ef049539f20d9764e41f379fd84..a88e64d4e9a5862c28160c9d1b7d3cd01edf0550 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 b0d082422d466ccff64c501fe8c7c1d0f4493bd0..7305ebddb5105454edc11e353db1e6a864a87ed1 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 2f38d97154373497f7dccce11fe6c6f932c93ecd..b39b5ced8a104971164e95d8132b7d6a4780a9f8 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 6454e18e2abe8c316d3320ebaa262bfc1bd6748c..411f88dd440254293204de7a2023c777f4d11ec9 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 813cfb366c1830bd3fc5e0df3ff1328931cd921d..9ad4c656c9bdf91bdfaf5492bad7ad5d43407a73 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 e648ea3429beb816fd5785cbe23184380efd0ba8..7c4b30b34952ddb058df0621bcd73b940e5574db 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 5c7a87260fab2cc41751905e25cec040096a5370..9cba68cfa51a0bf93b46ed2faebc01ccaea19262 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 0e2dc26ebe66396a0ed0cd93c74c290b30f18fb8..37207d1bf44b664c3a679bf14f906e38f4756bb0 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 a350cc6bfe6a657f7247e1b2b5ffb6b3737a1734..7b63462b349d7de9965b13bec7c1c85e57c25fcd 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 ccedde1371c359095c8fa9a326eb8f6276eb7ccc..ae890caa17a7a1f246d33f90a9d05085d05b02eb 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 439323b3b0ed9a3fbf77435044233c3b35b60c15..a288d7033950692f3ca05fee0501b3b091eb676b 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 583a0610bd0014fcffda1e6314403157cd1883a3..2f136c30a9896031168b027231203ae1dc5d0c3c 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 b42ee62c4d77b0ca2667cf127d47ae7f0a54db37..c75c9fcede58fb95d9fcd68cb7220edf39880948 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 d1efbdc1e6dc659e72674ad8b32428eb694bf811..cb08cc561da56cc53b8b32b3db4c804e3f808f3f 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 bd481f04276f7b18b0d5e5771e98f708ccf9c496..35a31ccacc32ac04c847ae13e9ee6a573e03fc31 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 af3b12e3b464bbe94057edcb19aaabc679b80e5b..d3358155bf8ab2fa77a58e211eed5b7990acfaa9 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 aebd4bb0ad01549971eac51f85f9c17c437214b0..70158273c6dd617cdf60f0ef3ca9b23f8d2cd253 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 94a2d904bf9408552118b6238466b158058e9154..1079c2b6eb3aacc3a3655a90c1e8454a8908f25d 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 d8ee58cfa872fe29803fbfbbcd2e9844c4a67e47..564a5cc44085ea14e4a17ee27f51b86f5dc9c28f 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 e89ca19489c240a676157a9a1a55458c1e822f02..95c0f0d63db63977e1e4f64220aad77568ac1865 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 37f48342827c89bf866bd0f89cba47871dff2095..3162173fa75af192a614d0c9c114761c5f66cce2 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 c1c252cdca60702334e1f6e0abae37836c5b7462..4a5a12681be2038c908318ffc953c3ad7a9bd431 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 9d7bf5e0d0f5b19d7505700db58ceb5169ae370d..8b0c717378faa6c9596b9c4b22a4d9dea1b9da65 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 70d47dbae6db44f299879771a69729a63928aedd..5b5504143647fe23fafb93e0a7df67b9b5b7f8c3 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 a101f10bb5b11be8cf75a8b89c647ca70ec65871..721847dc68abd0ea3d5590af9e9fe09d48277363 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)
 {
        /* writing any value to SCSYSSTAT reg will reset system */
index 20e0f7c9e03ed91678324170d8039ceadeea37a3..d66605dea55a217fc10df9fda8a94f3e5b1eb9ea 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 23c2e8e5c0faaa09d81910456d4de63a96a513da..d0ee74b7cf86bc2627cc9e7ebf3bdbd7c63400cb 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 f17d9a09e8fbf115c26a1f169553d2f6034c4d45..c0225da3fb21d6cfa5c762650ec095f90936c1da 100644 (file)
@@ -392,24 +392,22 @@ ENDPROC(__turn_mmu_on)
 
 #ifdef CONFIG_SMP_ON_UP
 __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
index fd9156698ab93798244f4560f9a4983e69d12e94..60636f499cb3eafd5318413dd4c83a97949abe91 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 f3dc76fdcea8591a8855782132376aba3262442a..bec34b83495870057d686573df9bbfd69865be76 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 3c9e0c40c679196ba02766ad7949ae1d504c1bf7..30b971d65815f342069719afca2052769ac99ba9 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 2e8391307f55542fe75dccdb618c444a67df4d8b..6dde8185205f946b11a16cd4ee248e69c3256d69 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 8d2f2daba0c001f2cfdffa637cc0478d9f1c563b..e0a028161ddee89a4119014ed83420bd0a21ad4e 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 6ee19504845f3b476980e9e79307fc3735331d03..ba6009f2767789040664995803d6f691cad2574a 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 c9be6d4d83e27cfd034cd8ea8df34948d3364a8c..bfb4fb1d7382018e24b4dfb561bbf7cb6d92967d 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 47701584df35c34966511b12e1c659294c49f685..731dd33bff511ad412e5e314bc6be36771d2eded 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 ed7a61ff916a1e57f392dbedc21ff0c12101aa7b..f83fc335c613db6e3ac14e7fcf2cf15cd6af5a45 100644 (file)
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
 #include <linux/io.h>
+#include <linux/sched.h>
 
 #include <asm/system.h>
 #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 +72,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 +217,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 +250,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 +273,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 20cfbcc6c60ca08eb1c38f465adf09436a67dd81..13d7b8f145bd3979f5ffeb08cf1e28652a512fce 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 5b0c77732dfc4435303b32b22b9fd5a24a541f17..8f9a64d650ee7896f70983ad0b9f72f717cf23ab 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 00bb1fc5e0175fb433dcb564ffce78ce46f2e0ff..e906e05bb41bdaded0ce50978bb9b7996a44ca1a 100644 (file)
@@ -275,8 +275,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 e8cb32fd7f135519610c2bb35c869f921832b62a..de9ec8ddd2ae21673964c8c3cf6224c180ae3c78 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 e20b98636ab444b1d6e21b4e00ab9ab5eb980a67..58e42f76603f5638675077b36c329e30a9475212 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 51920fc7fc5256b54e7c655ef7a491961db72913..10622c914abcbf338675316fc600928bd8251c50 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 d2f15f5cfd36d1b5cbb7f227e5669c1241cdde7c..34922b2d2e3fac135de325cb39af662ab1c7296e 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 befa321c4c1399b42084067ff601ec14703d937f..81985a665cb3ee420357bb53ea19b7268e9ab3ca 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 e66687b0b9de02450a952ed78c7bedaa086c755c..c2032041d26fb5276cdeef1ae302ff39115ecff5 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 df8d2f2872c6edce5e8d72a2ac668c7f10ebe336..fae49d12bc76c26224f9e016997ee7bc8b45b1d1 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, '.');
index 9e5dc8ed51e9a0530a87361bfcd571c91a36c6f8..97feb3ab6a69e9842961a2da169be26f07c5f55a 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 8cbbeade4b8a87df8eafe3de9ce7292131947969..a4aa1920a75ca5fa499b97028f334dd72290acee 100644 (file)
@@ -398,7 +398,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 +481,7 @@ void omap_sram_idle(void)
        }
 
        if (!is_suspending())
-               release_console_sem();
+               console_unlock();
 
 console_still_active:
        /* Disable IO-PAD and IO-CHAIN wakeup */
index d5233890370cb18ecd021fdcd9313877c5dc0c7d..cf600e22bf8e723668dc9a20c893e163d6f5c76a 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 302da7403a102a7317709b0529e58201dce5458d..32e91a9c8b6b7815ea1fd71789175d53b4bd3dcd 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 4e48e786bec728f625c1359ce9c0f785cdf99b53..7b7c2683ae7bb15cad4a2d32b4eab681884a0864 100644 (file)
@@ -42,6 +42,8 @@
 
 #include "timer-gp.h"
 
+#include <plat/common.h>
+
 /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
 #define MAX_GPTIMER_ID         12
 
@@ -176,10 +178,14 @@ 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
index b4575ae9648ee7220ffb40d31359e8f12b7cecbb..7ca138a943a9d3a66cc739e55fcaa1945c5ab684 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 a22bf67f2f78ca8aada648cc2ba2a6737de9f53f..6959d13d908a1e1242abe96e8b064b859f67ca11 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 4d1b4c5c938931065166555dffa9f5b7779f7cfe..0c8f6cf3e948270f55c55b3f3f61cca77e3f8a80 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 c18a740a415957b2bcd8e4ea30d192822b501c5f..2123b96b563822abe183140aba3de1f385993d05 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,25 @@ 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);
+
+       /* 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 686b304a7708793b42084840bd900234cac82f1c..ef4613b993a2c030829aaec7975aab8498f3d742 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 7b15d21f0f68b473fc7e8d87a859effdece7670d..fb4213a4e15a66ac06ff09070ec330d9463f0787 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)
  *
  */
 
index 9aa8d68d1a9c027e5b3660235a17b5ad55cf24eb..e9731b5a73edacc54f2d0a9340ca455e84a063e5 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 720a71433be60743fe01214a4fa335322c92e71f..ddd4a1b775f030a0b7635fe666aa31d5867aae63 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,
+       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 };
 
@@ -268,7 +276,9 @@ enum { MSTP001,
 static struct clk mstp_clks[MSTP_NR] = {
        [MSTP001] = MSTP(&div4_clks[DIV4_HP], SMSTPCR0, 1, 0), /* IIC2 */
        [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 +289,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 +299,25 @@ 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_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_lcdc_fb.0", &mstp_clks[MSTP100]), /* LCDC0 */
        CLKDEV_DEV_ID("sh_tmu.0", &mstp_clks[MSTP125]), /* TMU00 */
        CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP125]), /* TMU01 */
        CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* I2C0 */
+       CLKDEV_DEV_ID("sh-mipi-dsi.0", &mstp_clks[MSTP118]), /* DSITX */
        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 +328,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 f78a1ead71a5e3a8ce8d8b8a4229aaaca52ddc36..ca5f9d17b39abd6cb1f92ce2d33c09bf5f9e86b8 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 322d8d57cbcf754b09d15762bf7b0a947394c5d9..5d0e1503ece66fb9385f3ffc80abb88e60d2ed27 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 bd066206e110301dccfe6e13c1a24c3749b662fb..ad80488015136135443e3b1d59664b96a67b4fc6 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 d7723955dac7486519618d3e2c3715267eee667d..a217f68ba57c6c790d24f4f7eb3e50ddd925ec7a 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 412f5c63e65adabc23eab9bf520acaccccd7f399..66cd3f4fc8967a02a6f0462937cf4d5b640e23dc 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..66ad276
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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;
+};
+#endif
index de7dfad6f769d67d0c81bb10152b3def9beca491..17c74d21077c3663c2b466c928762be3b1ace248 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 3f7b5e9d83c51633556dca30b9fada357c49e0ba..9cdec5aa04a04bf57eb66a5bcc2c5966c3f99629 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 b1687b6abe63024daa40582b49446aa4eb3965cc..634bf1d3a311d13360c32c269fedbe81e146d3fd 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 a9ed3428a2fae616a75405c69692e38c2f3a7de4..1edae65a0e72c4cec6edea8810b8f841a4c1b46a 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 5164069ced42f0d0176369247fa40701292ea511..cddd684364dab2f6503d20132d8f5047615a2a52 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 18fe3cb195dce938ee47b3f37ac2ecd8c2f64298..b6333ae3f92aa22f8820720d5cf147089ce62efc 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 ea4644021fb9c0867c2e4ca4bd4bcb118e863f80..862dda95d61d2085c2bbc5e77b866f166b1e4ca3 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 c4b2b478b1a544e6ef768c3f3e6a3543ca37119c..85363084cc1a366f28417c9df6a7b914d7274e69 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 6b8088ec74af9ae775988a5abe33fa085bc92ce2..29b2afb4288f2bde34d42659e461791027e6e4fc 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 313b13073c540f7a5b22363dd71038ea1245da58..cd2062fe0f611e54fdb6e5528b6af24e13d3b509 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 92ecd8446ef80b6fe06c62bce45fe93a40f344bb..bc7e8ae479ee4f7f9be717cbcd38d0731773a6f9 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 0a221d48152dd6f116cb8938770d5fd0e5639968..c09577ddc3c5b1ee9c93fd07ccf160e9b6ceae33 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 c0b988ee30df44a33127a3cd33bf8204f237bf9d..db8d38a12a9aeb79522ddbbb819514ec0b6c97f0 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 864af5b68874387e088b612a86a3121351ded238..3e50d7857c2725bc05dcffaa0ffcab3212b9e10d 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 7b6a3370dbe23d573eb6080d3e815fb21530e747..362f59dd522860ad5085a16e25a4484999c1fbe0 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 4faa6b46a352d665a266f57f83d1fb226fa7e83f..023ff0df2692c2d2146908fe9d1ce391b83141c8 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 9d893eb68243d28cad56767b8e6733efd35a69fa..4e5a121b3c563b9a9b42479c6164614e9e67bd3f 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 97a2767c80f8ea8239eb987409133b9e345ba97f..cd0636bb24a0904d0d0ddcc3da12752f3830f8e9 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 f84774360c5bb17316a99365930eaf0df275a0c0..9f8fc84e4ac949be9b8c3b1105626bb5d8b5b3c6 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 0e7262c04cc2fe5ccf567d92826239d6304b1949..ccc432b722a0746681945133699484ec89b31615 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 4d14a002e7bd721d146ee0e18a5a94733b317a2b..566695472a8486148ca1d230aa59567a770a6ba6 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 fbee9d776f564b46aaca9ccb2337afca07b18c19..ac22124ccb6cc0515c9ac31317f32f25e04e6e90 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 05dd11db2f7d6b4809db3198b3d033833fbff992..944404b6ff08ad723cce862bb22815be4bb1b555 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 bcb14d1c56647639bca47adff02bce380c341038..b7c8451f26ac31e8d53813f840db601753dfff1f 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 4cf451024fd80eef5bef770e6f7b0c43c24eb79e..7e67ba31e9919655eb833e259ed970bd707b3e81 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 843aaa54a9e3c241a510d3934575ac180a5a8e84..141e5933e1aaf7f2be33a4617f43e7257288320e 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 dae7adf3b2a2ae731d003e0a049eacbc7cd61af4..97ebe09a7370eb3c58ea3ed1b721d7168563d1a4 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 f3414244bfed479a6ef5a000bedaeae42d60a1ab..c2457543e58c69fb6dc17ae093ac0e6e291aecc9 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 8c7e08f173d446084a28d1084193f772d5d873ee..baf1c1573e5ee4a9f51bf1af88399e22739e9dd4 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 bd3cb766d07803e0ebd6b0af2c2c26d7459c8b48..707cbf8a25903b008b306616405255f5100c8f26 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 82224f37c04e4d49a5ee4728b58b4ef505681a3f..4596935eadacc3e1f420a68188ea74cd1f17e8f3 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 433598c6e7736d7b7ede1eaf19dd4c768238c987..df267588efec99e8a9394b658c1f5a8e01435287 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 ded7d845cb399aa3bd1feaff7119c960497a4ba3..6c7b21585a43d33032b43ee9421186245122d5df 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 0ebc7d9aa426a75d14d0ab96fa950ce5a79e2b77..f50313657f3ebda037d9e92648f9cd65f7e4066a 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 700fb701c121affa69c937ae5376df45ff60808e..7450127b6455fef2dc6073aab34b069e482960be 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 b40156d217e376ff5a1584a6f36f0fef9f3f6373..5e797cf72043f757be28f019a62a1ed669688e9f 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 be866d95ed760a3054de1de9889566e69fd2a442..a566a2fe6b9b7478176629d37a9786dc5b2547ab 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 b64bdf759b82c19fdb5fdcebde86b836d3377d2f..853809510ee9059ae739dd116c95aa0f6d52ecc6 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 1bccd9a50986e2f359d1151e673df809194b6794..d496ae9a39b0c9f1f2c0339e124fc52f4721b2d5 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 00ce899e9e5d367b947164dc91e3c2815051a116..65f642167a50351bf95fa68e4481465ebf76efc2 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 613e62831c554e76e6e0c3bf852b6e4cba3d63bd..0a7a4c11d8b166e362cdd22ed0798d7c3bd2539f 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 a0c0df8be9c8d966f34b026a078b4f150b6c4139..7328a7cf7449b5c17f453472e828e01b101f408e 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 2ed48ae3d313cb71e086c02fb0b45f5362b9e685..0ad9db5126c7a4b6c29254e78a915012090a7bf5 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 590f72c9455dd33a3bbd9bca6b031115bed3ae47..71854d41c5a0238b16c9c6ff20c9953534ecc7c1 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 1b2853e39801f0719b8e6aaa30733bfec43c38cb..a85aabf92be59a4e7ce15b1d1cc4c680270e6d36 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 f73d38cc9c6632f2b85ae31af863b6fee7d6275e..87c7227fecb2d622001d5cbdb7509a8881ae8796 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 469f7f9d62e0805122105648e3e9b8aaef5c66c4..c346952f06dcdb4b8534a8766fab03294549e2fa 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 f6bcb039cd6d623526f8736c2cd69ad2fce93c3e..747499a1b31ef709fb42bed7f0c0acca23a07a74 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 b8ebe9e8a4936473ed47df2d22232f3473e0823a..b1b792610fdf49b9b5dd0ef2aeb60c060ba0d7a4 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 65f897d8c1e97b428f572bd4d777f3f0d9ea7aa0..6df692d1475f7ffb2549ab62929374a2daafcb54 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 342f77765f02f00ec7a71fb570ebef3874cea6d8..042425a026452c31f455755f074dd3bac833d196 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 c25dc2c2b1da7d48ae6c4dae9d7c1a6172a88687..7643d39925d68d0fb7bd37d6ed4f0c2d3a5ea426 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 e0f5b6d7f849b0d8b290e62185408c41735be849..fcf3b437a2d9a859365310bf35e0dae769db6005 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 5c291d65196be77c43e305d6d4d840dea1392612..ef4c1e442be34a4d9c3289e1b5b9d7b262617047 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 816c3ecaa2aa97866ffe4169d3b65c5f22d8acd7..a3d727ed6a1609689c1129973199d64755546ac9 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 84785686640a44ab462e94ad935a266137a05b4a..b8334163099defd3aa74fa17ed7ee042da5ae74f 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 354a964d084d04fbf9278408239f965801507c43..7c90ce2fc42b77713d7f34e0c9f3b481d8d0a468 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 9022307bd07389e93be3ebec59d11c3ab2c91365..367d07cebcd373786d9f3374d56e852235e8a2a8 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 3726068721a536c48ee358d106c179ce57be19dc..cb11384386ce194d72dcdfdae3f4c28d1d26cd6b 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 6136fad048e4db90cae6a13172142b85f839dab3..3bff779259b485179e52717d37dda19eb205fa2f 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 dce1fc7d67edf18e7d748b56d792baec8b2eb9a2..75246c9c1af82e9082baef90eabddc87e8e54b98 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 b204e2ecd0f1c6406e61b9ed4cdba737e1639228..27cefd41ac1fd5ab1c7dd8e8829bf1935fc3bd8e 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 5aa4ea9ebb10cd5c17bb41ff46c449bf23713e45..5087a510ca4fcfaefe8df4aa3eb46ed328312275 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 8494c6a276e8920b8055dcbfa5b913ae36942834..50c6f525db209ff01da71aae187ae3b9f6683aee 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 1df293bc2ab91f17419f454a04ad239239d91fbc..a3cfaaedab609d70e7c3facf7c97d4f4787d7a6c 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 7db26f1f082d097f24ffa51da083694e05f47a5a..f745c1287f3adc5dead96fd9a2379ae49d578121 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;
 }
index 402a59d7219b6f368b38b4c9425ed79fa4279539..4a693d02c1e133cc58a94bdb62acd918f8af1383 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 80b1a026795aec2b8c8dae642143b4f5424538da..2074bcc841eba775047c178a798fa399750c66ef 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 ea00c84d6b1b2bb665bf0e88cf8ed885b2f96385..cdd8c457402700fac38db075cfb279fb4bdf0f1f 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 c049376d0270064869450bb56948a4edd57c068e..9117c30ea3652386d8d56770df21839ccdf40fd2 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 882de25c6e8cc7d8f6bc9a55ef9a4c422fefcab2..b44f5ded2bbeff9fcf96a07ad6e47be6f59fdc3c 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 d11d93bf74f52bd4b14baea3e6fc3da16d83b271..19a02db7b818f50e64b79ccd8b3d5804525845a1 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 5f3402a2fbafe3c67cd549ac9c7335ff27aa3e1a..12731547e8bf3b104b87a6dfb17c8440ab3a5cb7 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 1beac7a51ed432ea386610b8b1bbe3132e04d6b7..f3cff26d6e740c983ebbe34b15b222a1adf66e68 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 b1577f741fa8c46789c4324662dcb87f6a6369ce..82a4bb51d5d85b4f6271b7f4a830f1150bea5b59 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 39478dd08e67dd8a5d34a76fecc21bc511e1f4b2..26a804e67bced56a5d447ae66d23ce40c3e3fd97 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 ae2d96e5d618eba94ed0428468ca2e9f025e983f..4203d101363cf23074e7ce0e22a6f19579bf92ba 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 28efdc33c1aeab89afde05ff5249ba5bdf2f20ac..5a484247e493ebb8b6f9be142cdcdfe0db978c92 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 a714e1aa072a0e4bf4981894ed2c00b71ce7ca6c..f51f709bbf3036f8ee7438eafe64226c1c02b043 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 2936dda938d78d057c2f8c9c7b370b4cf79cb4c6..65b131282837c93c9c1accc198815b2d67532ade 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)
index 704e7b92334c12aab0b279fe0e73d74abb7228b2..8b9dacaa0f6eaab4ff0b06718d42572a855dbdad 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 6ac2981a2cdf79caca86291c23917ce29336c220..2f5655c577affcd1d486b5b7cbd1e5f096b5780e 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 14934ff8d5c3e452f30c69bbd807ae15f77f30f0..16df72bfbd45d0d493e1ea124282315b8ee53dd4 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 5985a3b593d86d9da5bfd958b4bebd52a9056a0a..4e6ea50c7f33f75c84f916efe1d8835d189304b2 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 5a7857efb45dc1b9ccdbe0711337bdcb787c52db..f3dd74115a348de03e8caf7d70e7861f1e250e29 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 e8102018c8d4beb90fd9cba2159741467d1a4da8..bce0a20c37371dc806237ce6ea5c2d803fc0f89b 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 5c124a7ba2a717a836ba54beab71ffb492cfd5e0..618cc32691f244b8cd1da01251312e027fb2d31f 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 6ac2981a2cdf79caca86291c23917ce29336c220..2f5655c577affcd1d486b5b7cbd1e5f096b5780e 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 5f5018a71a3db9c7bf6b57bcfbdcbb3bf1883d7a..31680032053e56cd368b74eb1cfb331b15d8826b 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 ab8fbe7ad90b559e87fe966b26b95092fde355fd..b3f5eecff2a7ddd16a42aaf2d8c5579019c86c3c 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 ebc143c5368e275afd94f9e1bcbbd9b944e262e0..0249e4b7e1d34003ebfd138755aef15f42632079 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 548e6cc3bc28d59cf8eb594556f5000dfcf49ffe..f5ecc0566bc292f72b0020ac043bbfa7fd5a3300 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 f437cd1fafb8cfc84b7dd97382a7995d09278c67..5358f90b4dd2ccee0c6767a01ebbc4f238f77976 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 c78c7e7e41dfc2e8df3afd146c18f5891fd54242..6cd5a519ce5c26338b67a3f2c88238fd53aff5c6 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 927d58b2cd037d2ade5b060e90185bca10027994..22fdf2f0cc236922976f26a2281b9940589576c8 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 b806a4e32896c97dd1d9237fa5cfa588dd450f06..919005139f5a310442baf561dc6749a2326ec044 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 9749bc8758dbf95593a2201877785223728b063a..1cdff6b6327d2753b41f76e348ee0bde97cc84dc 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 502a8e9c084b4b8b5b8726cd53af32a06bbe638d..5135dc0b950aadbd325a0826c5918f8cca5bd6c4 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 3567b6f07b37c6221a53a07f65ce1c53c26ea3d4..75165dfa60c10990216691c95c2f25530b0a1fdf 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 6c4f7e9d33838dc5af7780e7343eb4336f88d343..5419adb219a84080eab0d4df2e6c20bf9eaa6b3e 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 dda158b2c8dc497ed77b30a3698fdeeeb7f1df1a..4044c9e0fb737d9962ad17178b8c05e14ffeaa9a 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 7e4fc76df53821d11892415e04ff47f6b41f9a18..c6b49938ee84d15e0fe4e12a447cca04d93e9713 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 6fe205fa7b61105f6d90f898774f449e7185ccae..1f69249b839a1286f1455e78246641823628a6bf 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 a741c55448d078bdf693338e58462e141105f5b3..b6e21c7cb6bdd533fb4a1d90e42de2751d4f7e43 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 cd32dd8c800810e14b129446f6e91627ac871b1d..798a553c9e80fb7154df4e42dcb06e1d9c7d7382 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 b15bfd1e69c820e5836f252f10e7d4047d3fd117..87d0340837aa8a03ce50bc80c2c508a3f1d2840f 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 0b60c06a943d28d4413f642cfa36770cb63f8a6a..0126e66d60cbbf92a0a59a68abbf06ada87fe599 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 63944a14b816acef585942ae6aa485959492a128..e5b73de08fc5057f82378cc8ff57221f94151db1 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 53edc134f27495f61ff0e3b3ba82abc5e34a4929..48a40aefaf58fa615985e2f41eb07b7c2dbf04d6 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 36de199f4c27790bf137cd98ed1efad9b3b687bb..d1606569b0019d735e571f6652c52816ce34c6f7 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 4b16c48b0c3647ddab040a9a43e2ddc3da6518d8..0e36abcd39ccfbdfa315965e250c453ebd2d692d 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 98f2c7736e871c19b5d9fbca65079a59e1aa7f5f..4dbf6269b3f90774a70a5ecb5496fae00e2fbeaf 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 5bea99b26fa80c938c604238ce5281e28621316b..7bbd52194fc3f847fd44e949ae660b132cd9bc58 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 6ae46bcdb20b6c399c97412d063c8db6efd458db..92a60aecad5ceaac2450ca3692fa15419a26b0f0 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 bf24e9309b9c9147a0f9a343d27efd110c6ff873..db5705e18b366564f660a4c74e201e70b34e29e3 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 6447261c61d0aa523d80ee802d60d0ff8f868589..d9f3db29ab95aa637471ec8468a02b7335eae489 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 f7033f3a5822b9914fbe9009f4338b4b7eed11b0..167c1d07b8091d03a86eef28960af143a48dccae 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 9d03b68aece83487912e44d22cab569b62195538..7270f3183bdaacf27af3e347236dfb5961a1293c 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 86bf001babe99a1049f8af64cb55effadf1f792f..9c9a123016c056eb535193be96fff1d8eee76e56 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 4925f507dc21be7472fe15ba281014c0409b8454..b5ad7387bbb0675acb4ec51e0ad8cc4e4ac9f3c2 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 efb779f8f6fe0da4f35ddaec00eed93f56814861..c16de9812920fab2630018924249c79e8f55dcf0 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 ab051458452bfffd961a5c225f4b732ea9d92118..d1142e9cd9a17169c93bda81a30180b56cd6e37f 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 814699754e0d988e042a50fdba29531dc1b5aff4..a97a42c6b2c84407df63a22a4b1581b1ddb18f56 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 1597aa1842faa4f7764090469da13eee05cbc9b1..75eb1b1f316c3e4ef54fcfe2f3af0221681edc7e 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 96f0d43cf08b7561f4d186b65fff4e0a0217b36b..dcbe2704e5edfa0cc09c98123384e7679883dd92 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 b4bfd4823458d4d8ec2e495e347afd11c7ac96a6..fa00487146f862bc20bcfdbc5cf3db9eacdd85c2 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 5a660024d22a60a2ff0be3c6f3e0bf1ecf5c1cf5..e83d6497e8b4edfb8d73983dc88c357e91055f16 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 39926a1a96b67b976617dd565493a197b1ed966f..f2925769dfa3b581923b8d7575b132e78b7c9297 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 3376bc8616cc16f32ecc46071371ce6cd1c011f6..1d1f2067f3e661674488d72ffef87b8cfbbb292b 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 6514f1bf0afb760dc7626ef490164f137e2933f7..15c66a571f99bdc4a9d2f89253e2a4068fac4464 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 f1f58e91dd80664edf5bca4f688b68fe67d751f8..3b0b6e8c85334d610099d554f5a7a72b941ffee9 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 d6457bc38c71c5abc943762ee48ca9f78d096fc7..55902d9cd0f2c4eaf1d2a839954e054ab5b30ec6 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 29acfab31516ef8e35cfaf26f38bdc66213b5174..9cba856277ff91f9fa62eadd07ce783eebf6f691 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 2b3e47653f6053c1ba69c3c0596574b477b9404c..2c0230e76d20562d8035d56c6f8749d062eef110 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 64840d717750f45af397b6d469bd972f7903a7b7..5b0463ef93893a1338b8af8643643cb7418f21f5 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 d9be37fc9cb74a156d56d08fbe8a4533b374ee37..30036b4cbeb11bed00b175103ca4b5830f89a984 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 3d25dd08907b395e7289d650986f4c24fbcbb1b7..81bfa1d4d8e3955dfb314446bde8f6c446656332 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 be697c9b23c6a077aa613fee75987fa7b17a6f9f..c415c4f0e5c24bd700016db767638cfbb817d242 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 7ec9287254d8b07a19f807aba09b44a6a2080aba..ee4b2be43c44ecb0ad11a13b7486444bd6e71821 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 a231b73b1a40d6f73a4b0e32e715a01712bb6672..44a451be359eaefc6940245a30101161e3e5a9f6 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 ab3a3dcec04d8888d720bc4c669fbd3bb1a0b714..f72d305a3f0803e4cb2788b3998ebb4f845c0efa 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 8ed41cf2b08d217a4c40ee3cf174d8cb6c7898bd..243bfa23fd5863c0d8198d61352b2c0a8db9812a 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 3f749b69ca71b732081ff166a35c1ec8cca43fc3..1fd41ec1dfb54396846832e9f42b904f65b97d68 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 83ce2f27b12a972423d8ce3f8ce4bc164d60251c..31d76261a3d5b4851066ac3059391c4760a92b9e 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 0888675c98dd6f344ba4740bfb5622790698c3d1..fed2946f73352489e15a5c0448bf6bdc717a00cc 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 f9305f30603abf8b56be9b8960aa263e5f2c7401..b647b182dacc17d6cf95fa79cee892fd8e0427bf 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 628d3e02253581b3b61e67e8e1e15e501f83a420..311ca367b62237b87bb78023f7687ef1f7d98c85 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 11bdd68e576239bffe235dc8b4b3d3a38709beed..fc770be465ff648cb6e5d33dc883e1782531613a 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 959f38ccb9a77fecae6656b41ed1e218df9bb0a5..7d69e9bf5e64b28d1129c731f39489e5758b5450 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 96deec63bcf3db53b62251cba32183f3daffbf7e..89178164af5ed19c19e6e359d86bdc5a7eadd0f2 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 d3db02f98dddf99d555aeb073d82136fbca457f8..a0bd1881081eba71d7c7326684823b7e1a41b139 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 2bbecbb4cbf9a3388749128d751503ce41595aa7..69422eb24d971db75359f589db8e286d34df7686 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 97fedceaa30bd97732d107cff0d03fc95279f11d..4182c772340bed92697e563f989aaab7f813a5d9 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 33b3c24f4edd8c9f6e1a05c69c9db4ab5a856e26..2dbb293163f5b3299d8f778ab62cd0a8009546ed 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 4613079a0ab1e3fdd7b83a0dbfb2058abdd5cdcb..ebeb4accad65508395d9fb3aea334919e43eb3fa 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 34b8c1a1e7524ee1122ee1165b2b02241b1bf00c..532ea9d93a15c8c9629134e6b56f0269e6f00350 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 651be09136fa90e9e9047ebc48a6128b6780b374..3c142ac1b344d3d9986208d3c59dce1ee971eb81 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 ded455e18339ac7348dca008f220faa78c636e3f..ff57d4828ffc3c0dfbf923f9f5e2753a3d0a44a8 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 63746a041d6b97aa6eec9fec3312b9e83ec4b547..3ed16d5c909db4d207d793b13dfbf0718959c9a2 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 f5f2a4e3e21b18736fcb730a911cb211d03dcd15..b1b7d2c5c059fcdd40e352ad260abf1f655cb79b 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 ac65b48b8ccd2dc52e91fec7efab37e0b62b100f..30a0a8e08fdd9c2436343eca79c43c2c82c1a372 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 17e4dd98eed7dc03fc5ac19eed4e2b73ab587ea8..a46942aac695184448df89b0324a75676867f5cf 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 fedd03fdf5d555bd3008735f51b8da98f9f859a4..07d77e51f1ba0637529033cce1f7f258e643a7dd 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 ebff7011282ec333c9e11c54d6e7ecf04344cd54..2ce7e9aff09e916d07fc6978ce914270d6e60f7b 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 865e93fb41fdc6e2a34473d66b6d105200beca86..18730ff9de7c887325481e40de065dfe741371de 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 8ece4c7744158515173830b1d13ff427d5e3961f..92f863ac8443dd53e77456961cf3a153e335a4b2 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 4ca9b4873c51051e2897a5f2658df31d41261a99..34c09144a6990895e1ff7e9f4a1e9d647f6919c5 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 e3b65d24207e1a857d308076881f7b2a4684f5cb..21c33faf61a2deff1ec60aacc87f069e5f5a686f 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 64cd0f3421a976a04abb94b1fb6745bef3f844b5..01cc2b1a7f9a2563c6c9409d508c70a973384ff7 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 01d03367917efd72743b624a0f5daebde6aecb1b..dfcffede16adcf56d2f4900757b582c2cceed446 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 89b2f962613700d81d874ffb5a6a09937e542157..47e399f2892ff4ebbec659430cd355585d949691 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 e3386cf6f5b70002c2ade5d898ea644c231d68a8..a6a002ed5681065a88e01819bea3d32d4c1f9081 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 9c13b9dffafa9fc916a0881b8d93e60ecf888315..6cf9d6614805bb9e53744e1c88653333a212fab1 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 f234c4d0b15ca7f35609142c63c2e274cabadd74..69b57daf402e056d0739e4ec50303f8349b78c0d 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 a4a795c807402ba799db74e74e95d8ed70847a9d..f3638ae0a627ceb6c481dae4bbc588616864548c 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 20d53a1aa7e48a24b805606fa3034954e692f3e6..6828eda02bdcfe58ff1183e655f6b1cd281b762c 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 6bd58338bf1a750b90331541bdc82a998f721016..7f7e4a8786029897df66ca0e49c64b2c6aa5065d 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 3a1f70292d9d4b213b3ad1b95de44ec85d9d3b83..959cd2cfc2756488fcbe4080a29b396653d5e8d5 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 eed42d8919e81391744b040411996697418c4b37..d2762d9dcb8e969ba84bc8d2ecae30b14c5e8bdb 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 e43ecb27dfd7a3c7a9b5bf0f4ba9e19ca2a2d580..7a7b731c57351a8564a94d88e54d06f46fc11d7b 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 c2e6ab51d335ce20746d4945df728ccdfd9bac83..c683bce4c26e9dce1392a4dd1977d0dc92c065b0 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 1d3b200659136f320b4731c40c0e317b3c2fbb24..a721cd3d793f2292fc54075c7382467b93013bcb 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 91fe73bd5ad27bea44efafd98da9e430f61b161e..a5699a1f7d0a735764a714c22a47ec219f6b01f1 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 6d300f2056042149ae4caeede2886115d10c3e66..b4da1a7e6449d2f51b052cbfce69ff60a3977766 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 b236a67e01fe1d161b07112284566ad93dd7d798..291f8221d5a6e07ec0368ef55945b4f64cab8ffc 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 001dead3cde97b9f5504c8a2f5ba9122a36ff1f6..f8b228aaa03a2726f811b2f60e14e8456a04288e 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 9dccefca00c362d4efb257dfb1cc2a48eec839be..99660c06219182bc67d6392574a0f76b26b9bf2d 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 d4b165d7d294e1442f105d6593e5ac31d9958268..10b5c4cd0e72bb393148a8d6e63aa800dc7a823d 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 89ba67274bda88e6903a7b87051052de9ee3eaee..45925d701d2a10556692fa67cc7b9e6f80394ec4 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 2ea6b405046a33668dbed34e2dcbdbbfeb73e057..f367985be6f77094a1e21538350d29def0ee3488 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 bffe3c775030bde06859cf53036acd7d0ed74a16..414eda381591dd0245c9df60845be0d7596c8125 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 fa5c9eefc9ad9f8179719d12953efc3c03d841e5..6d6463fe06fc25dc7ac17d3fac7d5d19e9ef28fa 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 385b1af37d75a839a2730af4f14942ad7de1ec74..8f7c1061891ad6b0819659ea204573faa8fbcbb4 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 222b704c1f4b86fbca398ee4a20e0402bd541a79..55e0725500dc77e050502150bc0bd45e5fc01e42 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 619702de9477b9ab73d755e2fbffa1fc570591f7..d724095530a6a7062c143194fbab45b2f94b563c 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 6bf56e83f957b17c2fc1846efa56b6c512bd235b..4b44beaa21ae22f019a7b8f0cb00f017b83f398d 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 a9a17d055766362fee26ef597094c897bc589d80..5b2b651dfb9853d3a77ef215294acb7a4f714717 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 820e32d8c42b4baa6489aec55987f977c6bf4cdf..f7fdb0318e4c108ad783534abd438c29bfb49053 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 b6db3f47af995d6393c4cb04ce2fd0750099f96c..77506b5d5a41db7408b311099f10c54c51478547 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 333a41bd2a6859415d93c582512814acb803f9aa..5d4db154bf597f5598701f79b725264eee9ad2c9 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 33db352f847e19d4fc95e990bed2b77dafadde14..ddcb9f37fa1ff771dcb1f51c52dc54f89706721e 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 f0c20dfbd4d3eeb6aec2e1ae43b1e4e05aab5be8..981abd6d4b57b31d13b31d5a0ecbaecdb18681a5 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 a883450dcdfa501a0317589ec4b1e5dc1cb6ff81..37b3d7227cddfc635d92d53e2204141e14ef3b37 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 ff95f90dc1714ca13cc3f59413b0ae0a5940cb93..3593b320c97c62962c17bb2400bec13a7084eb6d 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 8d6c90ea4783b6ebb4cd5f660e38c68b7c13a87e..de413acc34d6d09d54071812cada37aa4fb3f488 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 f53efe4a0e0cf40bb3c628f165782ea58ff0bbe3..5ea3124518fddd030460299c5a4e9319aead3652 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 432ebc28d25c2e7a94ea8cfaf263955e35bc8632..4b2441244eab820cc7ce36cf347b7cb07b40e41f 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 ce5e919d9b556b989af235b3e78d32e8cd4005eb..a360ba44b928cdf67dd3b79d1f1ac2803cc5df24 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 589e71e6dc1c54a38b374950a223a03f1413c2b6..be2829dd129f3281cab1be41b3496f672131a687 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 321fb47096d976a166c1cae4d01d13bd8e507cb1..036bfb2d18cd100237b9cf2bc6c209ca0eba29c9 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 b5e46399374eaf9d8238f9f62248b24035bb70fe..0c9c7ed7ec75ffba58f13b8dc1f278ae80a046ec 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 71145c3a64db6150b4cc39cacaa55eff34c444aa..0a92ca045641ff3f5553c3773b4d695dfa4f54d2 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 ca84c7fc24d54fc1febd78811d47d384ec7cebe8..69128740c14dcd2c693e2d5d71d713016d15da10 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 94d120ef99cfcf8fdcd34568814e55df7659d385..06f95492afc77d316bf13e631a4a063f372df939 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 2677b08199e76b3abc6dc5a64fd3f47d66110406..fceffb3cffbee43992d54fd454c1fd50691e3600 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 f9a3112e544210d68d1642fdc10da3f18f64ec82..219fd470ed22d402deae87a12ea3ca6333d29384 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 fcf0a398cd669b71282d74bcc344334f703dde31..e74d3a48370570c4dcc15351ab335ee9b7220e45 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 b9b63a609525fef6f35b57228bdd591292ad0c6d..94ebfee188db272b67f7601c1af976323cb4ef54 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 c4ed255af18b78f114e68fd8bec07255f7f40379..39518e91822f4fb2ac32bdbd753823330df1e898 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 f276c7cf555bb04a8aecced932f5db28b8d088af..2a490626015c550c9730f216fff4d09264bc40ba 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 3b9470883de552fc5023822ccd7e66e7843e45db..75f0bbf0f6e86f14b9aa9fc47160599dbbbd39c5 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 c7d68ff1a7366cf16108ccfec0ba7e12dbe8042a..6a22400f73c199385fd5e980e8137388be061bb7 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 5b1b10fd9740f7021aa261b2fdf874a3f8245384..5aac9a8bc53b2294dfbcb64df800d6aea078fdec 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 3aeb5949cfef6da423f675b4a2bb9249fd0e6bb4..99a19d1e9bf8418a671e81d71295eaae8d15ac81 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 d62c8016f4bcaf7cd603856a917dac4382a64901..c636f23f8c92194bcb0e79846ba8912f7598ad03 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 668215cae8906586fc80523cd74ef0c8d468f7d7..5c258823e694814a0c7c3e07b0391b919aa29fd9 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 63b90d477889fd042922f4fc2ca0ad7cd46f8fa6..55b54318fef68f6785c447cb1f2c0db4b714d14d 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 f9b83481b00e8780f0161f9da80554b154ed0458..9e146cdf63ded05591f572fa3b98d1b8400fafa0 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 93d7425ce6cd2e819f7f148227f3d15adb602b35..bfd634b5ada798b88e4bbacf4fe4af9ad75c4444 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 2fa05f7be4cb9977f273eee5979a24c366353eae..47133202a6253fb806728d88367432efbe12e954 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 a4353bef31c53aaac7b2e3c993cb1eebf126a291..baad8db21b61329c11755cb5b8815e8e99042471 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 49cffe003657728a9d9ec153abe4e19700b7b302..caba919f65d84530bd611e649028757a1eb9fc61 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 f87f0e15cfa725057a504446116de73781fe53d6..9c3f22c6cde14e2df4f650d130f221f9c41f4369 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 4f0c10a62b9d7bcd2551ad3665d2979fdc09ff4c..ebb2a66c99d3b9b79d8ee05f2230215259e2a659 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 d0a5b6763880108cb851e1fc0af3f708d8a521a0..8616fde0896f41ba81eb32b1c5261aed3892cfa6 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 bb8ba75b7c68dd8c4a16934416624623b49b2483..175295fbf4f35b87c0649c37d1da95a9a82799d8 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 96a7d067fbb260ce03f0d03a8163a3d755d4c08a..921a8470e18a591b70c88ad6796a08ee0c6a588c 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 4e10f508570ac38bb63b6f6fc6c9cc39861c9da7..0edb6842b13ddc461c55c961170a4f0a9eaac4b0 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 b85d8ddbb6668b77aed280e750e971c9619f5df0..b0b06d85788db98d474320736cf2df638f7fa9c5 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 8433d36619a1969a421b1cf82c543a867887905f..991d5998d6be6711a68e15ab8347b110ade13dd3 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.
@@ -247,15 +240,6 @@ struct machdep_calls {
         * claims to support kexec.
         */
        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.
-        */
-       void (*machine_kexec)(struct kimage *image);
 #endif /* CONFIG_KEXEC */
 
 #ifdef CONFIG_SUSPEND
index ff0005eec7dd0d3d3c54946bcbf51cdfdf8bb569..125fc1ad665d0fabe47288357fde12f78ad1eb87 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 667a498eaee1b6080c6907d39de1c2f9c6c58747..e68c69bf741a26b5c8e09d39fa847a1096516dd6 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 0ab8d869e3d61d83c8984c4492019e6d022e2e46..0c8b35d75232363f0fe66c7a9c6df2c6c53dcb0b 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 894e64fa481e94ca51b8c02419310a017ac2adf0..5c518ad3445c4a6e642d61a1ac24f35ee5846781 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 be5ab18b03b5e46394efbc55077b2a0d61f49a31..8d74a24c5502966373e996e54ec5eddea628dd2b 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 */
index 832c8c4db2541225ad007f5592b60ec8fe14776d..3d569e2aff18ecc3c3998ca2a6a7bf230755d66a 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 c22dc1ec1c944037d3ca347785a5be3899b978c0..56212bc0ab087c4b40bb21df3496c89849a01f06 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 df7e20c191cda3190c1396bc60921bd8c8df003f..49a170af81456ce722fa58cd70e5980370f5f70b 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,10 +83,13 @@ void arch_crash_save_vmcoreinfo(void)
  */
 void machine_kexec(struct kimage *image)
 {
-       if (ppc_md.machine_kexec)
-               ppc_md.machine_kexec(image);
-       else
-               default_machine_kexec(image);
+       int save_ftrace_enabled;
+
+       save_ftrace_enabled = __ftrace_enabled_save();
+
+       default_machine_kexec(image);
+
+       __ftrace_enabled_restore(save_ftrace_enabled);
 
        /* Fall back to normal restart if we're still alive. */
        machine_restart(NULL);
index 4dcf5f831e9d01f8694443ac7d56146b6f7a9777..b0dc8f7069cd5fb7bb41ec8b2a3bd9a046f3f57e 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 84906d3fc8607befb6e2abca027480f12120d17d..7a1d5cb76932312f7e15609fe5f84c077696eda3 100644 (file)
@@ -631,7 +631,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));
index 2b442e6c21e62b47409a35959e30d95b330e9f0f..bf5f5ce3a7bdd775b5b66ffc399426a2444aea71 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 0438f819fe6b1adf10a16c42f6b32b8b2c75d059..049dbecb5dbc7908eb991642bb629e695590341f 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 09e4dea4a85a5969d564f72a1d618a22caf20a12..09d31dbf43f990bdc29cbc7dc154349b3fda361d 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 1b2cdc8eec901fce78e21d279ca054684bec158c..bd74fac169be0e665e108b87110ee1cefb5d4718 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 cb737484c5aa2aa74f38df054143b208c4d74312..f4613118132e51235f38cd831ec3cfaf8417d680 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 661d354e4ff27d15ee97aa18f663110177ab8ca4..d0c4e15b77949a09ab29ef6d507ef86031bdcb2e 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 b54cd736a895215250fea8c2c99159a9aa0965b7..f859ead49a8d26c89b2c2aa33a0dbeb57bc0fb1e 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 0fea8811d45beb304bbf5d4163f6fd467940c521..82a434510d83d458bf242f95663df565a1cf925f 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 3ba4bb7d41bb0d8f3905d5f9123d992b47872371..2c64164722d05886cfde3e2a2da2cd9a8d8cd6d0 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 968c1c0b4d5bc9499ce80ed5bbd8bf6824341efc..d809836bcf5f36042841a256fd12436638d653bf 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 1b5749042756cc9e238431b5cb05bc69b5a5dde2..d31c594cfdf3ee68d84b7f7fa4603cc8bd7c7ab4 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 8547e86bfb42ff2650c50dea4bdb3533e647a1b6..acfaccea5f4fa4d08f36bab9efe60d24a366f554 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 02f7b113a31baf119c1528b04fdd319c156f770d..3c7c3f82d8424d67e24587cd40d2ef60f0647772 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 1106fd99627ff650ace3caa479722ff426013297..a138e14bad2e7292565bf807be59e784e1e77f89 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 649473a729b8843b251a2bbffaf26927b63ac15e..1b5dc1a2e1452abed0462c31879331514c94bdee 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 47a20cfb44864ede430b8277f05824439c267593..e5bc9f75d474c9d44718f29c14061b2e17384221 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 5d1b743dbe7e86ea662ec598d8d3f14498b3bc37..5b3da4b4ea79c4d235969c4e3b7f6ec54e2b28a6 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 53cbd53d8740537d86b7fe5ab13e19dfcdcecd75..77d38a5e2ff98b1a953088ca282b4986c1d046ec 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 a4fc6da87c2ec06355ccd8f04d6eab554bc022c4..c55d7ad9c6483f480b611a09444249f8db0b876b 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 9f99bef2adec8e1e39c8c37f6cca76fa18b06c94..8c6cab0132783634b76183d521b19ebe8d31a941 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 7c1342618a307560b187767d65ae6a6e24c4ddd0..b0c8469e5ddd76204b522464139bf0294ffd8151 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 4293fdcb53981a531d1324b528690d1d277c2a1d..27b2295f41f378e341acd86e23582fb19d80de2e 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 9883c50e463652163a5b91702882dbd343a99b6e..df1edbf507a2df28b5c78f08a5d0c8159e39e7ba 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 fff252209f635473c2ac00e17de45513b41c927f..8a9011dced149cd754fe6c0b1f0053a56a13dff0 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 9c8c6e1a2a154d4dff50db8d0d532201c5f991be..e3d8170ad00b98a8739d572fea653c22582a6953 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 33b662999fc66b68b8fbe5f1893aa5ce675e5d0c..701667acfd89e919f15202ef2161f445e15e0c93 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 1ce63624c9b9c8140a1eb9d348442b7fa2d560e8..ba515d8002457546db2e5138bbb229dbd39cb8e2 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 cfa5a087a886f5e9fa7ee5e90dd467e5003cc041..e0b0293bae63e5240e0df723b3725fbba52a7af2 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 27140a6b365d60b610c25ddc21d38e709cd4cc23..95470a472d2cf793ddad131f55805385a514e65f 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 083ea068e819e80a389d5610bc9e19243d4ed950..db85916b9e95aa8def960feff9b7b9ca1a5549f4 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 c2b0aaaedcaedd4e70249230b816db082ce734fe..672944f5b19c63031f128232345360869ff6a558 100644 (file)
@@ -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,
index 948fdb65693384826b77dbc6024a93bcb88246bd..38e862852dd0ce3fbcd10e9291c09fd35e6699d4 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 45d9c87d083ad89343b7c7862c5b62a911f86c2f..95695e97703e8727f5b82367781a03b2c861d532 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 e11b5fcb70ebe07d0bf7fd677a9c61943728d169..08948e4e1503fd64524437a9ef3fdf3dde0b5724 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 a81f0fbf7e602ff12ede15e42e8f7ba869ffded1..9bc161a02c71ba65ef8e1394cb1617738533bd9e 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 919c54afd98112c80760c4ec54799a4beb18a48f..0fe54445fda51ed21f14c73b47aef7e0000b4099 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 049d048b070d7ed5d2d7db2ddd9464a91f02626a..e351e14b433909e6b83e36bba70d86bf04918c3b 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 f8d1d0d47fe6b1a05c67f48e85051f4c50f6c13c..90a438acbfafcf00aa8281f03ca44228250189e4 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 564f3de65b4ae129675fc82c56feebb635fc9279..9f7634f08cf3da9c76419ec9e9296a04e0cfcd7d 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 3ed5ad92b029a09bb6c30823ae3472c14107e831..d5ed94d30aadf056130464e5184461654c99ad8a 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 15588a0ef4663054dc33d623e373f8edce90432a..283c5a6a03a6536d5b171830d0474ecc9849aff0 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 45143bbcfe5e487d53e33bddaa7193ab68a5275e..615e18810f4856e500b7964ffbfe82c78a843b20 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 63e35ec9075ca4ff6b813d946463655d905a5c60..62f084478f7e08448050cac33152f8f62bed8b72 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 4fab24de26b18404069994b908c79d3e4e481c50..6e6e7558e702cbdeb56a5fb7c5e048cb82f15e9b 100644 (file)
@@ -32,5 +32,6 @@ extern void arch_unregister_cpu(int);
 
 DECLARE_PER_CPU(int, cpu_state);
 
+int __cpuinit mwait_usable(const struct cpuinfo_x86 *);
 
 #endif /* _ASM_X86_CPU_H */
index f52d42e805853ea09532a86aca6290410bb2d83b..574dbc22893a9301914def19c5004b9ec1b851fe 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 a37229011b56bc5c013610e85cb3a597d2b7a8ff..b0ef2b449a9d6cb360c65104c6a207f4bdad505a 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 5ae87285a502418f32cebb3f0fc08264ca1060ba..0493be39607cfac8dd2dad1715aa3d06832a1fa5 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 2071a8b2b32f2fb35a40637f4cf4aa14db7dc35b..ebbc4d8ab1709e9427394f793af878cdd5cf9e66 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 8ee45167e8176d4a73814732428fad90f76c2966..7e172955ee57cf9b410d77cddda53c6c5daf6f12 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 */
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 7283e98deaae14ca8f712acf3759f11cf7e9fc2b..ec2c19a7b8efe4cc366ac709072460f0023ef296 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 e12246ff5aa6d2683ae8537a92da76e479a26bf7..6f8c5e9da97f0f3e4c0ac89557a3b2f1c3a5f01e 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 64101335de19aad09ec03d75dea8260b28051747..a6b6fcf7f0aee9665e00fc2ed8d8d9290fc0423a 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 d8286ed54ffaba86a0882baae443cd9d267b5a30..e764fc05d700365246d4e77f52a406bbfe1c7d22 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>
@@ -505,7 +506,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 __cpuinit mwait_usable(const struct cpuinfo_x86 *c)
 {
        u32 eax, ebx, ecx, edx;
 
index 763df77343dd99db4300a74304013ea685310f55..0cbe8c0b35edd290e98c989cfc48c5b4b0af350a 100644 (file)
@@ -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 b34ab80fddd5988fbf653d40ea457af003fc05e9..bf4700755184e32d4b4e549bd19f4014caa46468 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 38718041efc34fbf6d8f120fe90e26b6d37abbaa..6e121a2a49e1b672fc8c191ae8c7ee40733076d0 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 4996cf5f73a07db446c2fe3e1c9fe7070662b741..eba687f0cc0cee1d630c6630e539d78f7b478836 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 787c52ca49c3cf54dcb7cdc5712275d586460252..ebf6d7887a38fa54481b6b7645e42bb7c59499a7 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 1e72102e80c93348b9aaed53874b02546b03e624..95ea1551eebca344bee38ebc160ba8f3057c1734 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 f16434568a51da26ea8524ae11fa84f0c7405717..ae96e7b8051d0c46e786e0ef80581ae331c3f01a 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 7e8d3bc80af6969b5ae5e1a35ab15463000fd7eb..50542efe45fbbc9313e8d66670d99ce573d682a6 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 9d30105a0c4a8e79bfb4020e57645720a6d1ef5b..6a6fe8939645f948e248cbaf21933675899b5c62 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 8f2251d2a3f805b1f0128782e74260d7a3082545..fd12d7ce7ff93265ed620ac9ef96db2c676a6c94 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 b5a7f928234b064b34a0b9d2c8d2f9d869e7c635..a8a66a50d446342128776bfae67b27a5b97dd6f4 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 1d230ee081b40c66668507e06aa0f527d5893e33..b90038e40dd377b60c1f7c82a23eac923d9860ec 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 7368164843b9d6596fd8fe9909d0fbf810e9afb0..0234cd198c547d7d604f82131f3c712c3eab4f40 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 bb84fbc9921f903028bc475a73c3ade4df128581..095cd8084164506314f50d7b54dfdd54e33c9f34 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 6c9213ef15a1d69e83b381f88ce76d0d915eac02..60be1e0455daddb636998a03eb6d47e60d1eae81 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 7eb35f479461eb13e6f9578de8bb1184742f004b..b423bb16c3a8d1b7ea1d82e3c6d9f1238590e24c 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 10c7ad59c0e1bac4df5abb550feafe323b6da2e1..2aa042a5da6d06c05e29de99419e0322c77414a6 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 3e50c74ed4a1e5b3c5880d15f7b4025f3e5041af..e0ba17f0a7c89acc590ab487e5c51c1360697579 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 b17d8de9f6ffd5c98b7f02f610c8bc0ce1248ace..ab87396c2c07452c2f6b8485591103a6280d9b10 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 72e9d5eb083cf09c3b9d0c55850f9c362b175fa0..eb0b1f8dee6dca011b447504b7654ca5243b3f63 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 894a0ff2a94681e9653cf95659cf19823444e2d2..666271b65418b4d0be228a3009e8c4913043b54e 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 70e0b28801aa0bffc0ceafb7d1defa576eda9111..41d247daf461bd63a8b6abe6e1974106d57b334b 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 0e4dba0d0325329da4c4ebb508c4978c1094190f..82a1bd283db84208080aeb657ebe22ec869e78c7 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 258d628793eae2476cab0a7f9f8ec2ab5d53f651..e7213beaafc7914322f72520d40bcfd437b4ea5b 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 049e203bd62196e46d81cab6ab66c776479f5f70..3731e1c34b83b5d75ab25f08d0eefb706d7f85bc 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 74000f5b7daba14c0f1f3e364d02bf3694b7a020..54784bb42ceca0386be233e0f2653867d5c7bf90 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 8d5c9e0a495f8ab231101e051f824f52e7d5480a..b7491ee1fba642447242705c5a7ba48c677cce94 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 d44d3bc5b847363959fcf64e8d1751916d001c83..79a598c67fe3ad30ae599aacaefa2f776b6d0303 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 962a3ccff6fda012e10bfa9d6eed9adc7b2e4439..1055769f2f01ae97f4f69780fd93b1015512d870 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 8c15ff43f42b34ae639e51234ae2a2df8be187d1..bb2ccfad7376548569f99ed46653c4ee710f958e 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 d0bb0fd3e57a8d6015784598e4c262e1dc33c3d5..5ea1e06afa20637b652f87cbe9ee60b91fb62023 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 10998d369ad08d027a6f61e8315597e223dbb561..94e73c97cf85a83eaf6be8ceae3c347abb68f40e 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 528bcbaf4ce76180dc434d9ea2e3714794d79686..f08b55b7f3a08f5dff5209ad52268e78b59cacc6 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 6e5dd97949fee3de2aa09bd6011a856d7d44e4d8..1623b245dde23b226ae70d1c8233e89425b507d2 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 62a576e3436137f3ae9abfae82b4ed97615af4a9..967f08124eba46ae53684bfd0347ca5da14f740f 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 72e4183c193777add40ddff637eaa87806330296..99c140d8e348b38c364c94352af16c86de7b164d 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 1f484ba228fc0c63e47402175dd7a9225e062c4a..f4f0998d3967ef86511de9b06adf37b6dcaa990f 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 0e5798fcbb19d794d6766aa5c097907ddbfc4f75..59122cde247c2042e1121e6f33926eba1ec61cc1 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 347bee1726f1add50d50486634c7b46a957307d7..34be60c0e4484b880f6bf2da883e7ba1e7311ecd 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 cc4a38c5755824f758a51e466c033c2b3440dd8a..a7718bf2b9a18a24e0bdee7554736caa07976c2b 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 d94dd8974b55c5fb03845a52f64ec430c70a6ec1..5d797751e205b363a48e43b6484e2a9cc37fc317 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 8095306fcd8c6d3ee246a44f9a41306e37e7fa9f..905ce29a92e1784c82430c64e527d536e1c7f579 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 8e85f54a8e0ef396ed6d045f84a6f86587e34af0..f42e17e5c252cc98331da46b45270090b093195c 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 7c0e742271712a95ec20ff24a8e3d794442aa91a..bbecf293aeebfcd8729a2d9b43404e187af7c17b 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 15135c25aa9bc38e2e83f0ad70e0310c0d519381..2c477ce172fad15d44218da1cc66e3377822590e 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 6b0b5d08d97acf12d35016c96ce0eaaaa0126627..fe40e4c6554f2554310e055cfd96a289c1bf0d89 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 140a9d0029599f9103751efce5821368c73cb3b8..52566ff5e9034bfbb91e06c9132bea52ec91ef8c 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 d1e701709dac36b71afd0a1c68b2c936da27acfb..76a661fc1e0933cfa84aba0a6d90a449ac1e5da1 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 83155dd8671e739c7eeadaab9911b0404cc201df..a6c374ef9914e8bb57ad092498ba55feef512145 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 e5e313c663a57190a03edfdb2e43db6d1302e6f0..d458b041e6510aec0c91cd4b20c0080147975524 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 7c339d34ab422dffe32028cb284513910390ddf3..14988a86066fb70eaf9985cc49fbe1ff5b99ab4c 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
@@ -471,6 +471,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 +479,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;
        }
 
index 9acb86958c099c0bd84703f6179528a63b90fcfd..ca2c41a5331177707e46bf7b0d4f9407e8a24478 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 c59dc23405939b04492b897286202258933756a3..ce9aa9f9a9724e818d5d6e6fe568e35a3bf9d39c 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 10e477494dcf5fdedf4bd7ad787cdfc77587d1b4..80a81d0c4a80d36049aceac84b78ead5dffe0481 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 38bba66fcce554a62ed63b3f5afd76d7d18186ba..7dc80946f7bd3c0f10a09fb35b38d44f3f23d651 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 98fd210e87b28a31acb9e2cacf1014fa2d03796f..785a5ee64585eaad3c6a7f7101e475452d42467d 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 0b47a6dc92902f5333d3fc668597992a2bee24a1..9659cee6093e3f835caf4a082680d95f12bca97d 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 8dfbaa96e422ad3f4760133b504c40d90704ebd0..2ebd40e1a3ef947ff7672afde21c6f211d33ae00 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 1226689bdb1b7bd2890ccf02c91a20ed2343463b..e1141402dbed1868e4e473e21fe0bf09b8521daf 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 90488c1e0f3dc475d949dc578c6275e925726dc9..c57b5c707a777647199012484e3bff977aff180b 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 416845bc9c1fc3691ea67af29662d1a1ae9c5d5e..e9562a7cb2f91e4ba9a53a51342e3711c6c3a2b1 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 ce9314f79451ecf5a42e02486475a9bfeca54987..eb7386763712367d1814cecf1151f4acbd6e983b 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 18832205b631b4514941490f86adb308914dc10e..745a42b401f5030bc88b11b1b89aa2b21a455b14 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 b73bc50c5b76f1d5309be80c310383bc425d5e0f..74162a11817dc9b6bff8e30ba2d039a7c1ec47a9 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 3c61b48c73f5512341a875fe023fe6df4698850d..e7b372d176671e02383788e31f8a3490aa1debc9 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 be8c98b480d7ad9f542dd1b0af83e7ae1f8956c3..c7a2f1edd28276389d0a61bc5674ea6ee7e89b5d 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 f067bbb0d961f49c2ae75ea1c0d7e1b1b530d002..61b8c0e8b74d1b5bc115addeb1d04da535401b03 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 f17d2ff0031bc8933822698a60392b50f621bf11..0bde2230c028ed0f0cc28689e98eacccd7a9bd8b 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 38293fd3e088bd008fd5f9855ff72b15766bdb35..6c79c29f082df60156a83560de03a04f3bacbc60 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 95db4be0877baeb2acd0a664ecdf46cc38ffeb68..703d88ed0b3df53dbcfede8511ee95e83d7658d4 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 6af14e43f8394be3f6657994eb42eda9e92fd067..be1c56ead6535e68b5b73bb22a3a9451506f840d 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 d11e539ef76377c57a9b923bcb5338f3cce97180..49ec049c157e6b4e86e0d9b1de72f60fe9452b40 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 84e4d185aa255f16857f5942333cfd564dd8d3f7..236ead14b7f7a2c84f4b381bad84b468f2119456 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 10e104cf0fb9b6710af8132ef9cdc017bd235a0f..2571b4a310f4bd31119f506a6441877886c1390b 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 7a08d23befcd477fbff77dfc47cde724ac4f606a..1b48d9d28c9ae055b92e53a06302ae66a079b08f 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 4b50730cf9a0526c4ac6f4047376a7976a0081fc..f4a2787e8e92b1c178dbbf85b97e2c7218f2054f 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 7aae29f73d3f2dfbc5438ff874e05a7ff7855f5d..cc95e2000406c3a7a6ff6a9bf63b27752ce008fa 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 de17e10da0ed9c5593e3e1d1af8bfd0d9dd81ee4..f0d5e14f1f2c0040ff84c18a9a0dbaa6e73bcbed 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 1fa4289a687e6f7202ae27c164342ca0bc198048..55997e46948bfed2843f4a603f3871223b8abb4a 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 7ca35ea8acea8affed084ca06e11212b9e1ff22c..db502cd7d9349c2e1b6617319023d3d9f1ed3a5a 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 8c97cfd6a0fdc7bd099113766f9d5ddddf1c7389..e3bb00ccdff5982338d5e422e3c4aa643523de1c 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 1624436ba4c5edbdd9d171272df4585f08407ee0..c0c8842dd344b088649c3bc041d2df787f645ba5 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 d4af684620ca9e8307785518d49b793fb059c560..a979017d56b8e5cf23e7672574ed66f83c7b4a79 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 e972b667b09b8c7b4874f80032ecd90e6526b128..dc665cc554de762c455f801f57d1e03673c85e9d 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 675aaa91a770f2a78d3e0f9e9ae134ccf95ae446..df66e7b686bec836ae4fb2e13e64ac0f21756473 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 4093522eed45692012b5da617c57187ef20c4458..8ad93146dd3282a984918a1a9b6a4b57b4e5ed41 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 b44274a0b62c66fc0326d8f7b29b60ecee2ec384..fc380d3d45ab0f01ca413b7c6795532d65e45ca3 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 85c3cbd4304dedc9e63c4bd5854da2993edd3584..f610d88a66be86b823f6ceed6abd7e2876c3a81e 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 ad21c7d8bf4fcb4b20cf379c3df7c8c67efc7f48..050fd227951b6835d3be95bfa828fbae7951a3d5 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 5d1273b660ae4f21d7fc9b2e2e56ecf392504ea7..55accb7018bb24776f32541fddfe7cf7498383f8 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 3796811276ac51e73104ff1baed329225dfd6ee8..2ac28bbe8827822f975755b3b7dd7cabab0882a3 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 1ef8e0bb250bd0dccbedd533e4229fedcb739086..9c8eb71a12fb41f8a09e9ac4e48a1b95daa68452 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 e1d9c777b213a3f70b90e8a20f9dd5868a425c29..5f1605874655a2f425aa0c0abd79befcb9684a3c 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 50cc3be77724ce53eb3f611401f08bbe3b3a59b3..6f98d210e71c4f23ae4b3ccd01b84cc2574b2221 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 0cd925be5fc1383aa3ec0ca06b60895cff52443c..d93172fd15a8cfb38f7102cb799527a0f5a4b2ff 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 1e5ff803d9ad14ba678ba06fc4c28984995112eb..1d0ef15d158ff72779f32c814238130f13954425 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 a54dc39e304b2e2a0c34835aca4464b17032d251..b683cc2ff9d3cc15d0acd687f11a8d70bbcf17b3 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 d2a97921e249e87472966c2981fb9af12ef698dd..2ed294b7a4db9c401d094071c6c104d0c7b974a4 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 f52829cc294b2fd8abc5d45114ccceea4ab233be..c1bd02b1a058746f820988639baecb4ed73fc2b8 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 0cac7ec0d2ece0764806fae7a11994da0520ab23..fd7c6380e2941b9cf61500ace2d3a6021b80affe 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 df18be94fefe9e6753c6050b1964ee851298f7b1..5f7dc691c1838e0ea65d8d78ba5417e1a056c5ad 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 d3104af57e13b17f4a40f9bc769cc3da8ca5f101..d5fa520c3de5cb026ec5a4b4c09ff7a410da5552 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 41a9213dd5af638fb7dd179d86e9b56f4a1ce9fe..3bb8bf105ea2abb151f4e862db5d00339a9972a0 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 5808c89e9fac1638d26a240a42482baf72c8f7e8..b3234fa795b8591f62db87c30051c144ec250ee2 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 7096bcda0c723b2317affede650241fcbada6e9c..9fb03fa8ffde39b253a88cfe52359972491c70b4 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 d1c136692667b8d22ffb791be03b6a8d7274f184..1d76ac85b5e79fdd9c1c41573a92ddf78686aeab 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 4ef9f43ea9262273ed06686eae439b9675f5d10d..973883babee1fa3a98718c43b3903de75a9ec83e 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 41102a84272ffd0021f54e9541f14505dbe7b085..28b0d7a62b9976c5cf04e1043f5293f81f8189f0 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 a7d6ad9c111b6b71fe52f4d5870e0b620efaf356..cb1b104a69a20211804e8c5124f07c8d6c9ea9b9 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 2cd5be8fe10f40c547cea2ccb9190f509114ddd8..345f0c3c6ad2a336a1e8982a318ec2ca7742ce7a 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 ebef8a7fd7071f3c05c0e486e65552d5f007bf70..c53f0040e49016b041b364c8366ca8568d953a08 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 b01e45a415e3e44a0f40d69c87a95555ac37554a..3fd4526f3dba0f4de2d35f76c9c3c435ea64d1e4 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 a1f04e9b8030edc75ed951d5b2865ee3cab537cf..db7660f8b869a14789a8ae0e8d103fc6635c992f 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 7df1a4c952748bbac402c9d0392ccd4aa2bc10d1..e1fad0ee0136760806f8e3dcf1e1cb76b1509e7a 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 2f2e7760938cae09ca2f7092229855042454ce1c..01dd70d1de514eb8e8a03dfbc94995e35a6f90e3 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 2b0c3be2b1b886dc07a36ddd4e05a730a57d5b1c..bed08de7528c20e1762a8c989e89fece2a368bdf 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 8d81542194d457424d97afc5ed3fd1755a970cf9..9bb0cbd37b5e678d462702d909d7a165396f2342 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 40e2b279ea1281d0fa1e206238d2b1379ec5d403..a5faa1323a0290f77676419a07ccc05eed2313e5 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 d4b970c3630badddb8ea5992cd374b8ffc2379b0..f1464c03aa427865f4601cd01d58712ce7024b39 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 fe29eee5adb1560686e72db794b1986805c1793b..7eda78503422b7d651b046c2b05a76ac895d1fb0 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 8abb9629443df0f6cf8f769284b5684f6c89ddcd..3312d6368bf15bba6e193b14e2d3c47cf01dd804 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 c42f067cff9dfc811f611c07dd7af4c04ad197b9..8086805d44946ba73f0f2819271d2077d3755721 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 226c806ae98681be6a1a47a63fd742eab9f6f42e..9e66f90784269243cb5e30f815b50f299c16ccf9 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 d6ebf7ec622d6e8d46d9ddb5536fa7047494d90a..3a8a89ec2ca4195d14a90b620918f6f4aa9cd881 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 c80a2eea3a0189ba49a19ed0ea2380fbb5bc924a..4ce6e1147e807993cccc251af32632d0eabca6e8 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 f859b0386fe462d372b45a74a4159f02106e7489..33db7520c74be0c2937b837b31512dcec49fde58 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 1fd868b964fd2e7891ec8e358d5b37003cc68884..f9ea60872aa4ddad8cf1cd77c20a61a0ec7c0b41 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 33bff17c0bbce1900fd693267df986e6f3d653b2..0c7efef008bed3c2bcd652fae16bf9d0ae80ca29 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 545da40d7fa76cc56dea27e3963050026aaa12f5..50b8ad21116736185832c802d63529bbfa9532cd 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 7335f22aac2003efa96ddff143e05bb6cb4b1528..1bfcef736c5079695dd871d4490ae34bb612600b 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 887b8ba8c432e9e7d4771bd0343856952e415b55..7cc6d8625f1e66d488b3e8c0da0c885e2483db42 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 f8cd9e87d987aad52385ae15636eee43fced894d..410264b22a296011108454e353b21dbaaf646b2c 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 491191e6cf692bffe1811a22674a0eb0720c3771..231811e569399c5b75d2b7ba55be22bf82edbdbb 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 9f6a6e7e1c8e59a946624804ecd2354fd5a9c289..2ff657a28f26d3f8132c4e362b635bd198a3a1e9 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 d2ff4325c4270a6c34e063bccfdf020175ae72b6..428d44e2d162402d8f9d5bb3c9c6542e40e193b2 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 989d5c8678641c2bed8543a4200cac96c6bd4455..a55cb2bb5abbfdee7b448ced5baf23bb37c68a4a 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 83d7af8d0905a927a4316df20ce50aefe8af7c92..48db0944ce4a00e1256b4f888b4497e2ee584d2e 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 34f9c2bc5e1f917faf5666bb6a630953535cc9ca..0f2d395feabadb20e8ce47d88f53ff8d786e2427 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 4a8b9e6ea57a1fa73a670a7b1d06cdc4214a168a..4b7085dfc683bdef506be4fa62d0f29ae8af0465 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 fd2c07d1d3ac3bbba9a7c71128661887f5caf77a..7eb6c6cc1edf76000d8842edc6a1a36bf261a43b 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 8f0896281567525a3b67ab484a73c20383759a0a..0a697351cf6974474852370b843880ee3872ab7d 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 6fef83f04bcd01c8cad30b4481ab2ebc6e04ca08..aded299a2fa842210a7ee9c616ff321573f8c5c4 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 f21c486929a54a96fcf8bbcf5a6d34049b00bbf5..a9bcd816dc298f7fbc1be186080915ade6410766 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 ed794cd033eaf34417c5cf54d0ab27251ce38ef1..31f5a7832ef135e94659179fbec6a927098b5fa3 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 22f59ef604e06b840f95c0d16ffa048614091071..18f73c9d10bce26a71a469569a868c72bc75fabd 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 508537f884acb05c80245e6ac3beb6d9fc127e38..97dd9bbf055ace4b895b0a84bfb2b2b695a55679 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 d2906328535df5903b887ae3c744473e27061e64..b679ea693545db6fd16703268c9cbd6354cecfcd 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 c1b1c803ea9b62f8072a4af3d6ea8c8342aa1a91..191b6828cce99d300a20fd01d559b21628a0189c 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 b081cd46a15f83f5f3eaf114b2b10c52accdf496..f6bb75c6faf5ea4a653569e9653e3094a07b7056 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 49cf7b7fd816ca8b453b7f6c2e6b736d98b611a3..ce481da9bb451858da374fdee0e5f271196ab335 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 c7d0e05ef5a4ebccdf6586249136b0b4ac5c6ca9..c33a852d4f42a5d9b9113840bcd918680a3836b8 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 199528ff7f1d2edde7b17d832940117b33449a16..a946c689f03b164b5ab7131fe6506a6958553801 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 fd1fa2749ea50df81666681d6fa5c71f87c0560d..188340a017b4036422e900ccac69d44f44754780 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 18c59a85fdca95470ed9a6700ffd7027623d0477..1fb10cb8f11dfdaa660c0bf4ee9095a79986bd55 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 7965919000b1755d078ccb876c143ca2e54c24f0..84e0518442476ff1b49ad5f5a9ba30c52dcc505d 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 d35d109b8da22461b479fb3e849a4750dc25f9f1..30c21e1a9360c79adad9516dbd12787f9e892bd8 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 1f484c9a6888934bd82949a86e93339c033a13a1..98ad125e14ffc15fe2914eb249202d459bb342c4 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 6f12e314fbae86bf9e01f24d3f845dbf287cb851..916ae097c43c9ef99b4d44c41939d0c0d4d6301c 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 68bc227e7c4cc45b80e74e7f354826e6788ec6ad..ac1a599f5147640cc58135391260f0f202a411b1 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 54b6ab8040a6ed05039ce59d576969371e7fa3f8..fa5a1df42b79a40a817d27f036789d7bcd3a3c38 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 e2dd6de5d50c8dbd01246416a59f26dcda51c954..b0931818cf98f133bf000f49e7200c8bbd9611fb 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;
@@ -642,7 +644,7 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
        virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
        rcu_read_unlock();
        if (!virt_addr) {
-               virt_addr = ioremap_cache(phys_addr, size);
+               virt_addr = acpi_os_ioremap(phys_addr, size);
                unmap = 1;
        }
        if (!value)
@@ -678,7 +680,7 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
        virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
        rcu_read_unlock();
        if (!virt_addr) {
-               virt_addr = ioremap_cache(phys_addr, size);
+               virt_addr = acpi_os_ioremap(phys_addr, size);
                unmap = 1;
        }
 
index fdd3aeeb6defd06e1103a368e9bfd79bf837b364..d6a8cd14de2e824ddb15563aa625fa1d5236ea5a 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 c6b298d4c136c54a40fa7b4e4c13361000535642..c2328aed08361c0e8a8caf97666935f17c953a0c 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 328826381a2dc38def47aba259e78da11b24b5b0..b8d96ce37fc99798af81a27a2604f890cf6c4518 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 a31fe96f7de670927dd0a10f7c1abc74a89a03e6..d4e52e2148593e9fddde5884586683fc5ab14242 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 5defc74973d751a6283b10ac40bc29f257abbedd..600f6353ecf8743f608260b268a5a58c6442789e 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 d7e57db36bc835d83c11bcfb7aea1757cf46844e..538ec38ba995d92b8516699de5e68dcf7fbe736c 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 efdd18bc8663588d5db55942bea138fa353b6df6..4c5b5183225e04f244ca3638afe2d964d722f03a 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 d2239bbdb798faba32b70f2a122ee1222052d8e8..eca68caf5f46cedece0b5127ac615f33de325808 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 8cc536e49a0ae4a851b6bf42009eef01848a0023..d7d8026cde9948a562cf61f126fabd7960cafe5a 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 bca9cb89a118b02525fbf68ad7071e755f544c5c..487a54739854780c71ebce5de87d405f4b656e5d 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 fd96345bc35c2435cce7deabba774afe780c17c1..d57e8d0fb8235085b60180230d04dc8cd61f3033 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 656493a5e073262dc88efc646d254abd5c3646c7..42615b419dfb5bc4f30e0f6dfb2ad607015d95b7 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 949ed09c6361130c30c3ebda1bc4db02b00fa4c2..a126e614601fdea6f07043026dab6b3c8e07a24e 100644 (file)
@@ -47,46 +47,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 +106,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 0f175a866ef026a847d3ed287723423d4f268048..b7980a83ce2dddae54cf9ca4f866baf9228a0f35 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 1e9dffb337788806ec7e17cefc3a9348ea7938c3..5bc765d4c3cae96a604c45162e8c4bd18f039900 100644 (file)
@@ -30,25 +30,12 @@ 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
 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 826ab0939a128308b294207eda495207884f5361..fab3d3265adbec77ba71096587d924e9858d59f7 100644 (file)
@@ -68,6 +68,7 @@ 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;
@@ -869,21 +870,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 +937,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 e397df3ad98e2f451a51e9bcb91cd3c47deaa610..16402445f2b237303589ede6d768753bb08c6166 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 1f46f1cd9225c3c0d2a894bc80d3d1e74fe012e7..36e0fa161c2bf0b46206a6e0af00698935ad158b 100644 (file)
@@ -364,12 +364,14 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
                    tpm_protected_ordinal_duration[ordinal &
                                                   TPM_PROTECTED_ORDINAL_MASK];
 
-       if (duration_idx != TPM_UNDEFINED)
+       if (duration_idx != TPM_UNDEFINED) {
                duration = chip->vendor.duration[duration_idx];
-       if (duration <= 0)
+               /* if duration is 0, it's because chip->vendor.duration wasn't */
+               /* filled yet, so we set the lowest timeout just to give enough */
+               /* time for tpm_get_timeouts() to succeed */
+               return (duration <= 0 ? HZ : duration);
+       } else
                return 2 * 60 * HZ;
-       else
-               return duration;
 }
 EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
 
index c17a305ecb2806256c2f7c4f1e9e0e4c3f878734..dd21df55689d96a39d5fea3f66d2161dfec44467 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);
 }
 
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
deleted file mode 100644 (file)
index 896a2ce..0000000
+++ /dev/null
@@ -1,1838 +0,0 @@
-/*
- * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation
- * Copyright (C) 2009, 2010 Red Hat, 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.
- *
- * 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/cdev.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/poll.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/virtio.h>
-#include <linux/virtio_console.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include "hvc_console.h"
-
-/*
- * This is a global struct for storing common data for all the devices
- * this driver handles.
- *
- * Mainly, it has a linked list for all the consoles in one place so
- * that callbacks from hvc for get_chars(), put_chars() work properly
- * across multiple devices and multiple ports per device.
- */
-struct ports_driver_data {
-       /* Used for registering chardevs */
-       struct class *class;
-
-       /* Used for exporting per-port information to debugfs */
-       struct dentry *debugfs_dir;
-
-       /* List of all the devices we're handling */
-       struct list_head portdevs;
-
-       /* Number of devices this driver is handling */
-       unsigned int index;
-
-       /*
-        * This is used to keep track of the number of hvc consoles
-        * spawned by this driver.  This number is given as the first
-        * argument to hvc_alloc().  To correctly map an initial
-        * console spawned via hvc_instantiate to the console being
-        * hooked up via hvc_alloc, we need to pass the same vtermno.
-        *
-        * We also just assume the first console being initialised was
-        * the first one that got used as the initial console.
-        */
-       unsigned int next_vtermno;
-
-       /* All the console devices handled by this driver */
-       struct list_head consoles;
-};
-static struct ports_driver_data pdrvdata;
-
-DEFINE_SPINLOCK(pdrvdata_lock);
-
-/* This struct holds information that's relevant only for console ports */
-struct console {
-       /* We'll place all consoles in a list in the pdrvdata struct */
-       struct list_head list;
-
-       /* The hvc device associated with this console port */
-       struct hvc_struct *hvc;
-
-       /* The size of the console */
-       struct winsize ws;
-
-       /*
-        * This number identifies the number that we used to register
-        * with hvc in hvc_instantiate() and hvc_alloc(); this is the
-        * number passed on by the hvc callbacks to us to
-        * differentiate between the other console ports handled by
-        * this driver
-        */
-       u32 vtermno;
-};
-
-struct port_buffer {
-       char *buf;
-
-       /* size of the buffer in *buf above */
-       size_t size;
-
-       /* used length of the buffer */
-       size_t len;
-       /* offset in the buf from which to consume data */
-       size_t offset;
-};
-
-/*
- * This is a per-device struct that stores data common to all the
- * ports for that device (vdev->priv).
- */
-struct ports_device {
-       /* Next portdev in the list, head is in the pdrvdata struct */
-       struct list_head list;
-
-       /*
-        * Workqueue handlers where we process deferred work after
-        * notification
-        */
-       struct work_struct control_work;
-
-       struct list_head ports;
-
-       /* To protect the list of ports */
-       spinlock_t ports_lock;
-
-       /* To protect the vq operations for the control channel */
-       spinlock_t cvq_lock;
-
-       /* The current config space is stored here */
-       struct virtio_console_config config;
-
-       /* The virtio device we're associated with */
-       struct virtio_device *vdev;
-
-       /*
-        * A couple of virtqueues for the control channel: one for
-        * guest->host transfers, one for host->guest transfers
-        */
-       struct virtqueue *c_ivq, *c_ovq;
-
-       /* Array of per-port IO virtqueues */
-       struct virtqueue **in_vqs, **out_vqs;
-
-       /* Used for numbering devices for sysfs and debugfs */
-       unsigned int drv_index;
-
-       /* Major number for this device.  Ports will be created as minors. */
-       int chr_major;
-};
-
-/* This struct holds the per-port data */
-struct port {
-       /* Next port in the list, head is in the ports_device */
-       struct list_head list;
-
-       /* Pointer to the parent virtio_console device */
-       struct ports_device *portdev;
-
-       /* The current buffer from which data has to be fed to readers */
-       struct port_buffer *inbuf;
-
-       /*
-        * To protect the operations on the in_vq associated with this
-        * port.  Has to be a spinlock because it can be called from
-        * interrupt context (get_char()).
-        */
-       spinlock_t inbuf_lock;
-
-       /* Protect the operations on the out_vq. */
-       spinlock_t outvq_lock;
-
-       /* The IO vqs for this port */
-       struct virtqueue *in_vq, *out_vq;
-
-       /* File in the debugfs directory that exposes this port's information */
-       struct dentry *debugfs_file;
-
-       /*
-        * The entries in this struct will be valid if this port is
-        * hooked up to an hvc console
-        */
-       struct console cons;
-
-       /* Each port associates with a separate char device */
-       struct cdev *cdev;
-       struct device *dev;
-
-       /* Reference-counting to handle port hot-unplugs and file operations */
-       struct kref kref;
-
-       /* A waitqueue for poll() or blocking read operations */
-       wait_queue_head_t waitqueue;
-
-       /* The 'name' of the port that we expose via sysfs properties */
-       char *name;
-
-       /* We can notify apps of host connect / disconnect events via SIGIO */
-       struct fasync_struct *async_queue;
-
-       /* The 'id' to identify the port with the Host */
-       u32 id;
-
-       bool outvq_full;
-
-       /* Is the host device open */
-       bool host_connected;
-
-       /* We should allow only one process to open a port */
-       bool guest_connected;
-};
-
-/* This is the very early arch-specified put chars function. */
-static int (*early_put_chars)(u32, const char *, int);
-
-static struct port *find_port_by_vtermno(u32 vtermno)
-{
-       struct port *port;
-       struct console *cons;
-       unsigned long flags;
-
-       spin_lock_irqsave(&pdrvdata_lock, flags);
-       list_for_each_entry(cons, &pdrvdata.consoles, list) {
-               if (cons->vtermno == vtermno) {
-                       port = container_of(cons, struct port, cons);
-                       goto out;
-               }
-       }
-       port = NULL;
-out:
-       spin_unlock_irqrestore(&pdrvdata_lock, flags);
-       return port;
-}
-
-static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev,
-                                                dev_t dev)
-{
-       struct port *port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&portdev->ports_lock, flags);
-       list_for_each_entry(port, &portdev->ports, list)
-               if (port->cdev->dev == dev)
-                       goto out;
-       port = NULL;
-out:
-       spin_unlock_irqrestore(&portdev->ports_lock, flags);
-
-       return port;
-}
-
-static struct port *find_port_by_devt(dev_t dev)
-{
-       struct ports_device *portdev;
-       struct port *port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&pdrvdata_lock, flags);
-       list_for_each_entry(portdev, &pdrvdata.portdevs, list) {
-               port = find_port_by_devt_in_portdev(portdev, dev);
-               if (port)
-                       goto out;
-       }
-       port = NULL;
-out:
-       spin_unlock_irqrestore(&pdrvdata_lock, flags);
-       return port;
-}
-
-static struct port *find_port_by_id(struct ports_device *portdev, u32 id)
-{
-       struct port *port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&portdev->ports_lock, flags);
-       list_for_each_entry(port, &portdev->ports, list)
-               if (port->id == id)
-                       goto out;
-       port = NULL;
-out:
-       spin_unlock_irqrestore(&portdev->ports_lock, flags);
-
-       return port;
-}
-
-static struct port *find_port_by_vq(struct ports_device *portdev,
-                                   struct virtqueue *vq)
-{
-       struct port *port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&portdev->ports_lock, flags);
-       list_for_each_entry(port, &portdev->ports, list)
-               if (port->in_vq == vq || port->out_vq == vq)
-                       goto out;
-       port = NULL;
-out:
-       spin_unlock_irqrestore(&portdev->ports_lock, flags);
-       return port;
-}
-
-static bool is_console_port(struct port *port)
-{
-       if (port->cons.hvc)
-               return true;
-       return false;
-}
-
-static inline bool use_multiport(struct ports_device *portdev)
-{
-       /*
-        * This condition can be true when put_chars is called from
-        * early_init
-        */
-       if (!portdev->vdev)
-               return 0;
-       return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
-}
-
-static void free_buf(struct port_buffer *buf)
-{
-       kfree(buf->buf);
-       kfree(buf);
-}
-
-static struct port_buffer *alloc_buf(size_t buf_size)
-{
-       struct port_buffer *buf;
-
-       buf = kmalloc(sizeof(*buf), GFP_KERNEL);
-       if (!buf)
-               goto fail;
-       buf->buf = kzalloc(buf_size, GFP_KERNEL);
-       if (!buf->buf)
-               goto free_buf;
-       buf->len = 0;
-       buf->offset = 0;
-       buf->size = buf_size;
-       return buf;
-
-free_buf:
-       kfree(buf);
-fail:
-       return NULL;
-}
-
-/* Callers should take appropriate locks */
-static void *get_inbuf(struct port *port)
-{
-       struct port_buffer *buf;
-       struct virtqueue *vq;
-       unsigned int len;
-
-       vq = port->in_vq;
-       buf = virtqueue_get_buf(vq, &len);
-       if (buf) {
-               buf->len = len;
-               buf->offset = 0;
-       }
-       return buf;
-}
-
-/*
- * Create a scatter-gather list representing our input buffer and put
- * it in the queue.
- *
- * Callers should take appropriate locks.
- */
-static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf)
-{
-       struct scatterlist sg[1];
-       int ret;
-
-       sg_init_one(sg, buf->buf, buf->size);
-
-       ret = virtqueue_add_buf(vq, sg, 0, 1, buf);
-       virtqueue_kick(vq);
-       return ret;
-}
-
-/* Discard any unread data this port has. Callers lockers. */
-static void discard_port_data(struct port *port)
-{
-       struct port_buffer *buf;
-       struct virtqueue *vq;
-       unsigned int len;
-       int ret;
-
-       vq = port->in_vq;
-       if (port->inbuf)
-               buf = port->inbuf;
-       else
-               buf = virtqueue_get_buf(vq, &len);
-
-       ret = 0;
-       while (buf) {
-               if (add_inbuf(vq, buf) < 0) {
-                       ret++;
-                       free_buf(buf);
-               }
-               buf = virtqueue_get_buf(vq, &len);
-       }
-       port->inbuf = NULL;
-       if (ret)
-               dev_warn(port->dev, "Errors adding %d buffers back to vq\n",
-                        ret);
-}
-
-static bool port_has_data(struct port *port)
-{
-       unsigned long flags;
-       bool ret;
-
-       spin_lock_irqsave(&port->inbuf_lock, flags);
-       if (port->inbuf) {
-               ret = true;
-               goto out;
-       }
-       port->inbuf = get_inbuf(port);
-       if (port->inbuf) {
-               ret = true;
-               goto out;
-       }
-       ret = false;
-out:
-       spin_unlock_irqrestore(&port->inbuf_lock, flags);
-       return ret;
-}
-
-static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
-                                 unsigned int event, unsigned int value)
-{
-       struct scatterlist sg[1];
-       struct virtio_console_control cpkt;
-       struct virtqueue *vq;
-       unsigned int len;
-
-       if (!use_multiport(portdev))
-               return 0;
-
-       cpkt.id = port_id;
-       cpkt.event = event;
-       cpkt.value = value;
-
-       vq = portdev->c_ovq;
-
-       sg_init_one(sg, &cpkt, sizeof(cpkt));
-       if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt) >= 0) {
-               virtqueue_kick(vq);
-               while (!virtqueue_get_buf(vq, &len))
-                       cpu_relax();
-       }
-       return 0;
-}
-
-static ssize_t send_control_msg(struct port *port, unsigned int event,
-                               unsigned int value)
-{
-       /* Did the port get unplugged before userspace closed it? */
-       if (port->portdev)
-               return __send_control_msg(port->portdev, port->id, event, value);
-       return 0;
-}
-
-/* Callers must take the port->outvq_lock */
-static void reclaim_consumed_buffers(struct port *port)
-{
-       void *buf;
-       unsigned int len;
-
-       while ((buf = virtqueue_get_buf(port->out_vq, &len))) {
-               kfree(buf);
-               port->outvq_full = false;
-       }
-}
-
-static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
-                       bool nonblock)
-{
-       struct scatterlist sg[1];
-       struct virtqueue *out_vq;
-       ssize_t ret;
-       unsigned long flags;
-       unsigned int len;
-
-       out_vq = port->out_vq;
-
-       spin_lock_irqsave(&port->outvq_lock, flags);
-
-       reclaim_consumed_buffers(port);
-
-       sg_init_one(sg, in_buf, in_count);
-       ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf);
-
-       /* Tell Host to go! */
-       virtqueue_kick(out_vq);
-
-       if (ret < 0) {
-               in_count = 0;
-               goto done;
-       }
-
-       if (ret == 0)
-               port->outvq_full = true;
-
-       if (nonblock)
-               goto done;
-
-       /*
-        * Wait till the host acknowledges it pushed out the data we
-        * sent.  This is done for data from the hvc_console; the tty
-        * operations are performed with spinlocks held so we can't
-        * sleep here.  An alternative would be to copy the data to a
-        * buffer and relax the spinning requirement.  The downside is
-        * we need to kmalloc a GFP_ATOMIC buffer each time the
-        * console driver writes something out.
-        */
-       while (!virtqueue_get_buf(out_vq, &len))
-               cpu_relax();
-done:
-       spin_unlock_irqrestore(&port->outvq_lock, flags);
-       /*
-        * We're expected to return the amount of data we wrote -- all
-        * of it
-        */
-       return in_count;
-}
-
-/*
- * Give out the data that's requested from the buffer that we have
- * queued up.
- */
-static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count,
-                           bool to_user)
-{
-       struct port_buffer *buf;
-       unsigned long flags;
-
-       if (!out_count || !port_has_data(port))
-               return 0;
-
-       buf = port->inbuf;
-       out_count = min(out_count, buf->len - buf->offset);
-
-       if (to_user) {
-               ssize_t ret;
-
-               ret = copy_to_user(out_buf, buf->buf + buf->offset, out_count);
-               if (ret)
-                       return -EFAULT;
-       } else {
-               memcpy(out_buf, buf->buf + buf->offset, out_count);
-       }
-
-       buf->offset += out_count;
-
-       if (buf->offset == buf->len) {
-               /*
-                * We're done using all the data in this buffer.
-                * Re-queue so that the Host can send us more data.
-                */
-               spin_lock_irqsave(&port->inbuf_lock, flags);
-               port->inbuf = NULL;
-
-               if (add_inbuf(port->in_vq, buf) < 0)
-                       dev_warn(port->dev, "failed add_buf\n");
-
-               spin_unlock_irqrestore(&port->inbuf_lock, flags);
-       }
-       /* Return the number of bytes actually copied */
-       return out_count;
-}
-
-/* The condition that must be true for polling to end */
-static bool will_read_block(struct port *port)
-{
-       if (!port->guest_connected) {
-               /* Port got hot-unplugged. Let's exit. */
-               return false;
-       }
-       return !port_has_data(port) && port->host_connected;
-}
-
-static bool will_write_block(struct port *port)
-{
-       bool ret;
-
-       if (!port->guest_connected) {
-               /* Port got hot-unplugged. Let's exit. */
-               return false;
-       }
-       if (!port->host_connected)
-               return true;
-
-       spin_lock_irq(&port->outvq_lock);
-       /*
-        * Check if the Host has consumed any buffers since we last
-        * sent data (this is only applicable for nonblocking ports).
-        */
-       reclaim_consumed_buffers(port);
-       ret = port->outvq_full;
-       spin_unlock_irq(&port->outvq_lock);
-
-       return ret;
-}
-
-static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
-                             size_t count, loff_t *offp)
-{
-       struct port *port;
-       ssize_t ret;
-
-       port = filp->private_data;
-
-       if (!port_has_data(port)) {
-               /*
-                * If nothing's connected on the host just return 0 in
-                * case of list_empty; this tells the userspace app
-                * that there's no connection
-                */
-               if (!port->host_connected)
-                       return 0;
-               if (filp->f_flags & O_NONBLOCK)
-                       return -EAGAIN;
-
-               ret = wait_event_interruptible(port->waitqueue,
-                                              !will_read_block(port));
-               if (ret < 0)
-                       return ret;
-       }
-       /* Port got hot-unplugged. */
-       if (!port->guest_connected)
-               return -ENODEV;
-       /*
-        * We could've received a disconnection message while we were
-        * waiting for more data.
-        *
-        * This check is not clubbed in the if() statement above as we
-        * might receive some data as well as the host could get
-        * disconnected after we got woken up from our wait.  So we
-        * really want to give off whatever data we have and only then
-        * check for host_connected.
-        */
-       if (!port_has_data(port) && !port->host_connected)
-               return 0;
-
-       return fill_readbuf(port, ubuf, count, true);
-}
-
-static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
-                              size_t count, loff_t *offp)
-{
-       struct port *port;
-       char *buf;
-       ssize_t ret;
-       bool nonblock;
-
-       /* Userspace could be out to fool us */
-       if (!count)
-               return 0;
-
-       port = filp->private_data;
-
-       nonblock = filp->f_flags & O_NONBLOCK;
-
-       if (will_write_block(port)) {
-               if (nonblock)
-                       return -EAGAIN;
-
-               ret = wait_event_interruptible(port->waitqueue,
-                                              !will_write_block(port));
-               if (ret < 0)
-                       return ret;
-       }
-       /* Port got hot-unplugged. */
-       if (!port->guest_connected)
-               return -ENODEV;
-
-       count = min((size_t)(32 * 1024), count);
-
-       buf = kmalloc(count, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       ret = copy_from_user(buf, ubuf, count);
-       if (ret) {
-               ret = -EFAULT;
-               goto free_buf;
-       }
-
-       /*
-        * We now ask send_buf() to not spin for generic ports -- we
-        * can re-use the same code path that non-blocking file
-        * descriptors take for blocking file descriptors since the
-        * wait is already done and we're certain the write will go
-        * through to the host.
-        */
-       nonblock = true;
-       ret = send_buf(port, buf, count, nonblock);
-
-       if (nonblock && ret > 0)
-               goto out;
-
-free_buf:
-       kfree(buf);
-out:
-       return ret;
-}
-
-static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
-{
-       struct port *port;
-       unsigned int ret;
-
-       port = filp->private_data;
-       poll_wait(filp, &port->waitqueue, wait);
-
-       if (!port->guest_connected) {
-               /* Port got unplugged */
-               return POLLHUP;
-       }
-       ret = 0;
-       if (!will_read_block(port))
-               ret |= POLLIN | POLLRDNORM;
-       if (!will_write_block(port))
-               ret |= POLLOUT;
-       if (!port->host_connected)
-               ret |= POLLHUP;
-
-       return ret;
-}
-
-static void remove_port(struct kref *kref);
-
-static int port_fops_release(struct inode *inode, struct file *filp)
-{
-       struct port *port;
-
-       port = filp->private_data;
-
-       /* Notify host of port being closed */
-       send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
-
-       spin_lock_irq(&port->inbuf_lock);
-       port->guest_connected = false;
-
-       discard_port_data(port);
-
-       spin_unlock_irq(&port->inbuf_lock);
-
-       spin_lock_irq(&port->outvq_lock);
-       reclaim_consumed_buffers(port);
-       spin_unlock_irq(&port->outvq_lock);
-
-       /*
-        * Locks aren't necessary here as a port can't be opened after
-        * unplug, and if a port isn't unplugged, a kref would already
-        * exist for the port.  Plus, taking ports_lock here would
-        * create a dependency on other locks taken by functions
-        * inside remove_port if we're the last holder of the port,
-        * creating many problems.
-        */
-       kref_put(&port->kref, remove_port);
-
-       return 0;
-}
-
-static int port_fops_open(struct inode *inode, struct file *filp)
-{
-       struct cdev *cdev = inode->i_cdev;
-       struct port *port;
-       int ret;
-
-       port = find_port_by_devt(cdev->dev);
-       filp->private_data = port;
-
-       /* Prevent against a port getting hot-unplugged at the same time */
-       spin_lock_irq(&port->portdev->ports_lock);
-       kref_get(&port->kref);
-       spin_unlock_irq(&port->portdev->ports_lock);
-
-       /*
-        * Don't allow opening of console port devices -- that's done
-        * via /dev/hvc
-        */
-       if (is_console_port(port)) {
-               ret = -ENXIO;
-               goto out;
-       }
-
-       /* Allow only one process to open a particular port at a time */
-       spin_lock_irq(&port->inbuf_lock);
-       if (port->guest_connected) {
-               spin_unlock_irq(&port->inbuf_lock);
-               ret = -EMFILE;
-               goto out;
-       }
-
-       port->guest_connected = true;
-       spin_unlock_irq(&port->inbuf_lock);
-
-       spin_lock_irq(&port->outvq_lock);
-       /*
-        * There might be a chance that we missed reclaiming a few
-        * buffers in the window of the port getting previously closed
-        * and opening now.
-        */
-       reclaim_consumed_buffers(port);
-       spin_unlock_irq(&port->outvq_lock);
-
-       nonseekable_open(inode, filp);
-
-       /* Notify host of port being opened */
-       send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1);
-
-       return 0;
-out:
-       kref_put(&port->kref, remove_port);
-       return ret;
-}
-
-static int port_fops_fasync(int fd, struct file *filp, int mode)
-{
-       struct port *port;
-
-       port = filp->private_data;
-       return fasync_helper(fd, filp, mode, &port->async_queue);
-}
-
-/*
- * The file operations that we support: programs in the guest can open
- * a console device, read from it, write to it, poll for data and
- * close it.  The devices are at
- *   /dev/vport<device number>p<port number>
- */
-static const struct file_operations port_fops = {
-       .owner = THIS_MODULE,
-       .open  = port_fops_open,
-       .read  = port_fops_read,
-       .write = port_fops_write,
-       .poll  = port_fops_poll,
-       .release = port_fops_release,
-       .fasync = port_fops_fasync,
-       .llseek = no_llseek,
-};
-
-/*
- * The put_chars() callback is pretty straightforward.
- *
- * We turn the characters into a scatter-gather list, add it to the
- * output queue and then kick the Host.  Then we sit here waiting for
- * it to finish: inefficient in theory, but in practice
- * implementations will do it immediately (lguest's Launcher does).
- */
-static int put_chars(u32 vtermno, const char *buf, int count)
-{
-       struct port *port;
-
-       if (unlikely(early_put_chars))
-               return early_put_chars(vtermno, buf, count);
-
-       port = find_port_by_vtermno(vtermno);
-       if (!port)
-               return -EPIPE;
-
-       return send_buf(port, (void *)buf, count, false);
-}
-
-/*
- * get_chars() is the callback from the hvc_console infrastructure
- * when an interrupt is received.
- *
- * We call out to fill_readbuf that gets us the required data from the
- * buffers that are queued up.
- */
-static int get_chars(u32 vtermno, char *buf, int count)
-{
-       struct port *port;
-
-       /* If we've not set up the port yet, we have no input to give. */
-       if (unlikely(early_put_chars))
-               return 0;
-
-       port = find_port_by_vtermno(vtermno);
-       if (!port)
-               return -EPIPE;
-
-       /* If we don't have an input queue yet, we can't get input. */
-       BUG_ON(!port->in_vq);
-
-       return fill_readbuf(port, buf, count, false);
-}
-
-static void resize_console(struct port *port)
-{
-       struct virtio_device *vdev;
-
-       /* The port could have been hot-unplugged */
-       if (!port || !is_console_port(port))
-               return;
-
-       vdev = port->portdev->vdev;
-       if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE))
-               hvc_resize(port->cons.hvc, port->cons.ws);
-}
-
-/* We set the configuration at this point, since we now have a tty */
-static int notifier_add_vio(struct hvc_struct *hp, int data)
-{
-       struct port *port;
-
-       port = find_port_by_vtermno(hp->vtermno);
-       if (!port)
-               return -EINVAL;
-
-       hp->irq_requested = 1;
-       resize_console(port);
-
-       return 0;
-}
-
-static void notifier_del_vio(struct hvc_struct *hp, int data)
-{
-       hp->irq_requested = 0;
-}
-
-/* The operations for console ports. */
-static const struct hv_ops hv_ops = {
-       .get_chars = get_chars,
-       .put_chars = put_chars,
-       .notifier_add = notifier_add_vio,
-       .notifier_del = notifier_del_vio,
-       .notifier_hangup = notifier_del_vio,
-};
-
-/*
- * Console drivers are initialized very early so boot messages can go
- * out, so we do things slightly differently from the generic virtio
- * initialization of the net and block drivers.
- *
- * At this stage, the console is output-only.  It's too early to set
- * up a virtqueue, so we let the drivers do some boutique early-output
- * thing.
- */
-int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
-{
-       early_put_chars = put_chars;
-       return hvc_instantiate(0, 0, &hv_ops);
-}
-
-int init_port_console(struct port *port)
-{
-       int ret;
-
-       /*
-        * The Host's telling us this port is a console port.  Hook it
-        * up with an hvc console.
-        *
-        * To set up and manage our virtual console, we call
-        * hvc_alloc().
-        *
-        * The first argument of hvc_alloc() is the virtual console
-        * number.  The second argument is the parameter for the
-        * notification mechanism (like irq number).  We currently
-        * leave this as zero, virtqueues have implicit notifications.
-        *
-        * The third argument is a "struct hv_ops" containing the
-        * put_chars() get_chars(), notifier_add() and notifier_del()
-        * pointers.  The final argument is the output buffer size: we
-        * can do any size, so we put PAGE_SIZE here.
-        */
-       port->cons.vtermno = pdrvdata.next_vtermno;
-
-       port->cons.hvc = hvc_alloc(port->cons.vtermno, 0, &hv_ops, PAGE_SIZE);
-       if (IS_ERR(port->cons.hvc)) {
-               ret = PTR_ERR(port->cons.hvc);
-               dev_err(port->dev,
-                       "error %d allocating hvc for port\n", ret);
-               port->cons.hvc = NULL;
-               return ret;
-       }
-       spin_lock_irq(&pdrvdata_lock);
-       pdrvdata.next_vtermno++;
-       list_add_tail(&port->cons.list, &pdrvdata.consoles);
-       spin_unlock_irq(&pdrvdata_lock);
-       port->guest_connected = true;
-
-       /*
-        * Start using the new console output if this is the first
-        * console to come up.
-        */
-       if (early_put_chars)
-               early_put_chars = NULL;
-
-       /* Notify host of port being opened */
-       send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
-
-       return 0;
-}
-
-static ssize_t show_port_name(struct device *dev,
-                             struct device_attribute *attr, char *buffer)
-{
-       struct port *port;
-
-       port = dev_get_drvdata(dev);
-
-       return sprintf(buffer, "%s\n", port->name);
-}
-
-static DEVICE_ATTR(name, S_IRUGO, show_port_name, NULL);
-
-static struct attribute *port_sysfs_entries[] = {
-       &dev_attr_name.attr,
-       NULL
-};
-
-static struct attribute_group port_attribute_group = {
-       .name = NULL,           /* put in device directory */
-       .attrs = port_sysfs_entries,
-};
-
-static int debugfs_open(struct inode *inode, struct file *filp)
-{
-       filp->private_data = inode->i_private;
-       return 0;
-}
-
-static ssize_t debugfs_read(struct file *filp, char __user *ubuf,
-                           size_t count, loff_t *offp)
-{
-       struct port *port;
-       char *buf;
-       ssize_t ret, out_offset, out_count;
-
-       out_count = 1024;
-       buf = kmalloc(out_count, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       port = filp->private_data;
-       out_offset = 0;
-       out_offset += snprintf(buf + out_offset, out_count,
-                              "name: %s\n", port->name ? port->name : "");
-       out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "guest_connected: %d\n", port->guest_connected);
-       out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "host_connected: %d\n", port->host_connected);
-       out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "outvq_full: %d\n", port->outvq_full);
-       out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "is_console: %s\n",
-                              is_console_port(port) ? "yes" : "no");
-       out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "console_vtermno: %u\n", port->cons.vtermno);
-
-       ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset);
-       kfree(buf);
-       return ret;
-}
-
-static const struct file_operations port_debugfs_ops = {
-       .owner = THIS_MODULE,
-       .open  = debugfs_open,
-       .read  = debugfs_read,
-};
-
-static void set_console_size(struct port *port, u16 rows, u16 cols)
-{
-       if (!port || !is_console_port(port))
-               return;
-
-       port->cons.ws.ws_row = rows;
-       port->cons.ws.ws_col = cols;
-}
-
-static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
-{
-       struct port_buffer *buf;
-       unsigned int nr_added_bufs;
-       int ret;
-
-       nr_added_bufs = 0;
-       do {
-               buf = alloc_buf(PAGE_SIZE);
-               if (!buf)
-                       break;
-
-               spin_lock_irq(lock);
-               ret = add_inbuf(vq, buf);
-               if (ret < 0) {
-                       spin_unlock_irq(lock);
-                       free_buf(buf);
-                       break;
-               }
-               nr_added_bufs++;
-               spin_unlock_irq(lock);
-       } while (ret > 0);
-
-       return nr_added_bufs;
-}
-
-static void send_sigio_to_port(struct port *port)
-{
-       if (port->async_queue && port->guest_connected)
-               kill_fasync(&port->async_queue, SIGIO, POLL_OUT);
-}
-
-static int add_port(struct ports_device *portdev, u32 id)
-{
-       char debugfs_name[16];
-       struct port *port;
-       struct port_buffer *buf;
-       dev_t devt;
-       unsigned int nr_added_bufs;
-       int err;
-
-       port = kmalloc(sizeof(*port), GFP_KERNEL);
-       if (!port) {
-               err = -ENOMEM;
-               goto fail;
-       }
-       kref_init(&port->kref);
-
-       port->portdev = portdev;
-       port->id = id;
-
-       port->name = NULL;
-       port->inbuf = NULL;
-       port->cons.hvc = NULL;
-       port->async_queue = NULL;
-
-       port->cons.ws.ws_row = port->cons.ws.ws_col = 0;
-
-       port->host_connected = port->guest_connected = false;
-
-       port->outvq_full = false;
-
-       port->in_vq = portdev->in_vqs[port->id];
-       port->out_vq = portdev->out_vqs[port->id];
-
-       port->cdev = cdev_alloc();
-       if (!port->cdev) {
-               dev_err(&port->portdev->vdev->dev, "Error allocating cdev\n");
-               err = -ENOMEM;
-               goto free_port;
-       }
-       port->cdev->ops = &port_fops;
-
-       devt = MKDEV(portdev->chr_major, id);
-       err = cdev_add(port->cdev, devt, 1);
-       if (err < 0) {
-               dev_err(&port->portdev->vdev->dev,
-                       "Error %d adding cdev for port %u\n", err, id);
-               goto free_cdev;
-       }
-       port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev,
-                                 devt, port, "vport%up%u",
-                                 port->portdev->drv_index, id);
-       if (IS_ERR(port->dev)) {
-               err = PTR_ERR(port->dev);
-               dev_err(&port->portdev->vdev->dev,
-                       "Error %d creating device for port %u\n",
-                       err, id);
-               goto free_cdev;
-       }
-
-       spin_lock_init(&port->inbuf_lock);
-       spin_lock_init(&port->outvq_lock);
-       init_waitqueue_head(&port->waitqueue);
-
-       /* Fill the in_vq with buffers so the host can send us data. */
-       nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock);
-       if (!nr_added_bufs) {
-               dev_err(port->dev, "Error allocating inbufs\n");
-               err = -ENOMEM;
-               goto free_device;
-       }
-
-       /*
-        * If we're not using multiport support, this has to be a console port
-        */
-       if (!use_multiport(port->portdev)) {
-               err = init_port_console(port);
-               if (err)
-                       goto free_inbufs;
-       }
-
-       spin_lock_irq(&portdev->ports_lock);
-       list_add_tail(&port->list, &port->portdev->ports);
-       spin_unlock_irq(&portdev->ports_lock);
-
-       /*
-        * Tell the Host we're set so that it can send us various
-        * configuration parameters for this port (eg, port name,
-        * caching, whether this is a console port, etc.)
-        */
-       send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
-
-       if (pdrvdata.debugfs_dir) {
-               /*
-                * Finally, create the debugfs file that we can use to
-                * inspect a port's state at any time
-                */
-               sprintf(debugfs_name, "vport%up%u",
-                       port->portdev->drv_index, id);
-               port->debugfs_file = debugfs_create_file(debugfs_name, 0444,
-                                                        pdrvdata.debugfs_dir,
-                                                        port,
-                                                        &port_debugfs_ops);
-       }
-       return 0;
-
-free_inbufs:
-       while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
-               free_buf(buf);
-free_device:
-       device_destroy(pdrvdata.class, port->dev->devt);
-free_cdev:
-       cdev_del(port->cdev);
-free_port:
-       kfree(port);
-fail:
-       /* The host might want to notify management sw about port add failure */
-       __send_control_msg(portdev, id, VIRTIO_CONSOLE_PORT_READY, 0);
-       return err;
-}
-
-/* No users remain, remove all port-specific data. */
-static void remove_port(struct kref *kref)
-{
-       struct port *port;
-
-       port = container_of(kref, struct port, kref);
-
-       sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
-       device_destroy(pdrvdata.class, port->dev->devt);
-       cdev_del(port->cdev);
-
-       kfree(port->name);
-
-       debugfs_remove(port->debugfs_file);
-
-       kfree(port);
-}
-
-/*
- * Port got unplugged.  Remove port from portdev's list and drop the
- * kref reference.  If no userspace has this port opened, it will
- * result in immediate removal the port.
- */
-static void unplug_port(struct port *port)
-{
-       struct port_buffer *buf;
-
-       spin_lock_irq(&port->portdev->ports_lock);
-       list_del(&port->list);
-       spin_unlock_irq(&port->portdev->ports_lock);
-
-       if (port->guest_connected) {
-               port->guest_connected = false;
-               port->host_connected = false;
-               wake_up_interruptible(&port->waitqueue);
-
-               /* Let the app know the port is going down. */
-               send_sigio_to_port(port);
-       }
-
-       if (is_console_port(port)) {
-               spin_lock_irq(&pdrvdata_lock);
-               list_del(&port->cons.list);
-               spin_unlock_irq(&pdrvdata_lock);
-#if 0
-               /*
-                * hvc_remove() not called as removing one hvc port
-                * results in other hvc ports getting frozen.
-                *
-                * Once this is resolved in hvc, this functionality
-                * will be enabled.  Till that is done, the -EPIPE
-                * return from get_chars() above will help
-                * hvc_console.c to clean up on ports we remove here.
-                */
-               hvc_remove(port->cons.hvc);
-#endif
-       }
-
-       /* Remove unused data this port might have received. */
-       discard_port_data(port);
-
-       reclaim_consumed_buffers(port);
-
-       /* Remove buffers we queued up for the Host to send us data in. */
-       while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
-               free_buf(buf);
-
-       /*
-        * We should just assume the device itself has gone off --
-        * else a close on an open port later will try to send out a
-        * control message.
-        */
-       port->portdev = NULL;
-
-       /*
-        * Locks around here are not necessary - a port can't be
-        * opened after we removed the port struct from ports_list
-        * above.
-        */
-       kref_put(&port->kref, remove_port);
-}
-
-/* Any private messages that the Host and Guest want to share */
-static void handle_control_message(struct ports_device *portdev,
-                                  struct port_buffer *buf)
-{
-       struct virtio_console_control *cpkt;
-       struct port *port;
-       size_t name_size;
-       int err;
-
-       cpkt = (struct virtio_console_control *)(buf->buf + buf->offset);
-
-       port = find_port_by_id(portdev, cpkt->id);
-       if (!port && cpkt->event != VIRTIO_CONSOLE_PORT_ADD) {
-               /* No valid header at start of buffer.  Drop it. */
-               dev_dbg(&portdev->vdev->dev,
-                       "Invalid index %u in control packet\n", cpkt->id);
-               return;
-       }
-
-       switch (cpkt->event) {
-       case VIRTIO_CONSOLE_PORT_ADD:
-               if (port) {
-                       dev_dbg(&portdev->vdev->dev,
-                               "Port %u already added\n", port->id);
-                       send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
-                       break;
-               }
-               if (cpkt->id >= portdev->config.max_nr_ports) {
-                       dev_warn(&portdev->vdev->dev,
-                               "Request for adding port with out-of-bound id %u, max. supported id: %u\n",
-                               cpkt->id, portdev->config.max_nr_ports - 1);
-                       break;
-               }
-               add_port(portdev, cpkt->id);
-               break;
-       case VIRTIO_CONSOLE_PORT_REMOVE:
-               unplug_port(port);
-               break;
-       case VIRTIO_CONSOLE_CONSOLE_PORT:
-               if (!cpkt->value)
-                       break;
-               if (is_console_port(port))
-                       break;
-
-               init_port_console(port);
-               /*
-                * Could remove the port here in case init fails - but
-                * have to notify the host first.
-                */
-               break;
-       case VIRTIO_CONSOLE_RESIZE: {
-               struct {
-                       __u16 rows;
-                       __u16 cols;
-               } size;
-
-               if (!is_console_port(port))
-                       break;
-
-               memcpy(&size, buf->buf + buf->offset + sizeof(*cpkt),
-                      sizeof(size));
-               set_console_size(port, size.rows, size.cols);
-
-               port->cons.hvc->irq_requested = 1;
-               resize_console(port);
-               break;
-       }
-       case VIRTIO_CONSOLE_PORT_OPEN:
-               port->host_connected = cpkt->value;
-               wake_up_interruptible(&port->waitqueue);
-               /*
-                * If the host port got closed and the host had any
-                * unconsumed buffers, we'll be able to reclaim them
-                * now.
-                */
-               spin_lock_irq(&port->outvq_lock);
-               reclaim_consumed_buffers(port);
-               spin_unlock_irq(&port->outvq_lock);
-
-               /*
-                * If the guest is connected, it'll be interested in
-                * knowing the host connection state changed.
-                */
-               send_sigio_to_port(port);
-               break;
-       case VIRTIO_CONSOLE_PORT_NAME:
-               /*
-                * Skip the size of the header and the cpkt to get the size
-                * of the name that was sent
-                */
-               name_size = buf->len - buf->offset - sizeof(*cpkt) + 1;
-
-               port->name = kmalloc(name_size, GFP_KERNEL);
-               if (!port->name) {
-                       dev_err(port->dev,
-                               "Not enough space to store port name\n");
-                       break;
-               }
-               strncpy(port->name, buf->buf + buf->offset + sizeof(*cpkt),
-                       name_size - 1);
-               port->name[name_size - 1] = 0;
-
-               /*
-                * Since we only have one sysfs attribute, 'name',
-                * create it only if we have a name for the port.
-                */
-               err = sysfs_create_group(&port->dev->kobj,
-                                        &port_attribute_group);
-               if (err) {
-                       dev_err(port->dev,
-                               "Error %d creating sysfs device attributes\n",
-                               err);
-               } else {
-                       /*
-                        * Generate a udev event so that appropriate
-                        * symlinks can be created based on udev
-                        * rules.
-                        */
-                       kobject_uevent(&port->dev->kobj, KOBJ_CHANGE);
-               }
-               break;
-       }
-}
-
-static void control_work_handler(struct work_struct *work)
-{
-       struct ports_device *portdev;
-       struct virtqueue *vq;
-       struct port_buffer *buf;
-       unsigned int len;
-
-       portdev = container_of(work, struct ports_device, control_work);
-       vq = portdev->c_ivq;
-
-       spin_lock(&portdev->cvq_lock);
-       while ((buf = virtqueue_get_buf(vq, &len))) {
-               spin_unlock(&portdev->cvq_lock);
-
-               buf->len = len;
-               buf->offset = 0;
-
-               handle_control_message(portdev, buf);
-
-               spin_lock(&portdev->cvq_lock);
-               if (add_inbuf(portdev->c_ivq, buf) < 0) {
-                       dev_warn(&portdev->vdev->dev,
-                                "Error adding buffer to queue\n");
-                       free_buf(buf);
-               }
-       }
-       spin_unlock(&portdev->cvq_lock);
-}
-
-static void in_intr(struct virtqueue *vq)
-{
-       struct port *port;
-       unsigned long flags;
-
-       port = find_port_by_vq(vq->vdev->priv, vq);
-       if (!port)
-               return;
-
-       spin_lock_irqsave(&port->inbuf_lock, flags);
-       if (!port->inbuf)
-               port->inbuf = get_inbuf(port);
-
-       /*
-        * Don't queue up data when port is closed.  This condition
-        * can be reached when a console port is not yet connected (no
-        * tty is spawned) and the host sends out data to console
-        * ports.  For generic serial ports, the host won't
-        * (shouldn't) send data till the guest is connected.
-        */
-       if (!port->guest_connected)
-               discard_port_data(port);
-
-       spin_unlock_irqrestore(&port->inbuf_lock, flags);
-
-       wake_up_interruptible(&port->waitqueue);
-
-       /* Send a SIGIO indicating new data in case the process asked for it */
-       send_sigio_to_port(port);
-
-       if (is_console_port(port) && hvc_poll(port->cons.hvc))
-               hvc_kick();
-}
-
-static void control_intr(struct virtqueue *vq)
-{
-       struct ports_device *portdev;
-
-       portdev = vq->vdev->priv;
-       schedule_work(&portdev->control_work);
-}
-
-static void config_intr(struct virtio_device *vdev)
-{
-       struct ports_device *portdev;
-
-       portdev = vdev->priv;
-
-       if (!use_multiport(portdev)) {
-               struct port *port;
-               u16 rows, cols;
-
-               vdev->config->get(vdev,
-                                 offsetof(struct virtio_console_config, cols),
-                                 &cols, sizeof(u16));
-               vdev->config->get(vdev,
-                                 offsetof(struct virtio_console_config, rows),
-                                 &rows, sizeof(u16));
-
-               port = find_port_by_id(portdev, 0);
-               set_console_size(port, rows, cols);
-
-               /*
-                * We'll use this way of resizing only for legacy
-                * support.  For newer userspace
-                * (VIRTIO_CONSOLE_F_MULTPORT+), use control messages
-                * to indicate console size changes so that it can be
-                * done per-port.
-                */
-               resize_console(port);
-       }
-}
-
-static int init_vqs(struct ports_device *portdev)
-{
-       vq_callback_t **io_callbacks;
-       char **io_names;
-       struct virtqueue **vqs;
-       u32 i, j, nr_ports, nr_queues;
-       int err;
-
-       nr_ports = portdev->config.max_nr_ports;
-       nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2;
-
-       vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL);
-       io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL);
-       io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL);
-       portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
-                                 GFP_KERNEL);
-       portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
-                                  GFP_KERNEL);
-       if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs ||
-                       !portdev->out_vqs) {
-               err = -ENOMEM;
-               goto free;
-       }
-
-       /*
-        * For backward compat (newer host but older guest), the host
-        * spawns a console port first and also inits the vqs for port
-        * 0 before others.
-        */
-       j = 0;
-       io_callbacks[j] = in_intr;
-       io_callbacks[j + 1] = NULL;
-       io_names[j] = "input";
-       io_names[j + 1] = "output";
-       j += 2;
-
-       if (use_multiport(portdev)) {
-               io_callbacks[j] = control_intr;
-               io_callbacks[j + 1] = NULL;
-               io_names[j] = "control-i";
-               io_names[j + 1] = "control-o";
-
-               for (i = 1; i < nr_ports; i++) {
-                       j += 2;
-                       io_callbacks[j] = in_intr;
-                       io_callbacks[j + 1] = NULL;
-                       io_names[j] = "input";
-                       io_names[j + 1] = "output";
-               }
-       }
-       /* Find the queues. */
-       err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs,
-                                             io_callbacks,
-                                             (const char **)io_names);
-       if (err)
-               goto free;
-
-       j = 0;
-       portdev->in_vqs[0] = vqs[0];
-       portdev->out_vqs[0] = vqs[1];
-       j += 2;
-       if (use_multiport(portdev)) {
-               portdev->c_ivq = vqs[j];
-               portdev->c_ovq = vqs[j + 1];
-
-               for (i = 1; i < nr_ports; i++) {
-                       j += 2;
-                       portdev->in_vqs[i] = vqs[j];
-                       portdev->out_vqs[i] = vqs[j + 1];
-               }
-       }
-       kfree(io_names);
-       kfree(io_callbacks);
-       kfree(vqs);
-
-       return 0;
-
-free:
-       kfree(portdev->out_vqs);
-       kfree(portdev->in_vqs);
-       kfree(io_names);
-       kfree(io_callbacks);
-       kfree(vqs);
-
-       return err;
-}
-
-static const struct file_operations portdev_fops = {
-       .owner = THIS_MODULE,
-};
-
-/*
- * Once we're further in boot, we get probed like any other virtio
- * device.
- *
- * If the host also supports multiple console ports, we check the
- * config space to see how many ports the host has spawned.  We
- * initialize each port found.
- */
-static int __devinit virtcons_probe(struct virtio_device *vdev)
-{
-       struct ports_device *portdev;
-       int err;
-       bool multiport;
-
-       portdev = kmalloc(sizeof(*portdev), GFP_KERNEL);
-       if (!portdev) {
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       /* Attach this portdev to this virtio_device, and vice-versa. */
-       portdev->vdev = vdev;
-       vdev->priv = portdev;
-
-       spin_lock_irq(&pdrvdata_lock);
-       portdev->drv_index = pdrvdata.index++;
-       spin_unlock_irq(&pdrvdata_lock);
-
-       portdev->chr_major = register_chrdev(0, "virtio-portsdev",
-                                            &portdev_fops);
-       if (portdev->chr_major < 0) {
-               dev_err(&vdev->dev,
-                       "Error %d registering chrdev for device %u\n",
-                       portdev->chr_major, portdev->drv_index);
-               err = portdev->chr_major;
-               goto free;
-       }
-
-       multiport = false;
-       portdev->config.max_nr_ports = 1;
-       if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) {
-               multiport = true;
-               vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT;
-
-               vdev->config->get(vdev, offsetof(struct virtio_console_config,
-                                                max_nr_ports),
-                                 &portdev->config.max_nr_ports,
-                                 sizeof(portdev->config.max_nr_ports));
-       }
-
-       /* Let the Host know we support multiple ports.*/
-       vdev->config->finalize_features(vdev);
-
-       err = init_vqs(portdev);
-       if (err < 0) {
-               dev_err(&vdev->dev, "Error %d initializing vqs\n", err);
-               goto free_chrdev;
-       }
-
-       spin_lock_init(&portdev->ports_lock);
-       INIT_LIST_HEAD(&portdev->ports);
-
-       if (multiport) {
-               unsigned int nr_added_bufs;
-
-               spin_lock_init(&portdev->cvq_lock);
-               INIT_WORK(&portdev->control_work, &control_work_handler);
-
-               nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock);
-               if (!nr_added_bufs) {
-                       dev_err(&vdev->dev,
-                               "Error allocating buffers for control queue\n");
-                       err = -ENOMEM;
-                       goto free_vqs;
-               }
-       } else {
-               /*
-                * For backward compatibility: Create a console port
-                * if we're running on older host.
-                */
-               add_port(portdev, 0);
-       }
-
-       spin_lock_irq(&pdrvdata_lock);
-       list_add_tail(&portdev->list, &pdrvdata.portdevs);
-       spin_unlock_irq(&pdrvdata_lock);
-
-       __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
-                          VIRTIO_CONSOLE_DEVICE_READY, 1);
-       return 0;
-
-free_vqs:
-       /* The host might want to notify mgmt sw about device add failure */
-       __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
-                          VIRTIO_CONSOLE_DEVICE_READY, 0);
-       vdev->config->del_vqs(vdev);
-       kfree(portdev->in_vqs);
-       kfree(portdev->out_vqs);
-free_chrdev:
-       unregister_chrdev(portdev->chr_major, "virtio-portsdev");
-free:
-       kfree(portdev);
-fail:
-       return err;
-}
-
-static void virtcons_remove(struct virtio_device *vdev)
-{
-       struct ports_device *portdev;
-       struct port *port, *port2;
-
-       portdev = vdev->priv;
-
-       spin_lock_irq(&pdrvdata_lock);
-       list_del(&portdev->list);
-       spin_unlock_irq(&pdrvdata_lock);
-
-       /* Disable interrupts for vqs */
-       vdev->config->reset(vdev);
-       /* Finish up work that's lined up */
-       cancel_work_sync(&portdev->control_work);
-
-       list_for_each_entry_safe(port, port2, &portdev->ports, list)
-               unplug_port(port);
-
-       unregister_chrdev(portdev->chr_major, "virtio-portsdev");
-
-       /*
-        * When yanking out a device, we immediately lose the
-        * (device-side) queues.  So there's no point in keeping the
-        * guest side around till we drop our final reference.  This
-        * also means that any ports which are in an open state will
-        * have to just stop using the port, as the vqs are going
-        * away.
-        */
-       if (use_multiport(portdev)) {
-               struct port_buffer *buf;
-               unsigned int len;
-
-               while ((buf = virtqueue_get_buf(portdev->c_ivq, &len)))
-                       free_buf(buf);
-
-               while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq)))
-                       free_buf(buf);
-       }
-
-       vdev->config->del_vqs(vdev);
-       kfree(portdev->in_vqs);
-       kfree(portdev->out_vqs);
-
-       kfree(portdev);
-}
-
-static struct virtio_device_id id_table[] = {
-       { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID },
-       { 0 },
-};
-
-static unsigned int features[] = {
-       VIRTIO_CONSOLE_F_SIZE,
-       VIRTIO_CONSOLE_F_MULTIPORT,
-};
-
-static struct virtio_driver virtio_console = {
-       .feature_table = features,
-       .feature_table_size = ARRAY_SIZE(features),
-       .driver.name =  KBUILD_MODNAME,
-       .driver.owner = THIS_MODULE,
-       .id_table =     id_table,
-       .probe =        virtcons_probe,
-       .remove =       virtcons_remove,
-       .config_changed = config_intr,
-};
-
-static int __init init(void)
-{
-       int err;
-
-       pdrvdata.class = class_create(THIS_MODULE, "virtio-ports");
-       if (IS_ERR(pdrvdata.class)) {
-               err = PTR_ERR(pdrvdata.class);
-               pr_err("Error %d creating virtio-ports class\n", err);
-               return err;
-       }
-
-       pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL);
-       if (!pdrvdata.debugfs_dir) {
-               pr_warning("Error %ld creating debugfs dir for virtio-ports\n",
-                          PTR_ERR(pdrvdata.debugfs_dir));
-       }
-       INIT_LIST_HEAD(&pdrvdata.consoles);
-       INIT_LIST_HEAD(&pdrvdata.portdevs);
-
-       return register_virtio_driver(&virtio_console);
-}
-
-static void __exit fini(void)
-{
-       unregister_virtio_driver(&virtio_console);
-
-       class_destroy(pdrvdata.class);
-       if (pdrvdata.debugfs_dir)
-               debugfs_remove_recursive(pdrvdata.debugfs_dir);
-}
-module_init(init);
-module_exit(fini);
-
-MODULE_DEVICE_TABLE(virtio, id_table);
-MODULE_DESCRIPTION("Virtio console driver");
-MODULE_LICENSE("GPL");
index cfb0f5278415a2d371f2a6902ec0670183f6bc10..effe7974aa9a742b78e893d5ef508fca63481376 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 01b886e6882215f526dab803ebb66531919df544..79c47e88d5d1ed17059aa99c9370168af7530d12 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 a8c8d9c19d740d4686e312be1ebbf1f4b15967e3..ca8ee8093d6c604266c13b94a0949f4ca6c0abba 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 68f942cb30f26808e58b9004107e56dce21df2f9..0c56989cd9073b4d0770a5ad4d15d11a907605c1 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 be0492398ef9573be4eb752b78e485e5b22d0e71..24ff35511e2b1b6a890e7fc9f9499e75c74459d1 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 c2e194c5866717633d426636cc5cd5e43efa821e..7ed08fd1214eccc7bfd9f231e41a68de67ea6250 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 e8b6a13515bdd4906a438e0b25c3319b832f0dbe..e710424b59ea7f793ef1c10c18215dc2716bb7a0 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 d81cc748e77f424c1201fd823bea18a5464ac83c..54d70a47afc1a7f4e6f5f566899090b46bfb804a 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 64828a7db77b7afd7f71b7471c04ac45de6944cf..0902d44600394fd1d6888bd6e5065bda884d2e03 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 5c4f9b9ecdc0759d590b691dd75587a0efd25970..6977a1ce9d98171b9f5e43cc0127e13d87ea3b5b 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 844f3c972b04dd8a55ccde3ab6a84766940b9e31..17bd766f20811ae5622a4276adf78de9a77c5208 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();
index 72fea2bcfc4f77241a7b1087e558637841279afb..66796bb82d3e540b1db6d356308916a534be22b5 100644 (file)
@@ -60,7 +60,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,                \
@@ -752,6 +752,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 5969f46ac2d6023740204c74e62d25265cfc736f..a0149c619cdd117026f2c4f32309ee462b623455 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;
index 3dfc848ff7556e325ee4fdddd1642a44d44d1252..cf4f74c7c6fb6fb7fa8dcedc4839ce2910039846 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 dcfdf4151b6dedddec0f45ba21f2c81156e1fe27..d2f445e825f200b10aad8aef884ddb2ec2671fc9 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 70433ae50ac80fe4fe44f90be74c4cb5840c3715..b0abdc64aa9f63aba4b018626da562421deb2a84 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 b8e509ae065e41c0e5580b48454609dfc3314b55..062f353497e6ee6add30b8fd3469da200fcba7f6 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);
 }
 
 /*
@@ -348,8 +359,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 +846,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);
@@ -1278,12 +1295,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",
index 40a407f41f61954fb5bd89cff03256b5283c3c35..5cfc68940f17dcaaa76b528a1eaf863402a5046c 100644 (file)
 #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)
 #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 98967f3b7724e1554713fa665e62b67f6abbddcd..d7f237deaaf01700c6b217b3aefb2227c43a686f 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);
@@ -6286,7 +6307,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;
 
index f295a7aaadf9e54edb9cbe905739890e3c2edbe4..64fd64443ca69a3e064551e3ebd25e2c08c6a624 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 03e3370725179bd14785aef19bf83f5c13c285ee..6218fa97aa1e27385749a449a055ccdd9df7a1c8 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;
@@ -1291,6 +1299,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 be9087e4c9beeb4c561ebc474a2b38a6124ce8cd..6d6fde85a636248e373d9ef288450597f1ba6f91 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 21d6c29c2d21cfde556d99b7fd7152cb7f2d2001..de70959b9ed51371a42eefccba299b76ab738274 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 2aef5cd3acf578197c1530454c37a345e1efee3f..49e5e99917e22bbf8c8b02cae4d8dce23205b475 100644 (file)
@@ -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 13bb672a16f49cf09e18161b231b7c53477bada2..f658a04eecf951e8dc3b132d4ec4b679e282ccc7 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 01bffc4412d2edcfbe957066f0768c708570cb30..9821fcacc3d2f561ed10da893509ac3ace7d5b21 100644 (file)
@@ -848,9 +848,6 @@ 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 *);
index 7ecc4adc1e4575aca6ef2791752c25300ff7668b..8d9968e1cba8fc47f0b655d16d8aa46c9b8c0554 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 2d7ea75a09d49deb0f21f9228828dd58c7663c47..37e21d2be95be028185748d77e34a6adaf8fa4a4 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 38e523e1099519379f62c8bc017887198b5fdd5c..459ff08241e571400eb63e9e84c2cdae9a150bb7 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 e6ea7d83187f9e71c4d96c9e610d142671fb9140..eb18a7e89f5b51b567964fa5a72f1f10f9324412 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 b9e68b2d30aa5c1819426e63212f72ba8ce7c926..f880ff776db8562842142ebbc5482632e9ff2ecd 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 b0ab185b86f6ad9ee4bddd9eeff65d5601ca70c4..842954fe74c51e411defe35c88647e1a03103773 100644 (file)
@@ -606,14 +606,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 +619,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 +644,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;
@@ -1006,6 +994,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 +1046,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 +1101,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);
@@ -1162,6 +1158,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 +1212,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 +1263,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);
index 4e7778d44b8d36fa4491c97de47aa5f4d400919f..695de9a38506dea0aa19c8b2ec315486c7b26bb1 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 a8973acb39870e2af0c253f92daec14cd80bf146..677af91b555cefc3dec7536b6c08dd1e831927ab 100644 (file)
@@ -2201,6 +2201,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));
index b758dc7f2f2c62ce510850797f1b37ecb85efdd9..d4d4db49a8b8dc88a48b0a09c18bec85f1d9eb8c 100644 (file)
@@ -232,7 +232,7 @@ draw_auto(struct radeon_device *rdev)
 
 }
 
-/* emits 30 */
+/* emits 34 */
 static void
 set_default_state(struct radeon_device *rdev)
 {
@@ -245,6 +245,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 +499,14 @@ set_default_state(struct radeon_device *rdev)
        radeon_ring_write(rdev, 0x00000000);
        radeon_ring_write(rdev, 0x00000000);
 
+       /* 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 +537,10 @@ static inline uint32_t i2f(uint32_t input)
 int evergreen_blit_init(struct radeon_device *rdev)
 {
        u32 obj_size;
-       int r;
+       int 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 +548,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++] = 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,6 +588,12 @@ int evergreen_blit_init(struct radeon_device *rdev)
                return r;
        }
 
+       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);
        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);
        radeon_bo_kunmap(rdev->r600_blit.shader_obj);
@@ -652,7 +679,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 += 50; /* 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 +687,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); /* 34 */
        set_shaders(rdev); /* 16 */
        return 0;
 }
index 46da5142b1314da56b716c8feba1eae082e9e7dd..5f15820efe124579534c0654dba191ee6001e689 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);
@@ -2347,10 +2347,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);
 }
@@ -3522,7 +3522,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;
        }
index cf862ca580bf898bfb43452ad76edd9b2e78b1c9..55fe5ba7def36e058a11bf71e54fae83b8615ad9 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;
index c387346f93a9d5a924bc6aab769e92aebba8fe91..0b59ed7c7d2cc9c4fa37554911c1a40a69119009 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 3c8677f9e38550f05e9940fd12a728d8178a58c8..2ce80d976568c41b2cba34926ae2264c535bdbef 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 aca2236268fae105ce75c6546a06ba4dfb09fb2d..1e10e3e2ba2a388362bf5ea7cd6ab15b618f3dfa 100644 (file)
@@ -1287,6 +1287,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));
index 33cda016b083be82ca99f6a382da813d28e777a2..f869897c745699ab4494738e390a689081fe4e59 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 1573202a6418f655f03906edef82737c21982250..52777902bbcc365c2a2dce237ae79cfe8e120af8 100644 (file)
@@ -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 */
index 26091d602b848b966dd0342217362abf0218ddcb..0d478932b1a9499ea50ef75d56e1a104a434b546 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);
index d5680a0c87af4a557d18e12f30626a98ed6fae59..275b26a708d6505a9f44ae2c8a0b5f45cbf2f971 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 8fd184286c0b8343618bf9d6e0c08e63888a9ce5..5e90984d5ad2817aea7f4dde6bebae7a8d8c50b7 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;
index a289646e8aa46b83a848b4ca9327139593068110..9ec830c77af0be7afdba4c9b32f13f1b277bdbe8 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 28a53e4a925f0c15a23b0d85dbc8145c1e4036a5..8387d32caaa76be06f95aa79bbb30fda15916f5f 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 3cd4dace57c76ed7938e1217984c49c29bce8afd..ec93a75369e671c9b9d0b98407ad5c5e901a4eb2 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 5512e4e5e636ebb91ea73e99d63a4e60bb95bbe6..c76283d9eb3dbd4b0ab40ee5729c2576365f6df1 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 5d569f41f4aeadbe04ee1d1c21cb165d4bf8c338..64b57af937143bd84ac8d31b0383ad91614c51e0 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 8d0e31a22027a911cf7ad2daceb1f5a5b0ca8758..96c83a9a76bb8f54c4d7615f217f9f82127c66fd 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 c380c65da41798faf91b9e730f585be97a7b49d6..ace2b1623b214671d6e49e115d4b3c2f3755230e 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 24cca2f69dfcfb54df9d4a9a02196f83a5b1242b..2560f01c1a632561f32ad67c7af6d4bea22705b3 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 4edb3bef94a649b95d90e19e2b1920339b8d9cf3..0f20fd17cf066ad6b32a868dd8069c0be83077cf 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 ce0372f0615ebd37474a1ab9e93ecc3a3d40e79f..4c0743660e9c7684c12184b9824c94ffe655f4eb 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 2d68cf3c223b7cb401a76481d9064aa040ea2eef..b5e892017e0c57497f7726d59812a56144f35ea8 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 1b674b7d4584ee74b1f8399f87ea9d5e62c22dfc..d805e8e579671d4218a9e1517a487aca1daed761 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 98ccfeb3f5aafcf2306666221eccc026aa632140..9827c5e686cb380d4a0c79f5c1e7a2a1d3c4c9a4 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 7acb32e7f8173de556aaa2fa93db2fecae20603a..1fa091e05690fe345817c9858b7c020e7c005eec 100644 (file)
@@ -263,7 +263,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,15 +273,11 @@ 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,
 };
 
index 03efc074967e2b5344f18acc25f23d2ecf14b2c0..da314c3fec23f905c37313439aa64573a0f5b0e3 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 55855eeabae72c34b45ccc0890ac940dc27e8dc3..cda8eac55fff167abdff061e24e8da5040ab8009 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 07c2cd43109c1ea0332cfaefa0bdb30ceb801db3..1903c0f5b9257d2384cec4a8763cf116c2bb904e 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 7b3c0b8fa432842b091b20611d79a59364903020..c7a92028f450953b264ac6d8d950eeef9135c4a6 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 4e5571b72cda460ddda5363f1738dbeef2c103b7..468c627a28447efb78b9fb32b9a35351719d4f06 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 6069abe31e42b0b4a8f17cf0f08ac91ff4de3fe4..eb3006361ee4440179b46377e272f97e6c7010b3 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..ac471b7
--- /dev/null
@@ -0,0 +1,727 @@
+/*
+ * 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;
+       const struct tegra_kbc_platform_data *pdata;
+       unsigned short keycode[KBC_MAX_KEY];
+       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),
+};
+
+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;
+
+       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];
+               }
+
+               val >>= 8;
+       }
+       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 = ARRAY_SIZE(kbc->keycode);
+
+       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 b4a81ebfab92bb32f4949264ab6f9b81623569b0..c8f097a15d89a4865ba0c324cc63b76cec2646f9 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 bf5fd7f6a3134ee1fdf8b3119b10be9a5b1137f8..9c1e6ee8353187fe3d84a5fe0fb7b0f25260f601 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 da392c22fc6c045007194516c8a2ad2b004c03ee..aa186cf6c514526fec46d40d4d5a47bbe38af0e9 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 307eef77a172f2b3db4839096c491786955ae3cb..55f2c2293ec6a7aee2c1a7573af2c0d43c1f9c28 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 448c7724beb90eda75edc0ef2d83c04e1fd9357a..852816567241cf5f0f08cc72c55bbb38b854ab8b 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 6e362de3f412fe32a5755bdd49aed8bd891fecb5..8755f5f3ad37c2218de60b96782c0863615a705e 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 a29a7812bd46cea26613b813a3091eed476077aa..7729e547ba65d853581e115a4ce6428883549ecd 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 518782999fea2b2bf07e9aec0ebf6c9e25722d1c..367fa82a607e81ef8bf03d7b69c8bc231736fc65 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 0c9f4b158ff0db22b0f2bcbfb697da1307ad18db..61834ae282e13c72be5ea2fad3dca266debc91b3 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 f7fa9ef4cd6579d5ee9c9ec47e5cf57e2034498d..1507ce108d5b1f418f131265110f174cde22a0f6 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 cf1dba2e267c1510be41c901f02a058f94673bbb..22a3411e93c56bf7f8577334ab19d7a4e2003111 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 da3fa8dcdf5b924f71a7f117c05009f0fc671514..666daf77872e56239bbf59a002c180593996ae7a 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 991d93be0f447313945b6925a0a196c19a9586e2..ecc4bf3f37a937d74ab71f6c6cf91c9fc3763eb9 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 04b22128a47421cac65a6dd73480ee56c87ded1d..d21578ee95dec6f4b07a05b9ff70aa07e64ecada 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 b4eb675a807e6c71f021de8c84133bd6c26bc50b..9f1659c3d1f3fc895beaa4f30925e66eb55e662b 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 2e041fd0a00c41024aa6bfc8b42ee3a3d2b0ba4e..f3a29f264db9d6ca9624e8b18b21a8a67607728a 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 982f000a57ffc896eeeda4c8295db20fdb6ff8c6..9f47e383c57a5778bc39161c06d2c6631d317b46 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 e3fedc60fe7775bb0586492061ef63a50c0e0d27..1bd3dd762c6b9a9c955bbbb3f1035a709fd8bb83 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 2d4533ab22b7918e457f0a0bdfeccb03eb1f3bbd..afe85801d6ca8480309db96d77c9215b200dbd63 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 0ac5c619aecfcc60f56e152b1477522de44107bf..9aafa4e969a8c741c95f01bd01efa6d4bcf12019 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 78b089526e028745a30f32bccc90cd384ba632b3..6fc79f15dcbc67d00b86db6f115d66b4e74c731d 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 c9062ceddc719d25cb05fbe253c1f8d3dc46b8ae..bc6a67768af1ed7a7ecb35b6af176895bf69e533 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 8ca48f76dfa98dabba32e4af6175ff9e23066fcd..98ffb40728e34eeaed9f90e981950cae3610630e 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 fcf3828472b847b537887c8a6f996fe4d2093f79..f82d4a93feb3f205080a5bdc85d0dcf1b58f48ac 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 ef3e43a0319997ad88506f0498a3956ed9ea99fe..b8519ba511e5326373dd6b873aa687bff3f0e94b 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 ce222055526d4d6debba76d1e07b416f2e65d0ad..ba25fa0b0fc2a5bfb098a94c258f9d913c1806c5 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 6360c681ded9672db8ef5e21fd6128b01eeba336..6c2e929bd79f6d01c86b987d7a3f62a63c64c760 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 d3ad3e75a35a49eb52977a84f14853364a6e51cc..cc4acd2f920d6e1efd0842dbe49545f8b02ca360 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 122c72806916560ce6c3ce3c676e626c0ff7574d..9fc1dd0ba4c35fc1d6030fb17dc90fbe75d5d849 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 3c5a4739ed70224b9ba11a3544a0a9ef2e935072..ecdffa6aac664e477b7608b563ee578d43b40936 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 d2970748a69fdc29c6da8e0cc325b03d4e4f3227..717656d2f749d48657e72b082f428f8c20d8956a 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 6cc5d130fbc84b3251a995499da96c504b8d59cf..4ce10dbeadd861c587ad274ccdd09e784b9a729e 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 6459a220b0dd46ddb22326e0595f8964ae4915d2..5c2a9058c09fd6966d4c47c8c44b8fd681e8d9a6 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 dd6bd364efa089d509ae78c0a28b20e0f63f62ad..7ecc8e657663edba0c23a6b2cbb1628f1e7dd606 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 ac76dfe5b3fa09347c389950e6cf95e496f17441..60c176fe328ec4a38fb163e401428a148558a81e 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 80b3c319f69814e95b8b76740a76acb662281dc3..1ac49139158df8086148d77ec9695a00b08a628d 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 c179baf34cb420f84268c1e8f10e1c879e1270f0..337a41d4450ba2aee45171cfc7e92117baf7e24e 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 6811512b4e8304615102f53832e8fc13980fbb65..e7dc6b46fdfac2df6f6ead2661d4fed6ea4c4358 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 185baddcbf14545b829a0aba4e84f2917bcc935e..73230ff93b8ac0d117801a9b98ab8fbb69e6e11a 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 c59851b203da160a629298bb40bd27aa0c21680a..7a5f5300caf9a0fcab05acbd8febe0acf44035a8 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 0fef6efad537adb14000ac426d942f1d7871ecf2..079353e5d558daa640f72d4e315bc8ec4ea45e5b 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 */
@@ -858,7 +857,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
                        ir->rem--;
                        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);
+                                        * MS_TO_US(MCE_TIME_UNIT);
 
                        dev_dbg(ir->dev, "Storing %s with duration %d\n",
                                rawir.pulse ? "pulse" : "space",
index 72be8a02118cc7cbb9440a7baab9fa8128930dc1..512a2f4ada0e113ccc213ff5a5c50d0d93eaaf90 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 eb875af05e7943d3f8428c983d7ffa45e91d49b4..aa021600e9df352c33fdc0131bd5b2c8113774de 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 81e38cb0b8469ad69f37b679c39329173538b57d..a509d317e258d9580d146e5ea1473f9fbab36f39 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 f318b51448b3b0a3607210668bd7d9a16844b0b6..d2327dbb473f6aae0b3be765a7dd71886adca38c 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 49efcf660ba66cad6dc1e796beb23ea6282b7ca0..7f58756d72c8f8f69ff1bf125ab62769d744acad 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 fd62bf15d77975822af34af8d9a6d5e4088ebdfa..c6333595c6b90a3749fabfa8e3f90de1751fa2c3 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 49f1b8f1418e94ae36e6b80219581056246da045..55ffd60ffa7ff05b99099108937d61e8eafdeb00 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 916c13d5cf7d12c9a725f895227bd2b197017de6..6d6d1843791ce0a7ef880211b33f92c85bee4922 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 9606bc01b803c118db6ffeee85f21a3f58f046d7..aaffca8e13fde4a0aa2f3a30848b25590fcbc021 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 7edf80b0d01aabee0a080721f1ca2c36c90d66ec..9bad398429366934a83fc3d2c1c8cddabb6fbf50 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 133ec2bac18053018b547a45afd99fccd3a010b8..944af8adbe0c8095fb59ee11d50b567d25cc024c 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 f6f3e50d4bdf7f1fd04a87f57822278f70ad4c6a..306caac6d3fc05a15dfcfc7998e51e1bf10c168f 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 51765eb12d39b0e31f05f0ae66f9c13c417501dc..713b0e61536dd6a8f9edd330d708c0388f13d447 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 fe59a1c3f064369606fe7b99d9d3100c9c266ece..363aa600422103834cf7af9e5c9be88a2f26ece5 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 f16461844c5c0063e281da22b8cd3e27fe6d28f4..6fc09dd41b9dd56581ae6d5b9b597beea94ce0d6 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 1f532e31cd49b28b3c8f998ce73ed0cce3da2120..9f3bfc1eb2402648a25dc0c1e90ce21cc374e50b 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 ebd5c4338ebb3f2fd10492dccc5d0a429325c1ec..10550bd93b062851cd8154e9f5f541a0dc849178 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 193abab6b355e90b619a3a57d4ab434a551640b5..d93ad74a34c5fbe46631bb579836b03b6e4bb42a 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"
@@ -80,20 +81,6 @@ static struct vpif_config_params config_params = {
 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 4e12ec8cac6f5ad863861ce95c37430deb628294..7a4196dfdce19c649acb61b07e5f3600b719fc33 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 412c65d54fe1a3e9397aae9455edf49fc295862c..cdf659abdc2ab73ba172d85fc6a6aa75db4390c1 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 a2a7cd166bbf6e2afa12120ac55f25725f7ba388..b53aaa8830753bc18937d672d1fe2c5c046348a2 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 099d5df8c572dfc77e2ee1a85403a3b1a7b52bde..87f77a34eeabd092a678208dcac815caf0c230cc 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 cc77d144df3cc4bc68f77c9fc7a07a150db7b2ac..bf66189cb26de1fba4f58884e458b89adb08d2b7 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 62904393350104217490d8edbd002f6933fc0160..a09c4709d6139b9616e79804b39f0d1aa982ac1e 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 1eacb6c7926daa3737f1283d0bebd94bee8a83a8..8b398493f96bc65e63dd018bfd684109e16c9b6e 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 c1ae05f4661f240d2fc65b504f3881d41eeeac63..4bf2cab98d64cd2a4c38a8f77de2ffb57f1decf5 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 a594b36d6199cb5cc45e4f0b229a67be5daeb78d..4b2c483fce6f9d48fce457ad764d3f4e0fdc5466 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 d78226455d1f40f0e6a586c95bb64d3fe4be181f..987b4b69d7ab2a71a06d7dc0c39b235646ef47a2 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 b05bec7321b5d94df6a93efff96db96f053405da..99083038cec3b7ec55b8ba861c5c8a1c1ed175bd 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 442970073e8a553482492706d687243ec638876e..f21f2a258ae0ee5722ebebcd1e9925202bead369 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 97b77a26a2ebf46736ffe57c116e49bf55b8e3aa..41755226d389f61cd29d0e58a98f5e3f11825182 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 a35e87bb0388bb0264dfad8335008452356e5982..06b777f5379ef7c7f92198cbe53306e6387be183 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 de63c36806c09bbb2788faba8c1c6833c81863b8..ab54910418b4ccfa7e07a179f4dbe82ecef00d17 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 d2ce65dcbfdc16e48761f643415fee5f613e0147..5964691c0e95e66f8b6c56905181ba0281822b6f 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 c872b93a3351c02f7186402820437fc46a4ac98d..a7722b1aef9b5963d1dba5cd511a6860393e7dbf 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 a81536e78698bbb41eda812e8689735198cdbc73..cb4d0bf0d784787c68a8ee3ff3954e5b06a79f41 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 7607a288b51cd326b89db0f2f5826f101ba84c23..3884c9d300c5ed766f34eed7060cb59161494c77 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 e1c3b9328aceb9c0ae1de6df55ad608e102f47ee..8ab2c452c25effdba21d956e494bbe6b7ea3ff39 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 0edf93973b1c7eb2eb27e322e9799d95db90121e..04da228027360331195ebb9f38c8d77e74fc9ef5 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 c5244b4b47778648275daf975f7cc2b3cbdbdabf..aaf5428c57f57ac4fc3e37223074ec456973ebee 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 96f9986305b4f783d5919705470119de07b6cc09..81739a2f205e8e020ac789c984d60a143603e3ce 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 2700975abce5e277103830ef419485054d05976a..5615d7bd830455e8e1e269c94311601e6b4b8c16 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 6820f5d58b19d1933478a98bb0ff0b4f629d8ed9..f8801b50e64f2f20b5c5030bb76faaeafef073c8 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 40a06680502d15ee48254eede1721932449aab27..4271f86dfe015eab27bc91bec6d4149b25e175bd 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 cb08d00d0a31a03db86e2fd6822485d7f424ed96..fcf29897b71308f9148ddf40bdb515497e09f5c6 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 73504a3f87b75ffdbc21e958b00ef0001a7e71a0..c6cd68d66b533a9b08e87f114e5cba69d48bfe24 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 2d0bb17a30a29db28d831b10ab9be49f062399b1..d6f39ce1b7e1612dc53fb602a707f13c6d492359 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 e643386644107a9dabcf1c63a393826e0d6fb5dd..76c006b2bc83035edbadd8da3d907b2943069ed1 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 8e202b9039f18895358cb12d1762fa284f481bec..45552c3ff8d9ce701c36e3c75070260673911cfe 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 642839a11e8d061aeb5c7c7ab5d590dd6e961814..f7ef282cc600ccb75a39fa025b06774e6dcd5f26 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 bc9dd9034ab499c9dbafeeb0a117f2d341722097..e5bf865147d7a5ec4ffb0f43e2acff3bb1909816 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 7307638ac91d65e221f3f6f6981d874e7e39b141..348319371523849da40357078c7f812a22689c9b 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 3a162c6d54664e807ea368df14cf8015ed0c9b7b..e836e778dfb6ae08f3890b2f6d69759926fddf83 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 4040677457755e1a7908dca3af2701f07ef946f0..2e9c06175192cac3a2d5940ede21cbe57c15f2b5 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 8ba1995438568c2eaef60174081b6bd4e4dd59ff..457563b7a71bd98e246225eb2d4eb8026c1ebfde 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 a4a98811b9e3f982415e298e5cd7b35040e153b1..8215d5dcd4560fa8383215971709b1e92dc36b31 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 11a192b95ed47394eb667f9941e8d3e08f51ab70..87be52b5e1e3666528226966d5d7456d369faddb 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 b199ad4666bd4517cb8a56baa0ab499a0a8927d4..e2ef41cf72d74bdaca8425d34048a3a159895cb6 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 28ea4175b80e55f4850ef1eb571ea347a39d685c..7e06614292936b15576fbf3f669d62369fd1b025 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 a9cbcd6011d9c19e7e2ce97942a54a77287feefa..543542af272048ef0e5d6bfa07887f4eb6b44774 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 8f0c33116e0d1e65eaa7d3d91f76251ea2e56678..a3eccd81576625119350e6177cb834d72c7ba652 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 38c22f0a4263f02a986d586d54a68391c2f84457..933ef2ca658c377ad5ae0312512f6882bac1490d 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 9b2ae1b6cc75c736f9607b63c601af29ec576dea..6caed734a06ab0559892a869f330f0d0840f8865 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 5b5039a02031f87ebd1b6e35193e79fa9ae603bc..c089a0f6f1d034924553357e6645584bb82504ea 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 14b85d48316393242e8b3c2f91f8d3dc96faf0a6..865216e9362c55c956af81b737855e58ec1fc318 100644 (file)
@@ -6909,7 +6909,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 e0230fcb2e360f234543c5a89612cc81d5831265..3baa9f613ca36aa82efaff5742cbb463c698c13a 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 f7d1ee55185a527c4b0302acdbd30c5b5f523c1c..a6572e5ae369f76e065826fc5bc471902f0daaa1 100644 (file)
@@ -378,19 +378,17 @@ 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");
                goto error;
        }
 
-       /* until i2c is working properly */
-       retval = 0; /* hdpvr_register_i2c_ir(dev); */
+       retval = hdpvr_register_i2c_ir(dev);
        if (retval < 0)
                v4l2_err(&dev->v4l2_dev, "registering i2c IR devices failed\n");
-#endif /* CONFIG_I2C */
+#endif
 
        /* let the user know what node this device is now attached to */
        v4l2_info(&dev->v4l2_dev, "device now attached to %s\n",
index 24966aa02a70ec5d49a9e233ef185f96a06c3b1d..89b71faeaac2dce9f2216fadc8dd7b5987e702b2 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 struct i2c_board_info hdpvr_i2c_board_info = {
+       I2C_BOARD_INFO("ir_tx_z8f0811_hdpvr", Z8F0811_IR_TX_I2C_ADDR),
+       I2C_BOARD_INFO("ir_rx_z8f0811_hdpvr", Z8F0811_IR_RX_I2C_ADDR),
 };
 
-static int hdpvr_new_i2c_ir(struct hdpvr_device *dev, struct i2c_adapter *adap,
-                           const char *type, u8 addr)
+int hdpvr_register_i2c_ir(struct hdpvr_device *dev)
 {
-       struct i2c_board_info info;
+       struct i2c_client *c;
        struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data;
-       unsigned short addr_list[2] = { addr, I2C_CLIENT_END };
-
-       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->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_i2c_board_info.platform_data = init_data;
 
-       return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ?
-              -1 : 0;
-}
+       c = i2c_new_device(&dev->i2c_adapter, &hdpvr_i2c_board_info);
 
-int hdpvr_register_i2c_ir(struct hdpvr_device *dev)
-{
-       int i;
-       int ret = 0;
-
-       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]);
-
-       return ret;
+       return (c == NULL) ? -ENODEV : 0;
 }
 
-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 +120,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 +142,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 d38fe1043e47dc46951ef07eb051599e98744042..514aea76eaa5b68b30acf66b0ce4fd4446421fb5 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 37f1e4c7675d4cbc070ce700bb07ff3d55f594de..ee74e3be9a6ac60bea9291292082e850c0c4fcf5 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;
index c87b6bc455556dd7b4fbe607dc18dbdd909f5840..d2b20ad383a3e9e31a35032895143ab2ec59a4ee 100644 (file)
@@ -244,15 +244,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 +323,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 e103b8fc74525753ef0fe08d236bea3c818823eb..9fb86a081c0fe43f9f0f891ba7b3c47eb009b377 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 209ff97261a95814bf585e04bf957c160512f9c8..4904d25f689fdf61c60fc0d8db2d40f80fd473f8 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 c881a64b41fd9328a29abe9436a82682e613a7ac..d4e7c11553c3b427ee12e99631f2a65a224c9bfc 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 ac94a8bf883ed9ba82dc629db5d99c333beb50c1..305e6aaa844aca618c5aa4c81ee56137df723144 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 7cbe18c4ca9568f75f0c8f7d837e9e8981ac06e1..ccc884948f34b385563ccbf548c5f80b33cd4f08 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,56 @@ 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;
+               init_data->polling_interval      = 260; /* ms From lirc_zilog */
+               /* 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 e7aa588c6c5ad78d3f21e014cc32daba94970f74..deb8fcf4aa49550fb251407a092774a4284f9d32 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 3315a48a848b682f437c1e500286b655fe7ef15b..f65cad287b83e198eacd21ff4b30f279f2783bb3 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 41064c7b5ef8d896e2deb133fb89b10e72d09df3..b3d2cc729657df34e57bc300033bafc1baf2bdd6 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 864696b7a006e5e3ca8965dd33e23d0d59c6128f..c901721a1db3e7380d25a71da9b3597a5837cf66 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 a1ffe18640fe95778a6a1feca3e35aaa4d17416c..df33a1d188bbf1224716961cca57e79bd1afd17e 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 3f0871b550ad0dd030f0d99027f44ed9ea0ffc93..810eef43c216b86e153ad5b08fe8a432f2609986 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 8f81efcfcf56a7d9e481878a1723255170af7446..ef66d2af0c57c8adea19be12ad78e2b1c754883b 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 359e23290a7e99ae0301a6d6844a445343cb900e..341764a3a990e4cfb4c815aa7f41658ec92d82dd 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 7fe6f92af480bc46288b3eff1d0358a30bd501e4..ce64fe16bc604137d3522af06931ab562983865c 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 7e47f15f350d570c771a3d4b02262fbabf3dc149..f51327ef675734c1274669e4ff36f37f82d55b8b 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 019ee206cbee0224fb71c9a86678c05ecf3da7d2..fa35639d0c150bd6851a6c80cd393b464ca92eb9 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 9cdc3bb15b15aa008029e9e03f47b8dd04c0d1f7..9f2bac51964781f51c2e5b9789511d9b3d04668c 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 bac7d62866b731cc60e924a34521015b7c2cc288..0371bf502249baf416d78b85c88ca1ba218f28b0 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 b3a0ab0e4c2b6ce37ed2ff68321c154e45d5c1f0..74218ad677e4955d2dcb0941f68ed45c3fa4e85b 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 56302282566777daddc5c63bb2eff3582b0ba062..2d6de3e03e2dcca2e01f9322ef5c306d5bb473af 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 df06f01aac8953a482bb25fdf3261f2496b6504c..c1df7b82d36cc63f5f420ac71ff68cdc120ccee5 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 5decfd0bd61dc1d1369e8c5cd81fca8d681f1322..153ab977a013638a7d1a187d3bdb73a33c8d2345 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 17203586305cf57f931449de97a7db7c5d099262..5309ab95aada9a39914300833b1be38f4ec07ad9 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 f8f65df9b01746052a5fe457f3e9419a98e63ee2..f08f944ac53c64f5cc57877eaefcb9ec02c96c99 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 f49e49dc5928cf1acfa5b25d019162f99a3eb1db..5ebe280225d60a69f28bc81c5c4593a47e017365 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 16fe4f9b719b5af1839ea6cbebb7d03e3c6f8c01..03823327db25236c09199968baa6441458f70017 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 62d6f88cbab57deb4fb7141745f700ad68efceb4..aa07657744c3a8a5d1fff8437dbc04e0689dd115 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 df99edf3464ad59e4872ea82f008c13c9ae3e942..0ba59d5aeb7f54253171f56dc711b2a3e47f0f89 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 5488a2e82fe93a445dd9e38f695d7035703c39a3..f459fb2f9add61ac8c16063104578f3e21e48e66 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 a6cd335c943656a9ac67d37c15ea5d9eea3cc899..8e4183717d911d0c190e9fe6a8ff15b4a44a9a7e 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-4"
+#define DRV_MODULE_RELDATE      "2011/01/18"
 #define BNX2X_BC_VER            0x040200
 
 #define BNX2X_MULTI_QUEUE
index 6238d4f63989e5f5c6340b64d028cc37613600e2..548f5631c0dc1e56a2b7df3c5e3596e75639e2e5 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 43b0de24f3918cf42e886dfc7cbd022493bf21a4..7160ec51093e5c9d97c4382640690aa866793c58 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,14 +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);
+
+       DP(NETIF_MSG_LINK,
+                "bnx2x_8073_8727_external_rom_boot port %x:"
+                "Download complete. fw version = 0x%x\n",
+                port, fw_ver1);
+
+       return rc;
 }
 
 static void bnx2x_8073_set_xaui_low_power_mode(struct bnx2x *bp,
@@ -4108,6 +4158,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 +4383,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 +5155,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 +5852,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 +5972,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 +6239,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 */
@@ -6489,6 +6603,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);
@@ -7663,7 +7778,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 +7785,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 +7952,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 +8010,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 +8018,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 c939683e3d613c92761f648cacfe4d284b75f9bd..e01330bb36c754966543adde30179fae57e75b54 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 171782e2bb39354de45e011022235f3797e576c9..1024ae158227306aeacd30fa69159b3bfac97987 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 f4e638c651298aba65bae970216d4c0e7a7dfd00..5c6fba802f2b759561ee6c9c0c44bd3ea761b2c6 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 b1025b85acf1210f70da338f5df4292d316e5384..163e0b06eaa5d1aba0dda6aef0765016020e2b1a 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 d5a9db60ade9cf783273f57a7abac5679aea0003..986195eaa57cff44bb982149504c558944f09ade 100644 (file)
@@ -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 07ca159ba3f91ab643a167cda786d46a488c2e05..53c82a71778e8b20c80308aa1ceca1840272ab92 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 7ef83d06f7eddce14ef7a4cff8cc866a0a6bc572..2532b96315389bb4878b23060ba0a229f92692fb 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_IWUGO | 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);
 
diff --git a/drivers/net/can/softing/Kconfig b/drivers/net/can/softing/Kconfig
new file mode 100644 (file)
index 0000000..92bd6bd
--- /dev/null
@@ -0,0 +1,30 @@
+config CAN_SOFTING
+       tristate "Softing Gmbh CAN generic support"
+       depends on CAN_DEV
+       ---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
+       select 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..300fe75
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * 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 <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..5157e15
--- /dev/null
@@ -0,0 +1,893 @@
+/*
+ * 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 = {
+       .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 263a2944566f6948f759f029a875d6f4eb01e3ce..7ff170cbc7dcfa7ec73b8ffe055289aaba8093b9 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++;
        }
 }
index 059c1eec8c3ff79b23d7ea8e9a17c111c8c57429..ec35d458102c797ea7f19cf6fcacb9bff88aa408 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 119aa2000c24a7e7091c517588ab64b175e50c39..5ed8f9f9419f163c26703412bb03512537a7e966 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 9e3f4f54281d984053155cb9a4854f876120b251..4488bd581eca013be6b2cba3d362ce98ba505444 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 84134c766f3a86fca82195683be07de25cbf5fa1..a41b2cf4d9176d4629a84aecb05659347e00ea78 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 d7355306a738fbbe78b7848423ea203a6fd5c444..1bf12339441bb5887a4cfaf2c81abea647a41923 100644 (file)
@@ -2247,7 +2247,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);
index 7841a8f69998d5351bad0745350edcfa65972208..93b32d3666111c55179f66e9760bb838c1fc103d 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
@@ -11230,31 +11190,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 +13001,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 +13794,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 +14562,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 +14578,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 +14627,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 d62c8d937c820cf3a124a2250a351156b49a84c6..f528243e1a4fd73fc289d65ed63f24124aa79c5f 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 d776c4a8d3c1bda74b9699156d5b9690eed74863..04e8ce14a1d068d2fbb4cd2b3df38d7d299ae810 100644 (file)
@@ -54,7 +54,7 @@
 #include <linux/usb/usbnet.h>
 #include <linux/usb/cdc.h>
 
-#define        DRIVER_VERSION                          "30-Nov-2010"
+#define        DRIVER_VERSION                          "17-Jan-2011"
 
 /* CDC NCM subclass 3.2.1 */
 #define USB_CDC_NCM_NDP16_LENGTH_MIN           0x10
@@ -868,15 +868,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 +904,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 +911,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:
@@ -1020,8 +1025,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;
index 5e98643a4a214b2734d738cc7a24b55ef0225298..7dc84971f26f8720f8aea9384e33a669d1b825b7 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 d143e8b72b5b7bd1ce021f48f666a3b5a21949dc..cc14b4a75048ca623fae4519cb11b946630f01ce 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 8e17fc8a7fe7ee512ff0af5881ab595c7983b690..81254be85b92629288e21f6f94ecbfe5f4ac5a1b 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 7fadeed37f032ba4ddd0342e67ed1c392dbe6739..fb5d245ac8781c7b0f385767a4ef1697f7024122 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 019a74d533a6e88caaa1cf26078ffd5e57d06159..09ae4ef0fd51fbf2dda13c6b138d76f75007577c 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 ea2e7d714bdad0888e070dc61faf5acfba26ff15..5e300bd3d26457fe999cc41185c6cce42b07eb22 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 81f9cf294decc7cacb29019979454b9e18805fda..9ecca93392e8a563fc9775caa814b3ae64120917 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 6137634e46ca6d87fcea94dbd7eacf3607448b60..06fb2c850535f3dc2f84db86a5988bd110c1c160 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 1ce506f231107a22893f9da8aba0faa8dde5e686..780ac5eac501d401470e6fdb99d14c5f085f4cc7 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 33f36029fa4f9b351f9a3157b563783b5b2dcf50..7a5ffca21958a45657e1cf23370e01bb31e498f8 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 1afb8bb85756ee55e5a2a82d5f1f825279c803ea..9f01e50d5cda718e391f9582f71064f82c5f8733 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 5a3dfec45e96004d02c84a33cbb39ff9aa201d45..ea9fde6706461cb12560b53018ef101a87be5481 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 f90a6ca94a7682705d0180bd74119873d6fc2416..c79c97be6cd4417afd8a2cf2ff0776c11856f17b 100644 (file)
@@ -592,14 +592,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))
@@ -969,6 +967,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 +1014,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
 
        /* Start ANI */
        ath_start_ani(common);
+       ath9k_ps_restore(sc);
 
        return r;
 }
@@ -1701,7 +1701,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 332d1feb5c18ece5b4024beefc21fb83826902f4..33a37edbaf79f5ce249dc5c8ca35812e85ecf60f 100644 (file)
@@ -2113,9 +2113,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 3f1e5f1bf84720932e25ffa88f63b4f80d972d9a..91a9f5253469948d573725ec54cc7b5e6f1e3208 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 97906dd442e628ea733dec41f6aac79c26b7c8d1..27b5a3eec9dc28dc12f17d8a47bf9ba25250085a 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 13a69ebf2a94cbe67834f5dd9dec9c752e6deaf2..5091d77e02ce7a8838237cd6cebe0d0f0eed733d 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 f0e1eb72befc0abff02c5f7e2f33d8d610c70cdd..be0ff78c1b1666178864c62e8f367a6fae939a9a 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 0b4e8590cbb77e067902f9d176043db0a713c4c9..029be3c6c030971f6aec1d9326e43185a8b6479a 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 0fa36aa6701a80fb1b06f03891bd3830d7f5e4ca..1758d4463247395c7e9d3d15a8e3be5010160744 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 a2d9d1e59260eab17097e0a12f16908eed26c552..a848e02e6be3d4537b5dd94c7017ec799cf7becb 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 dda70981b7a6f4ef3f4a29fc84f826111b1d0306..dc29348264c668e16c63a7909d59e82008a18109 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 de886f3dfd3926c8cd9f1974926ff1689baf027f..6e318ce411369176b7d43148656438806f2d316c 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 1752ef006d26e44f2154293ba9c6f052cf2480e0..a91d510a798b2a9e5f2e35c67c369979b273900f 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 ba3231d0819ee12163807147332297082341ee1c..b93a03259c16909b2e7a811a0aea1a4278239aa8 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 2728469d388494031c401a8dcbb64028370a1612..82583b0ff82dac05efd9c1d495654ccd244419cc 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 32221efd9ca979d9518d2e130d2e4ebe3cba777c..c571d6dd8f61f626bdaeb6405de5a3f8aa7a30a6 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 5c32f8dacf56d5fa265a8edbcd0e50d829bcb0a7..b93af3ebb5baa1ece794b9054ca0fbf84563f20e 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 467e82bd0929789867031a0ae31e1114d38e8274..a50391b6ba2a95b8afcc6d397a90c068c5f9bc36 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 4941cade319f5cef06d508d0b1f1354d951c1034..cdd97192dc693cc84d075e24af1450ba5aebd2e5 100644 (file)
@@ -97,18 +97,6 @@ config RTC_INTF_DEV
 
          If unsure, say Y.
 
-config RTC_INTF_DEV_UIE_EMUL
-       bool "RTC UIE emulation on dev interface"
-       depends on RTC_INTF_DEV
-       help
-         Provides an emulation for RTC_UIE if the underlying rtc chip
-         driver does not expose RTC_UIE ioctls. Those requests generate
-         once-per-second update interrupts, used for synchronization.
-
-         The emulation code will read the time from the hardware
-         clock several times per second, please enable this option
-         only if you know that you really need it.
-
 config RTC_DRV_TEST
        tristate "Test driver/device"
        help
index 90384b9f6b2c52bade8b2dd067ff31ffd73e7930..925006d331099699e27b26012050b81cd3acbcce 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,15 +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 (err)
+               return err;
+
        if (!rtc->ops)
                err = -ENODEV;
        else if (!rtc->ops->alarm_irq_enable)
@@ -235,12 +242,9 @@ 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);
@@ -488,10 +492,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 +508,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 +525,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 +641,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 +659,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 7a7a1b664781073aa09d10bfa134a1d9b8eb6b09..2ac8f6aff5a478e3bb34051aeacf3d9128890024 100644 (file)
@@ -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 e227e465bfc4686047e9f18f111681dfa6672364..d09b0c44fc3d35c89224fd699b2cf0a2624d283b 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);
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 de885a0f917a4ca747da4a46e44145068896ef8b..f33e2dd979348f4b78560d15b2f8e9f9d33ef09e 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 2d8cc455dbc746a9dfe5d7811b14dc97d2feb381..42cdaa9a4d8af3ca2587c2b6db269e4495c4b55a 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 50f2edd0827aa96988fb020aea900373d5c44385..e2a67fcfe3c8f1f3b1fb6a662cb63eb8b17856b0 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 65057329c994039aae87cea52071327d434689b4..add00462bc52c05ac7eaa9df0b1c878cf1d32683 100644 (file)
@@ -179,11 +179,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
@@ -216,7 +213,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
@@ -749,7 +753,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;
@@ -1060,7 +1064,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;
@@ -1075,11 +1078,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);
 }
@@ -1103,7 +1107,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)
@@ -1115,13 +1119,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)
 {
@@ -1154,12 +1157,10 @@ static void wl_remove(struct pci_dev *pdev)
 }
 
 static struct pci_driver wl_pci_driver = {
-       .name  = KBUILD_MODNAME,
-       .probe = wl_pci_probe,
-#ifdef LINUXSTA_PS
-       .suspend = wl_suspend,
-       .resume  = wl_resume,
-#endif                         /* LINUXSTA_PS */
+       .name     = KBUILD_MODNAME,
+       .probe    = wl_pci_probe,
+       .suspend  = wl_suspend,
+       .resume   = wl_resume,
        .remove   = __devexit_p(wl_remove),
        .id_table = wl_id_table,
 };
index 5eb41d64bc2363dc09cc9a1a7c247624212c9590..683bc5fd55eaf994dc3ec25c1c2c15ef7cc8f705 100644 (file)
@@ -5137,7 +5137,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);
index 4d1868d04bac93a6ecb49c2a51f456b3d62b12bf..0728c3c0cb0e258738e0f0c767eaec65e3adac95 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 26a35cfbf5721bc22b3d175c9c593dc043016b9f..58bbcd60b3d7ffb26922515d52e2d4d08a228e0b 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 9a159dea89d21db2200421f597dffd649df55e7f..431936338731f06cee25a19faf74cdc8460121ac 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 9d9313899fe5d1f54cc20d6413de183483f2d54c..95fa810255edd0b0bdef8a68fcdd971c644c70c6 100644 (file)
@@ -358,7 +358,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 4708b8e954f37627332e01eec066efa73a1b7ee6..d263904b3d1dcb8bd38569512868eda8705eb91b 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 685908995d49198e7b11a46ed0eba2ce500ca913..5d85efab658cfbac69fb8b3d055f89e7ec88740a 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 6309d521a864932aa09cfeb9b298b600cb3254ef..89ccf375a188c79fa586dc9036d7763e2d6d655c 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 e3387cd311457f067cc6ca90590a388a38c2e2b6..0f87ecac82fc044e84d7673152e71f3f9d3d821a 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 6aa312df4018a7500289169ae592491751e797d4..2d0263f07937be78af2c3e8717c4c19a4c36c6b3 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 0da6b9518af9ea4e068051ca24706e97aa917faa..235cab0eb0877483267fac5dbdf6c75364a5f59e 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 929ae579546773c5a6f1cd34fc58f908985df1dc..5938616f3e8fc957f120c7b6888740a3e554a9ef 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 dfd2c447e67d38aca01dfc833ee23ab6f1e77486..3a9c09881b2b7064e4d3109e5b4d05463a93d123 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 998485ebdbceb136c764449b3667872b32cc5090..925eabe14854d93cc0267110da2ba646758f0aaf 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 9bcf149c4260ad3a8020caccc98801fff40664de..1c3099b388e0acefd601621dbe05a9c6b78451b7 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 c553ab6262386ad4b68916f928ee25c770f3fbf2..76be7b8c620968218822c3216204e14ffdc2250b 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 ad29bb1275ab260dd37bb28440b2cbc80e3d8fbf..3fe5f4160194341e69ce5ff5ec789cda6326a0af 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,32 +493,32 @@ 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;
        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? */
        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);
+       ret = i2c_master_send(tx->c, buf, 1);
        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;
@@ -543,7 +558,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 +573,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 +700,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 +729,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 +751,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 +759,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 +779,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 +798,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 +815,26 @@ 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);
+       ret = i2c_master_send(tx->c, buf, 1);
        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 +848,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 +859,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 +873,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 +886,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 +911,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 +936,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 +969,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 +986,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 +1012,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 +1041,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 +1054,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 +1071,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 +1126,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 +1145,6 @@ static struct i2c_driver driver = {
        },
        .probe          = ir_probe,
        .remove         = ir_remove,
-       .command        = ir_command,
        .id_table       = ir_transceiver_id,
 };
 
@@ -1144,214 +1162,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 +1418,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 +1444,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 +1456,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 23fa049b51f22d941ebd8415f375c93ad3462898..a2f29d464051a53b86bb43158bd4c7716b01d63c 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 9f26dc9408bb757525599dbec98d47ca9a78ebc8..56a283d1a74dc7b01597052d0b6a2f83ae7de02e 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 701561d6b6fdc03a4ecad832ef39940653a023a4..236dd36d349a16b6a1c099f93e5ca4b867547590 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 ee68d51caa4e8e4dbd7a90337570d6815224dc9a..322bf49ee90670ff1b5fb175998f782db94905d9 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 8323c6aa81888c680498a34b8bcd2c08f79e976d..1411c7bf0d4072f35577a734ec06964cad3cbcf6 100644 (file)
@@ -141,12 +141,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) ?
@@ -154,7 +155,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)));
@@ -286,11 +287,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 a692ee88b9e9a3c3d97a4e97d7197ca9b2f71995..21ce2af447b527c61ddab279ee6533a6c74ee69b 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 0bc113c44d393423665b80f888c78660d67e8e6b..d007e4a12c14b8bd93370c4bb38a1aef5ca42cd5 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 408bb9b3303e89d7c0f95e1d8c25cb99af05cc94..07a7f5432597f4d88719850e15406435b9a9b412 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 fa1ee9d1188859c7965786acec309c96e35679a1..51b4a79e4b837ba506d1a8d0a771b098cee63158 100644 (file)
@@ -984,12 +984,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_query_dev;
-       }
-
        /* Clear interrupts */
        synaptics_rmi4_i2c_block_read(rmi4_data,
                        rmi4_data->fn01_data_base_addr + 1, intr_status,
@@ -1001,14 +995,19 @@ 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_query_dev;
+       }
+
+       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_query_dev:
        if (platformdata->regulator_en) {
                regulator_disable(rmi4_data->regulator);
index 571864555ddd894c73f2649ca43996b5bf7d77a4..27e0aa81a584b61f16626e788cce3981b0a9f75a 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 a3b0a183d5704e5052281a313455725e0ef1ced8..a3f69f6f505f8839d0b96c6b9b0055071450ac05 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 18aec55d8647fdcf3cb33111c7ff1a8f3aca2e78..8242c70e09dd27c0d95a9ce959ba64c91efa1c22 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 8fe017c3721fbb7415a8270059492fe83e47dd2f..eb9b9f1bc1387250f4382d23f721851c031c9693 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 30dbfb6d16f20febb872a60ab882490d9c87abfb..d73267961ef48774cbd8583fbdb1ec0daf7a25e3 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 b186b5fed2b96b7973388cd337dfce6f5cafc66d..a7ce51cc89099bfc26a8c777d604e1dc623d164e 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 3de6fd2539dcb65efa74d25040f25cf9c22beb6e..ae6ac82754a4dd1296071037dac674f713de618f 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 41a1fe5138f4e020c13683e59e362ecdc38b5be9..afc3b1a7188199bf29496fbb6e9933d6f3d37952 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 08bd26a245d50f6a74c9b2a47797e739b6fbbfaa..a35fe61268de3e974f8ece7f2edb0bd1e28b0468 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 8147d7202b2dc092e8986891baaf463e6e3f1bf3..bf69914709410cf054825933a638b7dd7060180a 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 7016fdd2509f5ce83e6bc29acd6b01ffcb9316c3..e19b932492e1e5443b916c210a0c261e6af61c2f 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 c43ef48b1a0fee3df1601497367e7350a20d057a..396277216e4ffdddf37e48d595e5a865b6546e46 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..e6bed5f
--- /dev/null
@@ -0,0 +1,13 @@
+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
+obj-$(CONFIG_VIRTIO_CONSOLE)   += virtio_console.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);
diff --git a/drivers/tty/hvc/virtio_console.c b/drivers/tty/hvc/virtio_console.c
new file mode 100644 (file)
index 0000000..896a2ce
--- /dev/null
@@ -0,0 +1,1838 @@
+/*
+ * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation
+ * Copyright (C) 2009, 2010 Red Hat, 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.
+ *
+ * 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/cdev.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/virtio.h>
+#include <linux/virtio_console.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include "hvc_console.h"
+
+/*
+ * This is a global struct for storing common data for all the devices
+ * this driver handles.
+ *
+ * Mainly, it has a linked list for all the consoles in one place so
+ * that callbacks from hvc for get_chars(), put_chars() work properly
+ * across multiple devices and multiple ports per device.
+ */
+struct ports_driver_data {
+       /* Used for registering chardevs */
+       struct class *class;
+
+       /* Used for exporting per-port information to debugfs */
+       struct dentry *debugfs_dir;
+
+       /* List of all the devices we're handling */
+       struct list_head portdevs;
+
+       /* Number of devices this driver is handling */
+       unsigned int index;
+
+       /*
+        * This is used to keep track of the number of hvc consoles
+        * spawned by this driver.  This number is given as the first
+        * argument to hvc_alloc().  To correctly map an initial
+        * console spawned via hvc_instantiate to the console being
+        * hooked up via hvc_alloc, we need to pass the same vtermno.
+        *
+        * We also just assume the first console being initialised was
+        * the first one that got used as the initial console.
+        */
+       unsigned int next_vtermno;
+
+       /* All the console devices handled by this driver */
+       struct list_head consoles;
+};
+static struct ports_driver_data pdrvdata;
+
+DEFINE_SPINLOCK(pdrvdata_lock);
+
+/* This struct holds information that's relevant only for console ports */
+struct console {
+       /* We'll place all consoles in a list in the pdrvdata struct */
+       struct list_head list;
+
+       /* The hvc device associated with this console port */
+       struct hvc_struct *hvc;
+
+       /* The size of the console */
+       struct winsize ws;
+
+       /*
+        * This number identifies the number that we used to register
+        * with hvc in hvc_instantiate() and hvc_alloc(); this is the
+        * number passed on by the hvc callbacks to us to
+        * differentiate between the other console ports handled by
+        * this driver
+        */
+       u32 vtermno;
+};
+
+struct port_buffer {
+       char *buf;
+
+       /* size of the buffer in *buf above */
+       size_t size;
+
+       /* used length of the buffer */
+       size_t len;
+       /* offset in the buf from which to consume data */
+       size_t offset;
+};
+
+/*
+ * This is a per-device struct that stores data common to all the
+ * ports for that device (vdev->priv).
+ */
+struct ports_device {
+       /* Next portdev in the list, head is in the pdrvdata struct */
+       struct list_head list;
+
+       /*
+        * Workqueue handlers where we process deferred work after
+        * notification
+        */
+       struct work_struct control_work;
+
+       struct list_head ports;
+
+       /* To protect the list of ports */
+       spinlock_t ports_lock;
+
+       /* To protect the vq operations for the control channel */
+       spinlock_t cvq_lock;
+
+       /* The current config space is stored here */
+       struct virtio_console_config config;
+
+       /* The virtio device we're associated with */
+       struct virtio_device *vdev;
+
+       /*
+        * A couple of virtqueues for the control channel: one for
+        * guest->host transfers, one for host->guest transfers
+        */
+       struct virtqueue *c_ivq, *c_ovq;
+
+       /* Array of per-port IO virtqueues */
+       struct virtqueue **in_vqs, **out_vqs;
+
+       /* Used for numbering devices for sysfs and debugfs */
+       unsigned int drv_index;
+
+       /* Major number for this device.  Ports will be created as minors. */
+       int chr_major;
+};
+
+/* This struct holds the per-port data */
+struct port {
+       /* Next port in the list, head is in the ports_device */
+       struct list_head list;
+
+       /* Pointer to the parent virtio_console device */
+       struct ports_device *portdev;
+
+       /* The current buffer from which data has to be fed to readers */
+       struct port_buffer *inbuf;
+
+       /*
+        * To protect the operations on the in_vq associated with this
+        * port.  Has to be a spinlock because it can be called from
+        * interrupt context (get_char()).
+        */
+       spinlock_t inbuf_lock;
+
+       /* Protect the operations on the out_vq. */
+       spinlock_t outvq_lock;
+
+       /* The IO vqs for this port */
+       struct virtqueue *in_vq, *out_vq;
+
+       /* File in the debugfs directory that exposes this port's information */
+       struct dentry *debugfs_file;
+
+       /*
+        * The entries in this struct will be valid if this port is
+        * hooked up to an hvc console
+        */
+       struct console cons;
+
+       /* Each port associates with a separate char device */
+       struct cdev *cdev;
+       struct device *dev;
+
+       /* Reference-counting to handle port hot-unplugs and file operations */
+       struct kref kref;
+
+       /* A waitqueue for poll() or blocking read operations */
+       wait_queue_head_t waitqueue;
+
+       /* The 'name' of the port that we expose via sysfs properties */
+       char *name;
+
+       /* We can notify apps of host connect / disconnect events via SIGIO */
+       struct fasync_struct *async_queue;
+
+       /* The 'id' to identify the port with the Host */
+       u32 id;
+
+       bool outvq_full;
+
+       /* Is the host device open */
+       bool host_connected;
+
+       /* We should allow only one process to open a port */
+       bool guest_connected;
+};
+
+/* This is the very early arch-specified put chars function. */
+static int (*early_put_chars)(u32, const char *, int);
+
+static struct port *find_port_by_vtermno(u32 vtermno)
+{
+       struct port *port;
+       struct console *cons;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdrvdata_lock, flags);
+       list_for_each_entry(cons, &pdrvdata.consoles, list) {
+               if (cons->vtermno == vtermno) {
+                       port = container_of(cons, struct port, cons);
+                       goto out;
+               }
+       }
+       port = NULL;
+out:
+       spin_unlock_irqrestore(&pdrvdata_lock, flags);
+       return port;
+}
+
+static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev,
+                                                dev_t dev)
+{
+       struct port *port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&portdev->ports_lock, flags);
+       list_for_each_entry(port, &portdev->ports, list)
+               if (port->cdev->dev == dev)
+                       goto out;
+       port = NULL;
+out:
+       spin_unlock_irqrestore(&portdev->ports_lock, flags);
+
+       return port;
+}
+
+static struct port *find_port_by_devt(dev_t dev)
+{
+       struct ports_device *portdev;
+       struct port *port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdrvdata_lock, flags);
+       list_for_each_entry(portdev, &pdrvdata.portdevs, list) {
+               port = find_port_by_devt_in_portdev(portdev, dev);
+               if (port)
+                       goto out;
+       }
+       port = NULL;
+out:
+       spin_unlock_irqrestore(&pdrvdata_lock, flags);
+       return port;
+}
+
+static struct port *find_port_by_id(struct ports_device *portdev, u32 id)
+{
+       struct port *port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&portdev->ports_lock, flags);
+       list_for_each_entry(port, &portdev->ports, list)
+               if (port->id == id)
+                       goto out;
+       port = NULL;
+out:
+       spin_unlock_irqrestore(&portdev->ports_lock, flags);
+
+       return port;
+}
+
+static struct port *find_port_by_vq(struct ports_device *portdev,
+                                   struct virtqueue *vq)
+{
+       struct port *port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&portdev->ports_lock, flags);
+       list_for_each_entry(port, &portdev->ports, list)
+               if (port->in_vq == vq || port->out_vq == vq)
+                       goto out;
+       port = NULL;
+out:
+       spin_unlock_irqrestore(&portdev->ports_lock, flags);
+       return port;
+}
+
+static bool is_console_port(struct port *port)
+{
+       if (port->cons.hvc)
+               return true;
+       return false;
+}
+
+static inline bool use_multiport(struct ports_device *portdev)
+{
+       /*
+        * This condition can be true when put_chars is called from
+        * early_init
+        */
+       if (!portdev->vdev)
+               return 0;
+       return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
+}
+
+static void free_buf(struct port_buffer *buf)
+{
+       kfree(buf->buf);
+       kfree(buf);
+}
+
+static struct port_buffer *alloc_buf(size_t buf_size)
+{
+       struct port_buffer *buf;
+
+       buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+       if (!buf)
+               goto fail;
+       buf->buf = kzalloc(buf_size, GFP_KERNEL);
+       if (!buf->buf)
+               goto free_buf;
+       buf->len = 0;
+       buf->offset = 0;
+       buf->size = buf_size;
+       return buf;
+
+free_buf:
+       kfree(buf);
+fail:
+       return NULL;
+}
+
+/* Callers should take appropriate locks */
+static void *get_inbuf(struct port *port)
+{
+       struct port_buffer *buf;
+       struct virtqueue *vq;
+       unsigned int len;
+
+       vq = port->in_vq;
+       buf = virtqueue_get_buf(vq, &len);
+       if (buf) {
+               buf->len = len;
+               buf->offset = 0;
+       }
+       return buf;
+}
+
+/*
+ * Create a scatter-gather list representing our input buffer and put
+ * it in the queue.
+ *
+ * Callers should take appropriate locks.
+ */
+static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf)
+{
+       struct scatterlist sg[1];
+       int ret;
+
+       sg_init_one(sg, buf->buf, buf->size);
+
+       ret = virtqueue_add_buf(vq, sg, 0, 1, buf);
+       virtqueue_kick(vq);
+       return ret;
+}
+
+/* Discard any unread data this port has. Callers lockers. */
+static void discard_port_data(struct port *port)
+{
+       struct port_buffer *buf;
+       struct virtqueue *vq;
+       unsigned int len;
+       int ret;
+
+       vq = port->in_vq;
+       if (port->inbuf)
+               buf = port->inbuf;
+       else
+               buf = virtqueue_get_buf(vq, &len);
+
+       ret = 0;
+       while (buf) {
+               if (add_inbuf(vq, buf) < 0) {
+                       ret++;
+                       free_buf(buf);
+               }
+               buf = virtqueue_get_buf(vq, &len);
+       }
+       port->inbuf = NULL;
+       if (ret)
+               dev_warn(port->dev, "Errors adding %d buffers back to vq\n",
+                        ret);
+}
+
+static bool port_has_data(struct port *port)
+{
+       unsigned long flags;
+       bool ret;
+
+       spin_lock_irqsave(&port->inbuf_lock, flags);
+       if (port->inbuf) {
+               ret = true;
+               goto out;
+       }
+       port->inbuf = get_inbuf(port);
+       if (port->inbuf) {
+               ret = true;
+               goto out;
+       }
+       ret = false;
+out:
+       spin_unlock_irqrestore(&port->inbuf_lock, flags);
+       return ret;
+}
+
+static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
+                                 unsigned int event, unsigned int value)
+{
+       struct scatterlist sg[1];
+       struct virtio_console_control cpkt;
+       struct virtqueue *vq;
+       unsigned int len;
+
+       if (!use_multiport(portdev))
+               return 0;
+
+       cpkt.id = port_id;
+       cpkt.event = event;
+       cpkt.value = value;
+
+       vq = portdev->c_ovq;
+
+       sg_init_one(sg, &cpkt, sizeof(cpkt));
+       if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt) >= 0) {
+               virtqueue_kick(vq);
+               while (!virtqueue_get_buf(vq, &len))
+                       cpu_relax();
+       }
+       return 0;
+}
+
+static ssize_t send_control_msg(struct port *port, unsigned int event,
+                               unsigned int value)
+{
+       /* Did the port get unplugged before userspace closed it? */
+       if (port->portdev)
+               return __send_control_msg(port->portdev, port->id, event, value);
+       return 0;
+}
+
+/* Callers must take the port->outvq_lock */
+static void reclaim_consumed_buffers(struct port *port)
+{
+       void *buf;
+       unsigned int len;
+
+       while ((buf = virtqueue_get_buf(port->out_vq, &len))) {
+               kfree(buf);
+               port->outvq_full = false;
+       }
+}
+
+static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
+                       bool nonblock)
+{
+       struct scatterlist sg[1];
+       struct virtqueue *out_vq;
+       ssize_t ret;
+       unsigned long flags;
+       unsigned int len;
+
+       out_vq = port->out_vq;
+
+       spin_lock_irqsave(&port->outvq_lock, flags);
+
+       reclaim_consumed_buffers(port);
+
+       sg_init_one(sg, in_buf, in_count);
+       ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf);
+
+       /* Tell Host to go! */
+       virtqueue_kick(out_vq);
+
+       if (ret < 0) {
+               in_count = 0;
+               goto done;
+       }
+
+       if (ret == 0)
+               port->outvq_full = true;
+
+       if (nonblock)
+               goto done;
+
+       /*
+        * Wait till the host acknowledges it pushed out the data we
+        * sent.  This is done for data from the hvc_console; the tty
+        * operations are performed with spinlocks held so we can't
+        * sleep here.  An alternative would be to copy the data to a
+        * buffer and relax the spinning requirement.  The downside is
+        * we need to kmalloc a GFP_ATOMIC buffer each time the
+        * console driver writes something out.
+        */
+       while (!virtqueue_get_buf(out_vq, &len))
+               cpu_relax();
+done:
+       spin_unlock_irqrestore(&port->outvq_lock, flags);
+       /*
+        * We're expected to return the amount of data we wrote -- all
+        * of it
+        */
+       return in_count;
+}
+
+/*
+ * Give out the data that's requested from the buffer that we have
+ * queued up.
+ */
+static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count,
+                           bool to_user)
+{
+       struct port_buffer *buf;
+       unsigned long flags;
+
+       if (!out_count || !port_has_data(port))
+               return 0;
+
+       buf = port->inbuf;
+       out_count = min(out_count, buf->len - buf->offset);
+
+       if (to_user) {
+               ssize_t ret;
+
+               ret = copy_to_user(out_buf, buf->buf + buf->offset, out_count);
+               if (ret)
+                       return -EFAULT;
+       } else {
+               memcpy(out_buf, buf->buf + buf->offset, out_count);
+       }
+
+       buf->offset += out_count;
+
+       if (buf->offset == buf->len) {
+               /*
+                * We're done using all the data in this buffer.
+                * Re-queue so that the Host can send us more data.
+                */
+               spin_lock_irqsave(&port->inbuf_lock, flags);
+               port->inbuf = NULL;
+
+               if (add_inbuf(port->in_vq, buf) < 0)
+                       dev_warn(port->dev, "failed add_buf\n");
+
+               spin_unlock_irqrestore(&port->inbuf_lock, flags);
+       }
+       /* Return the number of bytes actually copied */
+       return out_count;
+}
+
+/* The condition that must be true for polling to end */
+static bool will_read_block(struct port *port)
+{
+       if (!port->guest_connected) {
+               /* Port got hot-unplugged. Let's exit. */
+               return false;
+       }
+       return !port_has_data(port) && port->host_connected;
+}
+
+static bool will_write_block(struct port *port)
+{
+       bool ret;
+
+       if (!port->guest_connected) {
+               /* Port got hot-unplugged. Let's exit. */
+               return false;
+       }
+       if (!port->host_connected)
+               return true;
+
+       spin_lock_irq(&port->outvq_lock);
+       /*
+        * Check if the Host has consumed any buffers since we last
+        * sent data (this is only applicable for nonblocking ports).
+        */
+       reclaim_consumed_buffers(port);
+       ret = port->outvq_full;
+       spin_unlock_irq(&port->outvq_lock);
+
+       return ret;
+}
+
+static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
+                             size_t count, loff_t *offp)
+{
+       struct port *port;
+       ssize_t ret;
+
+       port = filp->private_data;
+
+       if (!port_has_data(port)) {
+               /*
+                * If nothing's connected on the host just return 0 in
+                * case of list_empty; this tells the userspace app
+                * that there's no connection
+                */
+               if (!port->host_connected)
+                       return 0;
+               if (filp->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+
+               ret = wait_event_interruptible(port->waitqueue,
+                                              !will_read_block(port));
+               if (ret < 0)
+                       return ret;
+       }
+       /* Port got hot-unplugged. */
+       if (!port->guest_connected)
+               return -ENODEV;
+       /*
+        * We could've received a disconnection message while we were
+        * waiting for more data.
+        *
+        * This check is not clubbed in the if() statement above as we
+        * might receive some data as well as the host could get
+        * disconnected after we got woken up from our wait.  So we
+        * really want to give off whatever data we have and only then
+        * check for host_connected.
+        */
+       if (!port_has_data(port) && !port->host_connected)
+               return 0;
+
+       return fill_readbuf(port, ubuf, count, true);
+}
+
+static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
+                              size_t count, loff_t *offp)
+{
+       struct port *port;
+       char *buf;
+       ssize_t ret;
+       bool nonblock;
+
+       /* Userspace could be out to fool us */
+       if (!count)
+               return 0;
+
+       port = filp->private_data;
+
+       nonblock = filp->f_flags & O_NONBLOCK;
+
+       if (will_write_block(port)) {
+               if (nonblock)
+                       return -EAGAIN;
+
+               ret = wait_event_interruptible(port->waitqueue,
+                                              !will_write_block(port));
+               if (ret < 0)
+                       return ret;
+       }
+       /* Port got hot-unplugged. */
+       if (!port->guest_connected)
+               return -ENODEV;
+
+       count = min((size_t)(32 * 1024), count);
+
+       buf = kmalloc(count, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = copy_from_user(buf, ubuf, count);
+       if (ret) {
+               ret = -EFAULT;
+               goto free_buf;
+       }
+
+       /*
+        * We now ask send_buf() to not spin for generic ports -- we
+        * can re-use the same code path that non-blocking file
+        * descriptors take for blocking file descriptors since the
+        * wait is already done and we're certain the write will go
+        * through to the host.
+        */
+       nonblock = true;
+       ret = send_buf(port, buf, count, nonblock);
+
+       if (nonblock && ret > 0)
+               goto out;
+
+free_buf:
+       kfree(buf);
+out:
+       return ret;
+}
+
+static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
+{
+       struct port *port;
+       unsigned int ret;
+
+       port = filp->private_data;
+       poll_wait(filp, &port->waitqueue, wait);
+
+       if (!port->guest_connected) {
+               /* Port got unplugged */
+               return POLLHUP;
+       }
+       ret = 0;
+       if (!will_read_block(port))
+               ret |= POLLIN | POLLRDNORM;
+       if (!will_write_block(port))
+               ret |= POLLOUT;
+       if (!port->host_connected)
+               ret |= POLLHUP;
+
+       return ret;
+}
+
+static void remove_port(struct kref *kref);
+
+static int port_fops_release(struct inode *inode, struct file *filp)
+{
+       struct port *port;
+
+       port = filp->private_data;
+
+       /* Notify host of port being closed */
+       send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
+
+       spin_lock_irq(&port->inbuf_lock);
+       port->guest_connected = false;
+
+       discard_port_data(port);
+
+       spin_unlock_irq(&port->inbuf_lock);
+
+       spin_lock_irq(&port->outvq_lock);
+       reclaim_consumed_buffers(port);
+       spin_unlock_irq(&port->outvq_lock);
+
+       /*
+        * Locks aren't necessary here as a port can't be opened after
+        * unplug, and if a port isn't unplugged, a kref would already
+        * exist for the port.  Plus, taking ports_lock here would
+        * create a dependency on other locks taken by functions
+        * inside remove_port if we're the last holder of the port,
+        * creating many problems.
+        */
+       kref_put(&port->kref, remove_port);
+
+       return 0;
+}
+
+static int port_fops_open(struct inode *inode, struct file *filp)
+{
+       struct cdev *cdev = inode->i_cdev;
+       struct port *port;
+       int ret;
+
+       port = find_port_by_devt(cdev->dev);
+       filp->private_data = port;
+
+       /* Prevent against a port getting hot-unplugged at the same time */
+       spin_lock_irq(&port->portdev->ports_lock);
+       kref_get(&port->kref);
+       spin_unlock_irq(&port->portdev->ports_lock);
+
+       /*
+        * Don't allow opening of console port devices -- that's done
+        * via /dev/hvc
+        */
+       if (is_console_port(port)) {
+               ret = -ENXIO;
+               goto out;
+       }
+
+       /* Allow only one process to open a particular port at a time */
+       spin_lock_irq(&port->inbuf_lock);
+       if (port->guest_connected) {
+               spin_unlock_irq(&port->inbuf_lock);
+               ret = -EMFILE;
+               goto out;
+       }
+
+       port->guest_connected = true;
+       spin_unlock_irq(&port->inbuf_lock);
+
+       spin_lock_irq(&port->outvq_lock);
+       /*
+        * There might be a chance that we missed reclaiming a few
+        * buffers in the window of the port getting previously closed
+        * and opening now.
+        */
+       reclaim_consumed_buffers(port);
+       spin_unlock_irq(&port->outvq_lock);
+
+       nonseekable_open(inode, filp);
+
+       /* Notify host of port being opened */
+       send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1);
+
+       return 0;
+out:
+       kref_put(&port->kref, remove_port);
+       return ret;
+}
+
+static int port_fops_fasync(int fd, struct file *filp, int mode)
+{
+       struct port *port;
+
+       port = filp->private_data;
+       return fasync_helper(fd, filp, mode, &port->async_queue);
+}
+
+/*
+ * The file operations that we support: programs in the guest can open
+ * a console device, read from it, write to it, poll for data and
+ * close it.  The devices are at
+ *   /dev/vport<device number>p<port number>
+ */
+static const struct file_operations port_fops = {
+       .owner = THIS_MODULE,
+       .open  = port_fops_open,
+       .read  = port_fops_read,
+       .write = port_fops_write,
+       .poll  = port_fops_poll,
+       .release = port_fops_release,
+       .fasync = port_fops_fasync,
+       .llseek = no_llseek,
+};
+
+/*
+ * The put_chars() callback is pretty straightforward.
+ *
+ * We turn the characters into a scatter-gather list, add it to the
+ * output queue and then kick the Host.  Then we sit here waiting for
+ * it to finish: inefficient in theory, but in practice
+ * implementations will do it immediately (lguest's Launcher does).
+ */
+static int put_chars(u32 vtermno, const char *buf, int count)
+{
+       struct port *port;
+
+       if (unlikely(early_put_chars))
+               return early_put_chars(vtermno, buf, count);
+
+       port = find_port_by_vtermno(vtermno);
+       if (!port)
+               return -EPIPE;
+
+       return send_buf(port, (void *)buf, count, false);
+}
+
+/*
+ * get_chars() is the callback from the hvc_console infrastructure
+ * when an interrupt is received.
+ *
+ * We call out to fill_readbuf that gets us the required data from the
+ * buffers that are queued up.
+ */
+static int get_chars(u32 vtermno, char *buf, int count)
+{
+       struct port *port;
+
+       /* If we've not set up the port yet, we have no input to give. */
+       if (unlikely(early_put_chars))
+               return 0;
+
+       port = find_port_by_vtermno(vtermno);
+       if (!port)
+               return -EPIPE;
+
+       /* If we don't have an input queue yet, we can't get input. */
+       BUG_ON(!port->in_vq);
+
+       return fill_readbuf(port, buf, count, false);
+}
+
+static void resize_console(struct port *port)
+{
+       struct virtio_device *vdev;
+
+       /* The port could have been hot-unplugged */
+       if (!port || !is_console_port(port))
+               return;
+
+       vdev = port->portdev->vdev;
+       if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE))
+               hvc_resize(port->cons.hvc, port->cons.ws);
+}
+
+/* We set the configuration at this point, since we now have a tty */
+static int notifier_add_vio(struct hvc_struct *hp, int data)
+{
+       struct port *port;
+
+       port = find_port_by_vtermno(hp->vtermno);
+       if (!port)
+               return -EINVAL;
+
+       hp->irq_requested = 1;
+       resize_console(port);
+
+       return 0;
+}
+
+static void notifier_del_vio(struct hvc_struct *hp, int data)
+{
+       hp->irq_requested = 0;
+}
+
+/* The operations for console ports. */
+static const struct hv_ops hv_ops = {
+       .get_chars = get_chars,
+       .put_chars = put_chars,
+       .notifier_add = notifier_add_vio,
+       .notifier_del = notifier_del_vio,
+       .notifier_hangup = notifier_del_vio,
+};
+
+/*
+ * Console drivers are initialized very early so boot messages can go
+ * out, so we do things slightly differently from the generic virtio
+ * initialization of the net and block drivers.
+ *
+ * At this stage, the console is output-only.  It's too early to set
+ * up a virtqueue, so we let the drivers do some boutique early-output
+ * thing.
+ */
+int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
+{
+       early_put_chars = put_chars;
+       return hvc_instantiate(0, 0, &hv_ops);
+}
+
+int init_port_console(struct port *port)
+{
+       int ret;
+
+       /*
+        * The Host's telling us this port is a console port.  Hook it
+        * up with an hvc console.
+        *
+        * To set up and manage our virtual console, we call
+        * hvc_alloc().
+        *
+        * The first argument of hvc_alloc() is the virtual console
+        * number.  The second argument is the parameter for the
+        * notification mechanism (like irq number).  We currently
+        * leave this as zero, virtqueues have implicit notifications.
+        *
+        * The third argument is a "struct hv_ops" containing the
+        * put_chars() get_chars(), notifier_add() and notifier_del()
+        * pointers.  The final argument is the output buffer size: we
+        * can do any size, so we put PAGE_SIZE here.
+        */
+       port->cons.vtermno = pdrvdata.next_vtermno;
+
+       port->cons.hvc = hvc_alloc(port->cons.vtermno, 0, &hv_ops, PAGE_SIZE);
+       if (IS_ERR(port->cons.hvc)) {
+               ret = PTR_ERR(port->cons.hvc);
+               dev_err(port->dev,
+                       "error %d allocating hvc for port\n", ret);
+               port->cons.hvc = NULL;
+               return ret;
+       }
+       spin_lock_irq(&pdrvdata_lock);
+       pdrvdata.next_vtermno++;
+       list_add_tail(&port->cons.list, &pdrvdata.consoles);
+       spin_unlock_irq(&pdrvdata_lock);
+       port->guest_connected = true;
+
+       /*
+        * Start using the new console output if this is the first
+        * console to come up.
+        */
+       if (early_put_chars)
+               early_put_chars = NULL;
+
+       /* Notify host of port being opened */
+       send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
+
+       return 0;
+}
+
+static ssize_t show_port_name(struct device *dev,
+                             struct device_attribute *attr, char *buffer)
+{
+       struct port *port;
+
+       port = dev_get_drvdata(dev);
+
+       return sprintf(buffer, "%s\n", port->name);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_port_name, NULL);
+
+static struct attribute *port_sysfs_entries[] = {
+       &dev_attr_name.attr,
+       NULL
+};
+
+static struct attribute_group port_attribute_group = {
+       .name = NULL,           /* put in device directory */
+       .attrs = port_sysfs_entries,
+};
+
+static int debugfs_open(struct inode *inode, struct file *filp)
+{
+       filp->private_data = inode->i_private;
+       return 0;
+}
+
+static ssize_t debugfs_read(struct file *filp, char __user *ubuf,
+                           size_t count, loff_t *offp)
+{
+       struct port *port;
+       char *buf;
+       ssize_t ret, out_offset, out_count;
+
+       out_count = 1024;
+       buf = kmalloc(out_count, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       port = filp->private_data;
+       out_offset = 0;
+       out_offset += snprintf(buf + out_offset, out_count,
+                              "name: %s\n", port->name ? port->name : "");
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "guest_connected: %d\n", port->guest_connected);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "host_connected: %d\n", port->host_connected);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "outvq_full: %d\n", port->outvq_full);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "is_console: %s\n",
+                              is_console_port(port) ? "yes" : "no");
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "console_vtermno: %u\n", port->cons.vtermno);
+
+       ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset);
+       kfree(buf);
+       return ret;
+}
+
+static const struct file_operations port_debugfs_ops = {
+       .owner = THIS_MODULE,
+       .open  = debugfs_open,
+       .read  = debugfs_read,
+};
+
+static void set_console_size(struct port *port, u16 rows, u16 cols)
+{
+       if (!port || !is_console_port(port))
+               return;
+
+       port->cons.ws.ws_row = rows;
+       port->cons.ws.ws_col = cols;
+}
+
+static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
+{
+       struct port_buffer *buf;
+       unsigned int nr_added_bufs;
+       int ret;
+
+       nr_added_bufs = 0;
+       do {
+               buf = alloc_buf(PAGE_SIZE);
+               if (!buf)
+                       break;
+
+               spin_lock_irq(lock);
+               ret = add_inbuf(vq, buf);
+               if (ret < 0) {
+                       spin_unlock_irq(lock);
+                       free_buf(buf);
+                       break;
+               }
+               nr_added_bufs++;
+               spin_unlock_irq(lock);
+       } while (ret > 0);
+
+       return nr_added_bufs;
+}
+
+static void send_sigio_to_port(struct port *port)
+{
+       if (port->async_queue && port->guest_connected)
+               kill_fasync(&port->async_queue, SIGIO, POLL_OUT);
+}
+
+static int add_port(struct ports_device *portdev, u32 id)
+{
+       char debugfs_name[16];
+       struct port *port;
+       struct port_buffer *buf;
+       dev_t devt;
+       unsigned int nr_added_bufs;
+       int err;
+
+       port = kmalloc(sizeof(*port), GFP_KERNEL);
+       if (!port) {
+               err = -ENOMEM;
+               goto fail;
+       }
+       kref_init(&port->kref);
+
+       port->portdev = portdev;
+       port->id = id;
+
+       port->name = NULL;
+       port->inbuf = NULL;
+       port->cons.hvc = NULL;
+       port->async_queue = NULL;
+
+       port->cons.ws.ws_row = port->cons.ws.ws_col = 0;
+
+       port->host_connected = port->guest_connected = false;
+
+       port->outvq_full = false;
+
+       port->in_vq = portdev->in_vqs[port->id];
+       port->out_vq = portdev->out_vqs[port->id];
+
+       port->cdev = cdev_alloc();
+       if (!port->cdev) {
+               dev_err(&port->portdev->vdev->dev, "Error allocating cdev\n");
+               err = -ENOMEM;
+               goto free_port;
+       }
+       port->cdev->ops = &port_fops;
+
+       devt = MKDEV(portdev->chr_major, id);
+       err = cdev_add(port->cdev, devt, 1);
+       if (err < 0) {
+               dev_err(&port->portdev->vdev->dev,
+                       "Error %d adding cdev for port %u\n", err, id);
+               goto free_cdev;
+       }
+       port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev,
+                                 devt, port, "vport%up%u",
+                                 port->portdev->drv_index, id);
+       if (IS_ERR(port->dev)) {
+               err = PTR_ERR(port->dev);
+               dev_err(&port->portdev->vdev->dev,
+                       "Error %d creating device for port %u\n",
+                       err, id);
+               goto free_cdev;
+       }
+
+       spin_lock_init(&port->inbuf_lock);
+       spin_lock_init(&port->outvq_lock);
+       init_waitqueue_head(&port->waitqueue);
+
+       /* Fill the in_vq with buffers so the host can send us data. */
+       nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock);
+       if (!nr_added_bufs) {
+               dev_err(port->dev, "Error allocating inbufs\n");
+               err = -ENOMEM;
+               goto free_device;
+       }
+
+       /*
+        * If we're not using multiport support, this has to be a console port
+        */
+       if (!use_multiport(port->portdev)) {
+               err = init_port_console(port);
+               if (err)
+                       goto free_inbufs;
+       }
+
+       spin_lock_irq(&portdev->ports_lock);
+       list_add_tail(&port->list, &port->portdev->ports);
+       spin_unlock_irq(&portdev->ports_lock);
+
+       /*
+        * Tell the Host we're set so that it can send us various
+        * configuration parameters for this port (eg, port name,
+        * caching, whether this is a console port, etc.)
+        */
+       send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+
+       if (pdrvdata.debugfs_dir) {
+               /*
+                * Finally, create the debugfs file that we can use to
+                * inspect a port's state at any time
+                */
+               sprintf(debugfs_name, "vport%up%u",
+                       port->portdev->drv_index, id);
+               port->debugfs_file = debugfs_create_file(debugfs_name, 0444,
+                                                        pdrvdata.debugfs_dir,
+                                                        port,
+                                                        &port_debugfs_ops);
+       }
+       return 0;
+
+free_inbufs:
+       while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
+               free_buf(buf);
+free_device:
+       device_destroy(pdrvdata.class, port->dev->devt);
+free_cdev:
+       cdev_del(port->cdev);
+free_port:
+       kfree(port);
+fail:
+       /* The host might want to notify management sw about port add failure */
+       __send_control_msg(portdev, id, VIRTIO_CONSOLE_PORT_READY, 0);
+       return err;
+}
+
+/* No users remain, remove all port-specific data. */
+static void remove_port(struct kref *kref)
+{
+       struct port *port;
+
+       port = container_of(kref, struct port, kref);
+
+       sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
+       device_destroy(pdrvdata.class, port->dev->devt);
+       cdev_del(port->cdev);
+
+       kfree(port->name);
+
+       debugfs_remove(port->debugfs_file);
+
+       kfree(port);
+}
+
+/*
+ * Port got unplugged.  Remove port from portdev's list and drop the
+ * kref reference.  If no userspace has this port opened, it will
+ * result in immediate removal the port.
+ */
+static void unplug_port(struct port *port)
+{
+       struct port_buffer *buf;
+
+       spin_lock_irq(&port->portdev->ports_lock);
+       list_del(&port->list);
+       spin_unlock_irq(&port->portdev->ports_lock);
+
+       if (port->guest_connected) {
+               port->guest_connected = false;
+               port->host_connected = false;
+               wake_up_interruptible(&port->waitqueue);
+
+               /* Let the app know the port is going down. */
+               send_sigio_to_port(port);
+       }
+
+       if (is_console_port(port)) {
+               spin_lock_irq(&pdrvdata_lock);
+               list_del(&port->cons.list);
+               spin_unlock_irq(&pdrvdata_lock);
+#if 0
+               /*
+                * hvc_remove() not called as removing one hvc port
+                * results in other hvc ports getting frozen.
+                *
+                * Once this is resolved in hvc, this functionality
+                * will be enabled.  Till that is done, the -EPIPE
+                * return from get_chars() above will help
+                * hvc_console.c to clean up on ports we remove here.
+                */
+               hvc_remove(port->cons.hvc);
+#endif
+       }
+
+       /* Remove unused data this port might have received. */
+       discard_port_data(port);
+
+       reclaim_consumed_buffers(port);
+
+       /* Remove buffers we queued up for the Host to send us data in. */
+       while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
+               free_buf(buf);
+
+       /*
+        * We should just assume the device itself has gone off --
+        * else a close on an open port later will try to send out a
+        * control message.
+        */
+       port->portdev = NULL;
+
+       /*
+        * Locks around here are not necessary - a port can't be
+        * opened after we removed the port struct from ports_list
+        * above.
+        */
+       kref_put(&port->kref, remove_port);
+}
+
+/* Any private messages that the Host and Guest want to share */
+static void handle_control_message(struct ports_device *portdev,
+                                  struct port_buffer *buf)
+{
+       struct virtio_console_control *cpkt;
+       struct port *port;
+       size_t name_size;
+       int err;
+
+       cpkt = (struct virtio_console_control *)(buf->buf + buf->offset);
+
+       port = find_port_by_id(portdev, cpkt->id);
+       if (!port && cpkt->event != VIRTIO_CONSOLE_PORT_ADD) {
+               /* No valid header at start of buffer.  Drop it. */
+               dev_dbg(&portdev->vdev->dev,
+                       "Invalid index %u in control packet\n", cpkt->id);
+               return;
+       }
+
+       switch (cpkt->event) {
+       case VIRTIO_CONSOLE_PORT_ADD:
+               if (port) {
+                       dev_dbg(&portdev->vdev->dev,
+                               "Port %u already added\n", port->id);
+                       send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+                       break;
+               }
+               if (cpkt->id >= portdev->config.max_nr_ports) {
+                       dev_warn(&portdev->vdev->dev,
+                               "Request for adding port with out-of-bound id %u, max. supported id: %u\n",
+                               cpkt->id, portdev->config.max_nr_ports - 1);
+                       break;
+               }
+               add_port(portdev, cpkt->id);
+               break;
+       case VIRTIO_CONSOLE_PORT_REMOVE:
+               unplug_port(port);
+               break;
+       case VIRTIO_CONSOLE_CONSOLE_PORT:
+               if (!cpkt->value)
+                       break;
+               if (is_console_port(port))
+                       break;
+
+               init_port_console(port);
+               /*
+                * Could remove the port here in case init fails - but
+                * have to notify the host first.
+                */
+               break;
+       case VIRTIO_CONSOLE_RESIZE: {
+               struct {
+                       __u16 rows;
+                       __u16 cols;
+               } size;
+
+               if (!is_console_port(port))
+                       break;
+
+               memcpy(&size, buf->buf + buf->offset + sizeof(*cpkt),
+                      sizeof(size));
+               set_console_size(port, size.rows, size.cols);
+
+               port->cons.hvc->irq_requested = 1;
+               resize_console(port);
+               break;
+       }
+       case VIRTIO_CONSOLE_PORT_OPEN:
+               port->host_connected = cpkt->value;
+               wake_up_interruptible(&port->waitqueue);
+               /*
+                * If the host port got closed and the host had any
+                * unconsumed buffers, we'll be able to reclaim them
+                * now.
+                */
+               spin_lock_irq(&port->outvq_lock);
+               reclaim_consumed_buffers(port);
+               spin_unlock_irq(&port->outvq_lock);
+
+               /*
+                * If the guest is connected, it'll be interested in
+                * knowing the host connection state changed.
+                */
+               send_sigio_to_port(port);
+               break;
+       case VIRTIO_CONSOLE_PORT_NAME:
+               /*
+                * Skip the size of the header and the cpkt to get the size
+                * of the name that was sent
+                */
+               name_size = buf->len - buf->offset - sizeof(*cpkt) + 1;
+
+               port->name = kmalloc(name_size, GFP_KERNEL);
+               if (!port->name) {
+                       dev_err(port->dev,
+                               "Not enough space to store port name\n");
+                       break;
+               }
+               strncpy(port->name, buf->buf + buf->offset + sizeof(*cpkt),
+                       name_size - 1);
+               port->name[name_size - 1] = 0;
+
+               /*
+                * Since we only have one sysfs attribute, 'name',
+                * create it only if we have a name for the port.
+                */
+               err = sysfs_create_group(&port->dev->kobj,
+                                        &port_attribute_group);
+               if (err) {
+                       dev_err(port->dev,
+                               "Error %d creating sysfs device attributes\n",
+                               err);
+               } else {
+                       /*
+                        * Generate a udev event so that appropriate
+                        * symlinks can be created based on udev
+                        * rules.
+                        */
+                       kobject_uevent(&port->dev->kobj, KOBJ_CHANGE);
+               }
+               break;
+       }
+}
+
+static void control_work_handler(struct work_struct *work)
+{
+       struct ports_device *portdev;
+       struct virtqueue *vq;
+       struct port_buffer *buf;
+       unsigned int len;
+
+       portdev = container_of(work, struct ports_device, control_work);
+       vq = portdev->c_ivq;
+
+       spin_lock(&portdev->cvq_lock);
+       while ((buf = virtqueue_get_buf(vq, &len))) {
+               spin_unlock(&portdev->cvq_lock);
+
+               buf->len = len;
+               buf->offset = 0;
+
+               handle_control_message(portdev, buf);
+
+               spin_lock(&portdev->cvq_lock);
+               if (add_inbuf(portdev->c_ivq, buf) < 0) {
+                       dev_warn(&portdev->vdev->dev,
+                                "Error adding buffer to queue\n");
+                       free_buf(buf);
+               }
+       }
+       spin_unlock(&portdev->cvq_lock);
+}
+
+static void in_intr(struct virtqueue *vq)
+{
+       struct port *port;
+       unsigned long flags;
+
+       port = find_port_by_vq(vq->vdev->priv, vq);
+       if (!port)
+               return;
+
+       spin_lock_irqsave(&port->inbuf_lock, flags);
+       if (!port->inbuf)
+               port->inbuf = get_inbuf(port);
+
+       /*
+        * Don't queue up data when port is closed.  This condition
+        * can be reached when a console port is not yet connected (no
+        * tty is spawned) and the host sends out data to console
+        * ports.  For generic serial ports, the host won't
+        * (shouldn't) send data till the guest is connected.
+        */
+       if (!port->guest_connected)
+               discard_port_data(port);
+
+       spin_unlock_irqrestore(&port->inbuf_lock, flags);
+
+       wake_up_interruptible(&port->waitqueue);
+
+       /* Send a SIGIO indicating new data in case the process asked for it */
+       send_sigio_to_port(port);
+
+       if (is_console_port(port) && hvc_poll(port->cons.hvc))
+               hvc_kick();
+}
+
+static void control_intr(struct virtqueue *vq)
+{
+       struct ports_device *portdev;
+
+       portdev = vq->vdev->priv;
+       schedule_work(&portdev->control_work);
+}
+
+static void config_intr(struct virtio_device *vdev)
+{
+       struct ports_device *portdev;
+
+       portdev = vdev->priv;
+
+       if (!use_multiport(portdev)) {
+               struct port *port;
+               u16 rows, cols;
+
+               vdev->config->get(vdev,
+                                 offsetof(struct virtio_console_config, cols),
+                                 &cols, sizeof(u16));
+               vdev->config->get(vdev,
+                                 offsetof(struct virtio_console_config, rows),
+                                 &rows, sizeof(u16));
+
+               port = find_port_by_id(portdev, 0);
+               set_console_size(port, rows, cols);
+
+               /*
+                * We'll use this way of resizing only for legacy
+                * support.  For newer userspace
+                * (VIRTIO_CONSOLE_F_MULTPORT+), use control messages
+                * to indicate console size changes so that it can be
+                * done per-port.
+                */
+               resize_console(port);
+       }
+}
+
+static int init_vqs(struct ports_device *portdev)
+{
+       vq_callback_t **io_callbacks;
+       char **io_names;
+       struct virtqueue **vqs;
+       u32 i, j, nr_ports, nr_queues;
+       int err;
+
+       nr_ports = portdev->config.max_nr_ports;
+       nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2;
+
+       vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL);
+       io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL);
+       io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL);
+       portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
+                                 GFP_KERNEL);
+       portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
+                                  GFP_KERNEL);
+       if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs ||
+                       !portdev->out_vqs) {
+               err = -ENOMEM;
+               goto free;
+       }
+
+       /*
+        * For backward compat (newer host but older guest), the host
+        * spawns a console port first and also inits the vqs for port
+        * 0 before others.
+        */
+       j = 0;
+       io_callbacks[j] = in_intr;
+       io_callbacks[j + 1] = NULL;
+       io_names[j] = "input";
+       io_names[j + 1] = "output";
+       j += 2;
+
+       if (use_multiport(portdev)) {
+               io_callbacks[j] = control_intr;
+               io_callbacks[j + 1] = NULL;
+               io_names[j] = "control-i";
+               io_names[j + 1] = "control-o";
+
+               for (i = 1; i < nr_ports; i++) {
+                       j += 2;
+                       io_callbacks[j] = in_intr;
+                       io_callbacks[j + 1] = NULL;
+                       io_names[j] = "input";
+                       io_names[j + 1] = "output";
+               }
+       }
+       /* Find the queues. */
+       err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs,
+                                             io_callbacks,
+                                             (const char **)io_names);
+       if (err)
+               goto free;
+
+       j = 0;
+       portdev->in_vqs[0] = vqs[0];
+       portdev->out_vqs[0] = vqs[1];
+       j += 2;
+       if (use_multiport(portdev)) {
+               portdev->c_ivq = vqs[j];
+               portdev->c_ovq = vqs[j + 1];
+
+               for (i = 1; i < nr_ports; i++) {
+                       j += 2;
+                       portdev->in_vqs[i] = vqs[j];
+                       portdev->out_vqs[i] = vqs[j + 1];
+               }
+       }
+       kfree(io_names);
+       kfree(io_callbacks);
+       kfree(vqs);
+
+       return 0;
+
+free:
+       kfree(portdev->out_vqs);
+       kfree(portdev->in_vqs);
+       kfree(io_names);
+       kfree(io_callbacks);
+       kfree(vqs);
+
+       return err;
+}
+
+static const struct file_operations portdev_fops = {
+       .owner = THIS_MODULE,
+};
+
+/*
+ * Once we're further in boot, we get probed like any other virtio
+ * device.
+ *
+ * If the host also supports multiple console ports, we check the
+ * config space to see how many ports the host has spawned.  We
+ * initialize each port found.
+ */
+static int __devinit virtcons_probe(struct virtio_device *vdev)
+{
+       struct ports_device *portdev;
+       int err;
+       bool multiport;
+
+       portdev = kmalloc(sizeof(*portdev), GFP_KERNEL);
+       if (!portdev) {
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       /* Attach this portdev to this virtio_device, and vice-versa. */
+       portdev->vdev = vdev;
+       vdev->priv = portdev;
+
+       spin_lock_irq(&pdrvdata_lock);
+       portdev->drv_index = pdrvdata.index++;
+       spin_unlock_irq(&pdrvdata_lock);
+
+       portdev->chr_major = register_chrdev(0, "virtio-portsdev",
+                                            &portdev_fops);
+       if (portdev->chr_major < 0) {
+               dev_err(&vdev->dev,
+                       "Error %d registering chrdev for device %u\n",
+                       portdev->chr_major, portdev->drv_index);
+               err = portdev->chr_major;
+               goto free;
+       }
+
+       multiport = false;
+       portdev->config.max_nr_ports = 1;
+       if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) {
+               multiport = true;
+               vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT;
+
+               vdev->config->get(vdev, offsetof(struct virtio_console_config,
+                                                max_nr_ports),
+                                 &portdev->config.max_nr_ports,
+                                 sizeof(portdev->config.max_nr_ports));
+       }
+
+       /* Let the Host know we support multiple ports.*/
+       vdev->config->finalize_features(vdev);
+
+       err = init_vqs(portdev);
+       if (err < 0) {
+               dev_err(&vdev->dev, "Error %d initializing vqs\n", err);
+               goto free_chrdev;
+       }
+
+       spin_lock_init(&portdev->ports_lock);
+       INIT_LIST_HEAD(&portdev->ports);
+
+       if (multiport) {
+               unsigned int nr_added_bufs;
+
+               spin_lock_init(&portdev->cvq_lock);
+               INIT_WORK(&portdev->control_work, &control_work_handler);
+
+               nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock);
+               if (!nr_added_bufs) {
+                       dev_err(&vdev->dev,
+                               "Error allocating buffers for control queue\n");
+                       err = -ENOMEM;
+                       goto free_vqs;
+               }
+       } else {
+               /*
+                * For backward compatibility: Create a console port
+                * if we're running on older host.
+                */
+               add_port(portdev, 0);
+       }
+
+       spin_lock_irq(&pdrvdata_lock);
+       list_add_tail(&portdev->list, &pdrvdata.portdevs);
+       spin_unlock_irq(&pdrvdata_lock);
+
+       __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
+                          VIRTIO_CONSOLE_DEVICE_READY, 1);
+       return 0;
+
+free_vqs:
+       /* The host might want to notify mgmt sw about device add failure */
+       __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
+                          VIRTIO_CONSOLE_DEVICE_READY, 0);
+       vdev->config->del_vqs(vdev);
+       kfree(portdev->in_vqs);
+       kfree(portdev->out_vqs);
+free_chrdev:
+       unregister_chrdev(portdev->chr_major, "virtio-portsdev");
+free:
+       kfree(portdev);
+fail:
+       return err;
+}
+
+static void virtcons_remove(struct virtio_device *vdev)
+{
+       struct ports_device *portdev;
+       struct port *port, *port2;
+
+       portdev = vdev->priv;
+
+       spin_lock_irq(&pdrvdata_lock);
+       list_del(&portdev->list);
+       spin_unlock_irq(&pdrvdata_lock);
+
+       /* Disable interrupts for vqs */
+       vdev->config->reset(vdev);
+       /* Finish up work that's lined up */
+       cancel_work_sync(&portdev->control_work);
+
+       list_for_each_entry_safe(port, port2, &portdev->ports, list)
+               unplug_port(port);
+
+       unregister_chrdev(portdev->chr_major, "virtio-portsdev");
+
+       /*
+        * When yanking out a device, we immediately lose the
+        * (device-side) queues.  So there's no point in keeping the
+        * guest side around till we drop our final reference.  This
+        * also means that any ports which are in an open state will
+        * have to just stop using the port, as the vqs are going
+        * away.
+        */
+       if (use_multiport(portdev)) {
+               struct port_buffer *buf;
+               unsigned int len;
+
+               while ((buf = virtqueue_get_buf(portdev->c_ivq, &len)))
+                       free_buf(buf);
+
+               while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq)))
+                       free_buf(buf);
+       }
+
+       vdev->config->del_vqs(vdev);
+       kfree(portdev->in_vqs);
+       kfree(portdev->out_vqs);
+
+       kfree(portdev);
+}
+
+static struct virtio_device_id id_table[] = {
+       { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID },
+       { 0 },
+};
+
+static unsigned int features[] = {
+       VIRTIO_CONSOLE_F_SIZE,
+       VIRTIO_CONSOLE_F_MULTIPORT,
+};
+
+static struct virtio_driver virtio_console = {
+       .feature_table = features,
+       .feature_table_size = ARRAY_SIZE(features),
+       .driver.name =  KBUILD_MODNAME,
+       .driver.owner = THIS_MODULE,
+       .id_table =     id_table,
+       .probe =        virtcons_probe,
+       .remove =       virtcons_remove,
+       .config_changed = config_intr,
+};
+
+static int __init init(void)
+{
+       int err;
+
+       pdrvdata.class = class_create(THIS_MODULE, "virtio-ports");
+       if (IS_ERR(pdrvdata.class)) {
+               err = PTR_ERR(pdrvdata.class);
+               pr_err("Error %d creating virtio-ports class\n", err);
+               return err;
+       }
+
+       pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL);
+       if (!pdrvdata.debugfs_dir) {
+               pr_warning("Error %ld creating debugfs dir for virtio-ports\n",
+                          PTR_ERR(pdrvdata.debugfs_dir));
+       }
+       INIT_LIST_HEAD(&pdrvdata.consoles);
+       INIT_LIST_HEAD(&pdrvdata.portdevs);
+
+       return register_virtio_driver(&virtio_console);
+}
+
+static void __exit fini(void)
+{
+       unregister_virtio_driver(&virtio_console);
+
+       class_destroy(pdrvdata.class);
+       if (pdrvdata.debugfs_dir)
+               debugfs_remove_recursive(pdrvdata.debugfs_dir);
+}
+module_init(init);
+module_exit(fini);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio console driver");
+MODULE_LICENSE("GPL");
index 47d32281032c75322b1181c65ab710f00b7967c6..52fc0c9a6364e05edc80e8bdf4e4d28250f9a754 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..be0ebce
--- /dev/null
@@ -0,0 +1,1472 @@
+/* 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/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..88b1335
--- /dev/null
@@ -0,0 +1,2978 @@
+/*
+ *  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/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..e381b89
--- /dev/null
@@ -0,0 +1,1600 @@
+/*
+ * 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/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..beb1afa
--- /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_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/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..910870e
--- /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_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/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..93760b2
--- /dev/null
@@ -0,0 +1,869 @@
+/*======================================================================
+
+    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/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 c556ed9db13d82a4bd7dcff1bb599dce6abd8341..8e0dd254eb11cf3d9f503c7bda32bcb3e75ba09d 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)
index 464d09d97873dd535df3d9ce9b481be7fa98db55..0065da4b11c1a89eefba4d6c3ac17abb25c9a41d 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 ebae344ce910443b9d40d4bab4ca1158b910a4bf..c956ed6c83a3b9387936d480e6ea5e2dfe9085ff 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 eab3a1ff99e43c2468d35a3c770154e80a9bf7cd..a672ed192d33b038a9e28033d5f526e320ce9504 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 76407eca9ab0101567df390b39ea03b1b50e3d58..147ede3423df6228c781c39100a42937e6437f33 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 6b68a0fb461178a671a4dd1c1f74be0c10216fbf..1235ebda6e1c094bba7338e60c180bbd3823d4d3 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 6ee4451bfe2d204ebc8ecba57c7129fd494308e8..47085e5879abb57758601722bb62c7734380a254 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 bcc24779ba0e3145f713dd7bf6c0f73368763de3..18d02e32a3d5f6d38adcd3f1f90bafc4a84a6f1c 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 9da250563027630330d92831ac0adbe428feb1cb..df502a98d0df0611e206d7e32e12c1bf1a5b39df 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 b55d46070a2519cc6d0b38f5c7b49daf241f5337..f71e8e307e0f0c0b513c763b1ddfcb7b81f0cded 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 b98efae6a1cfdaaa08b786b45da8c92b56d7f73c..4310cc4b1cb5d5c019f9e032232de1e1dcc00ddb 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);
                }
index 1dc9739277b4941498619b88a98e6731e93fdcaf..06bb9d4587e936d3b052e9302deff3993d43ba95 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
index 31656a2b4ab487a1ec14500664930c1c82401b70..a1c67ae1572a2b8abf57ed9688d0a917a413aab7 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 f61fed07f76bb89d535cd181faf941b4178453d2..a2492b65f98c41a3b57e795c546f73eb6b551d46 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 f6ff8456d52d59fe027f88bbabf678982299282e..1ba4befe336b6b77741f163510c6e5890e7d0df6 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 0c8dd81dddcab5d10b38b9ce967d6e5d9e6cfab4..b120dbb64d0f385c24d73e75b5411d54edbe9119 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 2fc8636316c550eb8019799e99299e5551f2aac0..12ff6cffedc9d481fd2429fc537acd9d8ea6d41d 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 86e42892016d29564dd89bef520138cadd3263ce..5c761df7fa83cfb212943009bc7a10beb4a619fe 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 2c8353795226b7f87a3c957c5bc21f6224c477b3..3fabed33d940d9f2f6bbb094de137b82f5282bbc 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 6fee3cd58efe30db9f74137c47cdbf16339c5863..74dcf49bd015a99384b04678dff4f9f576f4a809 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 fa59b26fc5bce0c7812dd933a169fddb52ef2837..c8e360d7d9759dbde4eff329781c252d5d27e806 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 76179c39c0e3490b0a5e9240619b9e4ba18affb9..bed07d4aab0638c6065f1d1eb87350bf0f0fc428 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);
index 574b99ea07009a2467daa902d997a58c1b8657e9..79a66d622f9c265bdc2c8f6780f0df7c299a1235 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 df558f6f84e30eff6d6df0fc61c3bd67fb183387..3e8211c1ce5adaee7ebfd4ecb59a4ee6fbfa160f 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 */
@@ -1188,7 +1183,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 +1705,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,
@@ -2389,7 +2383,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);
@@ -2414,14 +2409,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 +2447,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",
@@ -2551,9 +2549,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
@@ -2625,7 +2625,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;
 }
 
@@ -2671,7 +2671,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,
@@ -2711,9 +2712,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 +2760,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 +2821,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 +2866,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;
 }
 
@@ -2900,6 +2907,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 +2918,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 +2958,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 +2976,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 +2993,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 +3016,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 +3075,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 45e4a3108cc31285fcb41c7a83972a621a72a68b..34cf4e1658773d870fc857c1338e4fe01df3af02 100644 (file)
@@ -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;
 }
 
@@ -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;
@@ -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 */
@@ -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;
@@ -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 170c367112d2e8046f39ec596703c126f2050f84..7f236fd220151ca5fa4f43cee6733e97867f2d5f 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
index 1732d9bc097eb1ff1b867a963e0a80d7ea6b7a8d..1616ad1793a4ac28970e33a5b0a58efd0fcb56a6 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 4ff21587ab03214373364681a664df5d56a66a16..f7a2057380321fa7c102b140ce0bf2f4374e9db1 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 e70014ab0976ae0ea737c8faa210544c233d4dcd..8acf165fe13b84e4fdefcdd8e94d8b008ead9666 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 059d9ac0ab5b14f4bb80895d1d69fbeb921970d9..770d799d5afb8ec0eadd650dc2c1f348dc7648c5 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 63f7cc45bcaca15b34691ce081fdd30b7b0007d8..7b8815ddf3688e725a1cbde438d1b74ea6120999 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 8d7731dbf478f9592d8dff350374dc6375649c44..735ea03157abad3e9692978767a9d0e61d92eabd 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 b92070c103cd4b4854ccee1aad7bc807b829b874..666e5a6edd827edcf9e7e3a2e65532104dc55ec9 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 a2668d08926096f827de803289fa7029d7475671..4787c0cd063fd7e8ef15082adbcc489a7bca9945 100644 (file)
@@ -676,7 +676,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) },
index bf0867285481bef7f839c5e2c2e7e5fa124f52bd..ed160def85847c44710c77c12436ec97b711c570 100644 (file)
 #define OCT_US101_PID          0x0421  /* OCT US101 USB to RS-232 */
 
 /*
- * Icom ID-1 digital transceiver
- */
-
-#define ICOM_ID1_VID            0x0C26
-#define ICOM_ID1_PID            0x0004
+ * Definitions for Icom Inc. devices
+ */
+#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)
index e6833e216fc9fa4e3628813d57f14891835caf6a..e4db5ad2bc55f1c37f2da2b15c086534e98248c7 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 6ab2a3f97fe832a1fdd0b2778c8bee1c713d63b7..178b22eb32b17f65a9a25ab67ad55a54ae786914 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 12ed594f5f808f63106ad4dedbcb9f7d35983237..99b97c04896f9402b37458106e6e3288c01575bb 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 2d8baf6ac472c3be9356f3aaa84aa1582d0fbf97..ce134dc28ddfb457997f7465d1bd1e62d0bef192 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 a10dd5676ccc0e70a930e0c7048daa675adc6f76..554a8693a463aabda0f4b514cad5574ab623b0be 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 cf1718394e18e3079452104948caf233292490c4..653465f61d4a9345f78a01ac9774684695c3cad4 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 748778288d94b649f4dec1cbad1f25ceac85ecb6..5f46838dfee5d842aa5863fc0c13171dde45bb21 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 5be866bb7a4132a1e078939abda73daecaf2e434..73613205be7ad283ec9f820f86c861ca9af6dec6 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 8ae4c6cbc38a04ea250d43aad68aa43081098245..08c9181b8e4823192ec880181bcccdb1fe3b4fd2 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 43eb9bdad422c91e4290f2204ee2f178d393b002..1b025f75dafd29c0868766bab5107d506168cbbf 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 214a3e504292e2f5c7066ec41b7ce27acd3886e9..30b73e68a904d65e7dadb3fdeee8acd73f65607c 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 cb8195cabfde82d0ce0cb9c16c5e441100ca1757..74cd4ccdb3fcc1b344de2e969df87c4882825ea4 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 765aa983bf58e6e3548a079d2e92223b03cd6eff..cbfb70bffdd05e842a9e9479297ffb95edb2a6e0 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 6954de50c0ffe5e22cc85ad909af0ceef1dde4fd..546a52179becbc783a825bda99efd61c8a2d8bff 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 f2ed6a31be77288733235eec2f60437d01d7ea91..95a82148ee81ec448e866b2b5b3b91ef93690c22 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 c854fdebe0aecc1755f8fa604cd21f3fd841c165..2c8553026222fb178a4b11d2ae4380751ce716c6 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 fcc1e32ce2566332a3bc6ad41b35fdaf5a23e8ff..24bd5d7c3deb49beeaa5b3d1837fa015c53bd7ae 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.
@@ -1872,6 +1881,15 @@ 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 ),
+
 UNUSUAL_DEV( 0x2116, 0x0320, 0x0001, 0x0001,
                "ST",
                "2A",
index d916ac04abab098ee480720cac0a1036642c9ab9..6bafb51bb43738a415ba09547a49bef21809f9a1 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 d583bea608fd755bfe1f16c24d5dc95e184aa316..391ac939f011cd9102184154c1cbcd42e09878b7 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 dd9de2e8058051e0a9b4c3e086f83f8ad071fb4a..4cb6a576c5672ea1576ed12c80fc46fbacbff8c8 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 767ab4fb1a053185feb354745e3e71f508e087bb..94e293fce1d2c8f6eb66f6fc03e44064eb270e0d 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 c4e17642d9c5b9e4a8bbbd61dad399311f0a58ee..92bda58485165a55ac2acc711ddfed5781bf49fe 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 c789c46e38af2040f55acd769ec514a32e2ce4f9..b224396b86d56ce0f63ecd765b14e6e59d010fd0 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 18c507874ff1476c372495f8ed7f1339dced996f..47c21fb2c82fc50b2ac1329c30c1055b96874391 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 d637e1f53172ac8180fcfec902cbe580dbca3072..cff742abdc5d4ce998e9e7819487cee271761f80 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 5a35f22372b9959e52f1a8ab267a17baaf492b92..2209e354f53110bc8b6670ce09c0626cf340941a 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 7ccc967831f05bca5aba179bb88ff7880f55b92f..9c092b8d64e6a5d0a205a71002afa5f917adf20b 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 c97491b8b39b1eb51f830f76f23469a1c655ef7e..915fd74da7a2554ae14c77be007667219f7fef19 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 c265aed09e04a2061ca224dd4354ffd178d9ccdc..8d61ef96eedd5b7942346950223513eaf4ed52e9 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 4ac1201ad6c2fb3229a60e1377f29b4eef78a2eb..e2bf95370e40bd63a5743b2ee26f5b6cd302095b 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 0a08f134122761df00476ffcc6243b566195db79..f4a32779168bb9cadb739ae0acd438ed3d635296 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 70b1d9d51c9601e2c4c338f58d29f7d4f59214dd..b4f19db9bb542ddfb453298498ca5e96413fe2a5 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 39bdbedf43b481253e7eb3586d15050c83abb94c..416851ca8754bec70bb54108c0a7c9cb663dde47 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 5743ea25e818814887fada1f82562e553dbfe2c2..318f6fb895b289d2c2b5b884dd7deebc8e1616cf 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 670ecaa0385a94f396acb74eadeb6e29d71edb1f..de366937c93362a68c73bcd6c18ba7e3f035241a 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 cb013919e9ce5fbfd29bb3f27521f62c99e394e1..7e3a490e8d76d882555f58a752242360a6ed948b 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 62498bd662fc91bab443c19da41797fd0f57e33e..f838d9e277f05e4fb5c9ee724d1f028a560e07a2 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 efe10ff86d6365ceaf5ab6f4fb3a0425b8f82c78..081dc47452742a769235d74c18cf49545efe72fd 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 9c0144ee7ae516f6d0042127f8acad4279249f46..65560a1a04392a14602533eaa23d5536941b0573 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 cea6403ae71c16ffbcded14282db1552244f8833..35f61dd0cb3a43f5a9e3f70ac0dc5a07136a91b1 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 b81168df253dbff37e562dc8ff70e0872a57a686..cf4beb9dc9bb5a9603679eaa35dc0e7e652d1fb1 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 dce8c97b4333b4871f356b6d5cac1c17f351a600..75738a92861000a75b87c7694d9980a241b9ca10 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 842d157e10258e5ed62d37c9fa628ada1d4afa8f..487911e2926cbc6a8924a477240fc083943bf8c5 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 74d9f546a2e8012b50ee4503fdebdb50297ce4fa..2b9e56a6bde4780933d444b1f7e29aada38274eb 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 bd4840a8a6b772f84c13f4356705e92302e21a39..bf12e53aed5cb6059568149b40d4c86692bf1b90 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 b7dc1800efa98b141665035d50463765ef623fef..bcb44a594ebcb944821cfe2f09d621f470cfa056 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 6913fe168c25f6d4249b2898c5663ede06fe2d8c..dfef88c803d45ec48129cb31236ad156231cfd4c 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 289edd519527ff948570261db01747be8c26e20f..4e66349e4366711a3e42c444a400e37fb2b8e1a7 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 85d76ec4c63e0c7ea2f65f10d072749256f9aeee..a2965ab92cfb815a289b21d8a30884e32db8c999 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 3e6934d4bea8eb24a7a538235eaf71141c84d02f..a20218c2fda8be0a98b4a219bff743db2a0b5018 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 ef8d9d558fc734183dd82a172e49f9ee7a07b8ae..4fb5b2bf23486c0bee03f0dd3de196aff7f40549 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 1c1236087f785a20b1351e375b6ea4b9e1d1444e..bbd000f88af7056ed8c5f52ae891c5375c8bd875 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 9a7921ae47637c691c69428cc9e67934e52ee240..3db9caa57edcbfcf260436b4cd4fb15e3fc070f4 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 60d27bc9eb83d82f61e448031495625e42c752d3..6b61ded701e10a23b61199b91536f2178c629275 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 e835eff551e342156ff1f1b1f1e657c089f435eb..5625463aa4796f3df3678dd29ed1bfb1135a32af 100644 (file)
@@ -710,10 +710,6 @@ static int fill_inode(struct inode *inode,
                        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 1e30d194a8e349f4f8a2bc951681a63c9c8d70b3..a1ee8fa3a8e7a4e8778fa624ef44154f67e2acf9 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 bf6f0f34082a082d1a39d3640f5a30956dbcb13d..9c5085465a63056ac493a5febe8b184163c933a6 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 6e12a6ba5f79daabc1bc455a3a4db464b240c00a..8c9eba6ef9df4999ce4894893900984d943695e5 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 43b19dd391912476c395ffbabaaabbacc28d0146..d87558448e3dd87628d520f68e4f976806e260f3 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 46af99ab3614d545675e41e788686b39fd51204b..fe1683590828a0ed011fa4a2e6ca6cc157292dca 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 ede98300a8cdb53ac362c69a8c3dd6743f748343..65829d32128c253a661ecd61dc50f4893bc9f52d 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 7ed36536e7540171cd2bcca9f20b79555a5f73d8..f1c68629f2770a44434e1fa9895a532d7a65c419 100644 (file)
@@ -297,7 +297,6 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
 
        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;
index 7852cd6770517a8a5da7877fb788a834a0534c86..ac51cd2d33aed1a444debff691bfa710e3a5100a 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 430f510a1720a5659a2ea73eef0cf7bcf0a22182..fc0fd4fde306b989c1593ef11ce2611fd49dca54 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 a437ec391a015fb7c05725543d6c118eadefc466..1e7636b145a88a180c8459f65bf86d51d6c165f6 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,7 +368,7 @@ 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);
@@ -390,6 +393,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 66f3d50d067682aa2203e30676550cce6421ec3a..0db5f1de022780f93fdd91e689fc3eb1ee820052 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;
+       }
+
+       rc = E_md4hash(ses->password, temp_key);
+       if (rc) {
+               cFYI(1, "%s Can't generate NT hash, error: %d", __func__, rc);
+               return rc;
+       }
 
-       E_md4hash(ses->password, temp_key);
-       mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE);
+       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 0;
+       return rc;
 }
 
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
@@ -700,14 +708,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 d9f652a522a6994097d7ec4008abacb0cfc0b65a..f2970136d17d06c27e0654bbf4f13e302b3dc815 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 851030f749391729a315a915ba0c934cb6e981cf..14789a97304e7179ca9f71da7f3fd4ed28b51b26 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.69"
 #endif                         /* _CIFSFS_H */
index 606ca8bb710245484d32b3ec91415d2901812da4..edd5b29b53c9a354ac6c0a8d934a793c0221cea0 100644 (file)
@@ -161,32 +161,27 @@ 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  */
@@ -199,8 +194,6 @@ struct TCP_Server_Info {
        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,19 +203,52 @@ 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
  */
@@ -446,11 +472,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 +534,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 +557,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 */
@@ -622,12 +661,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 +826,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 de36b09763a84e7fb6016b93222fc74ee263d540..b5c8cc5d7a7fa4c2d38be38b3b34b30b4a65e818 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 e6d1481b16c1403cbe1c7fcae04e11abcc3f91f9..8096f27ad9a86405731bf7edcc35b1e66fbe5e4d 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 2f6795e524d3f39c34c2a1dbed77e11149f9330c..3106f5e5c63301609b21df1bf1f93251a2b7beda 100644 (file)
@@ -331,37 +331,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 +450,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 +563,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 +702,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 +1236,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 +1349,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 +1431,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 +1706,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 +1735,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 +3132,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);
@@ -5562,7 +5607,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 9f59887badd2255457a384feffee95a98a2fb9e7..47d8ff623683524a4a264e7317a8e707a5a209ed 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,26 @@ 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);
+
+       /* no need to ping if we got a response recently */
+       if (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 +361,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 +414,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? */);
@@ -559,10 +587,11 @@ incomplete_rcv:
                        continue;
                }
 
+               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) &&
@@ -603,20 +632,19 @@ 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;
+                               list_del_init(&mid_entry->qhead);
+                               mid_entry->callback(mid_entry);
 #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;
                                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 +653,10 @@ multi_t2_fnd:
                                else
                                        smallbuf = NULL;
                        }
-                       wake_up_process(task_to_wake);
                } 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 +704,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 +731,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 +1342,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 +1568,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 +1601,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 +1677,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 +1698,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 +1750,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 +2271,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 +2584,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 +2942,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 +2971,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 +2987,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 +3028,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 +3038,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 d843631c028d5939f57992701e95943318fe14ab..0de17c1db608fc1af7da8b1e43ea1a97572238fe 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);
@@ -726,12 +734,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 +756,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 +805,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 +826,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 +847,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 +867,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 +888,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 +915,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 +928,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 +956,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 +969,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 +998,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 +1006,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 +1019,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);
@@ -1239,7 +1218,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 +1356,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 +1528,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 +1619,242 @@ 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;
-       unsigned int bytes_read = 0;
-       unsigned int total_read = 0;
-       unsigned int current_read_size;
-       struct cifs_sb_info *cifs_sb;
+       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)
+{
+       size_t total_written = 0, written = 0;
+       unsigned long num_pages, npages;
+       size_t copied, len, cur_len, i;
+       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;
+       unsigned int total_read, bytes_read = 0;
+       size_t len, cur_len;
+       int iov_offset = 0;
+       struct cifs_sb_info *cifs_sb;
+       struct cifsTconInfo *pTcon;
        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 +1862,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 +1893,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 +2011,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 +2472,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 6c9ee8014ff0426e6aaed09f77a8ebffe9a406b3..8852470b4fbb50b55907cbbd2f4d75357a9f0776 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 306769de2fb5369e221df1975dba3b904b6b1d5c..02cd60aefbff8906671c4f018dc38028efda4975 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[8],  md5_hash[9],  md5_hash[10], md5_hash[11],\
        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)) {
+               cERROR(1, "%s: Crypto md5 allocation error %d\n", __func__, rc);
+               return PTR_ERR(md5);
+       }
+       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,
@@ -56,7 +93,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 +106,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 +132,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 +145,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 43f10281bc19e80be48303e1bd9c974b4882cb37..a09e077ba92531e7d8614fc2ce0f8878613c36fb 100644 (file)
@@ -571,7 +571,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 +637,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 6783ce6cdc895371d8edcfa9a79b06940223b5d5..8d9189f644777714342473ea795456e5f145f2ad 100644 (file)
@@ -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 eb746486e49e8da35ee1b7d940e964f191fe9df9..1adc9625a344be288bc0151eda20a5874569eaa3 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;
@@ -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 b6b6dcb500bf5e11d017a05cae57778edd4e18da..04721485925d9ffc763e5cfd3233a6de34cd789b 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 192ea51af20f49c8976fa734ca44f79e988d7f6b..b5450e9f40c022e7b7de3db1a0286cb1bcd089fc 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)) {
+               cERROR(1, "%s: Crypto md4 allocation error %d\n", __func__, rc);
+               return PTR_ERR(md4);
+       }
+       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 +160,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 +182,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 +257,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 +274,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 59ca81b16919ea2a9d978ced67df60315499711c..c1ccca1a933ffca32d96800dd697bbb1d504d761 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)
 {
@@ -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,81 @@ 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;
+
+       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 +426,81 @@ 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;
+       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 +509,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 +531,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;
@@ -457,65 +575,20 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
        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)
+       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;
-               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;
-       }
-
-       /* 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);
-               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 != 0)
+               goto out;
 
-               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);
-               /* 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) {
@@ -559,19 +632,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 +657,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 +681,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 +720,20 @@ 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)
+       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;
-               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);
-               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 != 0)
+               goto out;
 
-               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);
-               /* 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 +775,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 +811,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 +849,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 +867,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 +884,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 +903,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 +917,22 @@ 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) {
+               if (wait_for_response(ses->server, midQ) == 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;
-                       }
-               }
-
-               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);
+       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 +976,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 9f493ee4dcba79c6c590692a15ea088ff94522b0..2a6bd9a4ae975fdc3eedf9723b551fc9e5f65836 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 85882f6ba5f73c66b614a79ad3594a3dab5dc2b0..b044705eedd4f0836cbcbe5d0f92bf6fb6e39cf7 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 7aa767d4f06f4ebcfcc0ee7e23a117e8aa99ee5c..85c8cc8f24732c59c52943b6b8810780c2e94428 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 cb10a06775e48faf6220436624ec952d82340d20..48ce561fafacb8ca92ba2ef978db8736926e1bfc 100644 (file)
@@ -1161,7 +1161,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,
@@ -4558,27 +4558,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 +4582,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 +4590,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)
index 2232b3c780bd9678a2e80394b674444ee8401a14..7aa7d4f8984aa3271eac65e268cd4e5e0db05564 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 732a183efdb3d183dd43fc05a70ddbdc80df05e6..3e00a66e7cbd04c707ce22686647e5800c7621a4 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 16c2ecac7eb78cec5da5c6ce6dea798fc64ad7b0..ec73ed70bae1afc669b69e1cdbc162d93acec7d8 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 5f1bcb2f06f3e89878bed401d1ad2a23f2e0070f..b7c99bfb3da6dcb9897a85b201f1a2212b03bace 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 199016528fcbefa5f7a59ece47380568b0cf0f4d..e3d29426905848101510bf0fea21f4fa2378794a 100644 (file)
@@ -134,33 +134,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
  */
@@ -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 d3b44f9bd747a2e4516595bdcff096d6f132543a..46d93ce7311bb107a39005e0a66c818064e41ef2 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 4bb91cb2620d8c389b1f021e2d996955f3550b8a..89587573fe50660ee9a13ebc8890b94f1c4adfd8 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 23112c263f81902cb4e8ba1b09c0a31ce3bf7596..14e0f9371d1463900258ef60c361c3079f55c707 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 192f2f8602659fffb693625ef93fb474d499f08e..bd3ca32879e79db9de680e650475e2704de7d566 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 364e4328f3923851f427fd5951e1cd3b309e9949..bbbc6bf5cb2e42a8b1440c31eafa2e0f2c0c5a77 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 e6ace0d93c71485870be33434830740941aa43ac..9943a75bb6d1d94766c7992be26034372152e4ad 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 d8512423ba7298ee56368fd27e42d4d01fd7cee2..1cc600e77bb43aa14ba3d1547d5780c2a0e7c0a5 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 4644f04b4b46661bab07f5fe2d5b38d4373d602d..cf9fdbdabc675ad635e7d2183904d930d6995f5c 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 9f88c5f4c7e2a9a192f4579590b9e9f4bb8a334e..27434277165570b4f1f00c06f42dc2ca6818804f 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 01c5e8b1941d2faea2732a181b1bec1fcdd85302..183c6b123d0f53bd43209cd6a6634aaa8b9f484f 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 51fe64ace55a34523f9f3d6fd461962e364c1b4e..f5c9b125e8ccee997a456bea20e87ae4dade07dd 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 9d992b0346e3fc481e851feb706943fc126e91f2..78936a8f40ab43583dc5bdda2c06e433e294404b 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/module.h>
 #include <linux/sunrpc/bc_xprt.h>
 #include <linux/xattr.h>
+#include <linux/utsname.h>
 
 #include "nfs4_fs.h"
 #include "delegation.h"
@@ -4572,27 +4573,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 2336d532cf66c3677441871842fb7b9ec31a9aad..e6742b57a04c725aeebd07ab6a2ad0e27bc95a9e 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 2ab8e5cb8f59f6410c4e407e90bd70ddaefd9fc9..4e2c168b6ee96701e9e7d5fd9ffca742d3a115ed 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 bc4089769735384073579926047d0347124f5b6b..1b1bc1a0fb0a6f30dcbd1029666242f5b3b8a46f 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 10d648ea128bf6345df70da0e15ee8ce443ab8e6..c8278f4046cba5a957705c1e43ee675dba388529 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 fc1c52571c03ea9eaf0d4e96a4026f119cd026e9..84c27d69d421e494c2c41359f06dd02eb2c32960 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 0994f6a76c0799ec86a482288256522a5735f72a..58fd707174e108714091c081604f7daa781d10f5 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);
 }
 
index b572b672718110e317a6895698bdf612b2e8eced..326e7475a22a40d1323be1786ffa089ffb3182e7 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 06d1f749ca8945264aded7f21c1c2b35285d52df..38f986d2447ea9ba0c7a657b0500c421bf2abbaa 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,
index 89e9e19b1b2eef328ddc36714be0db771e49bcc9..da42f7db50de42640a7fa56df21e21bbb48cf588 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 39df95a0ec25edc87e7c3e29aef2b9a707f95f9f..b1cf6bf4b41dea46feb35d8d6d02f4d5c88153f8 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);
@@ -31,6 +32,16 @@ EXPORT_SYMBOL(posix_acl_create_masq);
 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.
  */
@@ -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 6a0068841d96c00ef3b1bbc38182bf1db9b54f17..15af6222f8a4fb465251dd97610460a9bc79639e 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 eafc22ab1fdd5d830ae2c196dd4d7e8f7cd3e074..b701eaa482bfb4cc3d8b8d91c76884b91167fe11 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 84becd3e477257c7ab790bcb973b5e9accdd1e28..a2a622e079f08f55c5dfe2a8b40c8b8c59a04db5 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 b299961e1edbb8ef4dd16d28ccfd5c7cba2bfa28..b34bdb25490c8956b4733c29771bea3109ec2fcf 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 2575682a9eada129675ca642ae24b1dbf46c0eaa..0aab04f46827def240b7d5468de229e91a9770f5 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 2fb2882f0fa7b1a1b656f68596ec740d10650cd9..8ab48bc2fa7d4f17f75288ac64544b9894f15dfc 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 856756ca5ee493e29631b8e8108119c3268f5c80..c4eb400182564c13728fc88f95edf6db294eb2ac 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 818a5e063faf37c03c189c8043ec470f52024575..4661ae2b1cec8040adcadc4018deb63735309f92 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 f4b67588b9d69217d980f663b30b875e91249268..8c41feacbac56fade7f81f59444b50b3c00630d7 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 b06ede1d0bed4562e60e4067e729b9209de65e1d..f5e2a19e0f8eb25114fa8de3478b289d4972b8a9 100644 (file)
@@ -985,10 +985,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 +1009,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 f8e854b4fde87c49f17ff07dc87893b172bb6203..206a2815ced67399c9cfa248a45d185605e12aee 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 0ab56b32c7eb70484ed4a7fdcfdbac3595c1ecab..d0b3bc72005bd147557625e4afabdca058c6e163 100644 (file)
@@ -74,6 +74,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
index 4111cd3966c764b3c41300d1e7a51a7579ead435..dc3afd7739ff40754d1e04eda13178acc78ef3c2 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 98c6f73b675218bded1a6b326ecdf349cb241a07..6f8c21ce0d6d95fd8c45a5d3eea4ef0240fad1fd 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 75f2ef60e579e62f483213fa6a038cb235698054..d22e62623437aafb79d62f5492252e140f3a6cb7 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 55582bd66659140ed9592a85ec0189187bcfd4ac..8a0f044750c3207eff174c4137bcd77580465894 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 916eb7db14d9a09ff541882bf12905d9fd5068ea..3bd3291ef8d21fc09697b3c4aa5f7b76df4d1c87 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 9dc8125d04e5e09188c88695c42b13a4ae9b6a9b..9ca59be089779d6f3c4e570c926545d6441b85da 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 33dbc4e0ad622a94dbbf8aa67b49e0eacef0cbbc..76922793f64fa0d58606a4411f008ba8b9e88259 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 17714beb868ef5d17f57fc25323fea915e894ffc..5b6c391efc8e658adba3eac683f46ea3938495ab 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 9cf736ea4691b6c0ac206789f30f73f3ab6dd3ac..fc1575fd4596e484c0fc44c7614e6decb5e8c6b6 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 bc4a6deb73b0317ff06785b0b7770327ab437c21..ef1cef77d32ba0687491bdbb5852d32fe40075c8 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 a091cabca4b1266f1c3cbdaac7d44f2a4c81be4c..de39915f6b7fb389e8cf2c8b7be73184e1fa8db5 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 65b3f5888f42749510f4d51f7d9a0bed43e770bf..a3252a5ead669d360c37c1403c1fa0de9945a50d 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 241b8a04c83c83b5dfb082eed7b696c05b4e2840..e46ec95a8adac68abf713952066a5be8bc59c293 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 e5526354ba5eab0142eb58159fa862e18d11cd13..0a66cc45dd6b79a0fdb17be3368b87cdd1c646f5 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 ad2001683ba7385d50c875eda327c4ac41894c48..7e42bfee0e296a4dee55fc8de24e6caebfd1526d 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 cd77aa75c9623eec7edb38499969f437cc613ef4..7504bc99b29b7359f9ec503a6c0def183c98c2c9 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 d4136b28011fd692c4ffb45c78adcc8170e20a4b..0fc15dfb2e22c2bdeef92428960028d3efcc6540 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 939a431a6ab61b34bd1809964da9484e5e2a382b..64f838beaabffdeead528c4aaf2c4240fb9e9701 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 a3e334ab11191aeb596b93cfc28a7c4dcef85d4d..5af3ed52ef980d9c09e9ceff7221341108cfa2db 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 5dcb9537343c7a91d82317dd4e50aa7d385149f5..e228893591a95c09905a0728b49c8088496110a4 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 572189e37133d697db734ff2d8e10c1707917463..5d2a5e9544d9d4743202852cde379a60fb2f7600 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 68649336c4adf98618ff4d4fd8d9f1d6b2867062..6ebb81030d2d109ce9f99069b130c29a39ccfa11 100644 (file)
                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) = .;                       \
        }                                                               \
index e95a86b8b689b530ec8981ad1525bb6b49c2f142..e5c607a02d57cc337f3329b88bcd881cceef7b43 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 eb176bb1b15b722f8c1f78b1650f38302e85a60f..a2e910e01293a01fd229cd59dfb1c1bb69f7be1a 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 9774fe6a1a9705274bf9aaf96d074eaad86278b5..7453cfd593c813632c3cf103ea918c471266613e 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 a3b148a918740c509494b44cf2fda690d3261f96..0b84c61607e8ce808dbb6b2e611a01a6ade11646 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);
index 6042228954a74657422718a5799bd8877bab3558..294169e31364727edd70f699c821c0430d612649 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 e470d387dd496b0bb6233dc20f6569ccffe966f8..05e03284b92ac00d1eed1f85b7076a2a5fa0a956 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 6a64c6fa81affacd4761f47156f6fb1666ddf112..c1a95b7b58de736f228cfeef9bfe1f118e02bf29 100644 (file)
@@ -100,13 +100,6 @@ static inline struct irq_desc *move_irq_desc(struct irq_desc *desc, int node)
 #define get_irq_desc_data(desc)                ((desc)->irq_data.handler_data)
 #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
@@ -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 5a9d9059520b9fd36fb4049bef4e673a18a9cdd1..2fe6e84894a4bc10006511bbbb67b15d8197958d 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 08d7dc4ddf40b57047d1f1304be6b02dac2f2063..39f8453239f779edcd0e5dedfc2d293b34bf7b60 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 71c09b26c7592ff4a1f6351fd226c9442ef66e5d..4aef1dda64065e90bd846cd553b3c26fc93c594e 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 6a576f989437115eff8840a234b6057471a96a50..f512e189be5a496b2aa1b555c1fd34e056fc81e6 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 956a35532f47012d38712dbd64f2a12e5ddbd6d7..f6385fc17ad46a6137bb7fdd387f8f81bb91e492 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 bf173502d74418784c0c12128b43419a1242ceb3..38d3930928128b755d98ece1c2f8fe1437dfd19c 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 8b17fd8c790d8601f8aff0a33c7b909984e30545..e7c6385c668394240e237f16a92286d2f32aed5e 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;
+};
+
 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
index 112adf8bd47dd2c1d13800577f340d6cfa9c0b46..07b41951e3fa9eb7894032a4921cdd65a05c05bd 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 f321b578edeb452358497e832815d6cae6b36886..fabcb1e5c460f240ff1f9c5e5b1d6d720505d7c5 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 d68283a898bb8df089a5f04e29160eaea1c315b3..54211c1cd92634fb4f15bbcf5607948e499e3e52 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 94c1f03b50eb959302044572fecb1872295ba116..9a85412e0db6a4015388bc4ebb2c5466e6b55db0 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 223b14cd129cfc324b9e9bdcdb4b609666bb639d..eb354f6f26b333d078adb645a0488ae279935d13 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 3c995b4d742ccd080b9fc97a5ffdea8ee7d6d58c..a0b639f8e805b2390026999d6e7279b4158c636f 100644 (file)
@@ -235,8 +235,6 @@ extern int rtc_irq_set_freq(struct rtc_device *rtc,
                                struct rtc_task *task, int freq);
 extern int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled);
 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_aie_update_irq(void *private);
 void rtc_uie_update_irq(void *private);
@@ -246,8 +244,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 c50b458b8a3f48047556c3f120eb538971d26cd5..082884295f80028a9a9aa3ea4255ad2cea3984d0 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 059877b4d85b7c0734668bd9027745e0c10bea8b..7ad9751a0d8796e677fb2fdfd50cc4854bcf0eb7 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 387fa7d05c982b758942f83395e328949324fc1a..7faf933cced7018657d2212d543530484ce17ec9 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 dd6ee49a084464e8390041e041b3a2a8a855259a..a854fe89484e4404ed14086fc441498fdfe85e7d 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 16d682f4f7c3572fd946d736af644cd4ef9c0b27..c9049139a7a5a42f3a8f4d82d727355aeca9bce1 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 0093dd7c1d6f0eaf810001851902444269e82f44..800617b4ddd56c3dd0a790f97a4c73f2fa38de64 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);
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 a23c1fc685a1e3426c2ba6b578d7158621fcf917..2963263f31e213d785d6e17cee3c0863c1e9a201 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 ac7ce00f39cff70a1fdd70e9b32dfb4c4a62c46f..79827143d5acd925510f3ad7a4de2f912c49ff48 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 2d65b35cdab21e6f18718bf4c674ae1b585fb020..a659319e858257d0bfe2c736f8a97fb2b4fcdcb8 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 d69ab4aae032ce6ecf59e7bb490ac2a1269dfd01..97d063837b61fb48b315d04da9096375480772f8 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 b0316a7cf08d21f2ac68f1dc452894441948c155..daf1e57d9b266e9be3daf59e2c0e141351fa78d8 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 a29feb01854eb9ad0940cc52fe51bbc759614222..d2cf88407690e432f80938985d7cbcf4fb16d0ed 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 e9eee99d8b1f4668aef09526341d0e032a6f120b..160a407c19632a2220fa6fc5efc120086fd076ee 100644 (file)
@@ -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 2a128c8c2718646a360c889475b4118e4e6bdc70..e73ebdae323d83f21ed7480155597f364c2f6025 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 4e337906016e9fccb399a99fd2b402d3b74a6b8a..be788c0957d4abac813eef18abe7822177542969 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 00799c1d46288fb491e6eb07ccf17dc8406883cc..33c37c379e96458521a0111a968849139edcf586 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 31d766bf5d2ea02da6c5dc551a415799ae8166df..8e42fec7686d97815c3539d3da260984db63e90f 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 e2347eb6330682501e99bb3214ccfa9015a8a521..3540a7190122361a3cdaec62c08d7652693bde44 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 42ba65dff7d99e4eeadfe6175d70c2f9665ad431..0d2058da80f51888b503f4e92829bddbe884b264 100644 (file)
@@ -2291,22 +2291,6 @@ mark_held_locks(struct task_struct *curr, enum mark_type mark)
        return 1;
 }
 
-/*
- * 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:
  */
@@ -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 08107d1817582000af8df78667db22e6d88e5f59..0da1411222b9a2e11c1de4ed228e4028e8aef2b1 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 84522c7969870fa3a6024086c6a3559546b0e9db..126a302c481c060782e811e92e3fca0386271208 100644 (file)
@@ -2201,13 +2201,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 +2261,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 +5380,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 +5430,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 +6136,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 +6449,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 +6537,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 53d9a9ec88e6952cde88769ce6cd124c57f541d4..2ddbdc73aade6cbdeadc804575bcf145eb02dd29 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);
 
@@ -501,7 +501,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 +604,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 +659,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 +827,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 +993,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 +1004,7 @@ void resume_console(void)
                return;
        down(&console_sem);
        console_suspended = 0;
-       release_console_sem();
+       console_unlock();
 }
 
 /**
@@ -1027,21 +1027,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 +1050,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 +1103,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 +1149,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 +1158,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 +1179,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 +1197,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 +1205,7 @@ struct tty_driver *console_device(int *index)
                if (driver)
                        break;
        }
-       release_console_sem();
+       console_unlock();
        return driver;
 }
 
@@ -1208,17 +1216,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 +1348,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 +1360,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 +1404,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 +1426,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 ea3e5eff3878d75ec4f49b39c8139773626ccd1e..18d38e4ec7ba249ba46079beab5a773700a7eb3b 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 32a723b8f84cac397c51579a1f3099d35d1a25f0..9fb65628315709b36d4bb6d9bd100644d2a00992 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 5358e241cb20fdb12dd69f8308b9e0308ba08d96..7b859ffe5dadd677cce89f833ee43a242ea3a992 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 1dfae3d014b5934eba4b3be25bfbad746196b4b7..eb6cb8edd075d9372b0547162a2930b06d14cacc 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 c62ebae65cf0c5e5d1628b0368692a94cda37568..0c26e2df450ee534e79f1265851100245b30a9cd 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 4ec30e0699878d2f536df9ee6ce94d765f046403..9910744f0856c5a084b4f9721dca09f376415645 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 31b71a276b40eda1c64578666ac7e1fadb77642f..18da702ec813c491c758b6f28e86a31a71ba60b5 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 bc86bb32e12620c463699c9e461c836ce37733c1..0f1bd83db98523333b9fabde37d200512b20b77e 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 3e216e01bbd19191f440cf8b202af38007d06ece..c55ea2433471c2952bd65283cd72eb165d720bbe 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 5cf8c602b8804c054bbed65475b4815fd29d5b82..92b6e1e12d982931309e4ecf431a923ffff56c84 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 8ee6ec82f88a9cc2982bfcd73bc3bd86dcd490a8..11869faa6819767fba57f1e45789da7b56f15e74 100644 (file)
@@ -768,7 +768,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 +1844,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);
@@ -2384,8 +2388,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);
index 2d05adb984018776610f573de126f14bda4c9d2e..3967c2356e3710e9be11ea9c4901c6b206232406 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
index 5086bb962b4dd9ca6471afb76f0698facb914816..7ea2e033d7153ad23de9dc02c0c0786abc1e11e2 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 4693f79195d3bc4fd118a01cda1128c0ea1f9df9..a16be19a130545ce44fc4f8c6a3f9fde866b9159 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 d608331b3e4798c23607471dea52bbc483c69760..e0cc0146ae622a0f48060ccefc53ada28e299c59 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 e3b6e18fdac5718a09fef2ce874a911b52b09ab2..60a6088d0e5e9495a2f74da59d6fc92ce0247a7f 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 3ad483bdf505a560dcc3b9c3dfe2de4331539155..e9c0c61f2ddd0881bbb9dee37d3384dae0146ece 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 6d592a021072a89048b6edd0ec79c8f965b83d49..8be430b812def9f32058ffb8c7e259ff1375d98e 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;
 
@@ -453,6 +457,13 @@ unsigned long compaction_suitable(struct zone *zone, int order)
        if (!zone_watermark_ok(zone, 0, watermark, 0, 0))
                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 004c9c2aac788ebca9c7de0edb95244396b880f1..e187454d82f666a70bab08762ca92cd60b8f848c 100644 (file)
@@ -1203,6 +1203,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);
        }
 
@@ -1837,9 +1839,9 @@ 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);
@@ -1856,6 +1858,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);
index 177a5169bbde178323974f027940957a9b4fa4a9..ff0d9779cec8060fe9a161dd278943a39c29f58e 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 bd9bc214091b39b23c7b61182c81d17e2da7bf71..84225f3b71905ba8a2aa639a3007486b97715db1 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 400dc62697d78056eaa12c7a91ca9f9daa1d4c77..bdba245d8afd9a75babf696030255d2d239e11de 100644 (file)
@@ -683,13 +683,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 8ab8410314363871da25fa9f613578f5ebe01783..3878cfe399dc8733bbc0633aa248b3f4dea231f0 100644 (file)
@@ -600,23 +600,22 @@ 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
                __this_cpu_inc(mem->stat->count[MEM_CGROUP_STAT_PGPGOUT_COUNT]);
-       __this_cpu_inc(mem->stat->count[MEM_CGROUP_EVENTS]);
+
+       __this_cpu_add(mem->stat->count[MEM_CGROUP_EVENTS], nr_pages);
 
        preempt_enable();
 }
@@ -815,7 +814,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 +836,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 +856,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 +1026,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;
@@ -1615,7 +1607,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,6 +1832,7 @@ 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
@@ -2084,14 +2077,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 +2121,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 +2191,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 +2209,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 +2231,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 +2273,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 +2287,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:
@@ -2546,7 +2589,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 +2638,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 +4885,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++;
index 46fe8cc13d67f3acf80653434223577084fd8fcf..9f29a3b7aac2242c511b8a783226c247af301993 100644 (file)
@@ -888,7 +888,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.
  */
index 90c1439549fdf221ab1813b14ae0d5dc74adce45..a873e61e312e6dd7795b4b734a0370bc844d9f29 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;
index 0369f5b3ba1b3fcc510e99cdd68c5f7ed7d490c4..eb663fb533e06f45305ac0b348b2365ecb1615bb 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 3c2d5ddfa0d49f3cf31449e214d8fbd50e92ad08..49feb46e77b8802803d20009f758ec65d2db0835 100644 (file)
@@ -549,13 +549,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 47a50962ce817682ce618bc1a85d3216763e5d3c..148c6e630df2002d8f72b35cca1ed79b7bedb334 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>
@@ -2084,7 +2083,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 d4d9926c2201e5656229612e36226abb6865479f..65106fb61b8fce83c442d27e1eb848ab8e92ef67 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 b49fdf70a6d526d3700ed89c75651d02abccd921..2284e8129cb26b8d5554538cd71b7722deea3f13 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 97cb23dd3e6921db1dd7fba220544ebe04553e75..bf3f6f5a12c4466c0ca86140650fe3d195d450ec 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 dc2e28bed844a5dafe22a28e13f83572e57235d4..ee41fef04b21339868b9726e7f62cd79be741f13 100644 (file)
@@ -229,10 +229,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 6b90a41917347826f2a81fea590124a54af1f9bd..99cd8d9d891b475c57925be6ae54a88240f7adc8 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 8b602d881fd758f88a5d7a8cca8d2e7d03caeb92..9c4541bc488ab9b2a74dda2809929f842b9b97e6 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 38100170d380a1f794c1ea75b7723f36312a7212..a290854fdaa6ac68bba2443a51763723d5be7f62 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 c791fcda7b2d11bc4d2758701f1b200d73841f0c..7550abb0c96a36d60869009daecd20a601eb7263 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);
@@ -1068,39 +1079,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 +1106,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 +1873,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 ff8aaa736650b81caed4058323a79643ce0d2931..6b83776534fb45e29946f9666cb7a23654d4a431 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 21ede141018abf698a58bcf946e0058d6d06c499..c665de778b6026bdbcbea8696ca246f2647c9882 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 9d5e8accfab1d73f25e8a00ae45523a400b820ce..092dc88a7c64c63856f91a32d4c5511471476eaa 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 e88f610fdb7bb11e69cc1f5a0bf10846d5c7165c..883e9d74fddf6439b483f822b327371b78bb9670 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 54277df0f735abf601a44053fa29c9f85cc5c87b..24ea2d71e7eac37000285ea5cd348e1ecb14f156 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
  *
@@ -2001,7 +2002,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 +2024,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);
        }
 }
index 17741782a345f78328a881da5887f6e81834f5b6..ff2302910b5eb936c7618c24477c018cfdcd159f 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 a5f7535aab5b80798d20d278689872e08c2b4b3f..750db57f3bb3e628b44a481c11eea954d21ce88d 100644 (file)
@@ -1820,7 +1820,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 d31bb36ae0dc21cfdab61b90dd2f2fbfd665ce81..7cd1bc86d5911118a7a7bc6c1bc0ad7f1188ae6a 100644 (file)
@@ -2744,8 +2744,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 d900ab99814a7e54d8d2d9e14cd828314dd4e7ce..6b03f561caecfdd72c1fc0df2785c435acdb3cc4 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);
index 0c877a74e1f433699272953712458393045ff13c..3fb14b7c13cf1ed3bc5bb1439e6bfc35f907af96 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 04c8b69fd426457b3112aa379382a361fa9e9130..7927589813b54b5baa50ae29904c5b0e21f6a513 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 2746c1fa6417b73af42bfe40206405e456a176ac..2ada17129fce6ac9a7285f6033e30d0a9bc4b98a 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 d9bc85751c74c7376568fb2b59da450658b1afd5..a96e65674ac3e694e8e70fec1855324a694ccbf3 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 2549b29b062d00c0cdc5f5a5f6dc069ce8b86e64..eb7f82ebf4a325a1199bbe5610cd4191bc6e2df5 100644 (file)
@@ -4399,7 +4399,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 856f68466d49a8e0d01d03bf66748bd3ad218a1c..02f583b3744a7b633743e8c998ba1b3b0081a3fb 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 5b189c97c2fc16d28961955673c1fa94f3df21ad..fd6782e3a038a03b2a17f9da188ae1bc8d181f3f 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 373bd0416f69f9ad7e4645eebb574a3ec4eb4127..1534508f6c68a3c4f010657e94051e06a7d727c4 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);
@@ -738,13 +736,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;
index 7e74023ea6e4381ae006eb672369f98fb899cc79..da87428681cccc9d955fdc80ee6f8bd4998356dd 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 9109262abd24ccb44946d1e34edd086db60cec20..c766056d0488eb2826def69d7ba9e923e171304f 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 f138b195d657cf038ad68fde631fb5caebbeccf7..227ca82eef72178253b3f4adf831ce5ae297dd28 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 485d36bc9a460bdd9a67ab63a1b5ce1f12d53c54..a46ff06d7cb8ce9d8e31fd593555925c9aa07500 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 5950e3abead9b49a7bfc4a8d17d77ce250d1b578..b64b42bc774be82ce40133237624a848d237289f 100644 (file)
@@ -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 2b7eef37875ccbdd8c59c5f8d845746e9f9609d7..93297aaceb2b3d48e307bfb74549661bfaeda27f 100644 (file)
@@ -924,7 +924,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 +1787,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 f83cb370292b3b87a9610488e57ac8bef8f4b731..1781d99145e2d2594fc961e1a2fc9307aad957a5 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 eaf765876458f3a89e5a26af5d5ac3b09c556161..7fce6dfd2180af0ecaed0d3e82bb7afcc604001a 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 c80d1c210c5d621454acf3388a63440c3fbfe740..5f63ec58942c10ac5088c6e6fca6e40463235a0b 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 de55e642eafc2924bd2b6220aaac1d38e879954e..6b7fe4a84f138b903928a8c5f5f90f8fe3b855dc 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 60f4bdd4408e25888b4575bd9ab7b75441cab8c6..0f7bf3fdfea5a63683d86887e4d9fad99ff40a82 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 aa4d6337e43cab4f3a094d6b2028be50afdcada5..d468b479aa937f410a665045eb4018bfc08de255 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 2e45791d4f6cf7970d590fde138981254b359403..14a799de1c3535ed99c9af448080265fa406fe88 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 984c1b0c68369dd24b4837fd681126abc229ce92..fc12fe6f559796d11aaa8b4e769b26a6a28643e9 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 21f13da24763977eaea671c19a58357018f72899..436a2e75b322db524764a2483cd385e905aa4534 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 1c4bce86347977ec93b1fa5a0fdcceaf34cfe257..6a3006b38dc55e65c4629a967a326eed684d7fd1 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 966158d49dd105ce882ece6a6ccd6f072f5676ca..fbd710d619bf372535d21ef38c750c7e6e6c9cf0 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 a6009c5a2c97dbe446b162923fb997db00f00ee6..9f98dbd32d4c8176d6c940dd098f71fa0c00cb4d 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 239ec53a634dace6d29a3294c2a98e4c401539b8..edea8cefec6c9502e0a841e4bb4bd3ef11003495 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 77565e721811f5cc5789a24987be3b0c04a6b371..e93165820c3f02ec4edc072b26b04dcdd4645ce0 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 84ce48eadff4952e2552306fae3197858af86c59..d84e7329660fb5f21e5e87d11fae435e27907a8b 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 a09b0dd25f5061505a2cb2bbfbe3d9e9d091f3e8..8e02550ff3e88d9153a0d610dbdadb864ae06da7 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 7bd3bbba4710d82ff658bd6de998543bca0609a7..d802e941d365e9b53bf7c6be04bd1555bc0d1144 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 d0ee29063e5d80190412672552a5b2cfe4886c74..1f1ef70f34f2d2852a6007b0444ac5cd14fb7f4a 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 d5e1e0b08890fa2022b7fa309cb0e3600e1908ae..61291965c5f60a0354ee499f664df340845bc9e7 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 6c941050f5734d79354e657d0aec167d50923276..1bf090a885feed4791cab9b8a6947bde347f868e 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 792c0a611a6d115a5a272ca748af6c1804c762ef..07a5f35e39705bef3856d9605c4f96c65670b3c9 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 a46e825cbf0265311288115453ee25227baa28e4..89df6b5f203c534c64fffd3fc0547f611dedebea 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 56a133d8f37d192ffb1adbc45cad9610f5cbbc5b..a52aa7c88b41b48170791abd5eb06c839910dc84 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 c1eac8084ade445e06a38ff908dc95c207089781..1c2d43dc5107ecbe66bb8a5077876147ab785719 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 60924f6a52db2bbff40ddc953a50bb9d708febb5..31a0fd8189f1f85835ca1b7e4e99e093c178c1d5 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 d37f713e73ce7ef7937ef8bfe23a96960202c187..5620f084dede47a8887977fe10554b2f32f73b4e 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 28645502cd0dc0719f41c96f3e3ed0059d816d51..c35b5229e3cdca80bcd6b44da70b5123871e1874 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 70373966816e9845594919d870fca1f3e441ca65..525cf8a29cdde86c5c58557fd73ceb49e9c73dec 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 504bdd2452bd7ce1b995441662f16e02407f3fb3..930634e4514973ac0f79acc7037138acb576a2c3 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 0ea52d25a6bda8b3568fdb7752539403e93086b6..a3dc0d460def505eb2dc053866f0cc457d448c9f 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 86747151ee5b680ea1591bfb00aed4475e104f5f..68164031a74e0bc225844037ceedd45a40fc94cb 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 e9aa079296561507835e0e349a55f07b11bec5bb..02807fb163401bcbc9ff5cfc74bd6576b06ec918 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 c3f845cbcd48b6019dae5c3ca7df2bf4317a3b01..a53373207fb459223e52fadd718e5a2cc2dbb666 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 be9de387283722607dc025fd52095c3fdf6f6883..57363562f0f886a455e900fdf59a56417b379127 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 91acc9a243ec47dec8aabb6a67bcdd9b4f4aa671..24d3013c02312e7773ae1a864ed87e0ba1b571ee 100644 (file)
@@ -30,6 +30,8 @@
 
 #define DRIVER_NAME    "aaci-pl041"
 
+#define FRAME_PERIOD_US        21
+
 /*
  * PM support is not complete.  Turn it off.
  */
@@ -64,8 +66,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 +83,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 +106,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 +121,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 +182,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 +878,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)
index 10c3a871a12d904bad20cff78dfce56e8373cb92..b310702c646e40ef59afedeed630dc320b5570be 100644 (file)
 #include <linux/dw_dmac.h>
 
 #include <mach/cpu.h>
-#include <mach/hardware.h>
 #include <mach/gpio.h>
 
+#ifdef CONFIG_ARCH_AT91
+#include <mach/hardware.h>
+#endif
+
 #include "ac97c.h"
 
 enum {
index 6117595fc075bba219b7b8a97cbd4de0e9154859..573594bf3225810366186751b70b5ccf9b962a02 100644 (file)
@@ -979,31 +979,25 @@ snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec,
 
        snd_azf3328_dbgcallenter();
        switch (bitrate) {
-#define AZF_FMT_XLATE(in_freq, out_bits) \
-       do { \
-               case AZF_FREQ_ ## in_freq: \
-                       freq = SOUNDFORMAT_FREQ_ ## out_bits; \
-                       break; \
-       } while (0);
-       AZF_FMT_XLATE(4000, SUSPECTED_4000)
-       AZF_FMT_XLATE(4800, SUSPECTED_4800)
-       /* the AZF3328 names it "5510" for some strange reason: */
-       AZF_FMT_XLATE(5512, 5510)
-       AZF_FMT_XLATE(6620, 6620)
-       AZF_FMT_XLATE(8000, 8000)
-       AZF_FMT_XLATE(9600, 9600)
-       AZF_FMT_XLATE(11025, 11025)
-       AZF_FMT_XLATE(13240, SUSPECTED_13240)
-       AZF_FMT_XLATE(16000, 16000)
-       AZF_FMT_XLATE(22050, 22050)
-       AZF_FMT_XLATE(32000, 32000)
+       case AZF_FREQ_4000:  freq = SOUNDFORMAT_FREQ_SUSPECTED_4000; break;
+       case AZF_FREQ_4800:  freq = SOUNDFORMAT_FREQ_SUSPECTED_4800; break;
+       case AZF_FREQ_5512:
+               /* the AZF3328 names it "5510" for some strange reason */
+                            freq = SOUNDFORMAT_FREQ_5510; break;
+       case AZF_FREQ_6620:  freq = SOUNDFORMAT_FREQ_6620; break;
+       case AZF_FREQ_8000:  freq = SOUNDFORMAT_FREQ_8000; break;
+       case AZF_FREQ_9600:  freq = SOUNDFORMAT_FREQ_9600; break;
+       case AZF_FREQ_11025: freq = SOUNDFORMAT_FREQ_11025; break;
+       case AZF_FREQ_13240: freq = SOUNDFORMAT_FREQ_SUSPECTED_13240; break;
+       case AZF_FREQ_16000: freq = SOUNDFORMAT_FREQ_16000; break;
+       case AZF_FREQ_22050: freq = SOUNDFORMAT_FREQ_22050; break;
+       case AZF_FREQ_32000: freq = SOUNDFORMAT_FREQ_32000; break;
        default:
                snd_printk(KERN_WARNING "unknown bitrate %d, assuming 44.1kHz!\n", bitrate);
                /* fall-through */
-       AZF_FMT_XLATE(44100, 44100)
-       AZF_FMT_XLATE(48000, 48000)
-       AZF_FMT_XLATE(66200, SUSPECTED_66200)
-#undef AZF_FMT_XLATE
+       case AZF_FREQ_44100: freq = SOUNDFORMAT_FREQ_44100; break;
+       case AZF_FREQ_48000: freq = SOUNDFORMAT_FREQ_48000; break;
+       case AZF_FREQ_66200: freq = SOUNDFORMAT_FREQ_SUSPECTED_66200; break;
        }
        /* val = 0xff07; 3m27.993s (65301Hz; -> 64000Hz???) hmm, 66120, 65967, 66123 */
        /* val = 0xff09; 17m15.098s (13123,478Hz; -> 12000Hz???) hmm, 13237.2Hz? */
index 4a663471dadc1e1e00d712bd5656577aeba56984..74b0560289c00630aca0ba952d8c80a0316e7fd8 100644 (file)
@@ -381,7 +381,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a)
        snd_print_pcm_rates(a->rates, buf, sizeof(buf));
 
        if (a->format == AUDIO_CODING_TYPE_LPCM)
-               snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2 - 8));
+               snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2) - 8);
        else if (a->max_bitrate)
                snprintf(buf2, sizeof(buf2),
                                ", max bitrate = %d", a->max_bitrate);
index 269dbff70b92e57c7bee37c855ada9a20fd4b8db..2fa9ed99c32fef3637226677f168a7ebb8e9f0c8 100644 (file)
@@ -1721,7 +1721,9 @@ static void alc_apply_fixup(struct hda_codec *codec, int action)
 {
        struct alc_spec *spec = codec->spec;
        int id = spec->fixup_id;
+#ifdef CONFIG_SND_DEBUG_VERBOSE
        const char *modelname = spec->fixup_name;
+#endif
        int depth = 0;
 
        if (!spec->fixup_list)
@@ -10930,9 +10932,6 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec)
        return 0;
 }
 
-static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
-                                            const struct auto_pin_cfg *cfg);
-
 /* almost identical with ALC880 parser... */
 static int alc882_parse_auto_config(struct hda_codec *codec)
 {
@@ -10950,10 +10949,7 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
        err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
        if (err < 0)
                return err;
-       if (codec->vendor_id == 0x10ec0887)
-               err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       else
-               err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
        err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
@@ -12635,6 +12631,8 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
                           ALC262_HP_BPC),
        SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
                           ALC262_HP_BPC),
+       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series",
+                          ALC262_HP_BPC),
        SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
                           ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
@@ -14956,8 +14954,11 @@ static struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
        SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
        SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
-       SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
        SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
        {}
@@ -17134,7 +17135,7 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
 #define alc861vd_idx_to_mixer_switch(nid)      ((nid) + 0x0c)
 
 /* add playback controls from the parsed DAC table */
-/* Based on ALC880 version. But ALC861VD and ALC887 have separate,
+/* Based on ALC880 version. But ALC861VD has separate,
  * different NIDs for mute/unmute switch and volume control */
 static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
                                             const struct auto_pin_cfg *cfg)
@@ -19461,6 +19462,7 @@ enum {
        ALC662_FIXUP_ASPIRE,
        ALC662_FIXUP_IDEAPAD,
        ALC272_FIXUP_MARIO,
+       ALC662_FIXUP_CZC_P10T,
 };
 
 static const struct alc_fixup alc662_fixups[] = {
@@ -19481,7 +19483,14 @@ static const struct alc_fixup alc662_fixups[] = {
        [ALC272_FIXUP_MARIO] = {
                .type = ALC_FIXUP_FUNC,
                .v.func = alc272_fixup_mario,
-       }
+       },
+       [ALC662_FIXUP_CZC_P10T] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
+                       {}
+               }
+       },
 };
 
 static struct snd_pci_quirk alc662_fixup_tbl[] = {
@@ -19489,6 +19498,7 @@ static struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
+       SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
        {}
 };
 
index 7b62de089fee04cda4b7090196945621f3a62b58..20c6b079d0dfc33cfc4620006bbbe944e39e91b6 100644 (file)
@@ -580,6 +580,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
 {
        int err;
        struct snd_akm4xxx *ak;
+       unsigned char tmp;
 
        if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DELTA1010 &&
            ice->eeprom.gpiodir == 0x7b)
@@ -622,6 +623,12 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
                break;
        }
 
+       /* initialize the SPI clock to high */
+       tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
+       tmp |= ICE1712_DELTA_AP_CCLK;
+       snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+       udelay(5);
+
        /* initialize spdif */
        switch (ice->eeprom.subvendor) {
        case ICE1712_SUBDEVICE_AUDIOPHILE:
index 9f72d424969ca8ecede2b1301379cbed4959da3f..252719101c4214030c3ba8d664e68a87a02e2d8b 100644 (file)
@@ -392,7 +392,7 @@ static void dump_d1_registers(struct oxygen *chip,
        unsigned int i;
 
        snd_iprintf(buffer, "\nCS4398: 7?");
-       for (i = 2; i <= 8; ++i)
+       for (i = 2; i < 8; ++i)
                snd_iprintf(buffer, " %02x", data->cs4398_regs[i]);
        snd_iprintf(buffer, "\n");
        dump_cs4362a_registers(data, buffer);
index da2208e06b0d632299b61f1cc01a03fcf61bc911..5e4d499d8434ea7377e68419aa34c9b90f8bacd0 100644 (file)
@@ -129,7 +129,7 @@ static struct snd_soc_dai_link afeb9260_dai = {
        .cpu_dai_name = "atmel-ssc-dai.0",
        .codec_dai_name = "tlv320aic23-hifi",
        .platform_name = "atmel_pcm-audio",
-       .codec_name = "tlv320aic23-codec.0-0x1a",
+       .codec_name = "tlv320aic23-codec.0-001a",
        .init = afeb9260_tlv320aic23_init,
        .ops = &afeb9260_ops,
 };
index 3abeeddc67d3533a2c187acc5d606390310902b7..ae403597fd319e63327f0733eb1a779e4b208587 100644 (file)
@@ -1,6 +1,7 @@
 config SND_BF5XX_I2S
        tristate "SoC I2S Audio for the ADI BF5xx chip"
        depends on BLACKFIN
+       select SND_BF5XX_SOC_SPORT
        help
          Say Y or M if you want to add support for codecs attached to
          the Blackfin SPORT (synchronous serial ports) interface in I2S
@@ -35,6 +36,7 @@ config SND_BFIN_AD73311_SE
 config SND_BF5XX_TDM
        tristate "SoC I2S(TDM mode) Audio for the ADI BF5xx chip"
        depends on (BLACKFIN && SND_SOC)
+       select SND_BF5XX_SOC_SPORT
        help
          Say Y or M if you want to add support for codecs attached to
          the Blackfin SPORT (synchronous serial ports) interface in TDM
@@ -61,6 +63,10 @@ config SND_BF5XX_SOC_AD193X
 config SND_BF5XX_AC97
        tristate "SoC AC97 Audio for the ADI BF5xx chip"
        depends on BLACKFIN
+       select AC97_BUS
+       select SND_SOC_AC97_BUS
+       select SND_BF5XX_SOC_SPORT
+       select SND_BF5XX_SOC_AC97
        help
          Say Y or M if you want to add support for codecs attached to
          the Blackfin SPORT (synchronous serial ports) interface in slot 16
@@ -122,17 +128,12 @@ config SND_BF5XX_SOC_SPORT
 
 config SND_BF5XX_SOC_I2S
        tristate
-       select SND_BF5XX_SOC_SPORT
 
 config SND_BF5XX_SOC_TDM
        tristate
-       select SND_BF5XX_SOC_SPORT
 
 config SND_BF5XX_SOC_AC97
        tristate
-       select AC97_BUS
-       select SND_SOC_AC97_BUS
-       select SND_BF5XX_SOC_SPORT
 
 config SND_BF5XX_SPORT_NUM
        int "Set a SPORT for Sound chip"
index c5f856ec27ca1bedc8d0256cf5fe97d11ebac730..ffbac26b9bce5882e662e3dfc1a7a26081cbf91d 100644 (file)
@@ -260,9 +260,9 @@ static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
        pr_debug("%s : sport %d\n", __func__, dai->id);
        if (!dai->active)
                return 0;
-       if (dai->capture.active)
+       if (dai->capture_active)
                sport_rx_stop(sport);
-       if (dai->playback.active)
+       if (dai->playback_active)
                sport_tx_stop(sport);
        return 0;
 }
index e902b24c185605f1eefcfa6fbf5f9e3d7b67d061..ad28663f5bbdf3fe2ee53dacc57cd5ca46cfdb7a 100644 (file)
@@ -119,7 +119,7 @@ static struct snd_soc_dai_link bf5xx_ssm2602_dai = {
        .cpu_dai_name = "bf5xx-i2s",
        .codec_dai_name = "ssm2602-hifi",
        .platform_name = "bf5xx-pcm-audio",
-       .codec_name = "ssm2602-codec.0-0x1b",
+       .codec_name = "ssm2602-codec.0-001b",
        .ops = &bf5xx_ssm2602_ops,
 };
 
index 125123929f16c28d1e52ca01ebde662196f66253..5515ac9e05c70bca470a3f2fe913747cb95fe16f 100644 (file)
@@ -210,7 +210,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
 #ifdef CONFIG_PM
 static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
 {
-       struct sport_device *sport = dai->private_data;
+       struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
        if (!dai->active)
                return 0;
@@ -235,13 +235,13 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
                ret = -EBUSY;
        }
 
-       ret = sport_config_rx(sport, IRFS, 0x1F, 0, 0);
+       ret = sport_config_rx(sport, 0, 0x1F, 0, 0);
        if (ret) {
                pr_err("SPORT is busy!\n");
                ret = -EBUSY;
        }
 
-       ret = sport_config_tx(sport, ITFS, 0x1F, 0, 0);
+       ret = sport_config_tx(sport, 0, 0x1F, 0, 0);
        if (ret) {
                pr_err("SPORT is busy!\n");
                ret = -EBUSY;
@@ -303,14 +303,14 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev)
                goto sport_config_err;
        }
 
-       ret = sport_config_rx(sport_handle, IRFS, 0x1F, 0, 0);
+       ret = sport_config_rx(sport_handle, 0, 0x1F, 0, 0);
        if (ret) {
                pr_err("SPORT is busy!\n");
                ret = -EBUSY;
                goto sport_config_err;
        }
 
-       ret = sport_config_tx(sport_handle, ITFS, 0x1F, 0, 0);
+       ret = sport_config_tx(sport_handle, 0, 0x1F, 0, 0);
        if (ret) {
                pr_err("SPORT is busy!\n");
                ret = -EBUSY;
index 247a6a99feb8f8cb4d8249e5e83764b897fba15f..3351f77607b39d55a446435a2208fef475927ab7 100644 (file)
@@ -2386,7 +2386,7 @@ static int wm8994_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
        else
                val = 0;
 
-       return snd_soc_update_bits(codec, reg, mask, reg);
+       return snd_soc_update_bits(codec, reg, mask, val);
 }
 
 #define WM8994_RATES SNDRV_PCM_RATE_8000_96000
index 6045cbde492be5149ffd7c0b3002631a614ab15f..608c84c5aa8e6472e3bb43b20b279753f0a4a1c1 100644 (file)
@@ -1223,7 +1223,7 @@ static int wm8995_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
        else
                val = 0;
 
-       return snd_soc_update_bits(codec, reg, mask, reg);
+       return snd_soc_update_bits(codec, reg, mask, val);
 }
 
 /* The size in bits of the FLL divide multiplied by 10
index c466982eed2336706b48c697c39fe53b191376fc..613df5db0b329d338f7f7eec6c16458ffbfe001b 100644 (file)
@@ -91,6 +91,7 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op)
 static void calibrate_dc_servo(struct snd_soc_codec *codec)
 {
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+       s8 offset;
        u16 reg, reg_l, reg_r, dcs_cfg;
 
        /* If we're using a digital only path and have a previously
@@ -149,16 +150,14 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
                        hubs->dcs_codes);
 
                /* HPOUT1L */
-               if (reg_l + hubs->dcs_codes > 0 &&
-                   reg_l + hubs->dcs_codes < 0xff)
-                       reg_l += hubs->dcs_codes;
-               dcs_cfg = reg_l << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
+               offset = reg_l;
+               offset += hubs->dcs_codes;
+               dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
 
                /* HPOUT1R */
-               if (reg_r + hubs->dcs_codes > 0 &&
-                   reg_r + hubs->dcs_codes < 0xff)
-                       reg_r += hubs->dcs_codes;
-               dcs_cfg |= reg_r;
+               offset = reg_r;
+               offset += hubs->dcs_codes;
+               dcs_cfg |= (u8)offset;
 
                dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg);
 
index 0c2d6bacc6817847a167541b789fbff7ada7cf91..b36f0b39b0908017cd2b0c716e0447b42d08b564 100644 (file)
@@ -223,7 +223,7 @@ static struct snd_soc_dai_link da8xx_evm_dai = {
        .stream_name = "AIC3X",
        .cpu_dai_name= "davinci-mcasp.0",
        .codec_dai_name = "tlv320aic3x-hifi",
-       .codec_name = "tlv320aic3x-codec.0-001a",
+       .codec_name = "tlv320aic3x-codec.1-0018",
        .platform_name = "davinci-pcm-audio",
        .init = evm_aic3x_init,
        .ops = &evm_ops,
index fc592f0d5fc7886f4786dfe735d1ee6353add878..784cff5f67e81a2c53a32ea5c69279619f716359 100644 (file)
@@ -307,10 +307,10 @@ static int corgi_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_dai_link corgi_dai = {
        .name = "WM8731",
        .stream_name = "WM8731",
-       .cpu_dai_name = "pxa-is2-dai",
+       .cpu_dai_name = "pxa2xx-i2s",
        .codec_dai_name = "wm8731-hifi",
        .platform_name = "pxa-pcm-audio",
-       .codec_name = "wm8731-codec-0.001a",
+       .codec_name = "wm8731-codec-0.001b",
        .init = corgi_wm8731_init,
        .ops = &corgi_ops,
 };
index 6298ee115e2717df4976be9451831f7024da9a60..a7d4999f9b24f4c9d202b9d21647760be483502a 100644 (file)
@@ -276,7 +276,7 @@ static struct snd_soc_dai_link poodle_dai = {
        .cpu_dai_name = "pxa2xx-i2s",
        .codec_dai_name = "wm8731-hifi",
        .platform_name = "pxa-pcm-audio",
-       .codec_name = "wm8731-codec.0-001a",
+       .codec_name = "wm8731-codec.0-001b",
        .init = poodle_wm8731_init,
        .ops = &poodle_ops,
 };
index c2acb69b957a9ca45a23adb0815494512ef589ef..8e1571350630ecfeacacdd93eaab5a6a76c485d8 100644 (file)
@@ -315,10 +315,10 @@ static int spitz_wm8750_init(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_dai_link spitz_dai = {
        .name = "wm8750",
        .stream_name = "WM8750",
-       .cpu_dai_name = "pxa-is2",
+       .cpu_dai_name = "pxa2xx-i2s",
        .codec_dai_name = "wm8750-hifi",
        .platform_name = "pxa-pcm-audio",
-       .codec_name = "wm8750-codec.0-001a",
+       .codec_name = "wm8750-codec.0-001b",
        .init = spitz_wm8750_init,
        .ops = &spitz_ops,
 };
index 2d4f896d7fec56bcf792839efc30be78346eba48..3ceaef68e01de7aebab8d7d16a6715d3bcfedfbb 100644 (file)
@@ -104,6 +104,7 @@ static struct snd_soc_jack_gpio hs_jack_gpios[] = {
                .name           = "hsdet-gpio",
                .report         = SND_JACK_HEADSET,
                .debounce_time  = 200,
+               .invert         = 1,
        },
 };
 
@@ -192,7 +193,7 @@ static struct snd_soc_dai_link z2_dai = {
        .cpu_dai_name   = "pxa2xx-i2s",
        .codec_dai_name = "wm8750-hifi",
        .platform_name = "pxa-pcm-audio",
-       .codec_name     = "wm8750-codec.0-001a",
+       .codec_name     = "wm8750-codec.0-001b",
        .init           = z2_wm8750_init,
        .ops            = &z2_ops,
 };
index 3eec610c10f95541a6fb59358e8ead3f67ce4b9f..0d0ae2b9eef699075fe1ba2039d373ad44145f0b 100644 (file)
@@ -397,11 +397,11 @@ static struct snd_soc_dai_link neo1973_gta02_dai[] = {
 { /* Hifi Playback - for similatious use with voice below */
        .name = "WM8753",
        .stream_name = "WM8753 HiFi",
-       .cpu_dai_name = "s3c24xx-i2s",
+       .cpu_dai_name = "s3c24xx-iis",
        .codec_dai_name = "wm8753-hifi",
        .init = neo1973_gta02_wm8753_init,
        .platform_name = "samsung-audio",
-       .codec_name = "wm8753-codec.0-0x1a",
+       .codec_name = "wm8753-codec.0-001a",
        .ops = &neo1973_gta02_hifi_ops,
 },
 { /* Voice via BT */
@@ -410,7 +410,7 @@ static struct snd_soc_dai_link neo1973_gta02_dai[] = {
        .cpu_dai_name = "bluetooth-dai",
        .codec_dai_name = "wm8753-voice",
        .ops = &neo1973_gta02_voice_ops,
-       .codec_name = "wm8753-codec.0-0x1a",
+       .codec_name = "wm8753-codec.0-001a",
        .platform_name = "samsung-audio",
 },
 };
index c7a24514beb58c65b349616a52e3733bf3ec6667..d20815d5ab2eea86317f50c664604f6437269d08 100644 (file)
@@ -559,9 +559,9 @@ static struct snd_soc_dai_link neo1973_dai[] = {
        .name = "WM8753",
        .stream_name = "WM8753 HiFi",
        .platform_name = "samsung-audio",
-       .cpu_dai_name = "s3c24xx-i2s",
+       .cpu_dai_name = "s3c24xx-iis",
        .codec_dai_name = "wm8753-hifi",
-       .codec_name = "wm8753-codec.0-0x1a",
+       .codec_name = "wm8753-codec.0-001a",
        .init = neo1973_wm8753_init,
        .ops = &neo1973_hifi_ops,
 },
@@ -571,7 +571,7 @@ static struct snd_soc_dai_link neo1973_dai[] = {
        .platform_name = "samsung-audio",
        .cpu_dai_name = "bluetooth-dai",
        .codec_dai_name = "wm8753-voice",
-       .codec_name = "wm8753-codec.0-0x1a",
+       .codec_name = "wm8753-codec.0-001a",
        .ops = &neo1973_voice_ops,
 },
 };
index bb4292e3596c877ab5d02b118c2f513bfd7fbcaa..08fcaaa66907b3c04cfde7a43327a37c5fca139e 100644 (file)
@@ -94,8 +94,8 @@ static int simtec_hermes_init(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_dai_link simtec_dai_aic33 = {
        .name           = "tlv320aic33",
        .stream_name    = "TLV320AIC33",
-       .codec_name     = "tlv320aic3x-codec.0-0x1a",
-       .cpu_dai_name   = "s3c24xx-i2s",
+       .codec_name     = "tlv320aic3x-codec.0-001a",
+       .cpu_dai_name   = "s3c24xx-iis",
        .codec_dai_name = "tlv320aic3x-hifi",
        .platform_name  = "samsung-audio",
        .init           = simtec_hermes_init,
index fbba4e36772926f0891912a97066c06468a08d25..116e3e6701679778f1761b9474aa8d58dde30a0e 100644 (file)
@@ -85,8 +85,8 @@ static int simtec_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_dai_link simtec_dai_aic23 = {
        .name           = "tlv320aic23",
        .stream_name    = "TLV320AIC23",
-       .codec_name     = "tlv320aic3x-codec.0-0x1a",
-       .cpu_dai_name   = "s3c24xx-i2s",
+       .codec_name     = "tlv320aic3x-codec.0-001a",
+       .cpu_dai_name   = "s3c24xx-iis",
        .codec_dai_name = "tlv320aic3x-hifi",
        .platform_name  = "samsung-audio",
        .init           = simtec_tlv320aic23_init,
index cdc8ecbcb8ef6838bc9b22a336b4eecf93c89aad..2c09e93dd566f2a66b46dc5886df5119a017bec1 100644 (file)
@@ -228,7 +228,7 @@ static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
        .stream_name = "UDA134X",
        .codec_name = "uda134x-hifi",
        .codec_dai_name = "uda134x-hifi",
-       .cpu_dai_name = "s3c24xx-i2s",
+       .cpu_dai_name = "s3c24xx-iis",
        .ops = &s3c24xx_uda134x_ops,
        .platform_name  = "samsung-audio",
 };
index 2b5387d53ba5116db1f610ab28eaf656f962875a..7141c42e146920b887fe60ca1ba463bfbce90ea8 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 c056cdc0691258b159665ca3e8c74d2963543ccf..8879463807e4a06269e11e5594731ace4fd80ff2 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 def7ddc2fd4fbc1b1c57795f4c10c519729b035d..d97256d6598044fab9e9d092e190fd70bdca4d93 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 b9c6e54329713e326d74da9b08164e562e521d03..2b36defc5d73dd447fbe20ffd2d357c77d2c2058 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 fcd29e8af29fe7cbb14e4563c906688f62e10f78..b2f729fdb317e36c9677c9b058818a7b7e1bc378 100644 (file)
@@ -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 75183a4518e60d23db05e36e585fc178df731a19..c27e31f289e61b74f980923c88cd402ea2ab5f7c 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 29e7ffd8569068dea19b4385cc785a94ab9414fb..29acb894e035154432c708e1bf6ae7b7db5c2be1 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 150a606002eb7b4eb281e69c9c8287eed1931077..b766c2a9ac975614a7507156b258519ec2a50d0a 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 0ff11d9b13be9cb5bfc9f86259dbd972be148d2e..a482a191a0ca3efac6cafe16ec1c827ba70a97f6 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 ed5696198d3df6905fe78f1fc623ccaa5a7f1f75..5dcdba653d7021d4ed0e2b04ad53443b034833c7 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(cpucpu_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 05344c6210ac7a8a3a1ebd00c4448a0807fbf807..b6998e055767fd68b9d70d2462d6776238fe4e85 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 ?
index 2302ec051bb4f1b5171bb543b33284b29bf6f8b6..1478ab4ee2221e8dc5d44cd6677bf56e0d79205d 100644 (file)
@@ -459,7 +459,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 +576,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 989fa2dee2fd2ae441d98921b9e69a56c4fe50e2..f6a929e74981e48844b0af2d21599ff5bb725ac3 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 c749ba6136a0ac33d7cdae8bf5b6604f1ee524af..32f4f1f2f6e4410c5e94d25fd8a7113d2676f493 100644 (file)
@@ -636,13 +636,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, period);
                else
-                       ret += snprintf(s + ret, size - ret, "%11lld", period);
+                       ret += snprintf(s + ret, size - ret, "%11" PRIu64, period);
        }
 
        if (pair_hists) {
@@ -971,7 +971,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 +980,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 +1133,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 +1143,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 8be0b968ca0bcfa44c95248e14e3878481887b21..305c8484f200c67eecff39369db873687bc8655c 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 3a7eb6ec0eecf2c13dcd2ae098f56b4020d70301..a16ecab5229d3f73a99a2ae81d5dab6c24fdb0bb 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 bc2732ee23eb3d1de29d56366ffb93afcea8aed9..135f69baf966d8a2a2525c6f9478958cf2932bf2 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 b82cafb8377202462d16ef7ed36b8e546201c76b..458e3ecf17af9a829dd0cd82be8044221988af88 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 128aaab0aedad86403a0c722211e4d57cb982d8d..6e29d9c9dcccb50f63adac097bc512b56fb3e28c 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 313dac2d94ce9f7c9e74ef0e8995383866427dbf..105f00bfd5552b1b878c21b72b86a80705592252 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 b3637db025a25cba486b824c45c8291a368d7881..fb737fe9be918d093a8f6b377e434c8c74ffe88a 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");
 
@@ -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 15ccfba8cdf805111d56b1e7f3bf71431ef2c1e4..7821d0e6866f10e745762cc02c57237461ae0f8d 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 7d6b8331f8984764e23260eff33d4a13ea09317f..5f3689a3d0857be7431f8ed06eac3eb5e9707e18 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 ebda8c3fde9e6468ddbd84fc2df7e324ba862854..60c463c16028946541560f5f71e37617cfd69c9b 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 e35437dfa5b48aea8a0fb0237b2bf7ed7aaf90cd..e5158369106eee37234baf658d18cddec0539bb5 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 cfa55d686e3b9689fd6bfce089fb9d7207e85ab9..bdd33470b2356e2574c72719d4f40e620002b983 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 4780deac5974fb9e75a820b6cad1c0b07569954c..65b845bd4e3e792ca09ce01aa31da92ced51a302 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