aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@evo.osdl.org>2005-03-28 04:43:20 -0800
committerLinus Torvalds <torvalds@evo.osdl.org>2005-03-28 04:43:20 -0800
commit5a00e89e1cc9dcea7507aca74eabf5bceb26967f (patch)
tree7242cca7835e740c81d6707b6b00d965f504cf37
parentae55089235bcc2741c3a3466d30c0a7d62208886 (diff)
parentb489072eefdaaf41fb6a25cb940c40d2410bb3f1 (diff)
downloadhistory-5a00e89e1cc9dcea7507aca74eabf5bceb26967f.tar.gz
Merge whitespace and __nocast changes
-rw-r--r--Documentation/cachetlb.txt5
-rw-r--r--Documentation/cdrom/mcd4
-rw-r--r--Documentation/cdrom/mcdx17
-rw-r--r--Documentation/cdrom/packet-writing.txt8
-rw-r--r--Documentation/dvb/README.dibusb92
-rw-r--r--Documentation/dvb/contributors.txt3
-rw-r--r--Documentation/dvb/get_dvb_firmware58
-rw-r--r--Documentation/dvb/readme.txt7
-rw-r--r--Documentation/feature-removal-schedule.txt9
-rw-r--r--Documentation/kernel-parameters.txt10
-rw-r--r--Documentation/power/video.txt31
-rw-r--r--Documentation/spinlocks.txt26
-rw-r--r--arch/alpha/kernel/smp.c43
-rw-r--r--arch/alpha/kernel/srmcons.c27
-rw-r--r--arch/i386/kernel/apic.c2
-rw-r--r--arch/i386/kernel/apm.c21
-rw-r--r--arch/i386/kernel/cpu/mtrr/generic.c30
-rw-r--r--arch/i386/kernel/cpu/mtrr/if.c8
-rw-r--r--arch/i386/kernel/cpu/mtrr/mtrr.h1
-rw-r--r--arch/i386/kernel/cpu/mtrr/state.c4
-rw-r--r--arch/i386/kernel/dmi_scan.c2
-rw-r--r--arch/i386/kernel/io_apic.c2
-rw-r--r--arch/i386/kernel/irq.c5
-rw-r--r--arch/i386/kernel/mpparse.c5
-rw-r--r--arch/i386/kernel/nmi.c4
-rw-r--r--arch/i386/kernel/process.c2
-rw-r--r--arch/i386/kernel/quirks.c2
-rw-r--r--arch/i386/kernel/time.c75
-rw-r--r--arch/i386/kernel/traps.c7
-rw-r--r--arch/i386/mach-es7000/es7000plat.c14
-rw-r--r--arch/i386/math-emu/fpu_entry.c10
-rw-r--r--arch/i386/math-emu/fpu_system.h8
-rw-r--r--arch/i386/math-emu/get_address.c18
-rw-r--r--arch/i386/math-emu/load_store.c6
-rw-r--r--arch/i386/math-emu/reg_ld_str.c48
-rw-r--r--arch/i386/mm/hugetlbpage.c13
-rw-r--r--arch/i386/oprofile/backtrace.c13
-rw-r--r--arch/i386/pci/fixup.c20
-rw-r--r--arch/i386/power/swsusp.S13
-rw-r--r--arch/ia64/hp/common/sba_iommu.c2
-rw-r--r--arch/ia64/kernel/irq.c12
-rw-r--r--arch/ia64/lib/swiotlb.c2
-rw-r--r--arch/ia64/mm/hugetlbpage.c6
-rw-r--r--arch/ia64/mm/init.c3
-rw-r--r--arch/m32r/boot/compressed/Makefile5
-rw-r--r--arch/m32r/boot/compressed/head.S5
-rw-r--r--arch/m32r/boot/compressed/m32r_sio.c7
-rw-r--r--arch/m32r/boot/setup.S5
-rw-r--r--arch/m32r/kernel/entry.S21
-rw-r--r--arch/m32r/kernel/module.c6
-rw-r--r--arch/m32r/kernel/traps.c2
-rw-r--r--arch/m32r/mm/cache.c7
-rw-r--r--arch/m32r/mm/fault-nommu.c1
-rw-r--r--arch/m68k/atari/stram.c2
-rw-r--r--arch/mips/kernel/irixelf.c2
-rw-r--r--arch/mips/lib/Makefile4
-rw-r--r--arch/mips/vr41xx/common/Makefile2
-rw-r--r--arch/mips/vr41xx/common/ksyms.c30
-rw-r--r--arch/mips/vr41xx/common/rtc.c321
-rw-r--r--arch/ppc/8xx_io/cs4218_tdm.c2
-rw-r--r--arch/ppc/Kconfig12
-rw-r--r--arch/ppc/kernel/head_8xx.S2
-rw-r--r--arch/ppc/kernel/pci.c197
-rw-r--r--arch/ppc/kernel/setup.c10
-rw-r--r--arch/ppc/kernel/traps.c2
-rw-r--r--arch/ppc/mm/init.c24
-rw-r--r--arch/ppc/platforms/83xx/Makefile2
-rw-r--r--arch/ppc/platforms/83xx/mpc834x_sys.c5
-rw-r--r--arch/ppc/platforms/85xx/Makefile2
-rw-r--r--arch/ppc/platforms/85xx/mpc85xx_ads_common.c1
-rw-r--r--arch/ppc/platforms/85xx/mpc85xx_cds_common.c1
-rw-r--r--arch/ppc/platforms/85xx/sbc85xx.c1
-rw-r--r--arch/ppc/platforms/85xx/stx_gp3.c1
-rw-r--r--arch/ppc/platforms/chestnut.h4
-rw-r--r--arch/ppc/platforms/chrp_setup.c2
-rw-r--r--arch/ppc/platforms/hdpu.c90
-rw-r--r--arch/ppc/platforms/katana.h2
-rw-r--r--arch/ppc/platforms/pmac_setup.c1
-rw-r--r--arch/ppc/platforms/prep_setup.c2
-rw-r--r--arch/ppc/platforms/sandpoint.c7
-rw-r--r--arch/ppc/syslib/Makefile6
-rw-r--r--arch/ppc/syslib/mpc83xx_devices.c (renamed from arch/ppc/platforms/83xx/mpc83xx_devices.c)0
-rw-r--r--arch/ppc/syslib/mpc83xx_sys.c (renamed from arch/ppc/platforms/83xx/mpc83xx_sys.c)0
-rw-r--r--arch/ppc/syslib/mpc85xx_devices.c (renamed from arch/ppc/platforms/85xx/mpc85xx_devices.c)0
-rw-r--r--arch/ppc/syslib/mpc85xx_sys.c (renamed from arch/ppc/platforms/85xx/mpc85xx_sys.c)0
-rw-r--r--arch/ppc64/kernel/head.S2
-rw-r--r--arch/ppc64/kernel/misc.S4
-rw-r--r--arch/ppc64/kernel/pSeries_hvCall.S186
-rw-r--r--arch/ppc64/kernel/pSeries_iommu.c80
-rw-r--r--arch/ppc64/kernel/pSeries_reconfig.c12
-rw-r--r--arch/ppc64/kernel/pci.c137
-rw-r--r--arch/ppc64/kernel/pci_dn.c22
-rw-r--r--arch/ppc64/kernel/pmac_feature.c31
-rw-r--r--arch/ppc64/kernel/prom.c16
-rw-r--r--arch/ppc64/kernel/sys_ppc32.c4
-rw-r--r--arch/ppc64/kernel/syscalls.c3
-rw-r--r--arch/ppc64/mm/hugetlbpage.c14
-rw-r--r--arch/ppc64/mm/init.c13
-rw-r--r--arch/ppc64/mm/numa.c11
-rw-r--r--arch/s390/kernel/signal.c2
-rw-r--r--arch/s390/mm/fault.c9
-rw-r--r--arch/sh/kernel/cpu/sh4/sq.c2
-rw-r--r--arch/sh/mm/hugetlbpage.c6
-rw-r--r--arch/sh64/mm/hugetlbpage.c6
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c1
-rw-r--r--arch/sparc/mm/generic.c34
-rw-r--r--arch/sparc64/kernel/binfmt_aout32.c2
-rw-r--r--arch/sparc64/kernel/pci.c15
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c6
-rw-r--r--arch/sparc64/mm/generic.c50
-rw-r--r--arch/sparc64/mm/hugetlbpage.c6
-rw-r--r--arch/um/Kconfig3
-rw-r--r--arch/um/Kconfig.debug6
-rw-r--r--arch/um/Makefile-skas10
-rw-r--r--arch/um/Makefile-x86_644
-rw-r--r--arch/um/defconfig43
-rw-r--r--arch/um/drivers/Makefile9
-rw-r--r--arch/um/drivers/net_kern.c2
-rw-r--r--arch/um/drivers/slip_user.c6
-rw-r--r--arch/um/include/choose-mode.h7
-rw-r--r--arch/um/include/sysdep-i386/ptrace.h36
-rw-r--r--arch/um/include/sysdep-i386/sigcontext.h2
-rw-r--r--arch/um/include/sysdep-x86_64/ptrace.h58
-rw-r--r--arch/um/include/sysdep-x86_64/sigcontext.h2
-rw-r--r--arch/um/include/user_util.h2
-rw-r--r--arch/um/kernel/Makefile14
-rw-r--r--arch/um/kernel/gmon_syms.c20
-rw-r--r--arch/um/kernel/skas/Makefile8
-rw-r--r--arch/um/kernel/tt/Makefile18
-rw-r--r--arch/um/kernel/tt/ptproxy/Makefile5
-rw-r--r--arch/um/kernel/um_arch.c34
-rw-r--r--arch/um/kernel/user_util.c15
-rw-r--r--arch/um/os-Linux/Makefile6
-rw-r--r--arch/um/os-Linux/drivers/Makefile8
-rw-r--r--arch/um/os-Linux/sys-i386/Makefile5
-rw-r--r--arch/um/os-Linux/sys-x86_64/Makefile5
-rw-r--r--arch/um/scripts/Makefile.rules13
-rw-r--r--arch/um/sys-i386/Makefile19
-rw-r--r--arch/um/sys-x86_64/Makefile22
-rw-r--r--arch/x86_64/Kconfig36
-rw-r--r--arch/x86_64/defconfig80
-rw-r--r--arch/x86_64/ia32/ia32_aout.c2
-rw-r--r--arch/x86_64/ia32/ia32_signal.c38
-rw-r--r--arch/x86_64/kernel/e820.c16
-rw-r--r--arch/x86_64/kernel/entry.S2
-rw-r--r--arch/x86_64/kernel/head.S112
-rw-r--r--arch/x86_64/kernel/i8259.c6
-rw-r--r--arch/x86_64/kernel/pci-gart.c20
-rw-r--r--arch/x86_64/kernel/setup.c2
-rw-r--r--arch/x86_64/kernel/signal.c37
-rw-r--r--arch/x86_64/kernel/smp.c5
-rw-r--r--arch/x86_64/kernel/smpboot.c5
-rw-r--r--arch/x86_64/kernel/suspend_asm.S15
-rw-r--r--arch/x86_64/kernel/sys_x86_64.c2
-rw-r--r--arch/x86_64/kernel/time.c11
-rw-r--r--arch/x86_64/kernel/trampoline.S22
-rw-r--r--arch/x86_64/kernel/traps.c16
-rw-r--r--arch/x86_64/kernel/vmlinux.lds.S3
-rw-r--r--arch/x86_64/kernel/vsyscall.S169
-rw-r--r--arch/x86_64/kernel/vsyscall.c116
-rw-r--r--arch/x86_64/lib/bitops.c3
-rw-r--r--arch/x86_64/lib/delay.c2
-rw-r--r--arch/x86_64/lib/getuser.S65
-rw-r--r--arch/x86_64/lib/putuser.S77
-rw-r--r--arch/x86_64/mm/ioremap.c8
-rw-r--r--arch/x86_64/pci/k8-bus.c10
-rw-r--r--drivers/acpi/sleep/proc.c5
-rw-r--r--drivers/block/DAC960.c4
-rw-r--r--drivers/block/Kconfig10
-rw-r--r--drivers/block/cciss.c2
-rw-r--r--drivers/block/pktcdvd.c13
-rw-r--r--drivers/cdrom/Kconfig56
-rw-r--r--drivers/cdrom/Makefile1
-rw-r--r--drivers/cdrom/cdu31a.c706
-rw-r--r--drivers/cdrom/mcd.c1565
-rw-r--r--drivers/cdrom/mcd.h106
-rw-r--r--drivers/char/Kconfig8
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/agp/frontend.c4
-rw-r--r--drivers/char/agp/generic.c1
-rw-r--r--drivers/char/drm/drm_vm.c8
-rw-r--r--drivers/char/drm/i810_dma.c2
-rw-r--r--drivers/char/drm/i830_dma.c2
-rw-r--r--drivers/char/generic_serial.c115
-rw-r--r--drivers/char/hpet.c6
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c5
-rw-r--r--drivers/char/isicom.c6
-rw-r--r--drivers/char/mem.c34
-rw-r--r--drivers/char/n_tty.c8
-rw-r--r--drivers/char/specialix.c949
-rw-r--r--drivers/char/specialix_io8.h9
-rw-r--r--drivers/char/stallion.c29
-rw-r--r--drivers/char/tpm/tpm.c2
-rw-r--r--drivers/char/tpm/tpm.h1
-rw-r--r--drivers/char/tty_io.c1
-rw-r--r--drivers/char/vr41xx_rtc.c709
-rw-r--r--drivers/char/vt.c27
-rw-r--r--drivers/infiniband/core/mad.c14
-rw-r--r--drivers/input/serio/hil_mlc.c4
-rw-r--r--drivers/input/serio/hp_sdc.c8
-rw-r--r--drivers/isdn/hisax/elsa.c4
-rw-r--r--drivers/isdn/hisax/hfc_sx.c4
-rw-r--r--drivers/isdn/hisax/sedlbauer.c4
-rw-r--r--drivers/isdn/hisax/teles3.c4
-rw-r--r--drivers/isdn/hisax/w6692.c2
-rw-r--r--drivers/media/common/saa7146_core.c58
-rw-r--r--drivers/media/dvb/b2c2/b2c2-common.c2
-rw-r--r--drivers/media/dvb/b2c2/skystar2.c24
-rw-r--r--drivers/media/dvb/bt8xx/Kconfig4
-rw-r--r--drivers/media/dvb/bt8xx/bt878.c21
-rw-r--r--drivers/media/dvb/bt8xx/dst.c2
-rw-r--r--drivers/media/dvb/bt8xx/dst_priv.h1
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.c72
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.h1
-rw-r--r--drivers/media/dvb/dibusb/Kconfig3
-rw-r--r--drivers/media/dvb/dibusb/Makefile2
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-core.c144
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-dvb.c48
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c96
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-firmware.c4
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-pid.c80
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-remote.c177
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-usb.c150
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb.h44
-rw-r--r--drivers/media/dvb/dibusb/dvb-fe-dtt200u.c263
-rw-r--r--drivers/media/dvb/dvb-core/demux.h4
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c16
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ca_en50221.c14
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c40
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.h5
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c3
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c4
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c13
-rw-r--r--drivers/media/dvb/frontends/Kconfig12
-rw-r--r--drivers/media/dvb/frontends/Makefile1
-rw-r--r--drivers/media/dvb/frontends/at76c651.c2
-rw-r--r--drivers/media/dvb/frontends/cx22700.c2
-rw-r--r--drivers/media/dvb/frontends/cx22702.c2
-rw-r--r--drivers/media/dvb/frontends/cx24110.c2
-rw-r--r--drivers/media/dvb/frontends/dib3000-common.c2
-rw-r--r--drivers/media/dvb/frontends/dib3000-common.h8
-rw-r--r--drivers/media/dvb/frontends/dib3000.h2
-rw-r--r--drivers/media/dvb/frontends/dib3000mb.c79
-rw-r--r--drivers/media/dvb/frontends/dib3000mc.c16
-rw-r--r--drivers/media/dvb/frontends/dib3000mc_priv.h2
-rw-r--r--drivers/media/dvb/frontends/dvb_dummy_fe.c2
-rw-r--r--drivers/media/dvb/frontends/l64781.c7
-rw-r--r--drivers/media/dvb/frontends/l64781.h5
-rw-r--r--drivers/media/dvb/frontends/mt312.c3
-rw-r--r--drivers/media/dvb/frontends/mt352.c103
-rw-r--r--drivers/media/dvb/frontends/nxt2002.c48
-rw-r--r--drivers/media/dvb/frontends/nxt6000.c2
-rw-r--r--drivers/media/dvb/frontends/or51132.c6
-rw-r--r--drivers/media/dvb/frontends/or51211.c631
-rw-r--r--drivers/media/dvb/frontends/or51211.h44
-rw-r--r--drivers/media/dvb/frontends/sp8870.c2
-rw-r--r--drivers/media/dvb/frontends/sp887x.c2
-rw-r--r--drivers/media/dvb/frontends/stv0297.c3
-rw-r--r--drivers/media/dvb/frontends/stv0299.c2
-rw-r--r--drivers/media/dvb/frontends/tda10021.c6
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c8
-rw-r--r--drivers/media/dvb/frontends/tda8083.c2
-rw-r--r--drivers/media/dvb/frontends/tda80xx.c2
-rw-r--r--drivers/media/dvb/frontends/ves1820.c2
-rw-r--r--drivers/media/dvb/frontends/ves1x93.c14
-rw-r--r--drivers/media/dvb/ttpci/Kconfig1
-rw-r--r--drivers/media/dvb/ttpci/av7110.c256
-rw-r--r--drivers/media/dvb/ttpci/av7110.h3
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.c25
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.h2
-rw-r--r--drivers/media/dvb/ttpci/av7110_ca.c20
-rw-r--r--drivers/media/dvb/ttpci/av7110_ca.h2
-rw-r--r--drivers/media/dvb/ttpci/av7110_ipack.c1
-rw-r--r--drivers/media/dvb/ttpci/av7110_ir.c8
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c17
-rw-r--r--drivers/media/dvb/ttpci/budget-core.c5
-rw-r--r--drivers/media/dvb/ttpci/budget-patch.c2
-rw-r--r--drivers/media/dvb/ttpci/budget.c16
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c193
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusb_dec.c170
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusbdecfe.c4
-rw-r--r--drivers/media/video/bt819.c3
-rw-r--r--drivers/media/video/msp3400.c8
-rw-r--r--drivers/media/video/tvaudio.c1
-rw-r--r--drivers/net/Kconfig8
-rw-r--r--drivers/net/eepro100.c4
-rw-r--r--drivers/parport/parport_pc.c16
-rw-r--r--drivers/parport/parport_serial.c92
-rw-r--r--drivers/pci/pci.ids17
-rw-r--r--drivers/pci/quirks.c34
-rw-r--r--drivers/pcmcia/au1000_generic.c7
-rw-r--r--drivers/pcmcia/cs.c9
-rw-r--r--drivers/pcmcia/ds.c51
-rw-r--r--drivers/pcmcia/hd64465_ss.c15
-rw-r--r--drivers/pcmcia/i82092.c10
-rw-r--r--drivers/pcmcia/i82092aa.h1
-rw-r--r--drivers/pcmcia/i82365.c6
-rw-r--r--drivers/pcmcia/m32r_cfc.c7
-rw-r--r--drivers/pcmcia/m32r_pcc.c6
-rw-r--r--drivers/pcmcia/pd6729.c6
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c8
-rw-r--r--drivers/pcmcia/soc_common.c7
-rw-r--r--drivers/pcmcia/tcic.c6
-rw-r--r--drivers/pcmcia/vrc4171_card.c6
-rw-r--r--drivers/pcmcia/vrc4173_cardu.c6
-rw-r--r--drivers/pcmcia/yenta_socket.c2
-rw-r--r--drivers/pnp/pnpbios/core.c6
-rw-r--r--drivers/pnp/resource.c7
-rw-r--r--drivers/s390/block/dasd.c21
-rw-r--r--drivers/s390/block/dasd_eckd.c95
-rw-r--r--drivers/s390/block/dasd_eckd.h8
-rw-r--r--drivers/s390/block/dasd_erp.c3
-rw-r--r--drivers/s390/cio/chsc.c109
-rw-r--r--drivers/s390/cio/chsc.h14
-rw-r--r--drivers/s390/cio/device_ops.c33
-rw-r--r--drivers/s390/net/Kconfig9
-rw-r--r--drivers/s390/net/Makefile2
-rw-r--r--drivers/s390/net/claw.c4447
-rw-r--r--drivers/s390/net/claw.h335
-rw-r--r--drivers/s390/net/qeth.h105
-rw-r--r--drivers/s390/net/qeth_eddp.c643
-rw-r--r--drivers/s390/net/qeth_eddp.h85
-rw-r--r--drivers/s390/net/qeth_main.c644
-rw-r--r--drivers/s390/net/qeth_mpc.h5
-rw-r--r--drivers/s390/net/qeth_proc.c11
-rw-r--r--drivers/s390/net/qeth_sys.c186
-rw-r--r--drivers/s390/net/qeth_tso.c285
-rw-r--r--drivers/s390/net/qeth_tso.h58
-rw-r--r--drivers/s390/scsi/zfcp_aux.c2
-rw-r--r--drivers/sbus/char/flash.c2
-rw-r--r--drivers/sbus/char/vfc_dev.c6
-rw-r--r--drivers/serial/8250_pci.c21
-rw-r--r--drivers/serial/Kconfig15
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/au1x00_uart.c2
-rw-r--r--drivers/serial/ioc4_serial.c2
-rw-r--r--drivers/serial/jsm/Makefile8
-rw-r--r--drivers/serial/jsm/jsm.h437
-rw-r--r--drivers/serial/jsm/jsm_driver.c404
-rw-r--r--drivers/serial/jsm/jsm_neo.c1427
-rw-r--r--drivers/serial/jsm/jsm_tty.c1043
-rw-r--r--drivers/serial/m32r_sio.c156
-rw-r--r--drivers/serial/m32r_sio.h1
-rw-r--r--drivers/serial/m32r_sio_reg.h190
-rw-r--r--drivers/telephony/ixj.c2
-rw-r--r--drivers/usb/gadget/ether.c2
-rw-r--r--drivers/usb/media/pwc/pwc-if.c2
-rw-r--r--drivers/usb/serial/io_edgeport.c2
-rw-r--r--drivers/video/acornfb.c2
-rw-r--r--drivers/video/au1100fb.c2
-rw-r--r--drivers/video/controlfb.c2
-rw-r--r--drivers/video/fbmem.c10
-rw-r--r--drivers/video/sa1100fb.c2
-rw-r--r--drivers/video/sbuslib.c8
-rw-r--r--fs/Kconfig1
-rw-r--r--fs/afs/kafsasyncd.c2
-rw-r--r--fs/afs/kafstimod.c2
-rw-r--r--fs/attr.c7
-rw-r--r--fs/bad_inode.c14
-rw-r--r--fs/binfmt_aout.c2
-rw-r--r--fs/binfmt_elf.c2
-rw-r--r--fs/binfmt_elf_fdpic.c2
-rw-r--r--fs/binfmt_flat.c2
-rw-r--r--fs/binfmt_som.c2
-rw-r--r--fs/cifs/cifsfs.c2
-rw-r--r--fs/dcache.c1
-rw-r--r--fs/dquot.c12
-rw-r--r--fs/exec.c2
-rw-r--r--fs/ext2/super.c10
-rw-r--r--fs/ext3/inode.c83
-rw-r--r--fs/ext3/super.c29
-rw-r--r--fs/fat/inode.c3
-rw-r--r--fs/hfs/bnode.c12
-rw-r--r--fs/hfs/extent.c31
-rw-r--r--fs/hfs/inode.c22
-rw-r--r--fs/hfs/super.c152
-rw-r--r--fs/hfsplus/bnode.c12
-rw-r--r--fs/hfsplus/catalog.c39
-rw-r--r--fs/hfsplus/dir.c8
-rw-r--r--fs/hfsplus/hfsplus_fs.h12
-rw-r--r--fs/hfsplus/inode.c8
-rw-r--r--fs/hfsplus/options.c151
-rw-r--r--fs/hfsplus/super.c31
-rw-r--r--fs/hfsplus/tables.c2839
-rw-r--r--fs/hfsplus/unicode.c219
-rw-r--r--fs/hostfs/Makefile10
-rw-r--r--fs/hpfs/hpfs.h12
-rw-r--r--fs/hpfs/hpfs_fn.h4
-rw-r--r--fs/hppfs/Makefile10
-rw-r--r--fs/jbd/commit.c2
-rw-r--r--fs/jbd/journal.c1
-rw-r--r--fs/jbd/transaction.c33
-rw-r--r--fs/lockd/clntproc.c1
-rw-r--r--fs/lockd/svclock.c1
-rw-r--r--fs/mbcache.c2
-rw-r--r--fs/mpage.c12
-rw-r--r--fs/msdos/namei.c7
-rw-r--r--fs/pipe.c18
-rw-r--r--fs/proc/array.c2
-rw-r--r--fs/proc/task_mmu.c8
-rw-r--r--include/asm-alpha/pci.h6
-rw-r--r--include/asm-alpha/pgtable.h7
-rw-r--r--include/asm-alpha/spinlock.h99
-rw-r--r--include/asm-arm/pgtable.h7
-rw-r--r--include/asm-arm/tlb.h4
-rw-r--r--include/asm-arm26/pgtable.h7
-rw-r--r--include/asm-arm26/tlb.h4
-rw-r--r--include/asm-cris/pgalloc.h1
-rw-r--r--include/asm-frv/pgtable.h7
-rw-r--r--include/asm-generic/cputime.h2
-rw-r--r--include/asm-generic/pgtable.h4
-rw-r--r--include/asm-generic/tlb.h4
-rw-r--r--include/asm-h8300/pgtable.h7
-rw-r--r--include/asm-i386/hardirq.h7
-rw-r--r--include/asm-i386/msr.h15
-rw-r--r--include/asm-i386/pgalloc.h1
-rw-r--r--include/asm-i386/pgtable.h7
-rw-r--r--include/asm-i386/uaccess.h17
-rw-r--r--include/asm-ia64/page.h2
-rw-r--r--include/asm-ia64/pgalloc.h1
-rw-r--r--include/asm-ia64/pgtable.h12
-rw-r--r--include/asm-ia64/tlb.h4
-rw-r--r--include/asm-m32r/mmu.h18
-rw-r--r--include/asm-m32r/pgalloc.h1
-rw-r--r--include/asm-m32r/pgtable.h7
-rw-r--r--include/asm-m32r/serial.h138
-rw-r--r--include/asm-m68k/pgtable.h7
-rw-r--r--include/asm-m68knommu/pgtable.h7
-rw-r--r--include/asm-mips/pgtable.h18
-rw-r--r--include/asm-parisc/pgalloc.h1
-rw-r--r--include/asm-parisc/pgtable.h7
-rw-r--r--include/asm-ppc/machdep.h8
-rw-r--r--include/asm-ppc/mpc10x.h4
-rw-r--r--include/asm-ppc/mv64x60_defs.h2
-rw-r--r--include/asm-ppc/page.h2
-rw-r--r--include/asm-ppc/pci.h6
-rw-r--r--include/asm-ppc/pgtable.h21
-rw-r--r--include/asm-ppc64/hvcall.h14
-rw-r--r--include/asm-ppc64/machdep.h7
-rw-r--r--include/asm-ppc64/paca.h3
-rw-r--r--include/asm-ppc64/page.h8
-rw-r--r--include/asm-ppc64/pci.h7
-rw-r--r--include/asm-ppc64/pgalloc.h3
-rw-r--r--include/asm-ppc64/pgtable.h12
-rw-r--r--include/asm-s390/ccwdev.h3
-rw-r--r--include/asm-s390/cputime.h8
-rw-r--r--include/asm-s390/pgalloc.h1
-rw-r--r--include/asm-sh/pgalloc.h1
-rw-r--r--include/asm-sh/pgtable.h7
-rw-r--r--include/asm-sh64/pgalloc.h1
-rw-r--r--include/asm-sh64/pgtable.h8
-rw-r--r--include/asm-sparc/pgtable.h14
-rw-r--r--include/asm-sparc64/pgalloc.h2
-rw-r--r--include/asm-sparc64/pgtable.h12
-rw-r--r--include/asm-sparc64/tlb.h4
-rw-r--r--include/asm-um/archparam-i386.h2
-rw-r--r--include/asm-um/processor-generic.h2
-rw-r--r--include/asm-um/processor-i386.h8
-rw-r--r--include/asm-um/processor-x86_64.h8
-rw-r--r--include/asm-um/setup.h5
-rw-r--r--include/asm-um/signal.h3
-rw-r--r--include/asm-x86_64/io.h4
-rw-r--r--include/asm-x86_64/mmu_context.h10
-rw-r--r--include/asm-x86_64/mpspec.h2
-rw-r--r--include/asm-x86_64/msr.h8
-rw-r--r--include/asm-x86_64/page.h4
-rw-r--r--include/asm-x86_64/pgalloc.h6
-rw-r--r--include/asm-x86_64/pgtable.h7
-rw-r--r--include/asm-x86_64/segment.h7
-rw-r--r--include/asm-x86_64/uaccess.h29
-rw-r--r--include/linux/console.h8
-rw-r--r--include/linux/cpuset.h2
-rw-r--r--include/linux/debugfs.h2
-rw-r--r--include/linux/ext3_fs.h1
-rw-r--r--include/linux/generic_serial.h4
-rw-r--r--include/linux/hugetlb.h4
-rw-r--r--include/linux/jbd.h1
-rw-r--r--include/linux/kernel.h17
-rw-r--r--include/linux/mpage.h3
-rw-r--r--include/linux/pci_ids.h10
-rw-r--r--include/linux/sched.h14
-rw-r--r--include/linux/serial_core.h6
-rw-r--r--include/linux/suspend.h2
-rw-r--r--init/Kconfig10
-rw-r--r--init/main.c4
-rw-r--r--kernel/acct.c2
-rw-r--r--kernel/cpuset.c34
-rw-r--r--kernel/fork.c6
-rw-r--r--kernel/futex.c89
-rw-r--r--kernel/irq/proc.c10
-rw-r--r--kernel/kprobes.c5
-rw-r--r--kernel/posix-cpu-timers.c106
-rw-r--r--kernel/posix-timers.c12
-rw-r--r--kernel/power/main.c8
-rw-r--r--kernel/power/swsusp.c23
-rw-r--r--kernel/printk.c5
-rw-r--r--kernel/sched.c5
-rw-r--r--kernel/signal.c2
-rw-r--r--kernel/spinlock.c2
-rw-r--r--kernel/stop_machine.c7
-rw-r--r--kernel/sys_ni.c1
-rw-r--r--kernel/time.c11
-rw-r--r--lib/Kconfig.debug2
-rw-r--r--mm/filemap.c15
-rw-r--r--mm/fremap.c4
-rw-r--r--mm/memory.c28
-rw-r--r--mm/mempolicy.c6
-rw-r--r--mm/mmap.c12
-rw-r--r--mm/mprotect.c11
-rw-r--r--mm/nommu.c6
-rw-r--r--mm/rmap.c14
-rw-r--r--mm/slab.c117
-rw-r--r--mm/swapfile.c2
-rw-r--r--mm/vmscan.c110
-rw-r--r--net/rxrpc/krxiod.c2
-rw-r--r--net/rxrpc/krxsecd.c2
-rw-r--r--net/rxrpc/krxtimod.c2
-rw-r--r--net/sunrpc/svcsock.c1
-rw-r--r--scripts/checkstack.pl4
-rw-r--r--scripts/kconfig/gconf.c69
-rw-r--r--scripts/kconfig/gconf.glade40
-rw-r--r--security/selinux/avc.c174
-rw-r--r--security/selinux/hooks.c102
-rw-r--r--security/selinux/include/av_perm_to_string.h1
-rw-r--r--security/selinux/include/av_permissions.h1
-rw-r--r--security/selinux/include/avc.h7
-rw-r--r--security/selinux/include/avc_ss.h13
-rw-r--r--security/selinux/include/objsec.h2
-rw-r--r--security/selinux/selinuxfs.c4
-rw-r--r--security/selinux/ss/avtab.c29
-rw-r--r--security/selinux/ss/avtab.h6
-rw-r--r--security/selinux/ss/conditional.c2
-rw-r--r--security/selinux/ss/ebitmap.c43
-rw-r--r--security/selinux/ss/ebitmap.h1
-rw-r--r--security/selinux/ss/hashtab.c113
-rw-r--r--security/selinux/ss/hashtab.h38
-rw-r--r--security/selinux/ss/policydb.c10
-rw-r--r--security/selinux/ss/policydb.h3
-rw-r--r--security/selinux/ss/services.c18
-rw-r--r--security/selinux/ss/services.h6
-rw-r--r--security/selinux/ss/sidtab.c36
-rw-r--r--sound/core/pcm_native.c4
-rw-r--r--sound/oss/dmasound/dmasound_awacs.c9
543 files changed, 20797 insertions, 7328 deletions
diff --git a/Documentation/cachetlb.txt b/Documentation/cachetlb.txt
index b8faf93d38268..e132fb1163b07 100644
--- a/Documentation/cachetlb.txt
+++ b/Documentation/cachetlb.txt
@@ -142,6 +142,11 @@ changes occur:
The ia64 sn2 platform is one example of a platform
that uses this interface.
+8) void lazy_mmu_prot_update(pte_t pte)
+ This interface is called whenever the protection on
+ any user PTEs change. This interface provides a notification
+ to architecture specific code to take appropiate action.
+
Next, we have the cache flushing interfaces. In general, when Linux
is changing an existing virtual-->physical mapping to a new value,
diff --git a/Documentation/cdrom/mcd b/Documentation/cdrom/mcd
deleted file mode 100644
index 39537f9f0b085..0000000000000
--- a/Documentation/cdrom/mcd
+++ /dev/null
@@ -1,4 +0,0 @@
-This driver does not support XA or MultiSession CDs (PhotoCDs). Use the
-experimental driver mcdx.c for that.
-
-You can use mcd for one interface, and mcdx for another.
diff --git a/Documentation/cdrom/mcdx b/Documentation/cdrom/mcdx
index 4ea89e32373e7..2bac4b7ff6da8 100644
--- a/Documentation/cdrom/mcdx
+++ b/Documentation/cdrom/mcdx
@@ -1,16 +1,3 @@
-This is a first attempt to create an `improved' driver for the Mitsumi drives.
-It is able to "live together" with mcd.c, if you have at least two Mitsumi
-drives: each driver can use its own drive.
-
-To allow this "coexistence" as long as mcdx.c is not a superset of mcd.c,
-this driver has to use its own device files. We use MAJOR 20 for it. So,
-you have to do
-
- # mknod /dev/mcdx0 b 20 0
- # mknod /dev/mcdx1 b 20 1
-
-and so on, one entry for each drive to support, once.
-
If you are using the driver as a module, you can specify your ports and IRQs
like
@@ -25,9 +12,7 @@ This driver:
ordinary CDs;
o supports up to 5 drives (of course, you'll need free
IRQs, i/o ports and slots);
- o uses much less kernel memory than the standard mcd driver
- (no extra driver internal buffers!).
- o plays audio (like the `old' driver, I hope)
+ o plays audio
This version doesn't support yet:
diff --git a/Documentation/cdrom/packet-writing.txt b/Documentation/cdrom/packet-writing.txt
index b402e4c949dab..3d44c561fe6d9 100644
--- a/Documentation/cdrom/packet-writing.txt
+++ b/Documentation/cdrom/packet-writing.txt
@@ -62,6 +62,14 @@ generates aligned writes.
# mount /dev/pktcdvd/dev_name /cdrom -t udf -o rw,noatime
+Packet writing for DVD-RAM media
+--------------------------------
+
+DVD-RAM discs are random writable, so using the pktcdvd driver is not
+necessary. However, using the pktcdvd driver can improve performance
+in the same way it does for DVD+RW media.
+
+
Notes
-----
diff --git a/Documentation/dvb/README.dibusb b/Documentation/dvb/README.dibusb
index be4b5e2770c8c..7a9e958513f30 100644
--- a/Documentation/dvb/README.dibusb
+++ b/Documentation/dvb/README.dibusb
@@ -1,7 +1,7 @@
-Documentation for dib3000mb frontend driver and dibusb device driver
+Documentation for dib3000* frontend drivers and dibusb device driver
====================================================================
-Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de),
+Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de),
dibusb and dib3000mb/mc drivers based on GPL code, which has
@@ -46,7 +46,7 @@ Produced and reselled by KWorld:
Others:
-------
-- Ultima Electronic/Artec T1 USB TVBOX (AN2135, AN2235, AN2235 with Panasonic Tuner)
+- Ultima Electronic/Artec T1 USB TVBOX (AN2135, AN2235, AN2235 with Panasonic Tuner)
http://82.161.246.249/products-tvbox.html
- Compro Videomate DVB-U2000 - DVB-T USB (2)
@@ -74,19 +74,27 @@ Supported devices USB2.0
- Artec T1 USB TVBOX (FX2) (2)
+- Hauppauge WinTV NOVA-T USB2
+ http://www.hauppauge.com/
+
+- KWorld/ADSTech Instant DVB-T USB2.0 (DiB3000M-B)
+
- DiBcom USB2.0 DVB-T reference device (non-public)
1) It is working almost.
-2) No test reports received yet.
+2) No test reports received yet.
0. NEWS:
- 2004-01-13 - moved the mirrored pid_filter_table back to dvb-dibusb
+ 2005-02-11 - added support for the KWorld/ADSTech Instant DVB-T USB2.0. Thanks a lot to Joachim von Caron
+ 2005-02-02 - added support for the Hauppauge Win-TV Nova-T USB2
+ 2005-01-31 - distorted streaming is finally gone for USB1.1 devices
+ 2005-01-13 - moved the mirrored pid_filter_table back to dvb-dibusb
- first almost working version for HanfTek UMT-010
- - found out, that Yakumo/HAMA/Typhoon are predessors of the HanfTek
- 2004-01-10 - refactoring completed, now everything is very delightful
+ - found out, that Yakumo/HAMA/Typhoon are predessors of the HanfTek UMT-010
+ 2005-01-10 - refactoring completed, now everything is very delightful
- tuner quirks for some weird devices (Artec T1 AN2235 device has sometimes a
- Panasonic Tuner assembled). Tunerprobing implemented. Thanks a lot to Gunnar Wittich.
+ Panasonic Tuner assembled). Tunerprobing implemented. Thanks a lot to Gunnar Wittich.
2004-12-29 - after several days of struggling around bug of no returning URBs fixed.
2004-12-26 - refactored the dibusb-driver, splitted into separate files
- i2c-probing enabled
@@ -106,7 +114,7 @@ Supported devices USB2.0
2004-09-28 - added support for a new device (Unkown, vendor ID is Hyper-Paltek)
2004-09-20 - added support for a new device (Compro DVB-U2000), thanks
to Amaury Demol for reporting
- - changed usb TS transfer method (several urbs, stopping transfer
+ - changed usb TS transfer method (several urbs, stopping transfer
before setting a new pid)
2004-09-13 - added support for a new device (Artec T1 USB TVBOX), thanks
to Christian Motschke for reporting
@@ -149,13 +157,20 @@ You can either use "get_dvb_firmware dibusb" to download the firmware or you
can get it directly via
for USB1.1 (AN2135)
-http://linuxtv.org/cgi-bin/cvsweb.cgi/dvb-kernel/firmware/dvb-dibusb-5.0.0.11.fw?rev=1.1&content-type=text/plain
+http://www.linuxtv.org/downloads/firmware/dvb-dibusb-5.0.0.11.fw
for USB1.1 (AN2235) (a few Artec T1 devices)
-http://linuxtv.org/cgi-bin/cvsweb.cgi/dvb-kernel/firmware/dvb-dibusb-an2235-1.fw?rev=1.1&content-type=text/plain
+http://www.linuxtv.org/downloads/firmware/dvb-dibusb-an2235-1.fw
+
+for USB2.0 (FX2) Hauppauge, DiBcom
+http://www.linuxtv.org/downloads/firmware/dvb-dibusb-6.0.0.5.fw
+
+for USB2.0 ADSTech/Kworld USB2.0
+http://www.linuxtv.org/downloads/firmware/dvb-dibusb-adstech-usb2-1.fw
+
+for USB2.0 HanfTek
+http://www.linuxtv.org/downloads/firmware/dvb-dibusb-an2235-1.fw
-for USB2.0 (FX2)
-http://linuxtv.org/cgi-bin/cvsweb.cgi/dvb-kernel/firmware/dvb-dibusb-6.0.0.5.fw?rev=1.1&content-type=text/plain
1.2. Compiling
@@ -191,13 +206,13 @@ turned on.
At this point you should be able to start a dvb-capable application. For myself
I used mplayer, dvbscan, tzap and kaxtv, they are working. Using the device
-in vdr (at least the USB2.0 one) is working.
+in vdr is working now also.
2. Known problems and bugs
-- none this time
+- Don't remove the USB device while running an DVB application, your system will die.
-2.1. Adding support for devices
+2.1. Adding support for devices
It is not possible to determine the range of devices based on the DiBcom
reference designs. This is because the reference design of DiBcom can be sold
@@ -213,56 +228,51 @@ of the device. I will add it to this list in order to make this clear to
others.
If you are familar with C you can also add the VID and PID of the device to
-the dvb-dibusb.h-file and create a patch and send it over to me or to
+the dvb-dibusb-core.c-file and create a patch and send it over to me or to
the linux-dvb mailing list, _after_ you have tried compiling and modprobing
it.
2.2. USB1.1 Bandwidth limitation
-Most of the current supported devices are USB1.1 and thus they have a
+Most of the currently supported devices are USB1.1 and thus they have a
maximum bandwidth of about 5-6 MBit/s when connected to a USB2.0 hub.
This is not enough for receiving the complete transport stream of a
DVB-T channel (which can be about 16 MBit/s). Normally this is not a
problem, if you only want to watch TV (this does not apply for HDTV),
-but watching a channel while recording another channel on the same
-frequency simply does not work. This applies to all USB1.1 DVB-T
-devices, not only dibusb)
-
-A special problem of the dibusb for the USB1.1 is, that the USB control
-IC has a problem with write accesses while having MPEG2-streaming
-enabled. When you set another pid while receiving MPEG2-TS it happens, that
-the stream is disturbed and probably data is lost (results in distortions of
-the video or strange beeps within the audio stream). DiBcom is preparing a
-firmware especially for Linux which perhaps solves the problem.
-
-Especially VDR users are victoms of this bug. VDR frequently requests new PIDs
-due the automatic scanning (introduced in 1.3.x, afaik) and epg-scan. Disabling
-these features is maybe a solution. Additionally this behaviour of VDR exceeds
-the USB1.1 bandwidth.
-
-Update:
-For the USB1.1 and VDR some work has been done (patches and comments are still
-very welcome). Maybe the problem is solved in the meantime because I now use
-the dmx_sw_filter function instead of dmx_sw_filter_packet. I hope the
+but watching a channel while recording another channel on the same
+frequency simply does not work very well. This applies to all USB1.1
+DVB-T devices, not just dibusb)
+
+Update: For the USB1.1 and VDR some work has been done (patches and comments
+are still very welcome). Maybe the problem is solved in the meantime because I
+now use the dmx_sw_filter function instead of dmx_sw_filter_packet. I hope the
linux-dvb software filter is able to get the best of the garbled TS.
+The bug, where the TS is distorted by a heavy usage of the device is gone
+definitely. All dibusb-devices I was using (Twinhan, Kworld, DiBcom) are
+working like charm now with VDR. Sometimes I even was able to record a channel
+and watch another one.
+
2.3. Comments
-Patches, comments and suggestions are very very welcome
+Patches, comments and suggestions are very very welcome.
3. Acknowledgements
Amaury Demol (ademol@dibcom.fr) and Francois Kanounnikoff from DiBcom for
- providing specs, code and help, on which the dvb-dibusb, dib3000mb and
+ providing specs, code and help, on which the dvb-dibusb, dib3000mb and
dib3000mc are based.
David Matthews for identifying a new device type (Artec T1 with AN2235)
and for extending dibusb with remote control event handling. Thank you.
Alex Woods for frequently answering question about usb and dvb
- stuff, a big thank you
+ stuff, a big thank you.
Bernd Wagner for helping with huge bug reports and discussions.
+ Gunnar Wittich and Joachim von Caron for their trust for giving me
+ root-shells on their machines to implement support for new devices.
+
Some guys on the linux-dvb mailing list for encouraging me
Peter Schildmann >peter.schildmann-nospam-at-web.de< for his
diff --git a/Documentation/dvb/contributors.txt b/Documentation/dvb/contributors.txt
index dd40ad665c502..c9d5ce3707012 100644
--- a/Documentation/dvb/contributors.txt
+++ b/Documentation/dvb/contributors.txt
@@ -72,5 +72,8 @@ Kenneth Aafløy <ke-aa@frisurf.no>
Ernst Peinlich <e.peinlich@inode.at>
for tuning/DiSEqC support for the DEC 3000-s
+Peter Beutner <p.beutner@gmx.net>
+ for the IR code for the ttusb-dec driver
+
(If you think you should be in this list, but you are not, drop a
line to the DVB mailing list)
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index 22d410e6e6401..3ffdcb394299f 100644
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -22,14 +22,15 @@ use File::Temp qw/ tempdir /;
use IO::Handle;
@components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t",
- "dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002" );
+ "dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002",
+ "or51211", "or51132_qam", "or51132_vsb");
# Check args
syntax() if (scalar(@ARGV) != 1);
$cid = $ARGV[0];
# Do it!
-for($i=0; $i < scalar(@components); $i++) {
+for ($i=0; $i < scalar(@components); $i++) {
if ($cid eq $components[$i]) {
$outfile = eval($cid);
die $@ if $@;
@@ -79,8 +80,8 @@ sub sp887x {
wgetfile($sourcefile, $url);
unzip($sourcefile, $tmpdir);
unshield("$tmpdir/$cabfile", $tmpdir);
- verify("$tmpdir/sc_main.mc", $hash);
- copy("$tmpdir/sc_main.mc", $outfile);
+ verify("$tmpdir/ZEnglish/sc_main.mc", $hash);
+ copy("$tmpdir/ZEnglish/sc_main.mc", $outfile);
$outfile;
}
@@ -122,9 +123,9 @@ sub tda10046 {
}
sub av7110 {
- my $sourcefile = "dvb-ttpci-01.fw-261c";
- my $url = "http://www.linuxtv.org/download/dvb/firmware/$sourcefile";
- my $hash = "7b263de6b0b92d2347319c65adc7d4fb";
+ my $sourcefile = "dvb-ttpci-01.fw-261d";
+ my $url = "http://www.linuxtv.org/downloads/firmware/$sourcefile";
+ my $hash = "603431b6259715a8e88f376a53b64e2f";
my $outfile = "dvb-ttpci-01.fw";
checkstandard();
@@ -222,7 +223,7 @@ sub vp7041 {
}
sub dibusb {
- my $url = "http://linuxtv.org/cgi-bin/cvsweb.cgi/dvb-kernel/firmware/dvb-dibusb-5.0.0.11.fw?rev=1.1&content-type=text/plain";
+ my $url = "http://www.linuxtv.org/downloads/firmware/dvb-dibusb-5.0.0.11.fw";
my $outfile = "dvb-dibusb-5.0.0.11.fw";
my $hash = "fa490295a527360ca16dcdf3224ca243";
@@ -251,6 +252,45 @@ sub nxt2002 {
$outfile;
}
+sub or51211 {
+ my $fwfile = "dvb-fe-or51211.fw";
+ my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
+ my $hash = "d830949c771a289505bf9eafc225d491";
+
+ checkstandard();
+
+ wgetfile($fwfile, $url);
+ verify($fwfile, $hash);
+
+ $fwfile;
+}
+
+sub or51132_qam {
+ my $fwfile = "dvb-fe-or51132-qam.fw";
+ my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
+ my $hash = "7702e8938612de46ccadfe9b413cb3b5";
+
+ checkstandard();
+
+ wgetfile($fwfile, $url);
+ verify($fwfile, $hash);
+
+ $fwfile;
+}
+
+sub or51132_vsb {
+ my $fwfile = "dvb-fe-or51132-vsb.fw";
+ my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
+ my $hash = "c16208e02f36fc439a557ad4c613364a";
+
+ checkstandard();
+
+ wgetfile($fwfile, $url);
+ verify($fwfile, $hash);
+
+ $fwfile;
+}
+
# ---------------------------------------------------------------
# Utilities
@@ -292,7 +332,7 @@ sub unzip {
sub unshield {
my ($sourcefile, $todir) = @_;
- system("unshield -d \"$todir\" \"$sourcefile\" > /dev/null" ) and die ("unshield failed - unable to extract firmware");
+ system("unshield x -d \"$todir\" \"$sourcefile\" > /dev/null" ) and die ("unshield failed - unable to extract firmware");
}
sub verify {
diff --git a/Documentation/dvb/readme.txt b/Documentation/dvb/readme.txt
index a60c27d43b79a..754c98c6ad942 100644
--- a/Documentation/dvb/readme.txt
+++ b/Documentation/dvb/readme.txt
@@ -5,8 +5,9 @@ The main development site and CVS repository for these
drivers is http://linuxtv.org/.
The developer mailing list linux-dvb is also hosted there,
-see http://linuxtv.org/mailinglists.xml. Please check
-the archive http://linuxtv.org/mailinglists/linux-dvb/
+see http://linuxtv.org/lists.php. Please check
+the archive http://linuxtv.org/pipermail/linux-dvb/
+and the Wiki http://linuxtv.org/wiki/
before asking newbie questions on the list.
API documentation, utilities and test/example programs
@@ -15,7 +16,7 @@ are available as part of the old driver package for Linux 2.4
We plan to split this into separate packages, but it's not
been done yet.
-http://linuxtv.org/download/dvb/
+http://linuxtv.org/downloads/
What's inside this directory:
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index c56a8947986d9..2ea080c958bbd 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -37,3 +37,12 @@ When: May 2005
Why: Noone uses it, and it probably does not work, anyway. swsusp is
faster, more reliable, and people are actually using it.
Who: Pavel Machek <pavel@suse.cz>
+
+---------------------------
+
+What: io_remap_page_range() (macro or function)
+When: September 2005
+Why: Replaced by io_remap_pfn_range() which allows more memory space
+ addressabilty (by using a pfn) and supports sparc & sparc64
+ iospace as part of the pfn.
+Who: Randy Dunlap <rddunlap@osdl.org>
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 96b2234e17edc..4924d387a6573 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -80,6 +80,9 @@ restrictions referred to are that the relevant option is valid if:
VT Virtual terminal support is enabled.
WDT Watchdog support is enabled.
XT IBM PC/XT MFM hard disk support is enabled.
+ X86-64 X86-64 architecture is enabled.
+ More X86-64 boot options can be found in
+ Documentation/x86_64/boot-options.txt .
In addition, the following text indicates that the option:
@@ -403,7 +406,7 @@ running once the system is up.
dtc3181e= [HW,SCSI]
- earlyprintk= [x86, x86_64]
+ earlyprintk= [IA-32, X86-64]
earlyprintk=vga
earlyprintk=serial[,ttySn[,baudrate]]
@@ -635,6 +638,9 @@ running once the system is up.
keepinitrd [HW,ARM]
+ kstack=N [IA-32, X86-64] Print N words from the kernel stack
+ in oops dumps.
+
l2cr= [PPC]
lapic [IA-32,APIC] Enable the local APIC even if BIOS disabled it.
@@ -864,7 +870,7 @@ running once the system is up.
noexec [IA-64]
- noexec [i386, x86_64]
+ noexec [IA-32, X86-64]
noexec=on: enable non-executable mappings (default)
noexec=off: disable nn-executable mappings
diff --git a/Documentation/power/video.txt b/Documentation/power/video.txt
index eefd9355cc981..8686968416ca1 100644
--- a/Documentation/power/video.txt
+++ b/Documentation/power/video.txt
@@ -32,7 +32,7 @@ There are a few types of systems where video works after S3 resume:
acpi_sleep=s3_bios,s3_mode is needed.
(5) radeon systems, where X can soft-boot your video card. You'll need
- patched X, and plain text console (no vesafb or radeonfb), see
+ new enough X, and plain text console (no vesafb or radeonfb), see
http://www.doesi.gmxhome.de/linux/tm800s3/s3.html. Actually you
should probably use vbetool (6) instead.
@@ -64,11 +64,14 @@ Model hack (or "how to do it")
------------------------------------------------------------------------------
Acer Aspire 1406LC ole's late BIOS init (7), turn off DRI
Acer TM 242FX vbetool (6)
+Acer TM C300 vga=normal (only suspend on console, not in X), vbetool (6)
Acer TM 4052LCi s3_bios (2)
Acer TM 636Lci s3_bios vga=normal (2)
Acer TM 650 (Radeon M7) vga=normal plus boot-radeon (5) gets text console back
Acer TM 660 ??? (*)
-Acer TM 800 vga=normal, X patches, see webpage (5)
+Acer TM 800 vga=normal, X patches, see webpage (5) or vbetool (6)
+Acer TM 803 vga=normal, X patches, see webpage (5) or vbetool (6)
+Acer TM 803LCi vga=normal, vbetool (6)
Arima W730a vbetool needed (6)
Asus L2400D s3_mode (3)(***) (S1 also works OK)
Asus L3800C (Radeon M7) s3_bios (2) (S1 also works OK)
@@ -76,8 +79,9 @@ Asus M6NE ??? (*)
Athlon64 desktop prototype s3_bios (2)
Compal CL-50 ??? (*)
Compaq Armada E500 - P3-700 none (1) (S1 also works OK)
+Compaq Evo N620c vga=normal, s3_bios (2)
Dell 600m, ATI R250 Lf none (1), but needs xorg-x11-6.8.1.902-1
-Dell D600, ATI RV250 vga=normal (**), or try vbestate (6)
+Dell D600, ATI RV250 vga=normal and X, or try vbestate (6)
Dell Inspiron 4000 ??? (*)
Dell Inspiron 500m ??? (*)
Dell Inspiron 600m ??? (*)
@@ -85,11 +89,12 @@ Dell Inspiron 8200 ??? (*)
Dell Inspiron 8500 ??? (*)
Dell Inspiron 8600 ??? (*)
eMachines athlon64 machines vbetool needed (6) (someone please get me model #s)
-HP NC6000 s3_bios, may not use radeonfb (2)
+HP NC6000 s3_bios, may not use radeonfb (2); or vbetool (6)
HP NX7000 ??? (*)
HP Pavilion ZD7000 vbetool post needed, need open-source nv driver for X
HP Omnibook XE3 athlon version none (1)
-HP Omnibook XE3GC w/S3 Savage/IX-MV none (1)
+HP Omnibook XE3GC none (1), video is S3 Savage/IX-MV
+IBM TP T20, model 2647-44G none (1), video is S3 Inc. 86C270-294 Savage/IX-MV, vesafb gets "interesting" but X work.
IBM TP A31 / Type 2652-M5G s3_mode (3) [works ok with BIOS 1.04 2002-08-23, but not at all with BIOS 1.11 2004-11-05 :-(]
IBM TP R32 / Type 2658-MMG none (1)
IBM TP R40 2722B3G ??? (*)
@@ -97,20 +102,22 @@ IBM TP R50p / Type 1832-22U s3_bios (2)
IBM TP R51 ??? (*)
IBM TP T30 236681A ??? (*)
IBM TP T40 / Type 2373-MU4 none (1)
-IBM TP T40p ??? (*)
-IBM TP T41p none (1)
+IBM TP T40p none (1)
+IBM TP R40p s3_bios (2)
+IBM TP T41p s3_bios (2), switch to X after resume
IBM TP T42 ??? (*)
IBM ThinkPad T42p (2373-GTG) s3_bios (2)
IBM TP X20 ??? (*)
IBM TP X30 ??? (*)
IBM TP X31 / Type 2672-XXH none (1), use radeontool (http://fdd.com/software/radeon/) to turn off backlight.
-IBM TP X40 ??? (*)
+IBM Thinkpad X40 Type 2371-7JG s3_bios,s3_mode (4)
Medion MD4220 ??? (*)
Samsung P35 vbetool needed (6)
Sharp PC-AR10 (ATI rage) none (1)
Sony Vaio PCG-F403 ??? (*)
Sony Vaio PCG-N505SN ??? (*)
Sony Vaio vgn-s260 X or boot-radeon can init it (5)
+Toshiba Libretto L5 none (1)
Toshiba Satellite 4030CDT s3_mode (3)
Toshiba Satellite 4080XCDT s3_mode (3)
Toshiba Satellite 4090XCDT ??? (*)
@@ -121,14 +128,6 @@ Uniwill 244IIO ??? (*)
(*) from http://www.ubuntulinux.org/wiki/HoaryPMResults, not sure
which options to use. If you know, please tell me.
-(**) Text console is "strange" after resume. Backlight is switched on again
- by the X server. X server is:
- | X Window System Version 6.8.1.904 (6.8.2 RC 4)
- | Release Date: 2 February 2005
- | X Protocol Version 11, Revision 0, Release 6.8.1.904
- | Build Operating System: SuSE Linux [ELF] SuSE
- as present in SUSE 9.3preview3.
-
(***) To be tested with a newer kernel.
(****) Not with SMP kernel, UP only.
diff --git a/Documentation/spinlocks.txt b/Documentation/spinlocks.txt
index c6e24f82d34e6..c2122996631e4 100644
--- a/Documentation/spinlocks.txt
+++ b/Documentation/spinlocks.txt
@@ -1,3 +1,29 @@
+UPDATE March 21 2005 Amit Gud <gud@eth.net>
+
+Macros SPIN_LOCK_UNLOCKED and RW_LOCK_UNLOCKED are deprecated and will be
+removed soon. So for any new code dynamic initialization should be used:
+
+ spinlock_t xxx_lock;
+ rwlock_t xxx_rw_lock;
+
+ static int __init xxx_init(void)
+ {
+ spin_lock_init(&xxx_lock);
+ rw_lock_init(&xxx_rw_lock);
+ ...
+ }
+
+ module_init(xxx_init);
+
+Reasons for deprecation
+ - it hurts automatic lock validators
+ - it becomes intrusive for the realtime preemption patches
+
+Following discussion is still valid, however, with the dynamic initialization
+of spinlocks instead of static.
+
+-----------------------
+
On Fri, 2 Jan 1998, Doug Ledford wrote:
>
> I'm working on making the aic7xxx driver more SMP friendly (as well as
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index 1b469bb9c1aa4..8f1e78551b1e3 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -175,48 +175,6 @@ smp_callin(void)
cpu_idle();
}
-
-/*
- * Rough estimation for SMP scheduling, this is the number of cycles it
- * takes for a fully memory-limited process to flush the SMP-local cache.
- *
- * We are not told how much cache there is, so we have to guess.
- */
-static void __init
-smp_tune_scheduling (int cpuid)
-{
- struct percpu_struct *cpu;
- unsigned long on_chip_cache; /* kB */
- unsigned long freq; /* Hz */
- unsigned long bandwidth = 350; /* MB/s */
-
- cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset
- + cpuid * hwrpb->processor_size);
- switch (cpu->type)
- {
- case EV45_CPU:
- on_chip_cache = 16 + 16;
- break;
-
- case EV5_CPU:
- case EV56_CPU:
- on_chip_cache = 8 + 8 + 96;
- break;
-
- case PCA56_CPU:
- on_chip_cache = 16 + 8;
- break;
-
- case EV6_CPU:
- case EV67_CPU:
- default:
- on_chip_cache = 64 + 64;
- break;
- }
-
- freq = hwrpb->cycle_freq ? : est_cycle_freq;
-}
-
/* Wait until hwrpb->txrdy is clear for cpu. Return -1 on timeout. */
static int __init
wait_for_txrdy (unsigned long cpumask)
@@ -517,7 +475,6 @@ smp_prepare_cpus(unsigned int max_cpus)
current_thread_info()->cpu = boot_cpuid;
smp_store_cpu_info(boot_cpuid);
- smp_tune_scheduling(boot_cpuid);
smp_setup_percpu_timer(boot_cpuid);
/* Nothing to do on a UP box, or when told not to. */
diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c
index b5660fc3a68ef..3b30d4f1fc42d 100644
--- a/arch/alpha/kernel/srmcons.c
+++ b/arch/alpha/kernel/srmcons.c
@@ -164,29 +164,22 @@ srmcons_get_private_struct(struct srmcons_private **ps)
unsigned long flags;
int retval = 0;
- spin_lock_irqsave(&srmconsp_lock, flags);
-
- do {
- if (srmconsp != NULL) {
- *ps = srmconsp;
- break;
- }
+ if (srmconsp == NULL) {
+ spin_lock_irqsave(&srmconsp_lock, flags);
srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL);
- if (srmconsp == NULL) {
+ if (srmconsp == NULL)
retval = -ENOMEM;
- break;
+ else {
+ srmconsp->tty = NULL;
+ spin_lock_init(&srmconsp->lock);
+ init_timer(&srmconsp->timer);
}
- srmconsp->tty = NULL;
- spin_lock_init(&srmconsp->lock);
- init_timer(&srmconsp->timer);
-
- *ps = srmconsp;
- } while(0);
-
- spin_unlock_irqrestore(&srmconsp_lock, flags);
+ spin_unlock_irqrestore(&srmconsp_lock, flags);
+ }
+ *ps = srmconsp;
return retval;
}
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 58fd2a6962efb..35c1751ea0b02 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -1165,7 +1165,7 @@ fastcall void smp_apic_timer_interrupt(struct pt_regs *regs)
/*
* the NMI deadlock-detector uses this.
*/
- irq_stat[cpu].apic_timer_irqs++;
+ per_cpu(irq_stat, cpu).apic_timer_irqs++;
/*
* NOTE! We'd better ACK the irq immediately,
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index c52b88ea92593..45641a8725500 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -1202,10 +1202,11 @@ static int suspend(int vetoable)
}
device_suspend(PMSG_SUSPEND);
+ local_irq_disable();
device_power_down(PMSG_SUSPEND);
/* serialize with the timer interrupt */
- write_seqlock_irq(&xtime_lock);
+ write_seqlock(&xtime_lock);
/* protect against access to timer chip registers */
spin_lock(&i8253_lock);
@@ -1216,20 +1217,22 @@ static int suspend(int vetoable)
* We'll undo any timer changes due to interrupts below.
*/
spin_unlock(&i8253_lock);
- write_sequnlock_irq(&xtime_lock);
+ write_sequnlock(&xtime_lock);
+ local_irq_enable();
save_processor_state();
err = set_system_power_state(APM_STATE_SUSPEND);
restore_processor_state();
- write_seqlock_irq(&xtime_lock);
+ local_irq_disable();
+ write_seqlock(&xtime_lock);
spin_lock(&i8253_lock);
reinit_timer();
set_time();
ignore_normal_resume = 1;
spin_unlock(&i8253_lock);
- write_sequnlock_irq(&xtime_lock);
+ write_sequnlock(&xtime_lock);
if (err == APM_NO_ERROR)
err = APM_SUCCESS;
@@ -1237,6 +1240,7 @@ static int suspend(int vetoable)
apm_error("suspend", err);
err = (err == APM_SUCCESS) ? 0 : -EIO;
device_power_up();
+ local_irq_enable();
device_resume();
pm_send_all(PM_RESUME, (void *)0);
queue_event(APM_NORMAL_RESUME, NULL);
@@ -1255,17 +1259,22 @@ static void standby(void)
{
int err;
+ local_irq_disable();
device_power_down(PMSG_SUSPEND);
/* serialize with the timer interrupt */
- write_seqlock_irq(&xtime_lock);
+ write_seqlock(&xtime_lock);
/* If needed, notify drivers here */
get_time_diff();
- write_sequnlock_irq(&xtime_lock);
+ write_sequnlock(&xtime_lock);
+ local_irq_enable();
err = set_system_power_state(APM_STATE_STANDBY);
if ((err != APM_SUCCESS) && (err != APM_NO_ERROR))
apm_error("standby", err);
+
+ local_irq_disable();
device_power_up();
+ local_irq_enable();
}
static apm_event_t get_event(void)
diff --git a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c
index 5bc0cfedecbdf..a4cce454d09b2 100644
--- a/arch/i386/kernel/cpu/mtrr/generic.c
+++ b/arch/i386/kernel/cpu/mtrr/generic.c
@@ -92,6 +92,16 @@ void __init mtrr_state_warn(void)
printk(KERN_INFO "mtrr: corrected configuration.\n");
}
+/* Doesn't attempt to pass an error out to MTRR users
+ because it's quite complicated in some cases and probably not
+ worth it because the best error handling is to ignore it. */
+void mtrr_wrmsr(unsigned msr, unsigned a, unsigned b)
+{
+ if (wrmsr_safe(msr, a, b) < 0)
+ printk(KERN_ERR
+ "MTRR: CPU %u: Writing MSR %x to %x:%x failed\n",
+ smp_processor_id(), msr, a, b);
+}
int generic_get_free_region(unsigned long base, unsigned long size)
/* [SUMMARY] Get a free MTRR.
@@ -150,14 +160,14 @@ static int set_fixed_ranges(mtrr_type * frs)
rdmsr(MTRRfix64K_00000_MSR, lo, hi);
if (p[0] != lo || p[1] != hi) {
- wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
+ mtrr_wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
changed = TRUE;
}
for (i = 0; i < 2; i++) {
rdmsr(MTRRfix16K_80000_MSR + i, lo, hi);
if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) {
- wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2],
+ mtrr_wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2],
p[3 + i * 2]);
changed = TRUE;
}
@@ -166,7 +176,7 @@ static int set_fixed_ranges(mtrr_type * frs)
for (i = 0; i < 8; i++) {
rdmsr(MTRRfix4K_C0000_MSR + i, lo, hi);
if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) {
- wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2],
+ mtrr_wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2],
p[7 + i * 2]);
changed = TRUE;
}
@@ -184,7 +194,7 @@ static int set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr)
rdmsr(MTRRphysBase_MSR(index), lo, hi);
if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL)
|| (vr->base_hi & 0xfUL) != (hi & 0xfUL)) {
- wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
+ mtrr_wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
changed = TRUE;
}
@@ -192,7 +202,7 @@ static int set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr)
if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL)
|| (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) {
- wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
+ mtrr_wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
changed = TRUE;
}
return changed;
@@ -267,7 +277,7 @@ static void prepare_set(void)
rdmsr(MTRRdefType_MSR, deftype_lo, deftype_hi);
/* Disable MTRRs, and set the default type to uncached */
- wrmsr(MTRRdefType_MSR, deftype_lo & 0xf300UL, deftype_hi);
+ mtrr_wrmsr(MTRRdefType_MSR, deftype_lo & 0xf300UL, deftype_hi);
}
static void post_set(void)
@@ -276,7 +286,7 @@ static void post_set(void)
__flush_tlb();
/* Intel (P6) standard MTRRs */
- wrmsr(MTRRdefType_MSR, deftype_lo, deftype_hi);
+ mtrr_wrmsr(MTRRdefType_MSR, deftype_lo, deftype_hi);
/* Enable caches */
write_cr0(read_cr0() & 0xbfffffff);
@@ -330,11 +340,11 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base,
if (size == 0) {
/* The invalid bit is kept in the mask, so we simply clear the
relevant mask register to disable a range. */
- wrmsr(MTRRphysMask_MSR(reg), 0, 0);
+ mtrr_wrmsr(MTRRphysMask_MSR(reg), 0, 0);
} else {
- wrmsr(MTRRphysBase_MSR(reg), base << PAGE_SHIFT | type,
+ mtrr_wrmsr(MTRRphysBase_MSR(reg), base << PAGE_SHIFT | type,
(base & size_and_mask) >> (32 - PAGE_SHIFT));
- wrmsr(MTRRphysMask_MSR(reg), -size << PAGE_SHIFT | 0x800,
+ mtrr_wrmsr(MTRRphysMask_MSR(reg), -size << PAGE_SHIFT | 0x800,
(-size & size_and_mask) >> (32 - PAGE_SHIFT));
}
diff --git a/arch/i386/kernel/cpu/mtrr/if.c b/arch/i386/kernel/cpu/mtrr/if.c
index 0946844217b9c..1923e0aed26a8 100644
--- a/arch/i386/kernel/cpu/mtrr/if.c
+++ b/arch/i386/kernel/cpu/mtrr/if.c
@@ -98,16 +98,20 @@ mtrr_write(struct file *file, const char __user *buf, size_t len, loff_t * ppos)
unsigned long long base, size;
char *ptr;
char line[LINE_SIZE];
+ size_t linelen;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
+ if (!len)
+ return -EINVAL;
memset(line, 0, LINE_SIZE);
if (len > LINE_SIZE)
len = LINE_SIZE;
if (copy_from_user(line, buf, len - 1))
return -EFAULT;
- ptr = line + strlen(line) - 1;
- if (*ptr == '\n')
+ linelen = strlen(line);
+ ptr = line + linelen - 1;
+ if (linelen && *ptr == '\n')
*ptr = '\0';
if (!strncmp(line, "disable=", 8)) {
reg = simple_strtoul(line + 8, &ptr, 0);
diff --git a/arch/i386/kernel/cpu/mtrr/mtrr.h b/arch/i386/kernel/cpu/mtrr/mtrr.h
index 846603cbaea18..de1351245599e 100644
--- a/arch/i386/kernel/cpu/mtrr/mtrr.h
+++ b/arch/i386/kernel/cpu/mtrr/mtrr.h
@@ -94,4 +94,5 @@ extern unsigned int num_var_ranges;
void finalize_mtrr_state(void);
void mtrr_state_warn(void);
char *mtrr_attrib_to_str(int x);
+void mtrr_wrmsr(unsigned, unsigned, unsigned);
diff --git a/arch/i386/kernel/cpu/mtrr/state.c b/arch/i386/kernel/cpu/mtrr/state.c
index 3d32fbf352845..f62ecd15811a9 100644
--- a/arch/i386/kernel/cpu/mtrr/state.c
+++ b/arch/i386/kernel/cpu/mtrr/state.c
@@ -42,7 +42,7 @@ void set_mtrr_cache_disable(struct set_mtrr_context *ctxt)
{
if (use_intel())
/* Disable MTRRs, and set the default type to uncached */
- wrmsr(MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL,
+ mtrr_wrmsr(MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL,
ctxt->deftype_hi);
else if (is_cpu(CYRIX))
/* Cyrix ARRs - everything else were excluded at the top */
@@ -60,7 +60,7 @@ void set_mtrr_done(struct set_mtrr_context *ctxt)
/* Restore MTRRdefType */
if (use_intel())
/* Intel (P6) standard MTRRs */
- wrmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+ mtrr_wrmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
else
/* Cyrix ARRs - everything else was excluded at the top */
setCx86(CX86_CCR3, ctxt->ccr3);
diff --git a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
index 5f159f58eeca0..6ed7e28f306cf 100644
--- a/arch/i386/kernel/dmi_scan.c
+++ b/arch/i386/kernel/dmi_scan.c
@@ -12,8 +12,6 @@
#include <linux/bootmem.h>
-int es7000_plat = 0;
-
struct dmi_header
{
u8 type;
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index 18bc0cbdcbe3e..9c1350e811d07 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -275,7 +275,7 @@ static struct irq_cpu_info {
#define IRQ_DELTA(cpu,irq) (irq_cpu_data[cpu].irq_delta[irq])
#define IDLE_ENOUGH(cpu,now) \
- (idle_cpu(cpu) && ((now) - irq_stat[(cpu)].idle_timestamp > 1))
+ (idle_cpu(cpu) && ((now) - per_cpu(irq_stat, (cpu)).idle_timestamp > 1))
#define IRQ_ALLOWED(cpu, allowed_mask) cpu_isset(cpu, allowed_mask)
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 3d4e563127e7f..73945a3c53c4c 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -16,6 +16,9 @@
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
+DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_maxaligned_in_smp;
+EXPORT_PER_CPU_SYMBOL(irq_stat);
+
#ifndef CONFIG_X86_LOCAL_APIC
/*
* 'what should we do if we get a hw irq event on an illegal vector'.
@@ -246,7 +249,7 @@ skip:
for (j = 0; j < NR_CPUS; j++)
if (cpu_online(j))
seq_printf(p, "%10u ",
- irq_stat[j].apic_timer_irqs);
+ per_cpu(irq_stat,j).apic_timer_irqs);
seq_putc(p, '\n');
#endif
seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
index 97de0290c9be9..1347ab4939e7e 100644
--- a/arch/i386/kernel/mpparse.c
+++ b/arch/i386/kernel/mpparse.c
@@ -982,6 +982,7 @@ void __init mp_override_legacy_irq (
return;
}
+int es7000_plat;
void __init mp_config_acpi_legacy_irqs (void)
{
@@ -996,9 +997,9 @@ void __init mp_config_acpi_legacy_irqs (void)
Dprintk("Bus #%d is ISA\n", MP_ISA_BUS);
/*
- * ES7000 has no legacy identity mappings
+ * Older generations of ES7000 have no legacy identity mappings
*/
- if (es7000_plat)
+ if (es7000_plat == 1)
return;
/*
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index 6bd4681df09f1..f5b0c5081bd65 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -110,7 +110,7 @@ int __init check_nmi_watchdog (void)
printk(KERN_INFO "testing NMI watchdog ... ");
for (cpu = 0; cpu < NR_CPUS; cpu++)
- prev_nmi_count[cpu] = irq_stat[cpu].__nmi_count;
+ prev_nmi_count[cpu] = per_cpu(irq_stat, cpu).__nmi_count;
local_irq_enable();
mdelay((10*1000)/nmi_hz); // wait 10 ticks
@@ -483,7 +483,7 @@ void nmi_watchdog_tick (struct pt_regs * regs)
*/
int sum, cpu = smp_processor_id();
- sum = irq_stat[cpu].apic_timer_irqs;
+ sum = per_cpu(irq_stat, cpu).apic_timer_irqs;
if (last_irq_sums[cpu] == sum) {
/*
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 4889645c6cd65..90cfff176251e 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -161,7 +161,7 @@ void cpu_idle (void)
if (!idle)
idle = default_idle;
- irq_stat[cpu].idle_timestamp = jiffies;
+ __get_cpu_var(irq_stat).idle_timestamp = jiffies;
idle();
}
schedule();
diff --git a/arch/i386/kernel/quirks.c b/arch/i386/kernel/quirks.c
index cef1810a55a3d..aaf89cb2bc514 100644
--- a/arch/i386/kernel/quirks.c
+++ b/arch/i386/kernel/quirks.c
@@ -37,7 +37,9 @@ static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
irqbalance_disable("");
#endif
noirqdebug_setup("");
+#ifdef CONFIG_PROC_FS
no_irq_affinity = 1;
+#endif
}
config &= ~0x2;
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index 6b5c98f3683af..9b55e30e4490c 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -204,19 +204,19 @@ static int set_rtc_mmss(unsigned long nowtime)
{
int retval;
+ WARN_ON(irqs_disabled());
+
/* gets recalled with irq locally disabled */
- spin_lock(&rtc_lock);
+ spin_lock_irq(&rtc_lock);
if (efi_enabled)
retval = efi_set_rtc_mmss(nowtime);
else
retval = mach_set_rtc_mmss(nowtime);
- spin_unlock(&rtc_lock);
+ spin_unlock_irq(&rtc_lock);
return retval;
}
-/* last time the cmos clock got updated */
-static long last_rtc_update;
int timer_ack;
@@ -268,24 +268,6 @@ static inline void do_timer_interrupt(int irq, void *dev_id,
do_timer_interrupt_hook(regs);
- /*
- * If we have an externally synchronized Linux clock, then update
- * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
- * called as close as possible to 500 ms before the new second starts.
- */
- if ((time_status & STA_UNSYNC) == 0 &&
- xtime.tv_sec > last_rtc_update + 660 &&
- (xtime.tv_nsec / 1000)
- >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
- (xtime.tv_nsec / 1000)
- <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2) {
- last_rtc_update = xtime.tv_sec;
- if (efi_enabled) {
- if (efi_set_rtc_mmss(xtime.tv_sec))
- last_rtc_update -= 600;
- } else if (set_rtc_mmss(xtime.tv_sec))
- last_rtc_update -= 600;
- }
if (MCA_bus) {
/* The PS/2 uses level-triggered interrupts. You can't
@@ -342,6 +324,55 @@ unsigned long get_cmos_time(void)
return retval;
}
+static void sync_cmos_clock(unsigned long dummy);
+
+static struct timer_list sync_cmos_timer =
+ TIMER_INITIALIZER(sync_cmos_clock, 0, 0);
+
+static void sync_cmos_clock(unsigned long dummy)
+{
+ struct timeval now, next;
+ int fail = 1;
+
+ /*
+ * If we have an externally synchronized Linux clock, then update
+ * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+ * called as close as possible to 500 ms before the new second starts.
+ * This code is run on a timer. If the clock is set, that timer
+ * may not expire at the correct time. Thus, we adjust...
+ */
+ if ((time_status & STA_UNSYNC) != 0)
+ /*
+ * Not synced, exit, do not restart a timer (if one is
+ * running, let it run out).
+ */
+ return;
+
+ do_gettimeofday(&now);
+ if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
+ now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2)
+ fail = set_rtc_mmss(now.tv_sec);
+
+ next.tv_usec = USEC_AFTER - now.tv_usec;
+ if (next.tv_usec <= 0)
+ next.tv_usec += USEC_PER_SEC;
+
+ if (!fail)
+ next.tv_sec = 659;
+ else
+ next.tv_sec = 0;
+
+ if (next.tv_usec >= USEC_PER_SEC) {
+ next.tv_sec++;
+ next.tv_usec -= USEC_PER_SEC;
+ }
+ mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next));
+}
+
+void notify_arch_cmos_timer(void)
+{
+ mod_timer(&sync_cmos_timer, jiffies + 1);
+}
static long clock_cmos_diff, sleep_start;
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index f87f8b13bcfbe..7b5b97f209b7f 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -1030,3 +1030,10 @@ void __init trap_init(void)
trap_init_hook();
}
+
+static int __init kstack_setup(char *s)
+{
+ kstack_depth_to_print = simple_strtoul(s, NULL, 0);
+ return 0;
+}
+__setup("kstack=", kstack_setup);
diff --git a/arch/i386/mach-es7000/es7000plat.c b/arch/i386/mach-es7000/es7000plat.c
index 9707a9e45b46a..d5936d500479f 100644
--- a/arch/i386/mach-es7000/es7000plat.c
+++ b/arch/i386/mach-es7000/es7000plat.c
@@ -138,7 +138,19 @@ parse_unisys_oem (char *oemptr, int oem_entries)
es7000_plat = 0;
} else {
printk("\nEnabling ES7000 specific features...\n");
- es7000_plat = 1;
+ /*
+ * Determine the generation of the ES7000 currently running.
+ *
+ * es7000_plat = 0 if the machine is NOT a Unisys ES7000 box
+ * es7000_plat = 1 if the machine is a 5xx ES7000 box
+ * es7000_plat = 2 if the machine is a x86_64 ES7000 box
+ *
+ */
+ if (!(boot_cpu_data.x86 <= 15 && boot_cpu_data.x86_model <= 2))
+ es7000_plat = 2;
+ else
+ es7000_plat = 1;
+
ioapic_renumber_irq = es7000_rename_gsi;
}
return es7000_plat;
diff --git a/arch/i386/math-emu/fpu_entry.c b/arch/i386/math-emu/fpu_entry.c
index 4162c3c1454aa..d93f16ef828f5 100644
--- a/arch/i386/math-emu/fpu_entry.c
+++ b/arch/i386/math-emu/fpu_entry.c
@@ -257,7 +257,7 @@ do_another_FPU_instruction:
}
RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(1);
+ FPU_code_access_ok(1);
FPU_get_user(FPU_modrm, (u_char __user *) FPU_EIP);
RE_ENTRANT_CHECK_ON;
FPU_EIP++;
@@ -589,7 +589,7 @@ static int valid_prefix(u_char *Byte, u_char __user **fpu_eip,
*override = (overrides) { 0, 0, PREFIX_DEFAULT }; /* defaults */
RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(1);
+ FPU_code_access_ok(1);
FPU_get_user(byte, ip);
RE_ENTRANT_CHECK_ON;
@@ -635,7 +635,7 @@ static int valid_prefix(u_char *Byte, u_char __user **fpu_eip,
do_next_byte:
ip++;
RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(1);
+ FPU_code_access_ok(1);
FPU_get_user(byte, ip);
RE_ENTRANT_CHECK_ON;
break;
@@ -686,7 +686,7 @@ int restore_i387_soft(void *s387, struct _fpstate __user *buf)
int offset, other, i, tags, regnr, tag, newtop;
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_READ, d, 7*4 + 8*10);
+ FPU_access_ok(VERIFY_READ, d, 7*4 + 8*10);
if (__copy_from_user(&S387->cwd, d, 7*4))
return -1;
RE_ENTRANT_CHECK_ON;
@@ -732,7 +732,7 @@ int save_i387_soft(void *s387, struct _fpstate __user * buf)
int offset = (S387->ftop & 7) * 10, other = 80 - offset;
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE, d, 7*4 + 8*10);
+ FPU_access_ok(VERIFY_WRITE, d, 7*4 + 8*10);
#ifdef PECULIAR_486
S387->cwd &= ~0xe080;
/* An 80486 sets nearly all of the reserved bits to 1. */
diff --git a/arch/i386/math-emu/fpu_system.h b/arch/i386/math-emu/fpu_system.h
index 380688765553a..bf26341c8bdea 100644
--- a/arch/i386/math-emu/fpu_system.h
+++ b/arch/i386/math-emu/fpu_system.h
@@ -66,7 +66,7 @@
#define instruction_address (*(struct address *)&I387.soft.fip)
#define operand_address (*(struct address *)&I387.soft.foo)
-#define FPU_verify_area(x,y,z) if ( !access_ok(x,y,z) ) \
+#define FPU_access_ok(x,y,z) if ( !access_ok(x,y,z) ) \
math_abort(FPU_info,SIGSEGV)
#undef FPU_IGNORE_CODE_SEGV
@@ -75,12 +75,12 @@
about 20% slower if applied to the code. Anyway, errors due to bad
code addresses should be much rarer than errors due to bad data
addresses. */
-#define FPU_code_verify_area(z)
+#define FPU_code_access_ok(z)
#else
/* A simpler test than access_ok() can probably be done for
- FPU_code_verify_area() because the only possible error is to step
+ FPU_code_access_ok() because the only possible error is to step
past the upper boundary of a legal code area. */
-#define FPU_code_verify_area(z) FPU_verify_area(VERIFY_READ,(void __user *)FPU_EIP,z)
+#define FPU_code_access_ok(z) FPU_access_ok(VERIFY_READ,(void __user *)FPU_EIP,z)
#endif
#define FPU_get_user(x,y) get_user((x),(y))
diff --git a/arch/i386/math-emu/get_address.c b/arch/i386/math-emu/get_address.c
index 59eee72186ec2..91175738e9480 100644
--- a/arch/i386/math-emu/get_address.c
+++ b/arch/i386/math-emu/get_address.c
@@ -81,7 +81,7 @@ static int sib(int mod, unsigned long *fpu_eip)
long offset;
RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(1);
+ FPU_code_access_ok(1);
FPU_get_user(base, (u_char __user *) (*fpu_eip)); /* The SIB byte */
RE_ENTRANT_CHECK_ON;
(*fpu_eip)++;
@@ -111,7 +111,7 @@ static int sib(int mod, unsigned long *fpu_eip)
/* 8 bit signed displacement */
long displacement;
RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(1);
+ FPU_code_access_ok(1);
FPU_get_user(displacement, (signed char __user *) (*fpu_eip));
offset += displacement;
RE_ENTRANT_CHECK_ON;
@@ -122,7 +122,7 @@ static int sib(int mod, unsigned long *fpu_eip)
/* 32 bit displacement */
long displacement;
RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(4);
+ FPU_code_access_ok(4);
FPU_get_user(displacement, (long __user *) (*fpu_eip));
offset += displacement;
RE_ENTRANT_CHECK_ON;
@@ -276,7 +276,7 @@ void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip,
{
/* Special case: disp32 */
RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(4);
+ FPU_code_access_ok(4);
FPU_get_user(address, (unsigned long __user *) (*fpu_eip));
(*fpu_eip) += 4;
RE_ENTRANT_CHECK_ON;
@@ -293,7 +293,7 @@ void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip,
case 1:
/* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(1);
+ FPU_code_access_ok(1);
FPU_get_user(address, (signed char __user *) (*fpu_eip));
RE_ENTRANT_CHECK_ON;
(*fpu_eip)++;
@@ -301,7 +301,7 @@ void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip,
case 2:
/* 32 bit displacement */
RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(4);
+ FPU_code_access_ok(4);
FPU_get_user(address, (long __user *) (*fpu_eip));
(*fpu_eip) += 4;
RE_ENTRANT_CHECK_ON;
@@ -362,7 +362,7 @@ void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip,
{
/* Special case: disp16 */
RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(2);
+ FPU_code_access_ok(2);
FPU_get_user(address, (unsigned short __user *) (*fpu_eip));
(*fpu_eip) += 2;
RE_ENTRANT_CHECK_ON;
@@ -372,7 +372,7 @@ void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip,
case 1:
/* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(1);
+ FPU_code_access_ok(1);
FPU_get_user(address, (signed char __user *) (*fpu_eip));
RE_ENTRANT_CHECK_ON;
(*fpu_eip)++;
@@ -380,7 +380,7 @@ void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip,
case 2:
/* 16 bit displacement */
RE_ENTRANT_CHECK_OFF;
- FPU_code_verify_area(2);
+ FPU_code_access_ok(2);
FPU_get_user(address, (unsigned short __user *) (*fpu_eip));
(*fpu_eip) += 2;
RE_ENTRANT_CHECK_ON;
diff --git a/arch/i386/math-emu/load_store.c b/arch/i386/math-emu/load_store.c
index a6f08b8774838..85314be2fef8d 100644
--- a/arch/i386/math-emu/load_store.c
+++ b/arch/i386/math-emu/load_store.c
@@ -208,7 +208,7 @@ int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
break;
case 024: /* fldcw */
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_READ, data_address, 2);
+ FPU_access_ok(VERIFY_READ, data_address, 2);
FPU_get_user(control_word, (unsigned short __user *) data_address);
RE_ENTRANT_CHECK_ON;
if ( partial_status & ~control_word & CW_Exceptions )
@@ -243,7 +243,7 @@ int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
break;
case 034: /* fstcw m16int */
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE,data_address,2);
+ FPU_access_ok(VERIFY_WRITE,data_address,2);
FPU_put_user(control_word, (unsigned short __user *) data_address);
RE_ENTRANT_CHECK_ON;
return 1;
@@ -255,7 +255,7 @@ int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
break;
case 036: /* fstsw m2byte */
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE,data_address,2);
+ FPU_access_ok(VERIFY_WRITE,data_address,2);
FPU_put_user(status_word(),(unsigned short __user *) data_address);
RE_ENTRANT_CHECK_ON;
return 1;
diff --git a/arch/i386/math-emu/reg_ld_str.c b/arch/i386/math-emu/reg_ld_str.c
index 699fe331c6d37..f06ed41d191d5 100644
--- a/arch/i386/math-emu/reg_ld_str.c
+++ b/arch/i386/math-emu/reg_ld_str.c
@@ -91,7 +91,7 @@ int FPU_load_extended(long double __user *s, int stnr)
FPU_REG *sti_ptr = &st(stnr);
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_READ, s, 10);
+ FPU_access_ok(VERIFY_READ, s, 10);
__copy_from_user(sti_ptr, s, 10);
RE_ENTRANT_CHECK_ON;
@@ -106,7 +106,7 @@ int FPU_load_double(double __user *dfloat, FPU_REG *loaded_data)
unsigned m64, l64;
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_READ, dfloat, 8);
+ FPU_access_ok(VERIFY_READ, dfloat, 8);
FPU_get_user(m64, 1 + (unsigned long __user *) dfloat);
FPU_get_user(l64, (unsigned long __user *) dfloat);
RE_ENTRANT_CHECK_ON;
@@ -178,7 +178,7 @@ int FPU_load_single(float __user *single, FPU_REG *loaded_data)
int exp, tag, negative;
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_READ, single, 4);
+ FPU_access_ok(VERIFY_READ, single, 4);
FPU_get_user(m32, (unsigned long __user *) single);
RE_ENTRANT_CHECK_ON;
@@ -243,7 +243,7 @@ int FPU_load_int64(long long __user *_s)
FPU_REG *st0_ptr = &st(0);
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_READ, _s, 8);
+ FPU_access_ok(VERIFY_READ, _s, 8);
copy_from_user(&s,_s,8);
RE_ENTRANT_CHECK_ON;
@@ -274,7 +274,7 @@ int FPU_load_int32(long __user *_s, FPU_REG *loaded_data)
int negative;
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_READ, _s, 4);
+ FPU_access_ok(VERIFY_READ, _s, 4);
FPU_get_user(s, _s);
RE_ENTRANT_CHECK_ON;
@@ -302,7 +302,7 @@ int FPU_load_int16(short __user *_s, FPU_REG *loaded_data)
int s, negative;
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_READ, _s, 2);
+ FPU_access_ok(VERIFY_READ, _s, 2);
/* Cast as short to get the sign extended. */
FPU_get_user(s, _s);
RE_ENTRANT_CHECK_ON;
@@ -335,7 +335,7 @@ int FPU_load_bcd(u_char __user *s)
int sign;
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_READ, s, 10);
+ FPU_access_ok(VERIFY_READ, s, 10);
RE_ENTRANT_CHECK_ON;
for ( pos = 8; pos >= 0; pos--)
{
@@ -380,7 +380,7 @@ int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag, long double __user *d)
if ( st0_tag != TAG_Empty )
{
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE, d, 10);
+ FPU_access_ok(VERIFY_WRITE, d, 10);
FPU_put_user(st0_ptr->sigl, (unsigned long __user *) d);
FPU_put_user(st0_ptr->sigh, (unsigned long __user *) ((u_char __user *)d + 4));
@@ -397,7 +397,7 @@ int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag, long double __user *d)
/* The masked response */
/* Put out the QNaN indefinite */
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE,d,10);
+ FPU_access_ok(VERIFY_WRITE,d,10);
FPU_put_user(0, (unsigned long __user *) d);
FPU_put_user(0xc0000000, 1 + (unsigned long __user *) d);
FPU_put_user(0xffff, 4 + (short __user *) d);
@@ -607,7 +607,7 @@ int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double __user *dfloat)
/* The masked response */
/* Put out the QNaN indefinite */
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE,dfloat,8);
+ FPU_access_ok(VERIFY_WRITE,dfloat,8);
FPU_put_user(0, (unsigned long __user *) dfloat);
FPU_put_user(0xfff80000, 1 + (unsigned long __user *) dfloat);
RE_ENTRANT_CHECK_ON;
@@ -620,7 +620,7 @@ int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double __user *dfloat)
l[1] |= 0x80000000;
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE,dfloat,8);
+ FPU_access_ok(VERIFY_WRITE,dfloat,8);
FPU_put_user(l[0], (unsigned long __user *)dfloat);
FPU_put_user(l[1], 1 + (unsigned long __user *)dfloat);
RE_ENTRANT_CHECK_ON;
@@ -826,7 +826,7 @@ int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float __user *single)
/* The masked response */
/* Put out the QNaN indefinite */
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE,single,4);
+ FPU_access_ok(VERIFY_WRITE,single,4);
FPU_put_user(0xffc00000, (unsigned long __user *) single);
RE_ENTRANT_CHECK_ON;
return 1;
@@ -845,7 +845,7 @@ int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float __user *single)
templ |= 0x80000000;
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE,single,4);
+ FPU_access_ok(VERIFY_WRITE,single,4);
FPU_put_user(templ,(unsigned long __user *) single);
RE_ENTRANT_CHECK_ON;
@@ -906,7 +906,7 @@ int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long __user *d)
}
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE,d,8);
+ FPU_access_ok(VERIFY_WRITE,d,8);
copy_to_user(d, &tll, 8);
RE_ENTRANT_CHECK_ON;
@@ -963,7 +963,7 @@ int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long __user *d)
}
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE,d,4);
+ FPU_access_ok(VERIFY_WRITE,d,4);
FPU_put_user(t.sigl, (unsigned long __user *) d);
RE_ENTRANT_CHECK_ON;
@@ -1020,7 +1020,7 @@ int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d)
}
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE,d,2);
+ FPU_access_ok(VERIFY_WRITE,d,2);
FPU_put_user((short)t.sigl, d);
RE_ENTRANT_CHECK_ON;
@@ -1069,7 +1069,7 @@ int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d)
{
/* Produce the QNaN "indefinite" */
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE,d,10);
+ FPU_access_ok(VERIFY_WRITE,d,10);
for ( i = 0; i < 7; i++)
FPU_put_user(0, d+i); /* These bytes "undefined" */
FPU_put_user(0xc0, d+7); /* This byte "undefined" */
@@ -1088,7 +1088,7 @@ int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d)
}
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE,d,10);
+ FPU_access_ok(VERIFY_WRITE,d,10);
RE_ENTRANT_CHECK_ON;
for ( i = 0; i < 9; i++)
{
@@ -1186,7 +1186,7 @@ u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s)
^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
{
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_READ, s, 0x0e);
+ FPU_access_ok(VERIFY_READ, s, 0x0e);
FPU_get_user(control_word, (unsigned short __user *) s);
FPU_get_user(partial_status, (unsigned short __user *) (s+2));
FPU_get_user(tag_word, (unsigned short __user *) (s+4));
@@ -1206,7 +1206,7 @@ u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s)
else
{
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_READ, s, 0x1c);
+ FPU_access_ok(VERIFY_READ, s, 0x1c);
FPU_get_user(control_word, (unsigned short __user *) s);
FPU_get_user(partial_status, (unsigned short __user *) (s+4));
FPU_get_user(tag_word, (unsigned short __user *) (s+8));
@@ -1274,7 +1274,7 @@ void frstor(fpu_addr_modes addr_modes, u_char __user *data_address)
/* Copy all registers in stack order. */
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_READ,s,80);
+ FPU_access_ok(VERIFY_READ,s,80);
__copy_from_user(register_base+offset, s, other);
if ( offset )
__copy_from_user(register_base, s+other, offset);
@@ -1298,7 +1298,7 @@ u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user *d)
^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
{
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE,d,14);
+ FPU_access_ok(VERIFY_WRITE,d,14);
#ifdef PECULIAR_486
FPU_put_user(control_word & ~0xe080, (unsigned long __user *) d);
#else
@@ -1326,7 +1326,7 @@ u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user *d)
else
{
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE, d, 7*4);
+ FPU_access_ok(VERIFY_WRITE, d, 7*4);
#ifdef PECULIAR_486
control_word &= ~0xe080;
/* An 80486 sets nearly all of the reserved bits to 1. */
@@ -1356,7 +1356,7 @@ void fsave(fpu_addr_modes addr_modes, u_char __user *data_address)
d = fstenv(addr_modes, data_address);
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE,d,80);
+ FPU_access_ok(VERIFY_WRITE,d,80);
/* Copy all registers in stack order. */
__copy_to_user(d, register_base+offset, other);
diff --git a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c
index ceaeef55e5054..a8c45143088b7 100644
--- a/arch/i386/mm/hugetlbpage.c
+++ b/arch/i386/mm/hugetlbpage.c
@@ -46,7 +46,7 @@ static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma, struc
{
pte_t entry;
- mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+ add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
if (write_access) {
entry =
pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
@@ -86,7 +86,7 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
ptepage = pte_page(entry);
get_page(ptepage);
set_pte(dst_pte, entry);
- dst->rss += (HPAGE_SIZE / PAGE_SIZE);
+ add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
addr += HPAGE_SIZE;
}
return 0;
@@ -209,20 +209,23 @@ void unmap_hugepage_range(struct vm_area_struct *vma,
{
struct mm_struct *mm = vma->vm_mm;
unsigned long address;
- pte_t pte;
+ pte_t pte, *ptep;
struct page *page;
BUG_ON(start & (HPAGE_SIZE - 1));
BUG_ON(end & (HPAGE_SIZE - 1));
for (address = start; address < end; address += HPAGE_SIZE) {
- pte = ptep_get_and_clear(mm, address, huge_pte_offset(mm, address));
+ ptep = huge_pte_offset(mm, address);
+ if (!ptep)
+ continue;
+ pte = ptep_get_and_clear(mm, address, ptep);
if (pte_none(pte))
continue;
page = pte_page(pte);
put_page(page);
}
- mm->rss -= (end - start) >> PAGE_SHIFT;
+ add_mm_counter(mm ,rss, -((end - start) >> PAGE_SHIFT));
flush_tlb_range(vma, start, end);
}
diff --git a/arch/i386/oprofile/backtrace.c b/arch/i386/oprofile/backtrace.c
index 30056c4fa8047..52d72e074f7f9 100644
--- a/arch/i386/oprofile/backtrace.c
+++ b/arch/i386/oprofile/backtrace.c
@@ -18,7 +18,6 @@ struct frame_head {
unsigned long ret;
} __attribute__((packed));
-
static struct frame_head *
dump_backtrace(struct frame_head * head)
{
@@ -32,16 +31,6 @@ dump_backtrace(struct frame_head * head)
return head->ebp;
}
-
-#ifdef CONFIG_X86_4G
-/* With a 4G kernel/user split, user pages are not directly
- * accessible from the kernel, so don't try
- */
-static int pages_present(struct frame_head * head)
-{
- return 0;
-}
-#else
/* check that the page(s) containing the frame head are present */
static int pages_present(struct frame_head * head)
{
@@ -53,8 +42,6 @@ static int pages_present(struct frame_head * head)
return check_user_page_readable(mm, (unsigned long)(head + 1));
}
-#endif /* CONFIG_X86_4G */
-
/*
* | | /\ Higher addresses
diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c
index af18331b3fb29..be52c5ac4e054 100644
--- a/arch/i386/pci/fixup.c
+++ b/arch/i386/pci/fixup.c
@@ -343,7 +343,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC1, pcie_r
/*
* Fixup to mark boot BIOS video selected by BIOS before it changes
*
- * From information provided by "Jon Smirl" <jonsmirl@yahoo.com>
+ * From information provided by "Jon Smirl" <jonsmirl@gmail.com>
*
* The standard boot ROM sequence for an x86 machine uses the BIOS
* to select an initial video card for boot display. This boot video
@@ -354,12 +354,13 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC1, pcie_r
* See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW
* is marked here since the boot video device will be the only enabled
* video device at this point.
- *
- */static void __devinit pci_fixup_video(struct pci_dev *pdev)
+ */
+
+static void __devinit pci_fixup_video(struct pci_dev *pdev)
{
struct pci_dev *bridge;
struct pci_bus *bus;
- u16 l;
+ u16 config;
if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
return;
@@ -369,12 +370,17 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC1, pcie_r
while (bus) {
bridge = bus->self;
if (bridge) {
- pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &l);
- if (!(l & PCI_BRIDGE_CTL_VGA))
+ pci_read_config_word(bridge, PCI_BRIDGE_CONTROL,
+ &config);
+ if (!(config & PCI_BRIDGE_CTL_VGA))
return;
}
bus = bus->parent;
}
- pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
+ pci_read_config_word(pdev, PCI_COMMAND, &config);
+ if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
+ pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
+ printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev));
+ }
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
diff --git a/arch/i386/power/swsusp.S b/arch/i386/power/swsusp.S
index 171a6c85aac27..c4105286ff26f 100644
--- a/arch/i386/power/swsusp.S
+++ b/arch/i386/power/swsusp.S
@@ -51,6 +51,15 @@ copy_loop:
.p2align 4,,7
done:
+ /* Flush TLB, including "global" things (vmalloc) */
+ movl mmu_cr4_features, %eax
+ movl %eax, %edx
+ andl $~(1<<7), %edx; # PGE
+ movl %edx, %cr4; # turn off PGE
+ movl %cr3, %ecx; # flush TLB
+ movl %ecx, %cr3
+ movl %eax, %cr4; # turn PGE back on
+
movl saved_context_esp, %esp
movl saved_context_ebp, %ebp
movl saved_context_ebx, %ebx
@@ -58,5 +67,7 @@ done:
movl saved_context_edi, %edi
pushl saved_context_eflags ; popfl
- call swsusp_restore
+
+ xorl %eax, %eax
+
ret
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index a3a2d8dc48372..017c9ab5fc1b2 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -762,7 +762,7 @@ sba_io_pdir_entry(u64 *pdir_ptr, unsigned long vba)
#ifdef ENABLE_MARK_CLEAN
/**
* Since DMA is i-cache coherent, any (complete) pages that were written via
- * DMA can be marked as "clean" so that update_mmu_cache() doesn't have to
+ * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to
* flush them when they get mapped into an executable vm-area.
*/
static void
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
index 4413e54b123b0..28f2aadc38d00 100644
--- a/arch/ia64/kernel/irq.c
+++ b/arch/ia64/kernel/irq.c
@@ -94,12 +94,20 @@ skip:
/*
* This is updated when the user sets irq affinity via /proc
*/
-cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS];
+static cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS];
static unsigned long pending_irq_redir[BITS_TO_LONGS(NR_IRQS)];
-static cpumask_t irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 };
+/*
+ * Arch specific routine for deferred write to iosapic rte to reprogram
+ * intr destination.
+ */
+void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
+{
+ pending_irq_cpumask[irq] = mask_val;
+}
+
void set_irq_affinity_info (unsigned int irq, int hwid, int redir)
{
cpumask_t mask = CPU_MASK_NONE;
diff --git a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c
index e3e2fb75503a5..ab7b3ad99a7fa 100644
--- a/arch/ia64/lib/swiotlb.c
+++ b/arch/ia64/lib/swiotlb.c
@@ -444,7 +444,7 @@ swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir)
/*
* Since DMA is i-cache coherent, any (complete) pages that were written via
- * DMA can be marked as "clean" so that update_mmu_cache() doesn't have to
+ * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to
* flush them when they get mapped into an executable vm-area.
*/
static void
diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c
index 1d46b16764bd6..40ad8328ffd5c 100644
--- a/arch/ia64/mm/hugetlbpage.c
+++ b/arch/ia64/mm/hugetlbpage.c
@@ -73,7 +73,7 @@ set_huge_pte (struct mm_struct *mm, struct vm_area_struct *vma,
{
pte_t entry;
- mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+ add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
if (write_access) {
entry =
pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
@@ -116,7 +116,7 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
ptepage = pte_page(entry);
get_page(ptepage);
set_pte(dst_pte, entry);
- dst->rss += (HPAGE_SIZE / PAGE_SIZE);
+ add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
addr += HPAGE_SIZE;
}
return 0;
@@ -246,7 +246,7 @@ void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, unsig
put_page(page);
pte_clear(mm, address, pte);
}
- mm->rss -= (end - start) >> PAGE_SHIFT;
+ add_mm_counter(mm, rss, - ((end - start) >> PAGE_SHIFT));
flush_tlb_range(vma, start, end);
}
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index df0f1211517a8..65cf839573ea8 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -76,7 +76,7 @@ check_pgt_cache (void)
}
void
-update_mmu_cache (struct vm_area_struct *vma, unsigned long vaddr, pte_t pte)
+lazy_mmu_prot_update (pte_t pte)
{
unsigned long addr;
struct page *page;
@@ -85,7 +85,6 @@ update_mmu_cache (struct vm_area_struct *vma, unsigned long vaddr, pte_t pte)
return; /* not an executable page... */
page = pte_page(pte);
- /* don't use VADDR: it may not be mapped on this CPU (or may have just been flushed): */
addr = (unsigned long) page_address(page);
if (test_bit(PG_arch_1, &page->flags))
diff --git a/arch/m32r/boot/compressed/Makefile b/arch/m32r/boot/compressed/Makefile
index 994c9aa04bd38..d908e1d3c07f1 100644
--- a/arch/m32r/boot/compressed/Makefile
+++ b/arch/m32r/boot/compressed/Makefile
@@ -30,7 +30,12 @@ $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
CFLAGS_misc.o += -fpic
+ifdef CONFIG_MMU
LDFLAGS_piggy.o := -r --format binary --oformat elf32-m32r-linux -T
+else
+LDFLAGS_piggy.o := -r --format binary --oformat elf32-m32r -T
+endif
+
OBJCOPYFLAGS += -R .empty_zero_page
$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
diff --git a/arch/m32r/boot/compressed/head.S b/arch/m32r/boot/compressed/head.S
index 10b928ed0f507..07cfd6ad1ae46 100644
--- a/arch/m32r/boot/compressed/head.S
+++ b/arch/m32r/boot/compressed/head.S
@@ -138,6 +138,11 @@ startup:
ldi r0, -1
ldi r1, 0xd0 ; invalidate i-cache, copy back d-cache
stb r1, @r0
+#elif defined(CONFIG_CHIP_M32102)
+ /* Cache flush */
+ ldi r0, -2
+ ldi r1, 0x0100 ; invalidate
+ stb r1, @r0
#else
#error "put your cache flush function, please"
#endif
diff --git a/arch/m32r/boot/compressed/m32r_sio.c b/arch/m32r/boot/compressed/m32r_sio.c
index bdfd1c2839664..bad5475eff90c 100644
--- a/arch/m32r/boot/compressed/m32r_sio.c
+++ b/arch/m32r/boot/compressed/m32r_sio.c
@@ -46,9 +46,14 @@ static void putc(char c)
}
*BOOT_SIO0TXB = c;
}
-#else
+#else /* defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT) */
+#ifdef CONFIG_MMU
#define SIO0STS (volatile unsigned short *)(0xa0efd000 + 14)
#define SIO0TXB (volatile unsigned short *)(0xa0efd000 + 30)
+#else
+#define SIO0STS (volatile unsigned short *)(0x00efd000 + 14)
+#define SIO0TXB (volatile unsigned short *)(0x00efd000 + 30)
+#endif
static void putc(char c)
{
diff --git a/arch/m32r/boot/setup.S b/arch/m32r/boot/setup.S
index 1b95a8b8dc752..5d256434b4ade 100644
--- a/arch/m32r/boot/setup.S
+++ b/arch/m32r/boot/setup.S
@@ -75,6 +75,11 @@ ENTRY(boot)
ldi r1, #0x73 ; cache on (with invalidation)
; ldi r1, #0x00 ; cache off
st r1, @r0
+#elif defined(CONFIG_CHIP_M32102)
+ ldi r0, #-4 ;LDIMM (r0, M32R_MCCR)
+ ldi r1, #0x101 ; cache on (with invalidation)
+; ldi r1, #0x00 ; cache off
+ st r1, @r0
#else
#error unknown chip configuration
#endif
diff --git a/arch/m32r/kernel/entry.S b/arch/m32r/kernel/entry.S
index e71801637083b..dddbf6b5ed2ce 100644
--- a/arch/m32r/kernel/entry.S
+++ b/arch/m32r/kernel/entry.S
@@ -69,16 +69,17 @@
#include <asm/mmu_context.h>
#if !defined(CONFIG_MMU)
-#define sys_madvise sys_ni_syscall
-#define sys_readahead sys_ni_syscall
-#define sys_mprotect sys_ni_syscall
-#define sys_msync sys_ni_syscall
-#define sys_mlock sys_ni_syscall
-#define sys_munlock sys_ni_syscall
-#define sys_mlockall sys_ni_syscall
-#define sys_munlockall sys_ni_syscall
-#define sys_mremap sys_ni_syscall
-#define sys_mincore sys_ni_syscall
+#define sys_madvise sys_ni_syscall
+#define sys_readahead sys_ni_syscall
+#define sys_mprotect sys_ni_syscall
+#define sys_msync sys_ni_syscall
+#define sys_mlock sys_ni_syscall
+#define sys_munlock sys_ni_syscall
+#define sys_mlockall sys_ni_syscall
+#define sys_munlockall sys_ni_syscall
+#define sys_mremap sys_ni_syscall
+#define sys_mincore sys_ni_syscall
+#define sys_remap_file_pages sys_ni_syscall
#endif /* CONFIG_MMU */
#define R4(reg) @reg
diff --git a/arch/m32r/kernel/module.c b/arch/m32r/kernel/module.c
index 2d5c384488bd8..f6a79a016ce01 100644
--- a/arch/m32r/kernel/module.c
+++ b/arch/m32r/kernel/module.c
@@ -14,6 +14,8 @@
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/config.h>
#include <linux/moduleloader.h>
#include <linux/elf.h>
#include <linux/vmalloc.h>
@@ -31,7 +33,11 @@ void *module_alloc(unsigned long size)
{
if (size == 0)
return NULL;
+#ifdef CONFIG_MMU
return vmalloc_exec(size);
+#else
+ return vmalloc(size);
+#endif
}
diff --git a/arch/m32r/kernel/traps.c b/arch/m32r/kernel/traps.c
index 8f9fd2f67e2e2..01922271d17ee 100644
--- a/arch/m32r/kernel/traps.c
+++ b/arch/m32r/kernel/traps.c
@@ -95,8 +95,10 @@ void set_eit_vector_entries(void)
eit_vector[31] = 0xff000000UL;
eit_vector[32] = BRA_INSN(ei_handler, 32);
eit_vector[64] = BRA_INSN(pie_handler, 64);
+#ifdef CONFIG_MMU
eit_vector[68] = BRA_INSN(ace_handler, 68);
eit_vector[72] = BRA_INSN(tme_handler, 72);
+#endif /* CONFIG_MMU */
#ifdef CONFIG_SMP
eit_vector[184] = (unsigned long)smp_reschedule_interrupt;
eit_vector[185] = (unsigned long)smp_invalidate_interrupt;
diff --git a/arch/m32r/mm/cache.c b/arch/m32r/mm/cache.c
index e2dd92d693808..31b0789c19922 100644
--- a/arch/m32r/mm/cache.c
+++ b/arch/m32r/mm/cache.c
@@ -4,8 +4,6 @@
* Copyright (C) 2002 Hirokazu Takata
*/
-/* $Id$ */
-
#include <linux/config.h>
#include <asm/pgtable.h>
@@ -25,8 +23,8 @@
#define MCCR_DCACHE_CBINV (MCCR_CC|MCCR_DIV|MCCR_DCB)
#define CHECK_MCCR(mccr) (mccr = *MCCR)
#elif defined(CONFIG_CHIP_M32102)
-#define MCCR ((volatile unsigned long*)0xfffffffc)
-#define MCCR_IIV (1UL << 8) /* I-cache invalidate */
+#define MCCR ((volatile unsigned char*)0xfffffffe)
+#define MCCR_IIV (1UL << 0) /* I-cache invalidate */
#define MCCR_ICACHE_INV MCCR_IIV
#endif /* CONFIG_CHIP_XNUX2 || CONFIG_CHIP_M32700 */
@@ -65,4 +63,3 @@ void _flush_cache_copyback_all(void)
#endif
}
-
diff --git a/arch/m32r/mm/fault-nommu.c b/arch/m32r/mm/fault-nommu.c
index da267d843acfd..d9d488d782e8a 100644
--- a/arch/m32r/mm/fault-nommu.c
+++ b/arch/m32r/mm/fault-nommu.c
@@ -23,6 +23,7 @@
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/init.h>
+#include <linux/vt_kern.h> /* For unblank_screen() */
#include <asm/m32r.h>
#include <asm/system.h>
diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c
index 7ed86e722698f..5a3c106b40c83 100644
--- a/arch/m68k/atari/stram.c
+++ b/arch/m68k/atari/stram.c
@@ -635,7 +635,7 @@ static inline void unswap_pte(struct vm_area_struct * vma, unsigned long
set_pte(dir, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
swap_free(entry);
get_page(page);
- ++vma->vm_mm->rss;
+ inc_mm_counter(vma->vm_mm, rss);
}
static inline void unswap_pmd(struct vm_area_struct * vma, pmd_t *dir,
diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
index 4bbf1274743f4..4af20cd91f9f7 100644
--- a/arch/mips/kernel/irixelf.c
+++ b/arch/mips/kernel/irixelf.c
@@ -692,7 +692,7 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
/* Do this so that we can load the interpreter, if need be. We will
* change some of these later.
*/
- current->mm->rss = 0;
+ set_mm_counter(current->mm, rss, 0);
setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
current->mm->start_stack = bprm->p;
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index 0f4b55605612f..21b92b9dd0133 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -2,7 +2,9 @@
# Makefile for MIPS-specific library files..
#
-lib-y += csum_partial_copy.o dec_and_lock.o iomap.o memcpy.o promlib.o \
+lib-y += csum_partial_copy.o dec_and_lock.o memcpy.o promlib.o \
strlen_user.o strncpy_user.o strnlen_user.o
+obj-y += iomap.o
+
EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/vr41xx/common/Makefile b/arch/mips/vr41xx/common/Makefile
index 45a1dc6fc12cb..92c11e9bbb3fb 100644
--- a/arch/mips/vr41xx/common/Makefile
+++ b/arch/mips/vr41xx/common/Makefile
@@ -2,7 +2,7 @@
# Makefile for common code of the NEC VR4100 series.
#
-obj-y += bcu.o cmu.o giu.o icu.o init.o int-handler.o ksyms.o pmu.o rtc.o
+obj-y += bcu.o cmu.o giu.o icu.o init.o int-handler.o pmu.o
obj-$(CONFIG_VRC4173) += vrc4173.o
EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/vr41xx/common/ksyms.c b/arch/mips/vr41xx/common/ksyms.c
deleted file mode 100644
index c8c0d0a727d23..0000000000000
--- a/arch/mips/vr41xx/common/ksyms.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * ksyms.c, Export NEC VR4100 series specific functions needed for loadable modules.
- *
- * Copyright (C) 2003 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
- * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <linux/module.h>
-
-#include <asm/vr41xx/vr41xx.h>
-
-EXPORT_SYMBOL(vr41xx_set_rtclong1_cycle);
-EXPORT_SYMBOL(vr41xx_read_rtclong1_counter);
-EXPORT_SYMBOL(vr41xx_set_rtclong2_cycle);
-EXPORT_SYMBOL(vr41xx_read_rtclong2_counter);
-EXPORT_SYMBOL(vr41xx_set_tclock_cycle);
-EXPORT_SYMBOL(vr41xx_read_tclock_counter);
diff --git a/arch/mips/vr41xx/common/rtc.c b/arch/mips/vr41xx/common/rtc.c
deleted file mode 100644
index 07173afe1faf4..0000000000000
--- a/arch/mips/vr41xx/common/rtc.c
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * rtc.c, RTC(has only timer function) routines for NEC VR4100 series.
- *
- * Copyright (C) 2003-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
- *
- * 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/init.h>
-#include <linux/irq.h>
-#include <linux/smp.h>
-#include <linux/types.h>
-
-#include <asm/io.h>
-#include <asm/time.h>
-#include <asm/vr41xx/vr41xx.h>
-
-static uint32_t rtc1_base;
-static uint32_t rtc2_base;
-
-static uint64_t previous_elapsedtime;
-static unsigned int remainder_per_sec;
-static unsigned int cycles_per_sec;
-static unsigned int cycles_per_jiffy;
-static unsigned long epoch_time;
-
-#define CYCLES_PER_JIFFY (CLOCK_TICK_RATE / HZ)
-#define REMAINDER_PER_SEC (CLOCK_TICK_RATE - (CYCLES_PER_JIFFY * HZ))
-#define CYCLES_PER_100USEC ((CLOCK_TICK_RATE + (10000 / 2)) / 10000)
-
-#define ETIMELREG_TYPE1 KSEG1ADDR(0x0b0000c0)
-#define TCLKLREG_TYPE1 KSEG1ADDR(0x0b0001c0)
-
-#define ETIMELREG_TYPE2 KSEG1ADDR(0x0f000100)
-#define TCLKLREG_TYPE2 KSEG1ADDR(0x0f000120)
-
-/* RTC 1 registers */
-#define ETIMELREG 0x00
-#define ETIMEMREG 0x02
-#define ETIMEHREG 0x04
-/* RFU */
-#define ECMPLREG 0x08
-#define ECMPMREG 0x0a
-#define ECMPHREG 0x0c
-/* RFU */
-#define RTCL1LREG 0x10
-#define RTCL1HREG 0x12
-#define RTCL1CNTLREG 0x14
-#define RTCL1CNTHREG 0x16
-#define RTCL2LREG 0x18
-#define RTCL2HREG 0x1a
-#define RTCL2CNTLREG 0x1c
-#define RTCL2CNTHREG 0x1e
-
-/* RTC 2 registers */
-#define TCLKLREG 0x00
-#define TCLKHREG 0x02
-#define TCLKCNTLREG 0x04
-#define TCLKCNTHREG 0x06
-/* RFU */
-#define RTCINTREG 0x1e
- #define TCLOCK_INT 0x08
- #define RTCLONG2_INT 0x04
- #define RTCLONG1_INT 0x02
- #define ELAPSEDTIME_INT 0x01
-
-#define read_rtc1(offset) readw(rtc1_base + (offset))
-#define write_rtc1(val, offset) writew((val), rtc1_base + (offset))
-
-#define read_rtc2(offset) readw(rtc2_base + (offset))
-#define write_rtc2(val, offset) writew((val), rtc2_base + (offset))
-
-static inline uint64_t read_elapsedtime_counter(void)
-{
- uint64_t first, second;
- uint32_t first_mid, first_low;
- uint32_t second_mid, second_low;
-
- do {
- first_low = (uint32_t)read_rtc1(ETIMELREG);
- first_mid = (uint32_t)read_rtc1(ETIMEMREG);
- first = (uint64_t)read_rtc1(ETIMEHREG);
- second_low = (uint32_t)read_rtc1(ETIMELREG);
- second_mid = (uint32_t)read_rtc1(ETIMEMREG);
- second = (uint64_t)read_rtc1(ETIMEHREG);
- } while (first_low != second_low || first_mid != second_mid ||
- first != second);
-
- return (first << 32) | (uint64_t)((first_mid << 16) | first_low);
-}
-
-static inline void write_elapsedtime_counter(uint64_t time)
-{
- write_rtc1((uint16_t)time, ETIMELREG);
- write_rtc1((uint16_t)(time >> 16), ETIMEMREG);
- write_rtc1((uint16_t)(time >> 32), ETIMEHREG);
-}
-
-static inline void write_elapsedtime_compare(uint64_t time)
-{
- write_rtc1((uint16_t)time, ECMPLREG);
- write_rtc1((uint16_t)(time >> 16), ECMPMREG);
- write_rtc1((uint16_t)(time >> 32), ECMPHREG);
-}
-
-void vr41xx_set_rtclong1_cycle(uint32_t cycles)
-{
- write_rtc1((uint16_t)cycles, RTCL1LREG);
- write_rtc1((uint16_t)(cycles >> 16), RTCL1HREG);
-}
-
-uint32_t vr41xx_read_rtclong1_counter(void)
-{
- uint32_t first_high, first_low;
- uint32_t second_high, second_low;
-
- do {
- first_low = (uint32_t)read_rtc1(RTCL1CNTLREG);
- first_high = (uint32_t)read_rtc1(RTCL1CNTHREG);
- second_low = (uint32_t)read_rtc1(RTCL1CNTLREG);
- second_high = (uint32_t)read_rtc1(RTCL1CNTHREG);
- } while (first_low != second_low || first_high != second_high);
-
- return (first_high << 16) | first_low;
-}
-
-void vr41xx_set_rtclong2_cycle(uint32_t cycles)
-{
- write_rtc1((uint16_t)cycles, RTCL2LREG);
- write_rtc1((uint16_t)(cycles >> 16), RTCL2HREG);
-}
-
-uint32_t vr41xx_read_rtclong2_counter(void)
-{
- uint32_t first_high, first_low;
- uint32_t second_high, second_low;
-
- do {
- first_low = (uint32_t)read_rtc1(RTCL2CNTLREG);
- first_high = (uint32_t)read_rtc1(RTCL2CNTHREG);
- second_low = (uint32_t)read_rtc1(RTCL2CNTLREG);
- second_high = (uint32_t)read_rtc1(RTCL2CNTHREG);
- } while (first_low != second_low || first_high != second_high);
-
- return (first_high << 16) | first_low;
-}
-
-void vr41xx_set_tclock_cycle(uint32_t cycles)
-{
- write_rtc2((uint16_t)cycles, TCLKLREG);
- write_rtc2((uint16_t)(cycles >> 16), TCLKHREG);
-}
-
-uint32_t vr41xx_read_tclock_counter(void)
-{
- uint32_t first_high, first_low;
- uint32_t second_high, second_low;
-
- do {
- first_low = (uint32_t)read_rtc2(TCLKCNTLREG);
- first_high = (uint32_t)read_rtc2(TCLKCNTHREG);
- second_low = (uint32_t)read_rtc2(TCLKCNTLREG);
- second_high = (uint32_t)read_rtc2(TCLKCNTHREG);
- } while (first_low != second_low || first_high != second_high);
-
- return (first_high << 16) | first_low;
-}
-
-static void vr41xx_timer_ack(void)
-{
- uint64_t cur;
-
- write_rtc2(ELAPSEDTIME_INT, RTCINTREG);
-
- previous_elapsedtime += (uint64_t)cycles_per_jiffy;
- cycles_per_sec += cycles_per_jiffy;
-
- if (cycles_per_sec >= CLOCK_TICK_RATE) {
- cycles_per_sec = 0;
- remainder_per_sec = REMAINDER_PER_SEC;
- }
-
- cycles_per_jiffy = 0;
-
- do {
- cycles_per_jiffy += CYCLES_PER_JIFFY;
- if (remainder_per_sec > 0) {
- cycles_per_jiffy++;
- remainder_per_sec--;
- }
-
- cur = read_elapsedtime_counter();
- } while (cur >= previous_elapsedtime + (uint64_t)cycles_per_jiffy);
-
- write_elapsedtime_compare(previous_elapsedtime + (uint64_t)cycles_per_jiffy);
-}
-
-static void vr41xx_hpt_init(unsigned int count)
-{
-}
-
-static unsigned int vr41xx_hpt_read(void)
-{
- uint64_t cur;
-
- cur = read_elapsedtime_counter();
-
- return (unsigned int)cur;
-}
-
-static unsigned long vr41xx_gettimeoffset(void)
-{
- uint64_t cur;
- unsigned long gap;
-
- cur = read_elapsedtime_counter();
- gap = (unsigned long)(cur - previous_elapsedtime);
- gap = gap / CYCLES_PER_100USEC * 100; /* usec */
-
- return gap;
-}
-
-static unsigned long vr41xx_get_time(void)
-{
- uint64_t counts;
-
- counts = read_elapsedtime_counter();
- counts >>= 15;
-
- return epoch_time + (unsigned long)counts;
-
-}
-
-static int vr41xx_set_time(unsigned long sec)
-{
- if (sec < epoch_time)
- return -EINVAL;
-
- sec -= epoch_time;
-
- write_elapsedtime_counter((uint64_t)sec << 15);
-
- return 0;
-}
-
-void vr41xx_set_epoch_time(unsigned long time)
-{
- epoch_time = time;
-}
-
-static void __init vr41xx_time_init(void)
-{
- switch (current_cpu_data.cputype) {
- case CPU_VR4111:
- case CPU_VR4121:
- rtc1_base = ETIMELREG_TYPE1;
- rtc2_base = TCLKLREG_TYPE1;
- break;
- case CPU_VR4122:
- case CPU_VR4131:
- case CPU_VR4133:
- rtc1_base = ETIMELREG_TYPE2;
- rtc2_base = TCLKLREG_TYPE2;
- break;
- default:
- panic("Unexpected CPU of NEC VR4100 series");
- break;
- }
-
- mips_timer_ack = vr41xx_timer_ack;
-
- mips_hpt_init = vr41xx_hpt_init;
- mips_hpt_read = vr41xx_hpt_read;
- mips_hpt_frequency = CLOCK_TICK_RATE;
-
- if (epoch_time == 0)
- epoch_time = mktime(1970, 1, 1, 0, 0, 0);
-
- rtc_get_time = vr41xx_get_time;
- rtc_set_time = vr41xx_set_time;
-}
-
-static void __init vr41xx_timer_setup(struct irqaction *irq)
-{
- do_gettimeoffset = vr41xx_gettimeoffset;
-
- remainder_per_sec = REMAINDER_PER_SEC;
- cycles_per_jiffy = CYCLES_PER_JIFFY;
-
- if (remainder_per_sec > 0) {
- cycles_per_jiffy++;
- remainder_per_sec--;
- }
-
- previous_elapsedtime = read_elapsedtime_counter();
- write_elapsedtime_compare(previous_elapsedtime + (uint64_t)cycles_per_jiffy);
- write_rtc2(ELAPSEDTIME_INT, RTCINTREG);
-
- setup_irq(ELAPSEDTIME_IRQ, irq);
-}
-
-static int __init vr41xx_rtc_init(void)
-{
- board_time_init = vr41xx_time_init;
- board_timer_setup = vr41xx_timer_setup;
-
- return 0;
-}
-
-early_initcall(vr41xx_rtc_init);
diff --git a/arch/ppc/8xx_io/cs4218_tdm.c b/arch/ppc/8xx_io/cs4218_tdm.c
index be7cef18d828f..89fe0ceeaa402 100644
--- a/arch/ppc/8xx_io/cs4218_tdm.c
+++ b/arch/ppc/8xx_io/cs4218_tdm.c
@@ -55,7 +55,7 @@ static int irq_installed = 0;
static char **sound_buffers = NULL;
static char **sound_read_buffers = NULL;
-static spinlock_t cs4218_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(cs4218_lock);
/* Local copies of things we put in the control register. Output
* volume, like most codecs is really attenuation.
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index 59fbfc6e932d2..930103cf2b339 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -581,7 +581,6 @@ config SANDPOINT
config RADSTONE_PPC7D
bool "Radstone Technology PPC7D board"
- select MV64360
config ADIR
bool "SBS-Adirondack"
@@ -744,7 +743,7 @@ config PPC_GEN550
depends on SANDPOINT || MCPN765 || SPRUCE || PPLUS || PCORE || \
PRPMC750 || K2 || PRPMC800 || LOPEC || \
(EV64260 && !SERIAL_MPSC) || CHESTNUT || RADSTONE_PPC7D || \
- MPC834x_SYS
+ 83xx
default y
config FORCE
@@ -757,16 +756,11 @@ config GT64260
depends on EV64260 || CPCI690
default y
-config MV64360
+config MV64360 # Really MV64360 & MV64460
bool
- depends on KATANA || RADSTONE_PPC7D || HDPU
+ depends on CHESTNUT || KATANA || RADSTONE_PPC7D || HDPU
default y
-config MV64360
- bool
- depends on CHESTNUT
- default y
-
config MV64X60
bool
depends on (GT64260 || MV64360)
diff --git a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S
index 1917ed5aba7a9..5a7a64e91fc5e 100644
--- a/arch/ppc/kernel/head_8xx.S
+++ b/arch/ppc/kernel/head_8xx.S
@@ -307,7 +307,7 @@ InstructionTLBMiss:
stw r11, 4(r0)
mfspr r10, SPRN_SRR0 /* Get effective address of fault */
DO_8xx_CPU6(0x3780, r3)
- mtspr SPRN_MD_EPN, r1 /* Have to use MD_EPN for walk, MI_EPN can't */
+ mtspr SPRN_MD_EPN, r10 /* Have to use MD_EPN for walk, MI_EPN can't */
mfspr r10, SPRN_M_TWB /* Get level 1 table entry address */
/* If we are faulting a kernel address, we have to use the
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 8d9773e0ef47a..b8f67396ec48d 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -1478,97 +1478,145 @@ pci_resource_to_bus(struct pci_dev *pdev, struct resource *res)
return res->start;
}
-/*
- * Platform support for /proc/bus/pci/X/Y mmap()s,
- * modelled on the sparc64 implementation by Dave Miller.
- * -- paulus.
- */
-/*
- * Adjust vm_pgoff of VMA such that it is the physical page offset
- * corresponding to the 32-bit pci bus offset for DEV requested by the user.
- *
- * Basically, the user finds the base address for his device which he wishes
- * to mmap. They read the 32-bit value from the config space base register,
- * add whatever PAGE_SIZE multiple offset they wish, and feed this into the
- * offset parameter of mmap on /proc/bus/pci/XXX for that device.
- *
- * Returns negative error code on failure, zero on success.
- */
-static __inline__ int
-__pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state)
+static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
+ unsigned long *offset,
+ enum pci_mmap_state mmap_state)
{
- struct pci_controller *hose = (struct pci_controller *) dev->sysdata;
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- unsigned long size = vma->vm_end - vma->vm_start;
- unsigned long base;
- struct resource *res;
- int i;
- int ret = -EINVAL;
+ struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+ unsigned long io_offset = 0;
+ int i, res_bit;
if (hose == 0)
- return -EINVAL; /* should never happen */
- if (offset + size <= offset)
- return -EINVAL;
+ return NULL; /* should never happen */
+ /* If memory, add on the PCI bridge address offset */
if (mmap_state == pci_mmap_mem) {
- /* PCI memory space */
- base = hose->pci_mem_offset;
- for (i = 0; i < 3; ++i) {
- res = &hose->mem_resources[i];
- if (res->flags == 0)
- continue;
- if (offset >= res->start - base
- && offset + size - 1 <= res->end - base) {
- ret = 0;
- break;
- }
- }
- offset += hose->pci_mem_offset;
+ *offset += hose->pci_mem_offset;
+ res_bit = IORESOURCE_MEM;
} else {
- /* PCI I/O space */
- base = (unsigned long)hose->io_base_virt - isa_io_base;
- res = &hose->io_resource;
- if (offset >= res->start - base
- && offset + size - 1 <= res->end - base)
- ret = 0;
- offset += hose->io_base_phys;
+ io_offset = (unsigned long)hose->io_base_virt;
+ *offset += io_offset;
+ res_bit = IORESOURCE_IO;
}
- vma->vm_pgoff = offset >> PAGE_SHIFT;
- return ret;
-}
+ /*
+ * Check that the offset requested corresponds to one of the
+ * resources of the device.
+ */
+ for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+ struct resource *rp = &dev->resource[i];
+ int flags = rp->flags;
-/*
- * Set vm_flags of VMA, as appropriate for this architecture, for a pci device
- * mapping.
- */
-static __inline__ void
-__pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state)
-{
- vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+ /* treat ROM as memory (should be already) */
+ if (i == PCI_ROM_RESOURCE)
+ flags |= IORESOURCE_MEM;
+
+ /* Active and same type? */
+ if ((flags & res_bit) == 0)
+ continue;
+
+ /* In the range of this resource? */
+ if (*offset < (rp->start & PAGE_MASK) || *offset > rp->end)
+ continue;
+
+ /* found it! construct the final physical address */
+ if (mmap_state == pci_mmap_io)
+ *offset += hose->io_base_phys - _IO_BASE;
+ return rp;
+ }
+
+ return NULL;
}
/*
* Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
* device mapping.
*/
-static __inline__ void
-__pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
+static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
+ pgprot_t protection,
+ enum pci_mmap_state mmap_state,
+ int write_combine)
{
- int prot = pgprot_val(vma->vm_page_prot);
+ unsigned long prot = pgprot_val(protection);
+
+ /* Write combine is always 0 on non-memory space mappings. On
+ * memory space, if the user didn't pass 1, we check for a
+ * "prefetchable" resource. This is a bit hackish, but we use
+ * this to workaround the inability of /sysfs to provide a write
+ * combine bit
+ */
+ if (mmap_state != pci_mmap_mem)
+ write_combine = 0;
+ else if (write_combine == 0) {
+ if (rp->flags & IORESOURCE_PREFETCH)
+ write_combine = 1;
+ }
/* XXX would be nice to have a way to ask for write-through */
prot |= _PAGE_NO_CACHE;
- if (!write_combine)
+ if (write_combine)
+ prot &= ~_PAGE_GUARDED;
+ else
prot |= _PAGE_GUARDED;
- vma->vm_page_prot = __pgprot(prot);
+
+ printk("PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
+ prot);
+
+ return __pgprot(prot);
}
/*
+ * This one is used by /dev/mem and fbdev who have no clue about the
+ * PCI device, it tries to find the PCI device first and calls the
+ * above routine
+ */
+pgprot_t pci_phys_mem_access_prot(struct file *file,
+ unsigned long offset,
+ unsigned long size,
+ pgprot_t protection)
+{
+ struct pci_dev *pdev = NULL;
+ struct resource *found = NULL;
+ unsigned long prot = pgprot_val(protection);
+ int i;
+
+ if (page_is_ram(offset >> PAGE_SHIFT))
+ return prot;
+
+ prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+
+ for_each_pci_dev(pdev) {
+ for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+ struct resource *rp = &pdev->resource[i];
+ int flags = rp->flags;
+
+ /* Active and same type? */
+ if ((flags & IORESOURCE_MEM) == 0)
+ continue;
+ /* In the range of this resource? */
+ if (offset < (rp->start & PAGE_MASK) ||
+ offset > rp->end)
+ continue;
+ found = rp;
+ break;
+ }
+ if (found)
+ break;
+ }
+ if (found) {
+ if (found->flags & IORESOURCE_PREFETCH)
+ prot &= ~_PAGE_GUARDED;
+ pci_dev_put(pdev);
+ }
+
+ DBG("non-PCI map for %lx, prot: %lx\n", offset, prot);
+
+ return __pgprot(prot);
+}
+
+
+/*
* Perform the actual remap of the pages for a PCI device mapping, as
* appropriate for this architecture. The region in the process to map
* is described by vm_start and vm_end members of VMA, the base physical
@@ -1582,14 +1630,19 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state,
int write_combine)
{
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ struct resource *rp;
int ret;
- ret = __pci_mmap_make_offset(dev, vma, mmap_state);
- if (ret < 0)
- return ret;
+ rp = __pci_mmap_make_offset(dev, &offset, mmap_state);
+ if (rp == NULL)
+ return -EINVAL;
- __pci_mmap_set_flags(dev, vma, mmap_state);
- __pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
+ vma->vm_pgoff = offset >> PAGE_SHIFT;
+ vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+ vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
+ vma->vm_page_prot,
+ mmap_state, write_combine);
ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
vma->vm_end - vma->vm_start, vma->vm_page_prot);
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 1620ac2a17f48..e97ce635b99e6 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -41,6 +41,10 @@
#include <asm/xmon.h>
#include <asm/ocp.h>
+#if defined(CONFIG_85xx) || defined(CONFIG_83xx)
+#include <asm/ppc_sys.h>
+#endif
+
#if defined CONFIG_KGDB
#include <asm/kgdb.h>
#endif
@@ -246,6 +250,12 @@ int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "bogomips\t: %lu.%02lu\n",
lpj / (500000/HZ), (lpj / (5000/HZ)) % 100);
+#if defined(CONFIG_85xx) || defined(CONFIG_83xx)
+ if (cur_ppc_sys_spec->ppc_sys_name)
+ seq_printf(m, "chipset\t\t: %s\n",
+ cur_ppc_sys_spec->ppc_sys_name);
+#endif
+
#ifdef CONFIG_SMP
seq_printf(m, "\n");
#endif
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 916a181055c77..ed5c7acdca70a 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -412,7 +412,7 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword)
return -EINVAL;
/* Early out if we are an invalid form of lswi */
- if ((instword & INST_STRING_MASK) == INST_LSWX)
+ if ((instword & INST_STRING_MASK) == INST_LSWI)
if ((rA >= rT) || (rT == rA))
return -EINVAL;
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index d1d70a8651d9f..be02a7fec2b73 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -641,3 +641,27 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
}
#endif
}
+
+/*
+ * This is called by /dev/mem to know if a given address has to
+ * be mapped non-cacheable or not
+ */
+int page_is_ram(unsigned long pfn)
+{
+ unsigned long paddr = (pfn << PAGE_SHIFT);
+
+ return paddr < __pa(high_memory);
+}
+
+pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
+ unsigned long size, pgprot_t vma_prot)
+{
+ if (ppc_md.phys_mem_access_prot)
+ return ppc_md.phys_mem_access_prot(file, addr, size, vma_prot);
+
+ if (!page_is_ram(addr >> PAGE_SHIFT))
+ vma_prot = __pgprot(pgprot_val(vma_prot)
+ | _PAGE_GUARDED | _PAGE_NO_CACHE);
+ return vma_prot;
+}
+EXPORT_SYMBOL(phys_mem_access_prot);
diff --git a/arch/ppc/platforms/83xx/Makefile b/arch/ppc/platforms/83xx/Makefile
index ef702e0ea3c6f..eb55341d6a174 100644
--- a/arch/ppc/platforms/83xx/Makefile
+++ b/arch/ppc/platforms/83xx/Makefile
@@ -1,6 +1,4 @@
#
# Makefile for the PowerPC 83xx linux kernel.
#
-obj-$(CONFIG_83xx) += mpc83xx_sys.o mpc83xx_devices.o
-
obj-$(CONFIG_MPC834x_SYS) += mpc834x_sys.o
diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c
index 1260fd932f0a1..b3b0f51979d2b 100644
--- a/arch/ppc/platforms/83xx/mpc834x_sys.c
+++ b/arch/ppc/platforms/83xx/mpc834x_sys.c
@@ -143,7 +143,6 @@ mpc834x_sys_show_cpuinfo(struct seq_file *m)
pvid = mfspr(SPRN_PVR);
svid = mfspr(SPRN_SVR);
- seq_printf(m, "chip\t\t: MPC%s\n", cur_ppc_sys_spec->ppc_sys_name);
seq_printf(m, "Vendor\t\t: Freescale Inc.\n");
seq_printf(m, "Machine\t\t: mpc%s sys\n", cur_ppc_sys_spec->ppc_sys_name);
seq_printf(m, "core clock\t: %d MHz\n"
@@ -243,14 +242,14 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
memset(&p, 0, sizeof (p));
p.iotype = SERIAL_IO_MEM;
- p.membase = (unsigned char __iomem *)immrbar + 0x4500;
+ p.membase = (unsigned char __iomem *)(VIRT_IMMRBAR + 0x4500);
p.uartclk = binfo->bi_busfreq;
gen550_init(0, &p);
memset(&p, 0, sizeof (p));
p.iotype = SERIAL_IO_MEM;
- p.membase = (unsigned char __iomem *)immrbar + 0x4500;
+ p.membase = (unsigned char __iomem *)(VIRT_IMMRBAR + 0x4600);
p.uartclk = binfo->bi_busfreq;
gen550_init(1, &p);
diff --git a/arch/ppc/platforms/85xx/Makefile b/arch/ppc/platforms/85xx/Makefile
index b5161e38652fd..854fbd298ba2a 100644
--- a/arch/ppc/platforms/85xx/Makefile
+++ b/arch/ppc/platforms/85xx/Makefile
@@ -1,8 +1,6 @@
#
# Makefile for the PowerPC 85xx linux kernel.
#
-obj-$(CONFIG_85xx) += mpc85xx_sys.o mpc85xx_devices.o
-
obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads_common.o mpc8540_ads.o
obj-$(CONFIG_MPC8555_CDS) += mpc85xx_cds_common.o
obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads_common.o mpc8560_ads.o
diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
index 7e1e11a1195a0..ba9f9f562c458 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
+++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
@@ -129,7 +129,6 @@ mpc85xx_ads_show_cpuinfo(struct seq_file *m)
pvid = mfspr(SPRN_PVR);
svid = mfspr(SPRN_SVR);
- seq_printf(m, "chip\t\t: MPC%s\n", cur_ppc_sys_spec->ppc_sys_name);
seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
seq_printf(m, "Machine\t\t: mpc%sads\n", cur_ppc_sys_spec->ppc_sys_name);
seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000);
diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
index 59d80b69f7f8a..5e80b9dc4ed4f 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
+++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
@@ -146,7 +146,6 @@ mpc85xx_cds_show_cpuinfo(struct seq_file *m)
pvid = mfspr(SPRN_PVR);
svid = mfspr(SPRN_SVR);
- seq_printf(m, "chip\t\t: MPC%s\n", cur_ppc_sys_spec->ppc_sys_name);
seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
seq_printf(m, "Machine\t\t: CDS - MPC%s (%x)\n", cur_ppc_sys_spec->ppc_sys_name, cadmus[CM_VER]);
seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000);
diff --git a/arch/ppc/platforms/85xx/sbc85xx.c b/arch/ppc/platforms/85xx/sbc85xx.c
index f2f9e73fafed1..2d638c1c1bd6f 100644
--- a/arch/ppc/platforms/85xx/sbc85xx.c
+++ b/arch/ppc/platforms/85xx/sbc85xx.c
@@ -129,7 +129,6 @@ sbc8560_show_cpuinfo(struct seq_file *m)
pvid = mfspr(SPRN_PVR);
svid = mfspr(SPRN_SVR);
- seq_printf(m, "chip\t\t: MPC%s\n", cur_ppc_sys_spec->ppc_sys_name);
seq_printf(m, "Vendor\t\t: Wind River\n");
seq_printf(m, "Machine\t\t: SBC%s\n", cur_ppc_sys_spec->ppc_sys_name);
seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000);
diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/stx_gp3.c
index 3a1986067fdda..6184b533035a1 100644
--- a/arch/ppc/platforms/85xx/stx_gp3.c
+++ b/arch/ppc/platforms/85xx/stx_gp3.c
@@ -268,7 +268,6 @@ gp3_show_cpuinfo(struct seq_file *m)
memsize = total_memory;
- seq_printf(m, "chip\t\t: MPC%s\n", cur_ppc_sys_spec->ppc_sys_name);
seq_printf(m, "Vendor\t\t: RPC Electronics STx \n");
seq_printf(m, "Machine\t\t: GP3 - MPC%s\n", cur_ppc_sys_spec->ppc_sys_name);
seq_printf(m, "bus freq\t: %u.%.6u MHz\n", freq / 1000000,
diff --git a/arch/ppc/platforms/chestnut.h b/arch/ppc/platforms/chestnut.h
index b58f18f720881..0400b2be40ab5 100644
--- a/arch/ppc/platforms/chestnut.h
+++ b/arch/ppc/platforms/chestnut.h
@@ -28,8 +28,8 @@
* 0xffd00000-0xffd00004 - CPLD
* 0xffc00000-0xffc0000f - UART
* 0xffb00000-0xffb07fff - FRAM
- * 0xffa00000-0xffafffff - *** HOLE ***
- * 0xff800000-0xff9fffff - MV64460 Integrated SRAM
+ * 0xff840000-0xffafffff - *** HOLE ***
+ * 0xff800000-0xff83ffff - MV64460 Integrated SRAM
* 0xfe000000-0xff8fffff - *** HOLE ***
* 0xfc000000-0xfdffffff - 32bit Flash
* 0xf1010000-0xfbffffff - *** HOLE ***
diff --git a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c
index 163df2adf38a2..f23c4f3207605 100644
--- a/arch/ppc/platforms/chrp_setup.c
+++ b/arch/ppc/platforms/chrp_setup.c
@@ -527,6 +527,8 @@ chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.init = chrp_init2;
+ ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
+
ppc_md.restart = chrp_restart;
ppc_md.power_off = chrp_power_off;
ppc_md.halt = chrp_halt;
diff --git a/arch/ppc/platforms/hdpu.c b/arch/ppc/platforms/hdpu.c
index b6254cba8e9df..b659d7b3d7477 100644
--- a/arch/ppc/platforms/hdpu.c
+++ b/arch/ppc/platforms/hdpu.c
@@ -57,7 +57,6 @@ static void parse_bootinfo(unsigned long r3,
unsigned long r6, unsigned long r7);
static void hdpu_set_l1pe(void);
static void hdpu_cpustate_set(unsigned char new_state);
-static void hdpu_cpustate_set(unsigned char new_state);
#ifdef CONFIG_SMP
static spinlock_t timebase_lock = SPIN_LOCK_UNLOCKED;
static unsigned int timebase_upper = 0, timebase_lower = 0;
@@ -252,8 +251,6 @@ static void __init hdpu_setup_bridge(void)
MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
#endif
}
- hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_INIT_PCI);
-
hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_INIT_PCI);
@@ -262,7 +259,17 @@ static void __init hdpu_setup_bridge(void)
pci_dram_offset = 0; /* System mem at same addr on PCI & cpu bus */
ppc_md.pci_swizzle = common_swizzle;
ppc_md.pci_map_irq = hdpu_map_irq;
- hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_INIT_REG);
+
+ mv64x60_set_bus(&bh, 0, 0);
+ bh.hose_a->first_busno = 0;
+ bh.hose_a->last_busno = 0xff;
+ bh.hose_a->last_busno = pciauto_bus_scan(bh.hose_a, 0);
+
+ bh.hose_b->first_busno = bh.hose_a->last_busno + 1;
+ mv64x60_set_bus(&bh, 1, bh.hose_b->first_busno);
+ bh.hose_b->last_busno = 0xff;
+ bh.hose_b->last_busno = pciauto_bus_scan(bh.hose_b,
+ bh.hose_b->first_busno);
ppc_md.pci_exclude_device = mv64x60_pci_exclude_device;
@@ -333,6 +340,10 @@ static void __init hdpu_fixup_mpsc_pdata(struct platform_device *pd)
pdata->default_baud = ppcboot_bd.bi_baudrate;
else
pdata->default_baud = HDPU_DEFAULT_BAUD;
+ pdata->brg_clk_src = HDPU_MPSC_CLK_SRC;
+ pdata->brg_clk_freq = HDPU_MPSC_CLK_FREQ;
+}
+
#if defined(CONFIG_HDPU_FEATURES)
static void __init hdpu_fixup_cpustate_pdata(struct platform_device *pd)
{
@@ -342,10 +353,6 @@ static void __init hdpu_fixup_cpustate_pdata(struct platform_device *pd)
}
#endif
- pdata->brg_clk_src = HDPU_MPSC_CLK_SRC;
- pdata->brg_clk_freq = HDPU_MPSC_CLK_FREQ;
-}
-
static int __init hdpu_platform_notify(struct device *dev)
{
static struct {
@@ -354,14 +361,14 @@ static int __init hdpu_platform_notify(struct device *dev)
} dev_map[] = {
{
MPSC_CTLR_NAME ".0", hdpu_fixup_mpsc_pdata},
-#if defined(CONFIG_HDPU_FEATURES)
- {
- HDPU_CPUSTATE_NAME ".0", hdpu_fixup_cpustate_pdata},
-#endif
#if defined(CONFIG_MV643XX_ETH)
{
MV643XX_ETH_NAME ".0", hdpu_fixup_eth_pdata},
#endif
+#if defined(CONFIG_HDPU_FEATURES)
+ {
+ HDPU_CPUSTATE_NAME ".0", hdpu_fixup_cpustate_pdata},
+#endif
};
struct platform_device *pdev;
int i;
@@ -421,7 +428,6 @@ static void __init hdpu_setup_arch(void)
#endif
printk("SKY HDPU Compute Blade \n");
- hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_OK);
if (ppc_md.progress)
ppc_md.progress("hdpu_setup_arch: exit", 0);
@@ -460,8 +466,6 @@ unsigned long __init hdpu_find_end_of_memory(void)
return mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE,
MV64x60_TYPE_MV64360);
}
- hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_RESET);
-
static void hdpu_reset_board(void)
{
@@ -506,8 +510,6 @@ static void hdpu_restart(char *cmd)
hdpu_reset_board();
while (i-- > 0) ;
- hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_HALT);
-
panic("restart failed\n");
}
@@ -776,8 +778,6 @@ smp_hdpu_message_pass(int target, int msg, unsigned long data, int wait)
mv64x60_write(&bh, MV64360_CPU1_DOORBELL, 1 << msg);
break;
}
- hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_CPU1_KICK);
-
}
static void smp_hdpu_kick_cpu(int nr)
@@ -842,9 +842,6 @@ static void smp_hdpu_setup_cpu(int cpu_nr)
{
if (cpu_nr == 0) {
if (ppc_md.progress)
- hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR |
- CPUSTATE_KERNEL_CPU1_OK);
-
ppc_md.progress("smp_hdpu_setup_cpu 0", 0);
mv64x60_write(&bh, MV64360_CPU0_DOORBELL_CLR, 0xff);
mv64x60_write(&bh, MV64360_CPU0_DOORBELL_MASK, 0xff);
@@ -959,13 +956,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
platform_notify = hdpu_platform_notify;
#endif
return;
-static void hdpu_cpustate_set(unsigned char new_state)
-{
- unsigned int state = (new_state << 21);
- mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, (0xff << 21));
- mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, state);
-}
-
}
#if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE)
@@ -1006,6 +996,27 @@ static struct mtd_partition hdpu_partitions[] = {
.mask_flags = 0,
},{
.name = "bootEnv",
+ .size = 0x00040000,
+ .offset = 0x03EC0000,
+ .mask_flags = 0,
+ },{
+ .name = "bootROM",
+ .size = 0x00100000,
+ .offset = 0x03F00000,
+ .mask_flags = 0,
+ }
+};
+
+static int __init hdpu_setup_mtd(void)
+{
+
+ physmap_set_partitions(hdpu_partitions, 5);
+ return 0;
+}
+
+arch_initcall(hdpu_setup_mtd);
+#endif
+
#ifdef CONFIG_HDPU_FEATURES
static struct resource hdpu_cpustate_resources[] = {
@@ -1049,24 +1060,3 @@ static int __init hdpu_add_pds(void)
arch_initcall(hdpu_add_pds);
#endif
- .size = 0x00040000,
- .offset = 0x03EC0000,
- .mask_flags = 0,
- },{
- .name = "bootROM",
- .size = 0x00100000,
- .offset = 0x03F00000,
- .mask_flags = 0,
- }
-};
-
-static int __init hdpu_setup_mtd(void)
-{
-
- physmap_set_partitions(hdpu_partitions, 5);
- return 0;
-}
-
-arch_initcall(hdpu_setup_mtd);
-#endif
-
diff --git a/arch/ppc/platforms/katana.h b/arch/ppc/platforms/katana.h
index e96f6a1efb4e7..b82ed81950f59 100644
--- a/arch/ppc/platforms/katana.h
+++ b/arch/ppc/platforms/katana.h
@@ -24,7 +24,7 @@
* on a boundary that is a multiple of the window size):
*
* 0xff800000-0xffffffff - Boot window
- * 0xf8400000-0xf85fffff - Internal SRAM
+ * 0xf8400000-0xf843ffff - Internal SRAM
* 0xf8200000-0xf83fffff - CPLD
* 0xf8100000-0xf810ffff - MV64360 Registers (CONFIG_MV64X60_NEW_BASE)
* 0xf8000000-0xf80fffff - Socketed FLASH
diff --git a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c
index 7bc024c47e54f..4d324b630f4f8 100644
--- a/arch/ppc/platforms/pmac_setup.c
+++ b/arch/ppc/platforms/pmac_setup.c
@@ -669,6 +669,7 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.pcibios_fixup = pmac_pcibios_fixup;
ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook;
ppc_md.pcibios_after_init = pmac_pcibios_after_init;
+ ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
ppc_md.restart = pmac_restart;
ppc_md.power_off = pmac_power_off;
diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
index 67d74b7080fe1..bc926be95472f 100644
--- a/arch/ppc/platforms/prep_setup.c
+++ b/arch/ppc/platforms/prep_setup.c
@@ -1144,6 +1144,8 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
/* this gets changed later on if we have an OpenPIC -- Cort */
ppc_md.get_irq = i8259_irq;
+ ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
+
ppc_md.restart = prep_restart;
ppc_md.power_off = NULL; /* set in prep_setup_arch() */
ppc_md.halt = prep_halt;
diff --git a/arch/ppc/platforms/sandpoint.c b/arch/ppc/platforms/sandpoint.c
index 8674b8761167f..531bfa0e45121 100644
--- a/arch/ppc/platforms/sandpoint.c
+++ b/arch/ppc/platforms/sandpoint.c
@@ -202,13 +202,6 @@ sandpoint_setup_winbond_83553(struct pci_controller *hose)
0x48, /* ISA-to-PCI Addr Decoder Control */
0xf0);
- /* Enable RTC and Keyboard address locations. */
- early_write_config_byte(hose,
- 0,
- devfn,
- 0x4d, /* Chip Select Control Register */
- 0x00);
-
/* Enable Port 92. */
early_write_config_byte(hose,
0,
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
index a0bc6e4f83192..830d00da5db0b 100644
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -97,11 +97,13 @@ obj-$(CONFIG_MPC10X_OPENPIC) += open_pic.o
obj-$(CONFIG_40x) += dcr.o
obj-$(CONFIG_BOOKE) += dcr.o
obj-$(CONFIG_85xx) += open_pic.o ppc85xx_common.o ppc85xx_setup.o \
- ppc_sys.o
+ ppc_sys.o mpc85xx_sys.o \
+ mpc85xx_devices.o
ifeq ($(CONFIG_85xx),y)
obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o
endif
-obj-$(CONFIG_83xx) += ipic.o ppc83xx_setup.o ppc_sys.o
+obj-$(CONFIG_83xx) += ipic.o ppc83xx_setup.o ppc_sys.o \
+ mpc83xx_sys.o mpc83xx_devices.o
ifeq ($(CONFIG_83xx),y)
obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o
endif
diff --git a/arch/ppc/platforms/83xx/mpc83xx_devices.c b/arch/ppc/syslib/mpc83xx_devices.c
index 5c1a919eaabfb..5c1a919eaabfb 100644
--- a/arch/ppc/platforms/83xx/mpc83xx_devices.c
+++ b/arch/ppc/syslib/mpc83xx_devices.c
diff --git a/arch/ppc/platforms/83xx/mpc83xx_sys.c b/arch/ppc/syslib/mpc83xx_sys.c
index 29aa63350025c..29aa63350025c 100644
--- a/arch/ppc/platforms/83xx/mpc83xx_sys.c
+++ b/arch/ppc/syslib/mpc83xx_sys.c
diff --git a/arch/ppc/platforms/85xx/mpc85xx_devices.c b/arch/ppc/syslib/mpc85xx_devices.c
index a231795ee26f0..a231795ee26f0 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_devices.c
+++ b/arch/ppc/syslib/mpc85xx_devices.c
diff --git a/arch/ppc/platforms/85xx/mpc85xx_sys.c b/arch/ppc/syslib/mpc85xx_sys.c
index 389c509d85823..389c509d85823 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_sys.c
+++ b/arch/ppc/syslib/mpc85xx_sys.c
diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
index c90ba29fab703..fe05f3fbf9d05 100644
--- a/arch/ppc64/kernel/head.S
+++ b/arch/ppc64/kernel/head.S
@@ -37,6 +37,7 @@
#include <asm/bug.h>
#include <asm/cputable.h>
#include <asm/setup.h>
+#include <asm/hvcall.h>
#ifdef CONFIG_PPC_ISERIES
#define DO_SOFT_DISABLE
@@ -45,7 +46,6 @@
/*
* hcall interface to pSeries LPAR
*/
-#define HVSC .long 0x44000022
#define H_SET_ASR 0x30
/*
diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
index 306e1879ad787..90b41f48d21c0 100644
--- a/arch/ppc64/kernel/misc.S
+++ b/arch/ppc64/kernel/misc.S
@@ -680,10 +680,6 @@ _GLOBAL(kernel_thread)
ld r30,-16(r1)
blr
-#ifdef CONFIG_PPC_RTAS /* hack hack hack */
-#define ppc_rtas sys_ni_syscall
-#endif
-
/* Why isn't this a) automatic, b) written in 'C'? */
.balign 8
_GLOBAL(sys_call_table32)
diff --git a/arch/ppc64/kernel/pSeries_hvCall.S b/arch/ppc64/kernel/pSeries_hvCall.S
index df604cfcf9d4b..0715d30380199 100644
--- a/arch/ppc64/kernel/pSeries_hvCall.S
+++ b/arch/ppc64/kernel/pSeries_hvCall.S
@@ -1,7 +1,6 @@
/*
* arch/ppc64/kernel/pSeries_hvCall.S
*
- *
* This file contains the generic code to perform a call to the
* pSeries LPAR hypervisor.
* NOTE: this file will go away when we move to inline this work.
@@ -11,133 +10,114 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/sys.h>
-#include <asm/unistd.h>
-#include <asm/errno.h>
+#include <asm/hvcall.h>
#include <asm/processor.h>
-#include <asm/page.h>
-#include <asm/cache.h>
#include <asm/ppc_asm.h>
-/*
- * hcall interface to pSeries LPAR
- */
-#define HVSC .long 0x44000022
-
-/* long plpar_hcall(unsigned long opcode, R3
- unsigned long arg1, R4
- unsigned long arg2, R5
- unsigned long arg3, R6
- unsigned long arg4, R7
- unsigned long *out1, R8
- unsigned long *out2, R9
- unsigned long *out3); R10
- */
+#define STK_PARM(i) (48 + ((i)-3)*8)
.text
+
+/* long plpar_hcall(unsigned long opcode, R3
+ unsigned long arg1, R4
+ unsigned long arg2, R5
+ unsigned long arg3, R6
+ unsigned long arg4, R7
+ unsigned long *out1, R8
+ unsigned long *out2, R9
+ unsigned long *out3); R10
+ */
_GLOBAL(plpar_hcall)
mfcr r0
- std r0,-8(r1)
- stdu r1,-32(r1)
- std r8,-8(r1) /* Save out ptrs. */
- std r9,-16(r1)
- std r10,-24(r1)
-
- HVSC /* invoke the hypervisor */
+ std r8,STK_PARM(r8)(r1) /* Save out ptrs */
+ std r9,STK_PARM(r9)(r1)
+ std r10,STK_PARM(r10)(r1)
- ld r10,-8(r1) /* Fetch r4-r7 ret args. */
- std r4,0(r10)
- ld r10,-16(r1)
- std r5,0(r10)
- ld r10,-24(r1)
- std r6,0(r10)
+ stw r0,8(r1)
+
+ HVSC /* invoke the hypervisor */
+
+ lwz r0,8(r1)
+
+ ld r8,STK_PARM(r8)(r1) /* Fetch r4-r6 ret args */
+ ld r9,STK_PARM(r9)(r1)
+ ld r10,STK_PARM(r10)(r1)
+ std r4,0(r8)
+ std r5,0(r9)
+ std r6,0(r10)
- ld r1,0(r1)
- ld r0,-8(r1)
mtcrf 0xff,r0
- blr /* return r3 = status */
+ blr /* return r3 = status */
/* Simple interface with no output values (other than status) */
_GLOBAL(plpar_hcall_norets)
mfcr r0
- std r0,-8(r1)
- HVSC /* invoke the hypervisor */
- ld r0,-8(r1)
- mtcrf 0xff,r0
- blr /* return r3 = status */
-
+ stw r0,8(r1)
-/* long plpar_hcall_8arg_2ret(unsigned long opcode, R3
- unsigned long arg1, R4
- unsigned long arg2, R5
- unsigned long arg3, R6
- unsigned long arg4, R7
- unsigned long arg5, R8
- unsigned long arg6, R9
- unsigned long arg7, R10
- unsigned long arg8, 112(R1)
- unsigned long *out1); 120(R1)
+ HVSC /* invoke the hypervisor */
+ lwz r0,8(r1)
+ mtcrf 0xff,r0
+ blr /* return r3 = status */
+
+
+/* long plpar_hcall_8arg_2ret(unsigned long opcode, R3
+ unsigned long arg1, R4
+ unsigned long arg2, R5
+ unsigned long arg3, R6
+ unsigned long arg4, R7
+ unsigned long arg5, R8
+ unsigned long arg6, R9
+ unsigned long arg7, R10
+ unsigned long arg8, 112(R1)
+ unsigned long *out1); 120(R1)
*/
-
- .text
_GLOBAL(plpar_hcall_8arg_2ret)
mfcr r0
+ ld r11,STK_PARM(r11)(r1) /* put arg8 in R11 */
+ stw r0,8(r1)
- ld r11, 112(r1) /* put arg8 and out1 in R11 and R12 */
- ld r12, 120(r1)
-
- std r0,-8(r1)
- stdu r1,-32(r1)
-
- std r12,-8(r1) /* Save out ptr */
-
- HVSC /* invoke the hypervisor */
-
- ld r10,-8(r1) /* Fetch r4 ret arg */
- std r4,0(r10)
+ HVSC /* invoke the hypervisor */
- ld r1,0(r1)
- ld r0,-8(r1)
+ lwz r0,8(r1)
+ ld r10,STK_PARM(r12)(r1) /* Fetch r4 ret arg */
+ std r4,0(r10)
mtcrf 0xff,r0
- blr /* return r3 = status */
-
-
-/* long plpar_hcall_4out(unsigned long opcode, R3
- unsigned long arg1, R4
- unsigned long arg2, R5
- unsigned long arg3, R6
- unsigned long arg4, R7
- unsigned long *out1, (r4) R8
- unsigned long *out2, (r5) R9
- unsigned long *out3, (r6) R10
- unsigned long *out4); (r7) 112(R1). From Parameter save area.
+ blr /* return r3 = status */
+
+
+/* long plpar_hcall_4out(unsigned long opcode, R3
+ unsigned long arg1, R4
+ unsigned long arg2, R5
+ unsigned long arg3, R6
+ unsigned long arg4, R7
+ unsigned long *out1, R8
+ unsigned long *out2, R9
+ unsigned long *out3, R10
+ unsigned long *out4); 112(R1)
*/
_GLOBAL(plpar_hcall_4out)
mfcr r0
- std r0,-8(r1)
- ld r14,112(r1)
- stdu r1,-48(r1)
-
- std r8,32(r1) /* Save out ptrs. */
- std r9,24(r1)
- std r10,16(r1)
- std r14,8(r1)
-
- HVSC /* invoke the hypervisor */
-
- ld r14,32(r1) /* Fetch r4-r7 ret args. */
- std r4,0(r14)
- ld r14,24(r1)
- std r5,0(r14)
- ld r14,16(r1)
- std r6,0(r14)
- ld r14,8(r1)
- std r7,0(r14)
-
- ld r1,0(r1)
- ld r0,-8(r1)
+ stw r0,8(r1)
+
+ std r8,STK_PARM(r8)(r1) /* Save out ptrs */
+ std r9,STK_PARM(r9)(r1)
+ std r10,STK_PARM(r10)(r1)
+
+ HVSC /* invoke the hypervisor */
+
+ lwz r0,8(r1)
+
+ ld r8,STK_PARM(r8)(r1) /* Fetch r4-r7 ret args */
+ ld r9,STK_PARM(r9)(r1)
+ ld r10,STK_PARM(r10)(r1)
+ ld r11,STK_PARM(r11)(r1)
+ std r4,0(r8)
+ std r5,0(r9)
+ std r6,0(r10)
+ std r7,0(r11)
+
mtcrf 0xff,r0
- blr /* return r3 = status */
+ blr /* return r3 = status */
diff --git a/arch/ppc64/kernel/pSeries_iommu.c b/arch/ppc64/kernel/pSeries_iommu.c
index 5543aaa568e79..69130522a87e1 100644
--- a/arch/ppc64/kernel/pSeries_iommu.c
+++ b/arch/ppc64/kernel/pSeries_iommu.c
@@ -43,6 +43,7 @@
#include <asm/machdep.h>
#include <asm/abs_addr.h>
#include <asm/plpar_wrappers.h>
+#include <asm/pSeries_reconfig.h>
#include <asm/systemcfg.h>
#include "pci.h"
@@ -401,6 +402,8 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus)
struct device_node *dn, *pdn;
unsigned int *dma_window = NULL;
+ DBG("iommu_bus_setup_pSeriesLP, bus %p, bus->self %p\n", bus, bus->self);
+
dn = pci_bus_to_OF_node(bus);
/* Find nearest ibm,dma-window, walking up the device tree */
@@ -455,6 +458,78 @@ static void iommu_dev_setup_pSeries(struct pci_dev *dev)
}
}
+static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
+{
+ int err = NOTIFY_OK;
+ struct device_node *np = node;
+
+ switch (action) {
+ case PSERIES_RECONFIG_REMOVE:
+ if (np->iommu_table &&
+ get_property(np, "ibm,dma-window", NULL))
+ iommu_free_table(np);
+ break;
+ default:
+ err = NOTIFY_DONE;
+ break;
+ }
+ return err;
+}
+
+static struct notifier_block iommu_reconfig_nb = {
+ .notifier_call = iommu_reconfig_notifier,
+};
+
+static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
+{
+ struct device_node *pdn, *dn;
+ struct iommu_table *tbl;
+ int *dma_window = NULL;
+
+ DBG("iommu_dev_setup_pSeriesLP, dev %p (%s)\n", dev, dev->pretty_name);
+
+ /* dev setup for LPAR is a little tricky, since the device tree might
+ * contain the dma-window properties per-device and not neccesarily
+ * for the bus. So we need to search upwards in the tree until we
+ * either hit a dma-window property, OR find a parent with a table
+ * already allocated.
+ */
+ dn = pci_device_to_OF_node(dev);
+
+ for (pdn = dn; pdn && !pdn->iommu_table; pdn = pdn->parent) {
+ dma_window = (unsigned int *)get_property(pdn, "ibm,dma-window", NULL);
+ if (dma_window)
+ break;
+ }
+
+ /* Check for parent == NULL so we don't try to setup the empty EADS
+ * slots on POWER4 machines.
+ */
+ if (dma_window == NULL || pdn->parent == NULL) {
+ /* Fall back to regular (non-LPAR) dev setup */
+ DBG("No dma window for device, falling back to regular setup\n");
+ iommu_dev_setup_pSeries(dev);
+ return;
+ } else {
+ DBG("Found DMA window, allocating table\n");
+ }
+
+ if (!pdn->iommu_table) {
+ /* iommu_table_setparms_lpar needs bussubno. */
+ pdn->bussubno = pdn->phb->bus->number;
+
+ tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table),
+ GFP_KERNEL);
+
+ iommu_table_setparms_lpar(pdn->phb, pdn, tbl, dma_window);
+
+ pdn->iommu_table = iommu_init_table(tbl);
+ }
+
+ if (pdn != dn)
+ dn->iommu_table = pdn->iommu_table;
+}
+
static void iommu_bus_setup_null(struct pci_bus *b) { }
static void iommu_dev_setup_null(struct pci_dev *d) { }
@@ -479,13 +554,16 @@ void iommu_init_early_pSeries(void)
ppc_md.tce_free = tce_free_pSeriesLP;
}
ppc_md.iommu_bus_setup = iommu_bus_setup_pSeriesLP;
+ ppc_md.iommu_dev_setup = iommu_dev_setup_pSeriesLP;
} else {
ppc_md.tce_build = tce_build_pSeries;
ppc_md.tce_free = tce_free_pSeries;
ppc_md.iommu_bus_setup = iommu_bus_setup_pSeries;
+ ppc_md.iommu_dev_setup = iommu_dev_setup_pSeries;
}
- ppc_md.iommu_dev_setup = iommu_dev_setup_pSeries;
+
+ pSeries_reconfig_notifier_register(&iommu_reconfig_nb);
pci_iommu_init();
}
diff --git a/arch/ppc64/kernel/pSeries_reconfig.c b/arch/ppc64/kernel/pSeries_reconfig.c
index 153b1ff543b72..cb5443f2e49b8 100644
--- a/arch/ppc64/kernel/pSeries_reconfig.c
+++ b/arch/ppc64/kernel/pSeries_reconfig.c
@@ -164,16 +164,6 @@ out_err:
return err;
}
-/*
- * Prepare an OF node for removal from system
- * XXX move this to pSeries_iommu.c
- */
-static void of_cleanup_node(struct device_node *np)
-{
- if (np->iommu_table && get_property(np, "ibm,dma-window", NULL))
- iommu_free_table(np);
-}
-
static int pSeries_reconfig_remove_node(struct device_node *np)
{
struct device_node *parent, *child;
@@ -187,8 +177,6 @@ static int pSeries_reconfig_remove_node(struct device_node *np)
return -EBUSY;
}
- of_cleanup_node(np);
-
remove_node_proc_entries(np);
notifier_call_chain(&pSeries_reconfig_chain,
diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c
index 25b29e8104c09..fdd8f7869a68d 100644
--- a/arch/ppc64/kernel/pci.c
+++ b/arch/ppc64/kernel/pci.c
@@ -210,6 +210,11 @@ static int __init pcibios_init(void)
struct pci_controller *hose, *tmp;
struct pci_bus *bus;
+ /* For now, override phys_mem_access_prot. If we need it,
+ * later, we may move that initialization to each ppc_md
+ */
+ ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
+
#ifdef CONFIG_PPC_ISERIES
iSeries_pcibios_init();
#endif
@@ -330,25 +335,24 @@ int pci_proc_domain(struct pci_bus *bus)
*
* Returns negative error code on failure, zero on success.
*/
-static __inline__ int __pci_mmap_make_offset(struct pci_dev *dev,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state)
+static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
+ unsigned long *offset,
+ enum pci_mmap_state mmap_state)
{
struct pci_controller *hose = pci_bus_to_host(dev->bus);
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long io_offset = 0;
int i, res_bit;
if (hose == 0)
- return -EINVAL; /* should never happen */
+ return NULL; /* should never happen */
/* If memory, add on the PCI bridge address offset */
if (mmap_state == pci_mmap_mem) {
- offset += hose->pci_mem_offset;
+ *offset += hose->pci_mem_offset;
res_bit = IORESOURCE_MEM;
} else {
io_offset = (unsigned long)hose->io_base_virt;
- offset += io_offset;
+ *offset += io_offset;
res_bit = IORESOURCE_IO;
}
@@ -369,50 +373,106 @@ static __inline__ int __pci_mmap_make_offset(struct pci_dev *dev,
continue;
/* In the range of this resource? */
- if (offset < (rp->start & PAGE_MASK) || offset > rp->end)
+ if (*offset < (rp->start & PAGE_MASK) || *offset > rp->end)
continue;
/* found it! construct the final physical address */
if (mmap_state == pci_mmap_io)
- offset += hose->io_base_phys - io_offset;
-
- vma->vm_pgoff = offset >> PAGE_SHIFT;
- return 0;
+ *offset += hose->io_base_phys - io_offset;
+ return rp;
}
- return -EINVAL;
-}
-
-/*
- * Set vm_flags of VMA, as appropriate for this architecture, for a pci device
- * mapping.
- */
-static __inline__ void __pci_mmap_set_flags(struct pci_dev *dev,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state)
-{
- vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+ return NULL;
}
/*
* Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
* device mapping.
*/
-static __inline__ void __pci_mmap_set_pgprot(struct pci_dev *dev,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state,
- int write_combine)
+static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
+ pgprot_t protection,
+ enum pci_mmap_state mmap_state,
+ int write_combine)
{
- long prot = pgprot_val(vma->vm_page_prot);
+ unsigned long prot = pgprot_val(protection);
+
+ /* Write combine is always 0 on non-memory space mappings. On
+ * memory space, if the user didn't pass 1, we check for a
+ * "prefetchable" resource. This is a bit hackish, but we use
+ * this to workaround the inability of /sysfs to provide a write
+ * combine bit
+ */
+ if (mmap_state != pci_mmap_mem)
+ write_combine = 0;
+ else if (write_combine == 0) {
+ if (rp->flags & IORESOURCE_PREFETCH)
+ write_combine = 1;
+ }
/* XXX would be nice to have a way to ask for write-through */
prot |= _PAGE_NO_CACHE;
- if (!write_combine)
+ if (write_combine)
+ prot &= ~_PAGE_GUARDED;
+ else
prot |= _PAGE_GUARDED;
- vma->vm_page_prot = __pgprot(prot);
+
+ printk("PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
+ prot);
+
+ return __pgprot(prot);
}
/*
+ * This one is used by /dev/mem and fbdev who have no clue about the
+ * PCI device, it tries to find the PCI device first and calls the
+ * above routine
+ */
+pgprot_t pci_phys_mem_access_prot(struct file *file,
+ unsigned long offset,
+ unsigned long size,
+ pgprot_t protection)
+{
+ struct pci_dev *pdev = NULL;
+ struct resource *found = NULL;
+ unsigned long prot = pgprot_val(protection);
+ int i;
+
+ if (page_is_ram(offset >> PAGE_SHIFT))
+ return prot;
+
+ prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+
+ for_each_pci_dev(pdev) {
+ for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+ struct resource *rp = &pdev->resource[i];
+ int flags = rp->flags;
+
+ /* Active and same type? */
+ if ((flags & IORESOURCE_MEM) == 0)
+ continue;
+ /* In the range of this resource? */
+ if (offset < (rp->start & PAGE_MASK) ||
+ offset > rp->end)
+ continue;
+ found = rp;
+ break;
+ }
+ if (found)
+ break;
+ }
+ if (found) {
+ if (found->flags & IORESOURCE_PREFETCH)
+ prot &= ~_PAGE_GUARDED;
+ pci_dev_put(pdev);
+ }
+
+ DBG("non-PCI map for %lx, prot: %lx\n", offset, prot);
+
+ return __pgprot(prot);
+}
+
+
+/*
* Perform the actual remap of the pages for a PCI device mapping, as
* appropriate for this architecture. The region in the process to map
* is described by vm_start and vm_end members of VMA, the base physical
@@ -426,14 +486,19 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state,
int write_combine)
{
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ struct resource *rp;
int ret;
- ret = __pci_mmap_make_offset(dev, vma, mmap_state);
- if (ret < 0)
- return ret;
+ rp = __pci_mmap_make_offset(dev, &offset, mmap_state);
+ if (rp == NULL)
+ return -EINVAL;
- __pci_mmap_set_flags(dev, vma, mmap_state);
- __pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
+ vma->vm_pgoff = offset >> PAGE_SHIFT;
+ vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+ vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
+ vma->vm_page_prot,
+ mmap_state, write_combine);
ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
vma->vm_end - vma->vm_start, vma->vm_page_prot);
diff --git a/arch/ppc64/kernel/pci_dn.c b/arch/ppc64/kernel/pci_dn.c
index df1e21430d032..ec345462afc3f 100644
--- a/arch/ppc64/kernel/pci_dn.c
+++ b/arch/ppc64/kernel/pci_dn.c
@@ -27,6 +27,7 @@
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
+#include <asm/pSeries_reconfig.h>
#include "pci.h"
@@ -161,6 +162,25 @@ struct device_node *fetch_dev_dn(struct pci_dev *dev)
}
EXPORT_SYMBOL(fetch_dev_dn);
+static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
+{
+ struct device_node *np = node;
+ int err = NOTIFY_OK;
+
+ switch (action) {
+ case PSERIES_RECONFIG_ADD:
+ update_dn_pci_info(np, np->parent->phb);
+ break;
+ default:
+ err = NOTIFY_DONE;
+ break;
+ }
+ return err;
+}
+
+static struct notifier_block pci_dn_reconfig_nb = {
+ .notifier_call = pci_dn_reconfig_notifier,
+};
/*
* Actually initialize the phbs.
@@ -173,4 +193,6 @@ void __init pci_devs_phb_init(void)
/* This must be done first so the device nodes have valid pci info! */
list_for_each_entry_safe(phb, tmp, &hose_list, list_node)
pci_devs_phb_init_dynamic(phb);
+
+ pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb);
}
diff --git a/arch/ppc64/kernel/pmac_feature.c b/arch/ppc64/kernel/pmac_feature.c
index 601b378d08d8a..7f1062d222c9e 100644
--- a/arch/ppc64/kernel/pmac_feature.c
+++ b/arch/ppc64/kernel/pmac_feature.c
@@ -220,6 +220,36 @@ static long __pmac g5_mpic_enable(struct device_node* node, long param, long val
return 0;
}
+static long __pmac g5_eth_phy_reset(struct device_node* node, long param, long value)
+{
+ struct macio_chip* macio = &macio_chips[0];
+ struct device_node *phy;
+ int need_reset;
+
+ /*
+ * We must not reset the combo PHYs, only the BCM5221 found in
+ * the iMac G5.
+ */
+ phy = of_get_next_child(node, NULL);
+ if (!phy)
+ return -ENODEV;
+ need_reset = device_is_compatible(phy, "B5221");
+ of_node_put(phy);
+ if (!need_reset)
+ return 0;
+
+ /* PHY reset is GPIO 29, not in device-tree unfortunately */
+ MACIO_OUT8(K2_GPIO_EXTINT_0 + 29,
+ KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
+ /* Thankfully, this is now always called at a time when we can
+ * schedule by sungem.
+ */
+ msleep(10);
+ MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, 0);
+
+ return 0;
+}
+
#ifdef CONFIG_SMP
static long __pmac g5_reset_cpu(struct device_node* node, long param, long value)
{
@@ -306,6 +336,7 @@ static struct feature_table_entry g5_features[] __pmacdata = {
{ PMAC_FTR_ENABLE_MPIC, g5_mpic_enable },
{ PMAC_FTR_READ_GPIO, g5_read_gpio },
{ PMAC_FTR_WRITE_GPIO, g5_write_gpio },
+ { PMAC_FTR_GMAC_PHY_RESET, g5_eth_phy_reset },
#ifdef CONFIG_SMP
{ PMAC_FTR_RESET_CPU, g5_reset_cpu },
#endif /* CONFIG_SMP */
diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
index 62a98b9af5520..3e3c40f248cb9 100644
--- a/arch/ppc64/kernel/prom.c
+++ b/arch/ppc64/kernel/prom.c
@@ -1591,7 +1591,6 @@ static int of_finish_dynamic_node(struct device_node *node,
int unused3, int unused4)
{
struct device_node *parent = of_get_parent(node);
- u32 *regs;
int err = 0;
phandle *ibm_phandle;
@@ -1613,19 +1612,6 @@ static int of_finish_dynamic_node(struct device_node *node,
if ((ibm_phandle = (unsigned int *)get_property(node, "ibm,phandle", NULL)))
node->linux_phandle = *ibm_phandle;
- /* now do the rough equivalent of update_dn_pci_info, this
- * probably is not correct for phb's, but should work for
- * IOAs and slots.
- */
-
- node->phb = parent->phb;
-
- regs = (u32 *)get_property(node, "reg", NULL);
- if (regs) {
- node->busno = (regs[0] >> 16) & 0xff;
- node->devfn = (regs[0] >> 8) & 0xff;
- }
-
out:
of_node_put(parent);
return err;
@@ -1702,7 +1688,7 @@ static int prom_reconfig_notifier(struct notifier_block *nb, unsigned long actio
}
static struct notifier_block prom_reconfig_nb = {
- .notifier_call prom_reconfig_notifier,
+ .notifier_call = prom_reconfig_notifier,
.priority = 10, /* This one needs to run first */
};
diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c
index b238b0225b3fb..7cf7a9600025b 100644
--- a/arch/ppc64/kernel/sys_ppc32.c
+++ b/arch/ppc64/kernel/sys_ppc32.c
@@ -504,11 +504,11 @@ long sys32_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr,
switch (call) {
case SEMTIMEDOP:
- if (third)
+ if (fifth)
/* sign extend semid */
return compat_sys_semtimedop((int)first,
compat_ptr(ptr), second,
- compat_ptr(third));
+ compat_ptr(fifth));
/* else fall through for normal semop() */
case SEMOP:
/* struct sembuf is the same on 32 and 64bit :)) */
diff --git a/arch/ppc64/kernel/syscalls.c b/arch/ppc64/kernel/syscalls.c
index 365987190d71c..f2865ff8d2f93 100644
--- a/arch/ppc64/kernel/syscalls.c
+++ b/arch/ppc64/kernel/syscalls.c
@@ -256,6 +256,3 @@ void do_show_syscall_exit(unsigned long r3)
{
printk(" -> %lx, current=%p cpu=%d\n", r3, current, smp_processor_id());
}
-
-/* Only exists on P-series. */
-cond_syscall(ppc_rtas);
diff --git a/arch/ppc64/mm/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c
index 8b07a816a8c0b..c62ddaff07209 100644
--- a/arch/ppc64/mm/hugetlbpage.c
+++ b/arch/ppc64/mm/hugetlbpage.c
@@ -154,7 +154,7 @@ static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma,
{
pte_t entry;
- mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+ add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
if (write_access) {
entry =
pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
@@ -316,7 +316,7 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
ptepage = pte_page(entry);
get_page(ptepage);
- dst->rss += (HPAGE_SIZE / PAGE_SIZE);
+ add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
set_pte_at(dst, addr, dst_pte, entry);
addr += HPAGE_SIZE;
@@ -426,7 +426,7 @@ void unmap_hugepage_range(struct vm_area_struct *vma,
put_page(page);
}
- mm->rss -= (end - start) >> PAGE_SHIFT;
+ add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT));
flush_tlb_pending();
}
@@ -513,7 +513,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
vma = find_vma(mm, addr);
if (((TASK_SIZE - len) >= addr)
&& (!vma || (addr+len) <= vma->vm_start)
- && !is_hugepage_only_range(addr,len))
+ && !is_hugepage_only_range(mm, addr,len))
return addr;
}
start_addr = addr = mm->free_area_cache;
@@ -523,7 +523,7 @@ full_search:
while (TASK_SIZE - len >= addr) {
BUG_ON(vma && (addr >= vma->vm_end));
- if (touches_hugepage_low_range(addr, len)) {
+ if (touches_hugepage_low_range(mm, addr, len)) {
addr = ALIGN(addr+1, 1<<SID_SHIFT);
vma = find_vma(mm, addr);
continue;
@@ -584,7 +584,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
vma = find_vma(mm, addr);
if (TASK_SIZE - len >= addr &&
(!vma || addr + len <= vma->vm_start)
- && !is_hugepage_only_range(addr,len))
+ && !is_hugepage_only_range(mm, addr,len))
return addr;
}
@@ -597,7 +597,7 @@ try_again:
addr = (mm->free_area_cache - len) & PAGE_MASK;
do {
hugepage_recheck:
- if (touches_hugepage_low_range(addr, len)) {
+ if (touches_hugepage_low_range(mm, addr, len)) {
addr = (addr & ((~0) << SID_SHIFT)) - len;
goto hugepage_recheck;
} else if (touches_hugepage_high_range(addr, len)) {
diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c
index 2c8e6c6cc1e69..23813d03e1c42 100644
--- a/arch/ppc64/mm/init.c
+++ b/arch/ppc64/mm/init.c
@@ -912,3 +912,16 @@ void pgtable_cache_init(void)
if (!zero_cache)
panic("pgtable_cache_init(): could not create zero_cache!\n");
}
+
+pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
+ unsigned long size, pgprot_t vma_prot)
+{
+ if (ppc_md.phys_mem_access_prot)
+ return ppc_md.phys_mem_access_prot(file, addr, size, vma_prot);
+
+ if (!page_is_ram(addr >> PAGE_SHIFT))
+ vma_prot = __pgprot(pgprot_val(vma_prot)
+ | _PAGE_GUARDED | _PAGE_NO_CACHE);
+ return vma_prot;
+}
+EXPORT_SYMBOL(phys_mem_access_prot);
diff --git a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c
index 20df788778ef2..5c603ba982310 100644
--- a/arch/ppc64/mm/numa.c
+++ b/arch/ppc64/mm/numa.c
@@ -609,18 +609,13 @@ void __init do_init_bootmem(void)
new_range:
mem_start = read_n_cells(addr_cells, &memcell_buf);
mem_size = read_n_cells(size_cells, &memcell_buf);
- numa_domain = of_node_numa_domain(memory);
+ numa_domain = numa_enabled ? of_node_numa_domain(memory) : 0;
if (numa_domain != nid)
continue;
- if (mem_start < end_paddr &&
- (mem_start+mem_size) > start_paddr) {
- /* should be no overlaps ! */
- dbg("free_bootmem %lx %lx\n", mem_start, mem_size);
- free_bootmem_node(NODE_DATA(nid), mem_start,
- mem_size);
- }
+ dbg("free_bootmem %lx %lx\n", mem_start, mem_size);
+ free_bootmem_node(NODE_DATA(nid), mem_start, mem_size);
if (--ranges) /* process all ranges in cell */
goto new_range;
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index f9fb9fa358e1f..610c1d03e9757 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -282,7 +282,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
/* This is the X/Open sanctioned signal stack switching. */
if (ka->sa.sa_flags & SA_ONSTACK) {
- if (! on_sig_stack(sp))
+ if (! sas_ss_flags(sp))
sp = current->sas_ss_sp + current->sas_ss_size;
}
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index d6bd3d4298601..b1de24775c31e 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -87,6 +87,7 @@ static int __check_access_register(struct pt_regs *regs, int error_code)
if (areg == 0)
/* Access via access register 0 -> kernel address */
return 0;
+ save_access_regs(current->thread.acrs);
if (regs && areg < NUM_ACRS && current->thread.acrs[areg] <= 1)
/*
* access register contains 0 -> kernel address,
@@ -115,11 +116,11 @@ static inline int check_user_space(struct pt_regs *regs, int error_code)
* 3: Home Segment Table Descriptor
*/
int descriptor = S390_lowcore.trans_exc_code & 3;
- if (descriptor == 1) {
- save_access_regs(current->thread.acrs);
+ if (unlikely(descriptor == 1))
return __check_access_register(regs, error_code);
- }
- return descriptor >> 1;
+ if (descriptor == 2)
+ return current->thread.mm_segment.ar4;
+ return descriptor != 0;
}
/*
diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
index 8ab1855ff9362..8437ea7430fe0 100644
--- a/arch/sh/kernel/cpu/sh4/sq.c
+++ b/arch/sh/kernel/cpu/sh4/sq.c
@@ -379,7 +379,7 @@ static int sq_mmap(struct file *file, struct vm_area_struct *vma)
map = __sq_alloc_mapping(vma->vm_start, offset, size, "Userspace");
- if (io_remap_page_range(vma, map->sq_addr, map->addr,
+ if (io_remap_pfn_range(vma, map->sq_addr, map->addr >> PAGE_SHIFT,
size, vma->vm_page_prot))
return -EAGAIN;
diff --git a/arch/sh/mm/hugetlbpage.c b/arch/sh/mm/hugetlbpage.c
index ac807fdc6d99c..1f897bab2318a 100644
--- a/arch/sh/mm/hugetlbpage.c
+++ b/arch/sh/mm/hugetlbpage.c
@@ -62,7 +62,7 @@ static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long i;
pte_t entry;
- mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+ add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
if (write_access)
entry = pte_mkwrite(pte_mkdirty(mk_pte(page,
@@ -115,7 +115,7 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
pte_val(entry) += PAGE_SIZE;
dst_pte++;
}
- dst->rss += (HPAGE_SIZE / PAGE_SIZE);
+ add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
addr += HPAGE_SIZE;
}
return 0;
@@ -206,7 +206,7 @@ void unmap_hugepage_range(struct vm_area_struct *vma,
pte++;
}
}
- mm->rss -= (end - start) >> PAGE_SHIFT;
+ add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT));
flush_tlb_range(vma, start, end);
}
diff --git a/arch/sh64/mm/hugetlbpage.c b/arch/sh64/mm/hugetlbpage.c
index af566d7eee4b8..bcad2aefa4eea 100644
--- a/arch/sh64/mm/hugetlbpage.c
+++ b/arch/sh64/mm/hugetlbpage.c
@@ -62,7 +62,7 @@ static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long i;
pte_t entry;
- mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+ add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
if (write_access)
entry = pte_mkwrite(pte_mkdirty(mk_pte(page,
@@ -115,7 +115,7 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
pte_val(entry) += PAGE_SIZE;
dst_pte++;
}
- dst->rss += (HPAGE_SIZE / PAGE_SIZE);
+ add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
addr += HPAGE_SIZE;
}
return 0;
@@ -206,7 +206,7 @@ void unmap_hugepage_range(struct vm_area_struct *vma,
pte++;
}
}
- mm->rss -= (end - start) >> PAGE_SHIFT;
+ add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT));
flush_tlb_range(vma, start, end);
}
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index a7df400e9d484..f91b0e8d0dc84 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -164,6 +164,7 @@ EXPORT_SYMBOL(get_auxio);
#endif
EXPORT_SYMBOL(request_fast_irq);
EXPORT_SYMBOL(io_remap_page_range);
+EXPORT_SYMBOL(io_remap_pfn_range);
/* P3: iounit_xxx may be needed, sun4d users */
/* EXPORT_SYMBOL(iounit_map_dma_init); */
/* EXPORT_SYMBOL(iounit_map_dma_page); */
diff --git a/arch/sparc/mm/generic.c b/arch/sparc/mm/generic.c
index 70d2acb3d1bc6..db27eee3bda19 100644
--- a/arch/sparc/mm/generic.c
+++ b/arch/sparc/mm/generic.c
@@ -118,3 +118,37 @@ int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned
flush_tlb_range(vma, beg, end);
return error;
}
+
+int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
+ unsigned long pfn, unsigned long size, pgprot_t prot)
+{
+ int error = 0;
+ pgd_t * dir;
+ unsigned long beg = from;
+ unsigned long end = from + size;
+ struct mm_struct *mm = vma->vm_mm;
+ int space = GET_IOSPACE(pfn);
+ unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
+
+ prot = __pgprot(pg_iobits);
+ offset -= from;
+ dir = pgd_offset(mm, from);
+ flush_cache_range(vma, beg, end);
+
+ spin_lock(&mm->page_table_lock);
+ while (from < end) {
+ pmd_t *pmd = pmd_alloc(current->mm, dir, from);
+ error = -ENOMEM;
+ if (!pmd)
+ break;
+ error = io_remap_pmd_range(mm, pmd, from, end - from, offset + from, prot, space);
+ if (error)
+ break;
+ from = (from + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ }
+ spin_unlock(&mm->page_table_lock);
+
+ flush_tlb_range(vma, beg, end);
+ return error;
+}
diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
index 4de3e352e8327..b2854ef221d06 100644
--- a/arch/sparc64/kernel/binfmt_aout32.c
+++ b/arch/sparc64/kernel/binfmt_aout32.c
@@ -241,7 +241,7 @@ static int load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
current->mm->brk = ex.a_bss +
(current->mm->start_brk = N_BSSADDR(ex));
- current->mm->rss = 0;
+ set_mm_counter(current->mm, rss, 0);
current->mm->mmap = NULL;
compute_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 3f524d52d5313..bba140d98b1b8 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -18,6 +18,7 @@
#include <asm/uaccess.h>
#include <asm/pbm.h>
+#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/ebus.h>
#include <asm/isa.h>
@@ -734,12 +735,10 @@ static void __pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma
static void __pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state)
{
- /* Our io_remap_page_range takes care of this, do nothing. */
+ /* Our io_remap_page_range/io_remap_pfn_range takes care of this,
+ do nothing. */
}
-extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset,
- unsigned long size, pgprot_t prot, int space);
-
/* Perform the actual remap of the pages for a PCI device mapping, as appropriate
* for this architecture. The region in the process to map is described by vm_start
* and vm_end members of VMA, the base physical address is found in vm_pgoff.
@@ -761,10 +760,10 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
__pci_mmap_set_flags(dev, vma, mmap_state);
__pci_mmap_set_pgprot(dev, vma, mmap_state);
- ret = io_remap_page_range(vma, vma->vm_start,
- (vma->vm_pgoff << PAGE_SHIFT |
- (write_combine ? 0x1UL : 0x0UL)),
- vma->vm_end - vma->vm_start, vma->vm_page_prot, 0);
+ ret = io_remap_pfn_range(vma, vma->vm_start,
+ vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
if (ret)
return ret;
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 686e45899bfce..3cec1ebb083b0 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -87,7 +87,10 @@ extern int svr4_setcontext(svr4_ucontext_t *uc, struct pt_regs *regs);
extern int compat_sys_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *);
extern long sparc32_open(const char __user * filename, int flags, int mode);
-extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space);
+extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from,
+ unsigned long offset, unsigned long size, pgprot_t prot, int space);
+extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
+ unsigned long pfn, unsigned long size, pgprot_t prot);
extern void (*prom_palette)(int);
extern int __ashrdi3(int, int);
@@ -254,6 +257,7 @@ EXPORT_SYMBOL(pci_dma_supported);
/* I/O device mmaping on Sparc64. */
EXPORT_SYMBOL(io_remap_page_range);
+EXPORT_SYMBOL(io_remap_pfn_range);
/* Solaris/SunOS binary compatibility */
EXPORT_SYMBOL(_sigpause_common);
diff --git a/arch/sparc64/mm/generic.c b/arch/sparc64/mm/generic.c
index e379f744be0ab..6b31f6117a950 100644
--- a/arch/sparc64/mm/generic.c
+++ b/arch/sparc64/mm/generic.c
@@ -20,10 +20,6 @@
*
* They use a pgprot that sets PAGE_IO and does not check the
* mem_map table as this is independent of normal memory.
- *
- * As a special hack if the lowest bit of offset is set the
- * side-effect bit will be turned off. This is used as a
- * performance improvement on FFB/AFB. -DaveM
*/
static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte,
unsigned long address,
@@ -33,6 +29,8 @@ static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte,
{
unsigned long end;
+ /* clear hack bit that was used as a write_combine side-effect flag */
+ offset &= ~0x1UL;
address &= ~PMD_MASK;
end = address + size;
if (end > PMD_SIZE)
@@ -41,22 +39,22 @@ static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte,
pte_t entry;
unsigned long curend = address + PAGE_SIZE;
- entry = mk_pte_io((offset & ~(0x1UL)), prot, space);
+ entry = mk_pte_io(offset, prot, space);
if (!(address & 0xffff)) {
if (!(address & 0x3fffff) && !(offset & 0x3ffffe) && end >= address + 0x400000) {
- entry = mk_pte_io((offset & ~(0x1UL)),
+ entry = mk_pte_io(offset,
__pgprot(pgprot_val (prot) | _PAGE_SZ4MB),
space);
curend = address + 0x400000;
offset += 0x400000;
} else if (!(address & 0x7ffff) && !(offset & 0x7fffe) && end >= address + 0x80000) {
- entry = mk_pte_io((offset & ~(0x1UL)),
+ entry = mk_pte_io(offset,
__pgprot(pgprot_val (prot) | _PAGE_SZ512K),
space);
curend = address + 0x80000;
offset += 0x80000;
} else if (!(offset & 0xfffe) && end >= address + 0x10000) {
- entry = mk_pte_io((offset & ~(0x1UL)),
+ entry = mk_pte_io(offset,
__pgprot(pgprot_val (prot) | _PAGE_SZ64K),
space);
curend = address + 0x10000;
@@ -66,8 +64,6 @@ static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte,
} else
offset += PAGE_SIZE;
- if (offset & 0x1UL)
- pte_val(entry) &= ~(_PAGE_E);
do {
BUG_ON(!pte_none(*pte));
set_pte_at(mm, address, pte, entry);
@@ -150,3 +146,37 @@ int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned
return error;
}
+
+int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
+ unsigned long pfn, unsigned long size, pgprot_t prot)
+{
+ int error = 0;
+ pgd_t * dir;
+ unsigned long beg = from;
+ unsigned long end = from + size;
+ struct mm_struct *mm = vma->vm_mm;
+ int space = GET_IOSPACE(pfn);
+ unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
+
+ prot = __pgprot(pg_iobits);
+ offset -= from;
+ dir = pgd_offset(mm, from);
+ flush_cache_range(vma, beg, end);
+
+ spin_lock(&mm->page_table_lock);
+ while (from < end) {
+ pud_t *pud = pud_alloc(current->mm, dir, from);
+ error = -ENOMEM;
+ if (!pud)
+ break;
+ error = io_remap_pud_range(mm, pud, from, end - from, offset + from, prot, space);
+ if (error)
+ break;
+ from = (from + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ }
+ flush_tlb_range(vma, beg, end);
+ spin_unlock(&mm->page_table_lock);
+
+ return error;
+}
diff --git a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c
index 49b814f9c3716..ffa207795f1df 100644
--- a/arch/sparc64/mm/hugetlbpage.c
+++ b/arch/sparc64/mm/hugetlbpage.c
@@ -68,7 +68,7 @@ static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long i;
pte_t entry;
- mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+ add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
if (write_access)
entry = pte_mkwrite(pte_mkdirty(mk_pte(page,
@@ -123,7 +123,7 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
dst_pte++;
addr += PAGE_SIZE;
}
- dst->rss += (HPAGE_SIZE / PAGE_SIZE);
+ add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
}
return 0;
@@ -213,7 +213,7 @@ void unmap_hugepage_range(struct vm_area_struct *vma,
pte++;
}
}
- mm->rss -= (end - start) >> PAGE_SHIFT;
+ add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT));
flush_tlb_range(vma, start, end);
}
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index f1b33a2383255..9a23df1821236 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -3,7 +3,7 @@ config GENERIC_HARDIRQS
bool
default y
-config USERMODE
+config UML
bool
default y
@@ -244,7 +244,6 @@ config KERNEL_HALF_GIGS
config HIGHMEM
bool "Highmem support"
- depends on BROKEN
config KERNEL_STACK_ORDER
int "Kernel stack size order"
diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug
index 1ed853ad56901..c27cab081ad28 100644
--- a/arch/um/Kconfig.debug
+++ b/arch/um/Kconfig.debug
@@ -8,7 +8,7 @@ config FRAME_POINTER
config PT_PROXY
bool "Enable ptrace proxy"
- depends on XTERM_CHAN && DEBUG_INFO
+ depends on XTERM_CHAN && DEBUG_INFO && MODE_TT
help
This option enables a debugging interface which allows gdb to debug
the kernel without needing to actually attach to kernel threads.
@@ -16,7 +16,7 @@ config PT_PROXY
config GPROF
bool "Enable gprof support"
- depends on DEBUG_INFO
+ depends on DEBUG_INFO && MODE_SKAS
help
This allows profiling of a User-Mode Linux kernel with the gprof
utility.
@@ -29,7 +29,7 @@ config GPROF
config GCOV
bool "Enable gcov support"
- depends on DEBUG_INFO
+ depends on DEBUG_INFO && MODE_SKAS
help
This option allows developers to retrieve coverage data from a UML
session.
diff --git a/arch/um/Makefile-skas b/arch/um/Makefile-skas
index 3c7d2a3005134..fd18ec572271b 100644
--- a/arch/um/Makefile-skas
+++ b/arch/um/Makefile-skas
@@ -3,10 +3,12 @@
# Licensed under the GPL
#
-PROFILE += -pg
+GPROF_OPT += -pg
+GCOV_OPT += -fprofile-arcs -ftest-coverage
-CFLAGS-$(CONFIG_GCOV) += -fprofile-arcs -ftest-coverage
-CFLAGS-$(CONFIG_GPROF) += $(PROFILE)
-LINK-$(CONFIG_GPROF) += $(PROFILE)
+CFLAGS-$(CONFIG_GCOV) += $(GCOV_OPT)
+CFLAGS-$(CONFIG_GPROF) += $(GPROF_OPT)
+LINK-$(CONFIG_GCOV) += $(GCOV_OPT)
+LINK-$(CONFIG_GPROF) += $(GPROF_OPT)
GEN_HEADERS += $(ARCH_DIR)/include/skas_ptregs.h
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64
index 9638cac931650..a77971133e916 100644
--- a/arch/um/Makefile-x86_64
+++ b/arch/um/Makefile-x86_64
@@ -30,7 +30,3 @@ $(SYS_UTIL_DIR)/mk_thread: scripts_basic $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE
$(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@
CLEAN_FILES += $(SYS_HEADERS)
-
-LIBC_DIR := /usr/lib64
-
-export LIBC_DIR
diff --git a/arch/um/defconfig b/arch/um/defconfig
index 3e9a9fc8f5a98..fc3075c589d8c 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -1,10 +1,10 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11
-# Fri Mar 4 15:38:53 2005
+# Linux kernel version: 2.6.12-rc1-bk1
+# Sun Mar 20 16:53:00 2005
#
CONFIG_GENERIC_HARDIRQS=y
-CONFIG_USERMODE=y
+CONFIG_UML=y
CONFIG_MMU=y
CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
@@ -31,6 +31,7 @@ CONFIG_MCONSOLE=y
# CONFIG_SMP is not set
CONFIG_NEST_LEVEL=0
CONFIG_KERNEL_HALF_GIGS=1
+# CONFIG_HIGHMEM is not set
CONFIG_KERNEL_STACK_ORDER=2
CONFIG_UML_REAL_TIME_CLOCK=y
@@ -61,7 +62,6 @@ CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_BASE_FULL=y
-CONFIG_BASE_SMALL=0
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
@@ -70,6 +70,7 @@ CONFIG_CC_ALIGN_LABELS=0
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
#
# Loadable module support
@@ -215,38 +216,6 @@ CONFIG_DUMMY=m
CONFIG_TUN=m
#
-# Ethernet (10 or 100Mbit)
-#
-# CONFIG_NET_ETHERNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
-#
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# PCMCIA network device support
-#
-# CONFIG_NET_PCMCIA is not set
-
-#
-# PCMCIA network device support
-#
-# CONFIG_NET_PCMCIA is not set
-
-#
# Wan interfaces
#
# CONFIG_WAN is not set
@@ -431,7 +400,9 @@ CONFIG_CRC32=m
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
# CONFIG_SCHEDSTATS is not set
# CONFIG_DEBUG_SLAB is not set
# CONFIG_DEBUG_SPINLOCK is not set
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
index 0de2b074458eb..323f72c64cd20 100644
--- a/arch/um/drivers/Makefile
+++ b/arch/um/drivers/Makefile
@@ -41,11 +41,6 @@ obj-$(CONFIG_UML_WATCHDOG) += harddog.o
obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o
obj-$(CONFIG_UML_RANDOM) += random.o
-USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
+USER_OBJS := fd.o null.o pty.o tty.o xterm.o
-USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \
- null.o pty.o tty.o xterm.o
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
-
-$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 30e7167d792cc..4eeaf88c1e97b 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -383,7 +383,6 @@ static int eth_configure(int n, void *init, char *mac,
save = lp->user[0];
*lp = ((struct uml_net_private)
{ .list = LIST_HEAD_INIT(lp->list),
- .lock = SPIN_LOCK_UNLOCKED,
.dev = dev,
.fd = -1,
.mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0},
@@ -400,6 +399,7 @@ static int eth_configure(int n, void *init, char *mac,
.user = { save } });
init_timer(&lp->tl);
+ spin_lock_init(&lp->lock);
lp->tl.function = uml_net_user_timer_expire;
if (lp->have_mac)
memcpy(lp->mac, device->mac, sizeof(lp->mac));
diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c
index 3d8d4ca360215..d94846b1b4cfd 100644
--- a/arch/um/drivers/slip_user.c
+++ b/arch/um/drivers/slip_user.c
@@ -108,6 +108,9 @@ static int slip_tramp(char **argv, int fd)
err = -EINVAL;
}
}
+
+ os_close_file(fds[0]);
+
return(err);
}
@@ -128,6 +131,7 @@ static int slip_open(void *data)
sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0);
if(sfd < 0){
printk("Couldn't open tty for slip line, err = %d\n", -sfd);
+ os_close_file(mfd);
return(sfd);
}
if(set_up_tty(sfd)) return(-1);
@@ -175,7 +179,7 @@ static void slip_close(int fd, void *data)
sprintf(version_buf, "%d", UML_NET_VERSION);
- err = slip_tramp(argv, -1);
+ err = slip_tramp(argv, pri->slave);
if(err != 0)
printk("slip_tramp failed - errno = %d\n", -err);
diff --git a/arch/um/include/choose-mode.h b/arch/um/include/choose-mode.h
index 959e6d2ef77b7..8e6b62f5e9ac2 100644
--- a/arch/um/include/choose-mode.h
+++ b/arch/um/include/choose-mode.h
@@ -21,6 +21,13 @@
#define CHOOSE_MODE_PROC(tt, skas, args...) \
CHOOSE_MODE(tt(args), skas(args))
+extern int mode_tt;
+static inline void *__choose_mode(void *tt, void *skas) {
+ return mode_tt ? tt : skas;
+}
+
+#define __CHOOSE_MODE(tt, skas) (*( (typeof(tt) *) __choose_mode(&(tt), &(skas))))
+
#endif
/*
diff --git a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h
index 7a9638a5bc6b4..b514ea28d16c4 100644
--- a/arch/um/include/sysdep-i386/ptrace.h
+++ b/arch/um/include/sysdep-i386/ptrace.h
@@ -93,39 +93,39 @@ extern int mode_tt;
#define UPT_SC(r) ((r)->tt.sc)
#define UPT_IP(r) \
- CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs))
+ __CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs))
#define UPT_SP(r) \
- CHOOSE_MODE(SC_SP(UPT_SC(r)), REGS_SP((r)->skas.regs))
+ __CHOOSE_MODE(SC_SP(UPT_SC(r)), REGS_SP((r)->skas.regs))
#define UPT_EFLAGS(r) \
- CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs))
+ __CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs))
#define UPT_EAX(r) \
- CHOOSE_MODE(SC_EAX(UPT_SC(r)), REGS_EAX((r)->skas.regs))
+ __CHOOSE_MODE(SC_EAX(UPT_SC(r)), REGS_EAX((r)->skas.regs))
#define UPT_EBX(r) \
- CHOOSE_MODE(SC_EBX(UPT_SC(r)), REGS_EBX((r)->skas.regs))
+ __CHOOSE_MODE(SC_EBX(UPT_SC(r)), REGS_EBX((r)->skas.regs))
#define UPT_ECX(r) \
- CHOOSE_MODE(SC_ECX(UPT_SC(r)), REGS_ECX((r)->skas.regs))
+ __CHOOSE_MODE(SC_ECX(UPT_SC(r)), REGS_ECX((r)->skas.regs))
#define UPT_EDX(r) \
- CHOOSE_MODE(SC_EDX(UPT_SC(r)), REGS_EDX((r)->skas.regs))
+ __CHOOSE_MODE(SC_EDX(UPT_SC(r)), REGS_EDX((r)->skas.regs))
#define UPT_ESI(r) \
- CHOOSE_MODE(SC_ESI(UPT_SC(r)), REGS_ESI((r)->skas.regs))
+ __CHOOSE_MODE(SC_ESI(UPT_SC(r)), REGS_ESI((r)->skas.regs))
#define UPT_EDI(r) \
- CHOOSE_MODE(SC_EDI(UPT_SC(r)), REGS_EDI((r)->skas.regs))
+ __CHOOSE_MODE(SC_EDI(UPT_SC(r)), REGS_EDI((r)->skas.regs))
#define UPT_EBP(r) \
- CHOOSE_MODE(SC_EBP(UPT_SC(r)), REGS_EBP((r)->skas.regs))
+ __CHOOSE_MODE(SC_EBP(UPT_SC(r)), REGS_EBP((r)->skas.regs))
#define UPT_ORIG_EAX(r) \
- CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall)
+ __CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall)
#define UPT_CS(r) \
- CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
+ __CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
#define UPT_SS(r) \
- CHOOSE_MODE(SC_SS(UPT_SC(r)), REGS_SS((r)->skas.regs))
+ __CHOOSE_MODE(SC_SS(UPT_SC(r)), REGS_SS((r)->skas.regs))
#define UPT_DS(r) \
- CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs))
+ __CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs))
#define UPT_ES(r) \
- CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs))
+ __CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs))
#define UPT_FS(r) \
- CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs))
+ __CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs))
#define UPT_GS(r) \
- CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs))
+ __CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs))
#define UPT_SYSCALL_ARG1(r) UPT_EBX(r)
#define UPT_SYSCALL_ARG2(r) UPT_ECX(r)
@@ -222,7 +222,7 @@ struct syscall_args {
REGS_SEGV_IS_FIXABLE(&r->skas))
#define UPT_FAULT_ADDR(r) \
- CHOOSE_MODE(SC_FAULT_ADDR(UPT_SC(r)), REGS_FAULT_ADDR(&r->skas))
+ __CHOOSE_MODE(SC_FAULT_ADDR(UPT_SC(r)), REGS_FAULT_ADDR(&r->skas))
#define UPT_FAULT_WRITE(r) \
CHOOSE_MODE(SC_FAULT_WRITE(UPT_SC(r)), REGS_FAULT_WRITE(&r->skas))
diff --git a/arch/um/include/sysdep-i386/sigcontext.h b/arch/um/include/sysdep-i386/sigcontext.h
index 887fdb61ed77c..dfee589de3608 100644
--- a/arch/um/include/sysdep-i386/sigcontext.h
+++ b/arch/um/include/sysdep-i386/sigcontext.h
@@ -6,7 +6,7 @@
#ifndef __SYS_SIGCONTEXT_I386_H
#define __SYS_SIGCONTEXT_I386_H
-#include "sc.h"
+#include <sysdep/sc.h>
#define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
diff --git a/arch/um/include/sysdep-x86_64/ptrace.h b/arch/um/include/sysdep-x86_64/ptrace.h
index 65949994e2877..5eac9bed21ad3 100644
--- a/arch/um/include/sysdep-x86_64/ptrace.h
+++ b/arch/um/include/sysdep-x86_64/ptrace.h
@@ -104,37 +104,37 @@ union uml_pt_regs {
/* XXX */
extern int mode_tt;
-#define UPT_RBX(r) CHOOSE_MODE(SC_RBX(UPT_SC(r)), REGS_RBX((r)->skas.regs))
-#define UPT_RCX(r) CHOOSE_MODE(SC_RCX(UPT_SC(r)), REGS_RCX((r)->skas.regs))
-#define UPT_RDX(r) CHOOSE_MODE(SC_RDX(UPT_SC(r)), REGS_RDX((r)->skas.regs))
-#define UPT_RSI(r) CHOOSE_MODE(SC_RSI(UPT_SC(r)), REGS_RSI((r)->skas.regs))
-#define UPT_RDI(r) CHOOSE_MODE(SC_RDI(UPT_SC(r)), REGS_RDI((r)->skas.regs))
-#define UPT_RBP(r) CHOOSE_MODE(SC_RBP(UPT_SC(r)), REGS_RBP((r)->skas.regs))
-#define UPT_RAX(r) CHOOSE_MODE(SC_RAX(UPT_SC(r)), REGS_RAX((r)->skas.regs))
-#define UPT_R8(r) CHOOSE_MODE(SC_R8(UPT_SC(r)), REGS_R8((r)->skas.regs))
-#define UPT_R9(r) CHOOSE_MODE(SC_R9(UPT_SC(r)), REGS_R9((r)->skas.regs))
-#define UPT_R10(r) CHOOSE_MODE(SC_R10(UPT_SC(r)), REGS_R10((r)->skas.regs))
-#define UPT_R11(r) CHOOSE_MODE(SC_R11(UPT_SC(r)), REGS_R11((r)->skas.regs))
-#define UPT_R12(r) CHOOSE_MODE(SC_R12(UPT_SC(r)), REGS_R12((r)->skas.regs))
-#define UPT_R13(r) CHOOSE_MODE(SC_R13(UPT_SC(r)), REGS_R13((r)->skas.regs))
-#define UPT_R14(r) CHOOSE_MODE(SC_R14(UPT_SC(r)), REGS_R14((r)->skas.regs))
-#define UPT_R15(r) CHOOSE_MODE(SC_R15(UPT_SC(r)), REGS_R15((r)->skas.regs))
-#define UPT_CS(r) CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
-#define UPT_FS(r) CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs))
-#define UPT_GS(r) CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs))
-#define UPT_DS(r) CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs))
-#define UPT_ES(r) CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs))
-#define UPT_CS(r) CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
+#define UPT_RBX(r) __CHOOSE_MODE(SC_RBX(UPT_SC(r)), REGS_RBX((r)->skas.regs))
+#define UPT_RCX(r) __CHOOSE_MODE(SC_RCX(UPT_SC(r)), REGS_RCX((r)->skas.regs))
+#define UPT_RDX(r) __CHOOSE_MODE(SC_RDX(UPT_SC(r)), REGS_RDX((r)->skas.regs))
+#define UPT_RSI(r) __CHOOSE_MODE(SC_RSI(UPT_SC(r)), REGS_RSI((r)->skas.regs))
+#define UPT_RDI(r) __CHOOSE_MODE(SC_RDI(UPT_SC(r)), REGS_RDI((r)->skas.regs))
+#define UPT_RBP(r) __CHOOSE_MODE(SC_RBP(UPT_SC(r)), REGS_RBP((r)->skas.regs))
+#define UPT_RAX(r) __CHOOSE_MODE(SC_RAX(UPT_SC(r)), REGS_RAX((r)->skas.regs))
+#define UPT_R8(r) __CHOOSE_MODE(SC_R8(UPT_SC(r)), REGS_R8((r)->skas.regs))
+#define UPT_R9(r) __CHOOSE_MODE(SC_R9(UPT_SC(r)), REGS_R9((r)->skas.regs))
+#define UPT_R10(r) __CHOOSE_MODE(SC_R10(UPT_SC(r)), REGS_R10((r)->skas.regs))
+#define UPT_R11(r) __CHOOSE_MODE(SC_R11(UPT_SC(r)), REGS_R11((r)->skas.regs))
+#define UPT_R12(r) __CHOOSE_MODE(SC_R12(UPT_SC(r)), REGS_R12((r)->skas.regs))
+#define UPT_R13(r) __CHOOSE_MODE(SC_R13(UPT_SC(r)), REGS_R13((r)->skas.regs))
+#define UPT_R14(r) __CHOOSE_MODE(SC_R14(UPT_SC(r)), REGS_R14((r)->skas.regs))
+#define UPT_R15(r) __CHOOSE_MODE(SC_R15(UPT_SC(r)), REGS_R15((r)->skas.regs))
+#define UPT_CS(r) __CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
+#define UPT_FS(r) __CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs))
+#define UPT_GS(r) __CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs))
+#define UPT_DS(r) __CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs))
+#define UPT_ES(r) __CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs))
+#define UPT_CS(r) __CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
#define UPT_ORIG_RAX(r) \
- CHOOSE_MODE((r)->tt.orig_rax, REGS_ORIG_RAX((r)->skas.regs))
+ __CHOOSE_MODE((r)->tt.orig_rax, REGS_ORIG_RAX((r)->skas.regs))
-#define UPT_IP(r) CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs))
-#define UPT_SP(r) CHOOSE_MODE(SC_SP(UPT_SC(r)), REGS_SP((r)->skas.regs))
+#define UPT_IP(r) __CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs))
+#define UPT_SP(r) __CHOOSE_MODE(SC_SP(UPT_SC(r)), REGS_SP((r)->skas.regs))
#define UPT_EFLAGS(r) \
- CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs))
+ __CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs))
#define UPT_SC(r) ((r)->tt.sc)
-#define UPT_SYSCALL_NR(r) CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall)
+#define UPT_SYSCALL_NR(r) __CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall)
extern int user_context(unsigned long sp);
@@ -242,13 +242,13 @@ struct syscall_args {
REGS_SEGV_IS_FIXABLE(&r->skas))
#define UPT_FAULT_ADDR(r) \
- CHOOSE_MODE(SC_FAULT_ADDR(UPT_SC(r)), REGS_FAULT_ADDR(&r->skas))
+ __CHOOSE_MODE(SC_FAULT_ADDR(UPT_SC(r)), REGS_FAULT_ADDR(&r->skas))
#define UPT_FAULT_WRITE(r) \
CHOOSE_MODE(SC_FAULT_WRITE(UPT_SC(r)), REGS_FAULT_WRITE(&r->skas))
-#define UPT_TRAP(r) CHOOSE_MODE(SC_TRAP_TYPE(UPT_SC(r)), REGS_TRAP(&r->skas))
-#define UPT_ERR(r) CHOOSE_MODE(SC_FAULT_TYPE(UPT_SC(r)), REGS_ERR(&r->skas))
+#define UPT_TRAP(r) __CHOOSE_MODE(SC_TRAP_TYPE(UPT_SC(r)), REGS_TRAP(&r->skas))
+#define UPT_ERR(r) __CHOOSE_MODE(SC_FAULT_TYPE(UPT_SC(r)), REGS_ERR(&r->skas))
#endif
diff --git a/arch/um/include/sysdep-x86_64/sigcontext.h b/arch/um/include/sysdep-x86_64/sigcontext.h
index 6a0c346b64040..1e38a54ff4cf3 100644
--- a/arch/um/include/sysdep-x86_64/sigcontext.h
+++ b/arch/um/include/sysdep-x86_64/sigcontext.h
@@ -7,7 +7,7 @@
#ifndef __SYSDEP_X86_64_SIGCONTEXT_H
#define __SYSDEP_X86_64_SIGCONTEXT_H
-#include "sc.h"
+#include <sysdep/sc.h>
#define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h
index 4fc088eb73fa8..103cd320386cf 100644
--- a/arch/um/include/user_util.h
+++ b/arch/um/include/user_util.h
@@ -67,7 +67,7 @@ extern void *um_kmalloc(int size);
extern int switcheroo(int fd, int prot, void *from, void *to, int size);
extern void setup_machinename(char *machine_out);
extern void setup_hostinfo(void);
-extern void add_arg(char *cmd_line, char *arg);
+extern void add_arg(char *arg);
extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int));
extern void init_new_thread_signals(int altstack);
extern void do_exec(int old_pid, int new_pid);
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
index 2920be8f24299..dc796c1bf39ec 100644
--- a/arch/um/kernel/Makefile
+++ b/arch/um/kernel/Makefile
@@ -23,16 +23,16 @@ obj-$(CONFIG_SYSCALL_DEBUG) += syscall_user.o
obj-$(CONFIG_MODE_TT) += tt/
obj-$(CONFIG_MODE_SKAS) += skas/
-user-objs-$(CONFIG_TTY_LOG) += tty_log.o
+# This needs be compiled with frame pointers regardless of how the rest of the
+# kernel is built.
+CFLAGS_frame.o := -fno-omit-frame-pointer
-USER_OBJS := $(filter %_user.o,$(obj-y)) $(user-objs-y) config.o helper.o \
- main.o process.o tempfile.o time.o tty_log.o umid.o user_util.o frame.o
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+user-objs-$(CONFIG_TTY_LOG) += tty_log.o
-CFLAGS_frame.o := -fno-omit-frame-pointer
+USER_OBJS := $(user-objs-y) config.o helper.o main.o process.o tempfile.o \
+ time.o tty_log.o umid.o user_util.o frame.o
-$(USER_OBJS) : %.o: %.c
- $(CC) $(USER_CFLAGS) $(CFLAGS_$(notdir $@)) -c -o $@ $<
+include arch/um/scripts/Makefile.rules
targets += config.c
diff --git a/arch/um/kernel/gmon_syms.c b/arch/um/kernel/gmon_syms.c
index 31cca2b2a8bea..2c86e7fdb0143 100644
--- a/arch/um/kernel/gmon_syms.c
+++ b/arch/um/kernel/gmon_syms.c
@@ -5,14 +5,22 @@
#include "linux/module.h"
-#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3) || \
- (__GNUC__ == 3 && __GNUC_MINOR__ == 3 && __GNUC_PATCHLEVEL__ >= 4)
-extern void __gcov_init(void *);
-EXPORT_SYMBOL(__gcov_init);
-#else
extern void __bb_init_func(void *);
EXPORT_SYMBOL(__bb_init_func);
-#endif
+
+/* This is defined (and referred to in profiling stub code) only by some GCC
+ * versions in libgcov.
+ *
+ * Since SuSE backported the fix, we cannot handle it depending on GCC version.
+ * So, unconditinally export it. But also give it a weak declaration, which will
+ * be overriden by any other one.
+ */
+
+extern void __gcov_init(void *) __attribute__((weak));
+EXPORT_SYMBOL(__gcov_init);
+
+extern void __gcov_merge_add(void *) __attribute__((weak));
+EXPORT_SYMBOL(__gcov_merge_add);
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
index 867dff0729342..d37d1bfcd6f73 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -6,10 +6,8 @@
obj-y := exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
syscall_kern.o syscall_user.o time.o tlb.o trap_user.o uaccess.o \
-USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+subdir- := util
-$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+USER_OBJS := process.o time.o
-subdir- := util
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile
index 7c9eec5fded52..3d5177df3504c 100644
--- a/arch/um/kernel/tt/Makefile
+++ b/arch/um/kernel/tt/Makefile
@@ -12,21 +12,17 @@ obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \
obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/
-USER_OBJS := $(filter %_user.o,$(obj-y)) gdb.o time.o tracer.o
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+USER_OBJS := gdb.o time.o tracer.o
+
+include arch/um/scripts/Makefile.rules
UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS))
UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS))
-$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
-
-$(obj)/unmap.o: $(src)/unmap.c
- $(CC) $(UNMAP_CFLAGS) -c -o $@ $<
-
-LIBC_DIR ?= /usr/lib
+#XXX: partially copied from arch/um/scripts/Makefile.rules
+$(obj)/unmap.o: c_flags = -Wp,-MD,$(depfile) $(UNMAP_CFLAGS)
$(obj)/unmap_fin.o : $(obj)/unmap.o
- ld -r -o $(obj)/unmap_tmp.o $< -lc -L$(LIBC_DIR)
- objcopy $(obj)/unmap_tmp.o $@ -G switcheroo
+ $(LD) -r -o $(obj)/unmap_tmp.o $< $(shell $(CC) -print-file-name=libc.a)
+ $(OBJCOPY) $(obj)/unmap_tmp.o $@ -G switcheroo
diff --git a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile
index 9f9daf5c17837..3ad5b774de595 100644
--- a/arch/um/kernel/tt/ptproxy/Makefile
+++ b/arch/um/kernel/tt/ptproxy/Makefile
@@ -5,7 +5,6 @@
obj-y = proxy.o ptrace.o sysdep.o wait.o
-USER_OBJS := $(foreach file,$(obj-y),$(src)/$(file))
+USER_OBJS := $(obj-y)
-$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index bffd8316f8923..c75d1db0efc31 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -25,6 +25,7 @@
#include "asm/user.h"
#include "ubd_user.h"
#include "asm/current.h"
+#include "asm/setup.h"
#include "user_util.h"
#include "kern_util.h"
#include "kern.h"
@@ -40,6 +41,20 @@
#define DEFAULT_COMMAND_LINE "root=98:0"
+/* Changed in linux_main and setup_arch, which run before SMP is started */
+char command_line[COMMAND_LINE_SIZE] = { 0 };
+
+void add_arg(char *arg)
+{
+ if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
+ printf("add_arg: Too much command line!\n");
+ exit(1);
+ }
+ if(strlen(command_line) > 0)
+ strcat(command_line, " ");
+ strcat(command_line, arg);
+}
+
struct cpuinfo_um boot_cpu_data = {
.loops_per_jiffy = 0,
.ipi_pipe = { -1, -1 }
@@ -314,9 +329,11 @@ int linux_main(int argc, char **argv)
if((i == 1) && (argv[i][0] == ' ')) continue;
add = 1;
uml_checksetup(argv[i], &add);
- if(add) add_arg(saved_command_line, argv[i]);
+ if (add)
+ add_arg(argv[i]);
}
- if(have_root == 0) add_arg(saved_command_line, DEFAULT_COMMAND_LINE);
+ if(have_root == 0)
+ add_arg(DEFAULT_COMMAND_LINE);
mode_tt = force_tt ? 1 : !can_do_skas();
#ifndef CONFIG_MODE_TT
@@ -432,7 +449,7 @@ void __init setup_arch(char **cmdline_p)
{
notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
paging_init();
- strcpy(command_line, saved_command_line);
+ strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
*cmdline_p = command_line;
setup_hostinfo();
}
@@ -448,14 +465,3 @@ void __init check_bugs(void)
void apply_alternatives(void *start, void *end)
{
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c
index 92039485901da..954ff67cc8b3e 100644
--- a/arch/um/kernel/user_util.c
+++ b/arch/um/kernel/user_util.c
@@ -31,21 +31,6 @@
#include "ptrace_user.h"
#include "uml-config.h"
-#define COMMAND_LINE_SIZE _POSIX_ARG_MAX
-
-/* Changed in linux_main and setup_arch, which run before SMP is started */
-char command_line[COMMAND_LINE_SIZE] = { 0 };
-
-void add_arg(char *cmd_line, char *arg)
-{
- if (strlen(cmd_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
- printf("add_arg: Too much command line!\n");
- exit(1);
- }
- if(strlen(cmd_line) > 0) strcat(cmd_line, " ");
- strcat(cmd_line, arg);
-}
-
void stop(void)
{
while(1) sleep(1000000);
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
index f8378124be135..4ddf540284ce6 100644
--- a/arch/um/os-Linux/Makefile
+++ b/arch/um/os-Linux/Makefile
@@ -7,9 +7,7 @@ obj-y = elf_aux.o file.o process.o signal.o time.o tty.o user_syms.o drivers/ \
sys-$(SUBARCH)/
USER_OBJS := elf_aux.o file.o process.o signal.o time.o tty.o
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
-
-$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
+
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/drivers/Makefile b/arch/um/os-Linux/drivers/Makefile
index 52cae521eb65c..6c546dc9222bb 100644
--- a/arch/um/os-Linux/drivers/Makefile
+++ b/arch/um/os-Linux/drivers/Makefile
@@ -10,10 +10,4 @@ obj-y =
obj-$(CONFIG_UML_NET_ETHERTAP) += ethertap.o
obj-$(CONFIG_UML_NET_TUNTAP) += tuntap.o
-USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y)),$($(f)-objs))
-
-USER_OBJS = $(filter %_user.o,$(obj-y) $(USER_SINGLE_OBJS))
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
-
-$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/sys-i386/Makefile b/arch/um/os-Linux/sys-i386/Makefile
index bdfa841fca165..340ef26f5944c 100644
--- a/arch/um/os-Linux/sys-i386/Makefile
+++ b/arch/um/os-Linux/sys-i386/Makefile
@@ -5,7 +5,6 @@
obj-$(CONFIG_MODE_SKAS) = registers.o
-USER_OBJS := $(foreach file,$(obj-y),$(obj)/$(file))
+USER_OBJS := $(obj-y)
-$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/sys-x86_64/Makefile b/arch/um/os-Linux/sys-x86_64/Makefile
index bdfa841fca165..340ef26f5944c 100644
--- a/arch/um/os-Linux/sys-x86_64/Makefile
+++ b/arch/um/os-Linux/sys-x86_64/Makefile
@@ -5,7 +5,6 @@
obj-$(CONFIG_MODE_SKAS) = registers.o
-USER_OBJS := $(foreach file,$(obj-y),$(obj)/$(file))
+USER_OBJS := $(obj-y)
-$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules
new file mode 100644
index 0000000000000..143f6fea07632
--- /dev/null
+++ b/arch/um/scripts/Makefile.rules
@@ -0,0 +1,13 @@
+# ===========================================================================
+# arch/um: Generic definitions
+# ===========================================================================
+
+USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
+USER_OBJS += $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS))
+
+USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+
+$(USER_OBJS): c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) $(CFLAGS_$(notdir $@))
+
+quiet_cmd_make_link = SYMLINK $@
+cmd_make_link = rm -f $@; ln -sf $(srctree)/arch/$(SUBARCH)/$($(notdir $@)-dir)/$(notdir $@) $@
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
index 8a0994b696b00..71b47e6186051 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -5,7 +5,8 @@ obj-$(CONFIG_HIGHMEM) += highmem.o
obj-$(CONFIG_MODULES) += module.o
USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+
+include arch/um/scripts/Makefile.rules
SYMLINKS = bitops.c semaphore.c highmem.c module.c
@@ -13,22 +14,16 @@ SYMLINKS = bitops.c semaphore.c highmem.c module.c
# complete paths like $(src)/$f.
clean-files := $(SYMLINKS)
-SYMLINKS := $(foreach f,$(SYMLINKS),$(src)/$f)
+targets += $(SYMLINKS)
+
+SYMLINKS := $(foreach f,$(SYMLINKS),$(obj)/$f)
bitops.c-dir = lib
semaphore.c-dir = kernel
highmem.c-dir = mm
module.c-dir = kernel
-define make_link
- -rm -f $1
- ln -sf $(TOPDIR)/arch/i386/$($(notdir $1)-dir)/$(notdir $1) $1
-endef
-
-$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
-
-$(SYMLINKS):
- $(call make_link,$@)
+$(SYMLINKS): FORCE
+ $(call if_changed,make_link)
subdir- := util
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile
index 1ec504b768109..2129e3143559d 100644
--- a/arch/um/sys-x86_64/Makefile
+++ b/arch/um/sys-x86_64/Makefile
@@ -9,14 +9,20 @@ lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \
syscalls.o sysrq.o thunk.o
USER_OBJS := ptrace_user.o sigcontext.o
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+
+include arch/um/scripts/Makefile.rules
SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c memcpy.S \
semaphore.c thunk.S
-SYMLINKS := $(foreach f,$(SYMLINKS),$(src)/$f)
+# this needs to be before the foreach, because clean-files does not accept
+# complete paths like $(src)/$f.
clean-files := $(SYMLINKS)
+targets += $(SYMLINKS)
+
+SYMLINKS := $(foreach f,$(SYMLINKS),$(obj)/$f)
+
bitops.c-dir = lib
csum-copy.S-dir = lib
csum-partial.c-dir = lib
@@ -25,15 +31,7 @@ memcpy.S-dir = lib
semaphore.c-dir = kernel
thunk.S-dir = lib
-define make_link
- -rm -f $1
- ln -sf $(TOPDIR)/arch/x86_64/$($(notdir $1)-dir)/$(notdir $1) $1
-endef
-
-$(SYMLINKS):
- $(call make_link,$@)
-
-$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+$(SYMLINKS): FORCE
+ $(call if_changed,make_link)
CFLAGS_csum-partial.o := -Dcsum_partial=arch_csum_partial
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index 1dd759759a8d2..80c38c5d71fe4 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -53,23 +53,6 @@ config EARLY_PRINTK
bool
default y
-config HPET_TIMER
- bool
- default y
- help
- Use the IA-PC HPET (High Precision Event Timer) to manage
- time in preference to the PIT and RTC, if a HPET is
- present. The HPET provides a stable time base on SMP
- systems, unlike the RTC, but it is more expensive to access,
- as it is off-chip. You can find the HPET spec at
- <http://www.intel.com/labs/platcomp/hpet/hpetspec.htm>.
-
- If unsure, say Y.
-
-config HPET_EMULATE_RTC
- bool "Provide RTC interrupt"
- depends on HPET_TIMER && RTC=y
-
config GENERIC_ISA_DMA
bool
default y
@@ -254,7 +237,7 @@ config PREEMPT_BKL
config SCHED_SMT
bool "SMT (Hyperthreading) scheduler support"
depends on SMP
- default off
+ default n
help
SMT scheduler support improves the CPU scheduler's decision making
when dealing with Intel Pentium 4 chips with HyperThreading at a
@@ -309,6 +292,21 @@ config NR_CPUS
This is purely to save memory - each supported CPU requires
memory in the static kernel configuration.
+config HPET_TIMER
+ bool
+ default y
+ help
+ Use the IA-PC HPET (High Precision Event Timer) to manage
+ time in preference to the PIT and RTC, if a HPET is
+ present. The HPET provides a stable time base on SMP
+ systems, unlike the TSC, but it is more expensive to access,
+ as it is off-chip. You can find the HPET spec at
+ <http://www.intel.com/labs/platcomp/hpet/hpetspec.htm>.
+
+config HPET_EMULATE_RTC
+ bool "Provide RTC interrupt"
+ depends on HPET_TIMER && RTC=y
+
config GART_IOMMU
bool "IOMMU support"
depends on PCI
@@ -417,6 +415,8 @@ config UNORDERED_IO
from i386. Requires that the driver writer used memory barriers
properly.
+source "drivers/pci/pcie/Kconfig"
+
source "drivers/pci/Kconfig"
source "drivers/pcmcia/Kconfig"
diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig
index e81bc1839a9fa..9ce51dee30b30 100644
--- a/arch/x86_64/defconfig
+++ b/arch/x86_64/defconfig
@@ -1,13 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-bk7
-# Fri Jan 7 06:27:52 2005
+# Linux kernel version: 2.6.11-bk7
+# Sat Mar 12 23:43:44 2005
#
CONFIG_X86_64=y
CONFIG_64BIT=y
CONFIG_X86=y
CONFIG_MMU=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_X86_CMPXCHG=y
CONFIG_EARLY_PRINTK=y
CONFIG_HPET_TIMER=y
@@ -37,10 +38,12 @@ CONFIG_LOG_BUF_SHIFT=18
CONFIG_KOBJECT_UEVENT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+# CONFIG_CPUSETS is not set
# CONFIG_EMBEDDED is not set
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -50,6 +53,7 @@ CONFIG_CC_ALIGN_LABELS=0
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
#
# Loadable module support
@@ -93,6 +97,7 @@ CONFIG_GART_IOMMU=y
CONFIG_SWIOTLB=y
CONFIG_X86_MCE=y
CONFIG_X86_MCE_INTEL=y
+CONFIG_SECCOMP=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
@@ -137,13 +142,13 @@ CONFIG_ACPI_SYSTEM=y
#
CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_DEBUG is not set
-CONFIG_CPU_FREQ_PROC_INTF=y
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_24_API=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_TABLE=y
@@ -172,6 +177,20 @@ CONFIG_PCI_MSI=y
# CONFIG_PCI_NAMES is not set
#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
# Executable file formats / Emulations
#
CONFIG_BINFMT_ELF=y
@@ -191,6 +210,7 @@ CONFIG_UID16=y
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
# CONFIG_DEBUG_DRIVER is not set
#
@@ -216,6 +236,7 @@ CONFIG_BLK_DEV_FD=y
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
@@ -236,6 +257,7 @@ CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
#
# ATA/ATAPI/MFM/RLL support
@@ -352,6 +374,7 @@ CONFIG_SCSI_SATA=y
CONFIG_SCSI_ATA_PIIX=y
# CONFIG_SCSI_SATA_NV is not set
# CONFIG_SCSI_SATA_PROMISE is not set
+# CONFIG_SCSI_SATA_QSTOR is not set
# CONFIG_SCSI_SATA_SX4 is not set
# CONFIG_SCSI_SATA_SIL is not set
# CONFIG_SCSI_SATA_SIS is not set
@@ -514,7 +537,7 @@ CONFIG_FORCEDETH=y
# CONFIG_NATSEMI is not set
# CONFIG_NE2K_PCI is not set
CONFIG_8139CP=m
-CONFIG_8139TOO=m
+CONFIG_8139TOO=y
# CONFIG_8139TOO_PIO is not set
# CONFIG_8139TOO_TUNE_TWISTER is not set
# CONFIG_8139TOO_8129 is not set
@@ -597,18 +620,6 @@ CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_EVBUG is not set
#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
@@ -626,6 +637,19 @@ CONFIG_MOUSE_PS2=y
# CONFIG_INPUT_MISC is not set
#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
# Character devices
#
CONFIG_VT=y
@@ -682,6 +706,11 @@ CONFIG_MAX_RAW_DEVS=256
CONFIG_HANGCHECK_TIMER=y
#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
# I2C support
#
# CONFIG_I2C is not set
@@ -710,7 +739,7 @@ CONFIG_HANGCHECK_TIMER=y
# Graphics support
#
# CONFIG_FB is not set
-# CONFIG_VIDEO_SELECT is not set
+CONFIG_VIDEO_SELECT=y
#
# Console display driver support
@@ -778,6 +807,8 @@ CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_SPLIT_ISO is not set
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
CONFIG_USB_UHCI_HCD=y
# CONFIG_USB_SL811_HCD is not set
@@ -800,7 +831,7 @@ CONFIG_USB_STORAGE=y
# CONFIG_USB_STORAGE_FREECOM is not set
# CONFIG_USB_STORAGE_ISD200 is not set
# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_USBAT is not set
# CONFIG_USB_STORAGE_SDDR09 is not set
# CONFIG_USB_STORAGE_SDDR55 is not set
# CONFIG_USB_STORAGE_JUMPSHOT is not set
@@ -826,7 +857,6 @@ CONFIG_USB_HIDINPUT=y
#
# CONFIG_USB_MDC800 is not set
# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
#
# USB Multimedia devices
@@ -845,6 +875,7 @@ CONFIG_USB_HIDINPUT=y
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
#
# USB port drivers
@@ -860,7 +891,6 @@ CONFIG_USB_HIDINPUT=y
#
# CONFIG_USB_EMI62 is not set
# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_TIGL is not set
# CONFIG_USB_AUERSWALD is not set
# CONFIG_USB_RIO500 is not set
# CONFIG_USB_LEGOTOWER is not set
@@ -869,6 +899,8 @@ CONFIG_USB_HIDINPUT=y
# CONFIG_USB_CYTHERM is not set
# CONFIG_USB_PHIDGETKIT is not set
# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_TEST is not set
#
@@ -917,6 +949,10 @@ CONFIG_REISERFS_FS_POSIX_ACL=y
# CONFIG_REISERFS_FS_SECURITY is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
@@ -1058,12 +1094,14 @@ CONFIG_OPROFILE=y
#
CONFIG_DEBUG_KERNEL=y
CONFIG_MAGIC_SYSRQ=y
+# CONFIG_PRINTK_TIME is not set
# CONFIG_SCHEDSTATS is not set
# CONFIG_DEBUG_SLAB is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_KOBJECT is not set
# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_FS=y
CONFIG_INIT_DEBUG=y
# CONFIG_IOMMU_DEBUG is not set
CONFIG_KPROBES=y
diff --git a/arch/x86_64/ia32/ia32_aout.c b/arch/x86_64/ia32/ia32_aout.c
index 58d2c8a389168..1965efc974dc4 100644
--- a/arch/x86_64/ia32/ia32_aout.c
+++ b/arch/x86_64/ia32/ia32_aout.c
@@ -313,7 +313,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
(current->mm->start_brk = N_BSSADDR(ex));
current->mm->free_area_cache = TASK_UNMAPPED_BASE;
- current->mm->rss = 0;
+ set_mm_counter(current->mm, rss, 0);
current->mm->mmap = NULL;
compute_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
diff --git a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c
index 6729d42dc6d90..fbd09b5126ce4 100644
--- a/arch/x86_64/ia32/ia32_signal.c
+++ b/arch/x86_64/ia32/ia32_signal.c
@@ -49,12 +49,12 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
return -EFAULT;
/* If you change siginfo_t structure, please make sure that
- this code is fixed accordingly.
- It should never copy any pad contained in the structure
- to avoid security leaks, but must copy the generic
- 3 ints plus the relevant union member. */
- err = __put_user(from->si_signo, &to->si_signo);
- err |= __put_user(from->si_errno, &to->si_errno);
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
err |= __put_user((short)from->si_code, &to->si_code);
if (from->si_code < 0) {
@@ -72,6 +72,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
err |= __put_user(from->si_utime, &to->si_utime);
err |= __put_user(from->si_stime, &to->si_stime);
err |= __put_user(from->si_status, &to->si_status);
+ /* FALL THROUGH */
default:
case __SI_KILL >> 16:
err |= __put_user(from->si_uid, &to->si_uid);
@@ -81,7 +82,8 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
break;
case __SI_TIMER >> 16:
err |= __put_user(from->si_overrun, &to->si_overrun);
- err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr);
+ err |= __put_user(ptr_to_compat(from->si_ptr),
+ &to->si_ptr);
break;
case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
case __SI_MESGQ >> 16:
@@ -205,14 +207,14 @@ ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 __user *sc,
sc, sc->err, sc->eip, sc->cs, sc->eflags);
#endif
#define COPY(x) { \
- unsigned int reg; \
+ unsigned int reg; \
err |= __get_user(reg, &sc->e ##x); \
regs->r ## x = reg; \
}
#define RELOAD_SEG(seg,mask) \
- { unsigned int cur; \
- unsigned short pre; \
+ { unsigned int cur; \
+ unsigned short pre; \
err |= __get_user(pre, &sc->seg); \
asm volatile("movl %%" #seg ",%0" : "=r" (cur)); \
pre |= mask; \
@@ -377,19 +379,19 @@ ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, struct _fpstate_ia32 __
err |= __put_user(current->thread.error_code, &sc->err);
err |= __put_user((u32)regs->rip, &sc->eip);
eflags = regs->eflags;
- if (current->ptrace & PT_PTRACED) {
+ if (current->ptrace & PT_PTRACED)
eflags &= ~TF_MASK;
- }
err |= __put_user((u32)eflags, &sc->eflags);
err |= __put_user((u32)regs->rsp, &sc->esp_at_signal);
tmp = save_i387_ia32(current, fpstate, regs, 0);
if (tmp < 0)
- err = -EFAULT;
+ err = -EFAULT;
else {
clear_used_math();
stts();
- err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL), &sc->fpstate);
+ err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL),
+ &sc->fpstate);
}
/* non-iBCS2 extensions.. */
@@ -439,7 +441,7 @@ void ia32_setup_frame(int sig, struct k_sigaction *ka,
{
struct exec_domain *ed = current_thread_info()->exec_domain;
- err |= __put_user((ed
+ err |= __put_user((ed
&& ed->signal_invmap
&& sig < 32
? ed->signal_invmap[sig]
@@ -449,7 +451,8 @@ void ia32_setup_frame(int sig, struct k_sigaction *ka,
if (err)
goto give_sigsegv;
- err |= ia32_setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]);
+ err |= ia32_setup_sigcontext(&frame->sc, &frame->fpstate, regs,
+ set->sig[0]);
if (err)
goto give_sigsegv;
@@ -528,10 +531,9 @@ void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
-
{
struct exec_domain *ed = current_thread_info()->exec_domain;
- err |= __put_user((ed
+ err |= __put_user((ed
&& ed->signal_invmap
&& sig < 32
? ed->signal_invmap[sig]
diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c
index 5b65992b80d39..657003e461e67 100644
--- a/arch/x86_64/kernel/e820.c
+++ b/arch/x86_64/kernel/e820.c
@@ -507,21 +507,7 @@ void __init setup_memory_region(void)
void __init parse_memopt(char *p, char **from)
{
- /*
- * mem=XXX[kKmM] limits kernel memory to XXX+1MB
- *
- * It would be more logical to count from 0 instead of from
- * HIGH_MEMORY, but we keep that for now for i386 compatibility.
- *
- * No support for custom mapping like i386. The reason is
- * that we need to read the e820 map anyways to handle the
- * ACPI mappings in the direct map. Also on x86-64 there
- * should be always a good e820 map. This is only an upper
- * limit, you cannot force usage of memory not in e820.
- *
- * -AK
- */
- end_user_pfn = memparse(p, from) + HIGH_MEMORY;
+ end_user_pfn = memparse(p, from);
end_user_pfn >>= PAGE_SHIFT;
}
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
index fb9e742d5baa2..e38b68191e360 100644
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -516,7 +516,7 @@ retint_kernel:
bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
jnc retint_restore_args
bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */
- jc retint_restore_args
+ jnc retint_restore_args
movl $PREEMPT_ACTIVE,threadinfo_preempt_count(%rcx)
sti
call schedule
diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
index 30e92ff8b3c07..b6d8725c1f611 100644
--- a/arch/x86_64/kernel/head.S
+++ b/arch/x86_64/kernel/head.S
@@ -26,6 +26,7 @@
.text
.code32
+ .globl startup_32
/* %bx: 1 if coming from smp trampoline on secondary cpu */
startup_32:
@@ -37,11 +38,13 @@ startup_32:
* There is no stack until we set one up.
*/
- movl %ebx,%ebp /* Save trampoline flag */
-
+ /* Initialize the %ds segment register */
movl $__KERNEL_DS,%eax
movl %eax,%ds
-
+
+ /* Load new GDT with the 64bit segments using 32bit descriptor */
+ lgdt pGDT32 - __START_KERNEL_map
+
/* If the CPU doesn't support CPUID this will double fault.
* Unfortunately it is hard to check for CPUID without a stack.
*/
@@ -57,16 +60,13 @@ startup_32:
btl $29, %edx
jnc no_long_mode
- movl %edx,%edi
-
/*
* Prepare for entering 64bits mode
*/
- /* Enable PAE mode and PGE */
+ /* Enable PAE mode */
xorl %eax, %eax
btsl $5, %eax
- btsl $7, %eax
movl %eax, %cr4
/* Setup early boot stage 4 level pagetables */
@@ -79,14 +79,6 @@ startup_32:
/* Enable Long Mode */
btsl $_EFER_LME, %eax
- /* Enable System Call */
- btsl $_EFER_SCE, %eax
-
- /* No Execute supported? */
- btl $20,%edi
- jnc 1f
- btsl $_EFER_NX, %eax
-1:
/* Make changes effective */
wrmsr
@@ -94,38 +86,69 @@ startup_32:
xorl %eax, %eax
btsl $31, %eax /* Enable paging and in turn activate Long Mode */
btsl $0, %eax /* Enable protected mode */
- btsl $1, %eax /* Enable MP */
- btsl $4, %eax /* Enable ET */
- btsl $5, %eax /* Enable NE */
- btsl $16, %eax /* Enable WP */
- btsl $18, %eax /* Enable AM */
/* Make changes effective */
movl %eax, %cr0
- jmp reach_compatibility_mode
-reach_compatibility_mode:
-
/*
* At this point we're in long mode but in 32bit compatibility mode
* with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
- * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we load
+ * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use
* the new gdt/idt that has __KERNEL_CS with CS.L = 1.
*/
-
- testw %bp,%bp /* secondary CPU? */
- jnz second
-
- /* Load new GDT with the 64bit segment using 32bit descriptor */
- movl $(pGDT32 - __START_KERNEL_map), %eax
- lgdt (%eax)
-
-second:
- movl $(ljumpvector - __START_KERNEL_map), %eax
- /* Finally jump in 64bit mode */
- ljmp *(%eax)
+ ljmp $__KERNEL_CS, $(startup_64 - __START_KERNEL_map)
.code64
.org 0x100
-reach_long64:
+ .globl startup_64
+startup_64:
+ /* We come here either from startup_32
+ * or directly from a 64bit bootloader.
+ * Since we may have come directly from a bootloader we
+ * reload the page tables here.
+ */
+
+ /* Enable PAE mode and PGE */
+ xorq %rax, %rax
+ btsq $5, %rax
+ btsq $7, %rax
+ movq %rax, %cr4
+
+ /* Setup early boot stage 4 level pagetables. */
+ movq $(init_level4_pgt - __START_KERNEL_map), %rax
+ movq %rax, %cr3
+
+ /* Check if nx is implemented */
+ movl $0x80000001, %eax
+ cpuid
+ movl %edx,%edi
+
+ /* Setup EFER (Extended Feature Enable Register) */
+ movl $MSR_EFER, %ecx
+ rdmsr
+
+ /* Enable System Call */
+ btsl $_EFER_SCE, %eax
+
+ /* No Execute supported? */
+ btl $20,%edi
+ jnc 1f
+ btsl $_EFER_NX, %eax
+1:
+ /* Make changes effective */
+ wrmsr
+
+ /* Setup cr0 */
+ xorq %rax, %rax
+ btsq $31, %rax /* Enable paging */
+ btsq $0, %rax /* Enable protected mode */
+ btsq $1, %rax /* Enable MP */
+ btsq $4, %rax /* Enable ET */
+ btsq $5, %rax /* Enable NE */
+ btsq $16, %rax /* Enable WP */
+ btsq $18, %rax /* Enable AM */
+ /* Make changes effective */
+ movq %rax, %cr0
+
+ /* Setup a boot time stack */
movq init_rsp(%rip),%rsp
/* zero EFLAGS after setting rsp */
@@ -198,12 +221,12 @@ ENTRY(no_long_mode)
.org 0xf00
.globl pGDT32
pGDT32:
- .word gdt32_end-gdt_table32
- .long gdt_table32-__START_KERNEL_map
+ .word gdt_end-cpu_gdt_table
+ .long cpu_gdt_table-__START_KERNEL_map
.org 0xf10
ljumpvector:
- .long reach_long64-__START_KERNEL_map
+ .long startup_64-__START_KERNEL_map
.word __KERNEL_CS
ENTRY(stext)
@@ -334,12 +357,6 @@ gdt:
.endr
#endif
-ENTRY(gdt_table32)
- .quad 0x0000000000000000 /* This one is magic */
- .quad 0x0000000000000000 /* unused */
- .quad 0x00af9a000000ffff /* __KERNEL_CS */
-gdt32_end:
-
/* We need valid kernel segments for data and code in long mode too
* IRET will check the segment types kkeil 2000/10/28
* Also sysret mandates a special GDT layout
@@ -360,9 +377,8 @@ ENTRY(cpu_gdt_table)
.quad 0x00affa000000ffff /* __USER_CS */
.quad 0x00cf9a000000ffff /* __KERNEL32_CS */
.quad 0,0 /* TSS */
- .quad 0 /* LDT */
+ .quad 0,0 /* LDT */
.quad 0,0,0 /* three TLS descriptors */
- .quad 0 /* unused now */
.quad 0x00009a000000ffff /* __KERNEL16_CS - 16bit PM for S3 wakeup. */
/* base must be patched for real base address. */
gdt_end:
diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c
index 6a011a12d017d..d527012460100 100644
--- a/arch/x86_64/kernel/i8259.c
+++ b/arch/x86_64/kernel/i8259.c
@@ -477,6 +477,7 @@ void reschedule_interrupt(void);
void call_function_interrupt(void);
void invalidate_interrupt(void);
void thermal_interrupt(void);
+void i8254_timer_resume(void);
static void setup_timer(void)
{
@@ -493,6 +494,11 @@ static int timer_resume(struct sys_device *dev)
return 0;
}
+void i8254_timer_resume(void)
+{
+ setup_timer();
+}
+
static struct sysdev_class timer_sysclass = {
set_kset_name("timer"),
.resume = timer_resume,
diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c
index 6ef6085a78894..49d5d5f137fa4 100644
--- a/arch/x86_64/kernel/pci-gart.c
+++ b/arch/x86_64/kernel/pci-gart.c
@@ -720,6 +720,7 @@ static __init int init_k8_gatt(struct agp_kern_info *info)
unsigned aper_base, new_aper_base;
unsigned aper_size, gatt_size, new_aper_size;
+ printk(KERN_INFO "PCI-DMA: Disabling AGP.\n");
aper_size = aper_base = info->aper_size = 0;
for_all_nb(dev) {
new_aper_base = read_aperture(dev, &new_aper_size);
@@ -798,26 +799,15 @@ static int __init pci_iommu_init(void)
return -1;
}
- if (no_iommu || (!force_iommu && end_pfn < 0xffffffff>>PAGE_SHIFT) ||
- !iommu_aperture) {
+ if (no_iommu ||
+ (!force_iommu && end_pfn < 0xffffffff>>PAGE_SHIFT) ||
+ !iommu_aperture ||
+ (no_agp && init_k8_gatt(&info) < 0)) {
printk(KERN_INFO "PCI-DMA: Disabling IOMMU.\n");
no_iommu = 1;
return -1;
}
- if (no_agp) {
- int err = -1;
- printk(KERN_INFO "PCI-DMA: Disabling AGP.\n");
- no_agp = 1;
- if (force_iommu || end_pfn >= 0xffffffff>>PAGE_SHIFT)
- err = init_k8_gatt(&info);
- if (err < 0) {
- printk(KERN_INFO "PCI-DMA: Disabling IOMMU.\n");
- no_iommu = 1;
- return -1;
- }
- }
-
aper_size = info.aper_size * 1024 * 1024;
iommu_size = check_iommu_size(info.aper_base, aper_size);
iommu_pages = iommu_size >> PAGE_SHIFT;
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index 2d7f2d9e1e857..e50fc41de6b95 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -1077,6 +1077,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
"fid", /* frequency id control */
"vid", /* voltage id control */
"ttp", /* thermal trip */
+ "tm",
+ "stc"
};
diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c
index 16ee9e194352f..5ace32c6ac5c5 100644
--- a/arch/x86_64/kernel/signal.c
+++ b/arch/x86_64/kernel/signal.c
@@ -160,9 +160,8 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
- if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax)) {
+ if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax))
goto badframe;
- }
#ifdef DEBUG_SIG
printk("%d sigreturn rip:%lx rsp:%lx frame:%p rax:%lx\n",current->pid,regs.rip,regs.rsp,frame,eax);
@@ -253,28 +252,25 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if (used_math()) {
fp = get_stack(ka, regs, sizeof(struct _fpstate));
- frame = (void __user *)round_down((unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
+ frame = (void __user *)round_down(
+ (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
- if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) {
- goto give_sigsegv;
- }
+ if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate)))
+ goto give_sigsegv;
if (save_i387(fp) < 0)
err |= -1;
- } else {
+ } else
frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8;
- }
- if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) {
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
- }
if (ka->sa.sa_flags & SA_SIGINFO) {
err |= copy_siginfo_to_user(&frame->info, info);
- if (err) {
+ if (err)
goto give_sigsegv;
}
- }
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
@@ -288,9 +284,8 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if (sizeof(*set) == 16) {
__put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
__put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
- } else {
- err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
- }
+ } else
+ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
@@ -302,9 +297,8 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
goto give_sigsegv;
}
- if (err) {
+ if (err)
goto give_sigsegv;
- }
#ifdef DEBUG_SIG
printk("%d old rip %lx old rsp %lx old rax %lx\n", current->pid,regs->rip,regs->rsp,regs->rax);
@@ -357,7 +351,8 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
sigset_t *oldset, struct pt_regs *regs)
{
#ifdef DEBUG_SIG
- printk("handle_signal pid:%d sig:%lu rip:%lx rsp:%lx regs=%p\n", current->pid, sig,
+ printk("handle_signal pid:%d sig:%lu rip:%lx rsp:%lx regs=%p\n",
+ current->pid, sig,
regs->rip, regs->rsp, regs);
#endif
@@ -375,10 +370,11 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
regs->rax = -EINTR;
break;
}
- /* fallthrough */
+ /* fallthrough */
case -ERESTARTNOINTR:
regs->rax = regs->orig_rax;
regs->rip -= 2;
+ break;
}
}
@@ -418,9 +414,8 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
* kernel mode. Just return without doing anything
* if so.
*/
- if ((regs->cs & 3) != 3) {
+ if ((regs->cs & 3) != 3)
return 1;
- }
if (try_to_freeze(0))
goto no_signal;
diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c
index b183fafacd563..d0725cd1b9d68 100644
--- a/arch/x86_64/kernel/smp.c
+++ b/arch/x86_64/kernel/smp.c
@@ -25,6 +25,7 @@
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
#include <asm/mach_apic.h>
+#include <asm/mmu_context.h>
#include <asm/proto.h>
/*
@@ -41,7 +42,7 @@ static cpumask_t flush_cpumask;
static struct mm_struct * flush_mm;
static unsigned long flush_va;
static DEFINE_SPINLOCK(tlbstate_lock);
-#define FLUSH_ALL 0xffffffff
+#define FLUSH_ALL -1ULL
/*
* We cannot call mmdrop() because we are in interrupt context,
@@ -52,7 +53,7 @@ static inline void leave_mm (unsigned long cpu)
if (read_pda(mmu_state) == TLBSTATE_OK)
BUG();
clear_bit(cpu, &read_pda(active_mm)->cpu_vm_mask);
- __flush_tlb();
+ load_cr3(swapper_pg_dir);
}
/*
diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
index 0b621af5756d9..afd3600b919e5 100644
--- a/arch/x86_64/kernel/smpboot.c
+++ b/arch/x86_64/kernel/smpboot.c
@@ -88,8 +88,6 @@ extern unsigned char trampoline_end [];
static unsigned long __init setup_trampoline(void)
{
void *tramp = __va(SMP_TRAMPOLINE_BASE);
- extern volatile __u32 tramp_gdt_ptr;
- tramp_gdt_ptr = __pa_symbol(&cpu_gdt_table);
memcpy(tramp, trampoline_data, trampoline_end - trampoline_data);
return virt_to_phys(tramp);
}
@@ -718,6 +716,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
printk(KERN_NOTICE "SMP motherboard not detected.\n");
io_apic_irqs = 0;
cpu_online_map = cpumask_of_cpu(0);
+ cpu_set(0, cpu_sibling_map[0]);
phys_cpu_present_map = physid_mask_of_physid(0);
if (APIC_init_uniprocessor())
printk(KERN_NOTICE "Local APIC not detected."
@@ -744,6 +743,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
io_apic_irqs = 0;
cpu_online_map = cpumask_of_cpu(0);
+ cpu_set(0, cpu_sibling_map[0]);
phys_cpu_present_map = physid_mask_of_physid(0);
disable_apic = 1;
goto smp_done;
@@ -759,6 +759,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");
io_apic_irqs = 0;
cpu_online_map = cpumask_of_cpu(0);
+ cpu_set(0, cpu_sibling_map[0]);
phys_cpu_present_map = physid_mask_of_physid(0);
disable_apic = 1;
goto smp_done;
diff --git a/arch/x86_64/kernel/suspend_asm.S b/arch/x86_64/kernel/suspend_asm.S
index 1246f85cd8c01..53f8e1659511f 100644
--- a/arch/x86_64/kernel/suspend_asm.S
+++ b/arch/x86_64/kernel/suspend_asm.S
@@ -69,12 +69,21 @@ loop:
movq pbe_next(%rdx), %rdx
jmp loop
done:
+ /* Flush TLB, including "global" things (vmalloc) */
+ movq mmu_cr4_features(%rip), %rax
+ movq %rax, %rdx
+ andq $~(1<<7), %rdx; # PGE
+ movq %rdx, %cr4; # turn off PGE
+ movq %cr3, %rcx; # flush TLB
+ movq %rcx, %cr3
+ movq %rax, %cr4; # turn PGE back on
+
movl $24, %eax
movl %eax, %ds
movq saved_context_esp(%rip), %rsp
movq saved_context_ebp(%rip), %rbp
- movq saved_context_eax(%rip), %rax
+ /* Don't restore %rax, it must be 0 anyway */
movq saved_context_ebx(%rip), %rbx
movq saved_context_ecx(%rip), %rcx
movq saved_context_edx(%rip), %rdx
@@ -89,5 +98,7 @@ done:
movq saved_context_r14(%rip), %r14
movq saved_context_r15(%rip), %r15
pushq saved_context_eflags(%rip) ; popfq
- call swsusp_restore
+
+ xorq %rax, %rax
+
ret
diff --git a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86_64/kernel/sys_x86_64.c
index 38a286ca3bf5f..624bcf8e54731 100644
--- a/arch/x86_64/kernel/sys_x86_64.c
+++ b/arch/x86_64/kernel/sys_x86_64.c
@@ -38,7 +38,7 @@ asmlinkage long sys_pipe(int __user *fildes)
return error;
}
-long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
+asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long off)
{
long error;
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index fad50e22e7292..3bafe438fa750 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -46,7 +46,7 @@ EXPORT_SYMBOL(jiffies_64);
#ifdef CONFIG_CPU_FREQ
static void cpufreq_delayed_get(void);
#endif
-
+extern void i8254_timer_resume(void);
extern int using_apic_timer;
DEFINE_SPINLOCK(rtc_lock);
@@ -551,11 +551,10 @@ unsigned long get_cmos_time(void)
BCD_TO_BIN(year);
/*
- * This will work up to Dec 31, 2069.
+ * x86-64 systems only exists since 2002.
+ * This will work up to Dec 31, 2100
*/
-
- if ((year += 1900) < 1970)
- year += 100;
+ year += 2000;
return mktime(year, mon, day, hour, min, sec);
}
@@ -980,6 +979,8 @@ static int timer_resume(struct sys_device *dev)
if (vxtime.hpet_address)
hpet_reenable();
+ else
+ i8254_timer_resume();
sec = ctime + clock_cmos_diff;
write_seqlock_irqsave(&xtime_lock,flags);
diff --git a/arch/x86_64/kernel/trampoline.S b/arch/x86_64/kernel/trampoline.S
index 5ae9f853b3935..6d9c9a8e7d0ea 100644
--- a/arch/x86_64/kernel/trampoline.S
+++ b/arch/x86_64/kernel/trampoline.S
@@ -37,7 +37,6 @@ r_base = .
mov %cs, %ax # Code and data in the same place
mov %ax, %ds
- mov $1, %bx # Flag an SMP trampoline
cli # We should be safe anyway
movl $0xA5A5A5A5, trampoline_data - r_base
@@ -46,31 +45,20 @@ r_base = .
lidt idt_48 - r_base # load idt with 0, 0
lgdt gdt_48 - r_base # load gdt with whatever is appropriate
- movw $__KERNEL_DS,%ax
- movw %ax,%ds
- movw %ax,%es
-
xor %ax, %ax
inc %ax # protected mode (PE) bit
lmsw %ax # into protected mode
- jmp flush_instr
-flush_instr:
- ljmpl $__KERNEL32_CS, $0x00100000
- # jump to startup_32 in arch/x86_64/kernel/head.S
+ # flaush prefetch and jump to startup_32 in arch/x86_64/kernel/head.S
+ ljmpl $__KERNEL32_CS, $(startup_32-__START_KERNEL_map)
+ # Careful these need to be in the same 64K segment as the above;
idt_48:
.word 0 # idt limit = 0
.word 0, 0 # idt base = 0L
gdt_48:
- .short 0x0800 # gdt limit = 2048, 256 GDT entries
- .globl tramp_gdt_ptr
-tramp_gdt_ptr:
- .long 0 # gdt base = gdt (first SMP CPU)
- # this is filled in by C because the 64bit
- # linker doesn't support absolute 32bit
- # relocations.
-
+ .short __KERNEL32_CS + 7 # gdt limit
+ .long cpu_gdt_table-__START_KERNEL_map
.globl trampoline_end
trampoline_end:
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 72e672ef3260f..d87ac6496cc2a 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -124,10 +124,10 @@ unsigned long *in_exception_stack(int cpu, unsigned long stack)
int k;
for (k = 0; k < N_EXCEPTION_STACKS; k++) {
struct tss_struct *tss = &per_cpu(init_tss, cpu);
- unsigned long end = tss->ist[k] + EXCEPTION_STKSZ;
+ unsigned long start = tss->ist[k] - EXCEPTION_STKSZ;
- if (stack >= tss->ist[k] && stack <= end)
- return (unsigned long *)end;
+ if (stack >= start && stack < tss->ist[k])
+ return (unsigned long *)tss->ist[k];
}
return NULL;
}
@@ -348,7 +348,6 @@ void oops_end(void)
die_owner = -1;
bust_spinlocks(0);
spin_unlock(&die_lock);
- local_irq_enable(); /* make sure back scroll still works */
if (panic_on_oops)
panic("Oops");
}
@@ -617,15 +616,6 @@ asmlinkage void default_do_nmi(struct pt_regs *regs)
mem_parity_error(reason, regs);
if (reason & 0x40)
io_check_error(reason, regs);
-
- /*
- * Reassert NMI in case it became active meanwhile
- * as it's edge-triggered.
- */
- outb(0x8f, 0x70);
- inb(0x71); /* dummy */
- outb(0x0f, 0x70);
- inb(0x71); /* dummy */
}
asmlinkage void do_int3(struct pt_regs * regs, long error_code)
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index 65108e17effae..59ebd5beda874 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -7,11 +7,12 @@
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
-ENTRY(_start)
+ENTRY(phys_startup_64)
jiffies_64 = jiffies;
SECTIONS
{
. = 0xffffffff80100000;
+ phys_startup_64 = startup_64 - LOAD_OFFSET;
_text = .; /* Text and read-only data */
.text : {
*(.text)
diff --git a/arch/x86_64/kernel/vsyscall.S b/arch/x86_64/kernel/vsyscall.S
deleted file mode 100644
index 3bd9a27c7eede..0000000000000
--- a/arch/x86_64/kernel/vsyscall.S
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Code for the vsyscall page. This version uses the syscall instruction.
- */
-
-#include <asm/ia32_unistd.h>
-#include <asm/offset.h>
-
- .text
- .globl __kernel_vsyscall
- .type __kernel_vsyscall,@function
-__kernel_vsyscall:
-.LSTART_vsyscall:
- push %ebp
-.Lpush_ebp:
- movl %ecx, %ebp
- syscall
- popl %ebp
-.Lpop_ebp:
- ret
-.LEND_vsyscall:
- .size __kernel_vsyscall,.-.LSTART_vsyscall
-
- .balign 32
- .globl __kernel_sigreturn
- .type __kernel_sigreturn,@function
-__kernel_sigreturn:
-.LSTART_sigreturn:
- popl %eax
- movl $__NR_ia32_sigreturn, %eax
- syscall
-.LEND_sigreturn:
- .size __kernel_sigreturn,.-.LSTART_sigreturn
-
- .balign 32
- .globl __kernel_rt_sigreturn
- .type __kernel_rt_sigreturn,@function
-__kernel_rt_sigreturn:
-.LSTART_rt_sigreturn:
- movl $__NR_ia32_rt_sigreturn, %eax
- syscall
-.LEND_rt_sigreturn:
- .size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn
-
- .section .eh_frame,"a",@progbits
-.LSTARTFRAME:
- .long .LENDCIE-.LSTARTCIE
-.LSTARTCIE:
- .long 0 /* CIE ID */
- .byte 1 /* Version number */
- .string "zR" /* NUL-terminated augmentation string */
- .uleb128 1 /* Code alignment factor */
- .sleb128 -4 /* Data alignment factor */
- .byte 8 /* Return address register column */
- .uleb128 1 /* Augmentation value length */
- .byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */
- .byte 0x0c /* DW_CFA_def_cfa */
- .uleb128 4
- .uleb128 4
- .byte 0x88 /* DW_CFA_offset, column 0x8 */
- .uleb128 1
- .align 4
-.LENDCIE:
-
- .long .LENDFDE1-.LSTARTFDE1 /* Length FDE */
-.LSTARTFDE1:
- .long .LSTARTFDE1-.LSTARTFRAME /* CIE pointer */
- .long .LSTART_vsyscall-. /* PC-relative start address */
- .long .LEND_vsyscall-.LSTART_vsyscall
- .uleb128 0 /* Augmentation length */
- /* What follows are the instructions for the table generation.
- We have to record all changes of the stack pointer. */
- .byte 0x40 + .Lpush_ebp-.LSTART_vsyscall /* DW_CFA_advance_loc */
- .byte 0x0e /* DW_CFA_def_cfa_offset */
- .uleb128 8
- .byte 0x85, 0x02 /* DW_CFA_offset %ebp -8 */
- .byte 0x40 + .Lpop_ebp-.Lpush_ebp /* DW_CFA_advance_loc */
- .byte 0xc5 /* DW_CFA_restore %ebp */
- .byte 0x0e /* DW_CFA_def_cfa_offset */
- .uleb128 4
- .align 4
-.LENDFDE1:
-
- .long .LENDFDE2-.LSTARTFDE2 /* Length FDE */
-.LSTARTFDE2:
- .long .LSTARTFDE2-.LSTARTFRAME /* CIE pointer */
- /* HACK: The dwarf2 unwind routines will subtract 1 from the
- return address to get an address in the middle of the
- presumed call instruction. Since we didn't get here via
- a call, we need to include the nop before the real start
- to make up for it. */
- .long .LSTART_sigreturn-1-. /* PC-relative start address */
- .long .LEND_sigreturn-.LSTART_sigreturn+1
- .uleb128 0 /* Augmentation length */
- /* What follows are the instructions for the table generation.
- We record the locations of each register saved. This is
- complicated by the fact that the "CFA" is always assumed to
- be the value of the stack pointer in the caller. This means
- that we must define the CFA of this body of code to be the
- saved value of the stack pointer in the sigcontext. Which
- also means that there is no fixed relation to the other
- saved registers, which means that we must use DW_CFA_expression
- to compute their addresses. It also means that when we
- adjust the stack with the popl, we have to do it all over again. */
-
-#define do_cfa_expr(offset) \
- .byte 0x0f; /* DW_CFA_def_cfa_expression */ \
- .uleb128 1f-0f; /* length */ \
-0: .byte 0x74; /* DW_OP_breg4 */ \
- .sleb128 offset; /* offset */ \
- .byte 0x06; /* DW_OP_deref */ \
-1:
-
-#define do_expr(regno, offset) \
- .byte 0x10; /* DW_CFA_expression */ \
- .uleb128 regno; /* regno */ \
- .uleb128 1f-0f; /* length */ \
-0: .byte 0x74; /* DW_OP_breg4 */ \
- .sleb128 offset; /* offset */ \
-1:
-
- do_cfa_expr(IA32_SIGCONTEXT_esp+4)
- do_expr(0, IA32_SIGCONTEXT_eax+4)
- do_expr(1, IA32_SIGCONTEXT_ecx+4)
- do_expr(2, IA32_SIGCONTEXT_edx+4)
- do_expr(3, IA32_SIGCONTEXT_ebx+4)
- do_expr(5, IA32_SIGCONTEXT_ebp+4)
- do_expr(6, IA32_SIGCONTEXT_esi+4)
- do_expr(7, IA32_SIGCONTEXT_edi+4)
- do_expr(8, IA32_SIGCONTEXT_eip+4)
-
- .byte 0x42 /* DW_CFA_advance_loc 2 -- nop; popl eax. */
-
- do_cfa_expr(IA32_SIGCONTEXT_esp)
- do_expr(0, IA32_SIGCONTEXT_eax)
- do_expr(1, IA32_SIGCONTEXT_ecx)
- do_expr(2, IA32_SIGCONTEXT_edx)
- do_expr(3, IA32_SIGCONTEXT_ebx)
- do_expr(5, IA32_SIGCONTEXT_ebp)
- do_expr(6, IA32_SIGCONTEXT_esi)
- do_expr(7, IA32_SIGCONTEXT_edi)
- do_expr(8, IA32_SIGCONTEXT_eip)
-
- .align 4
-.LENDFDE2:
-
- .long .LENDFDE3-.LSTARTFDE3 /* Length FDE */
-.LSTARTFDE3:
- .long .LSTARTFDE3-.LSTARTFRAME /* CIE pointer */
- /* HACK: See above wrt unwind library assumptions. */
- .long .LSTART_rt_sigreturn-1-. /* PC-relative start address */
- .long .LEND_rt_sigreturn-.LSTART_rt_sigreturn+1
- .uleb128 0 /* Augmentation */
- /* What follows are the instructions for the table generation.
- We record the locations of each register saved. This is
- slightly less complicated than the above, since we don't
- modify the stack pointer in the process. */
-
- do_cfa_expr(IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_esp)
- do_expr(0, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_eax)
- do_expr(1, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ecx)
- do_expr(2, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_edx)
- do_expr(3, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ebx)
- do_expr(5, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ebp)
- do_expr(6, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_esi)
- do_expr(7, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_edi)
- do_expr(8, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_eip)
-
- .align 4
-.LENDFDE3:
diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
index f28a07c77b485..b4b8dc59663ad 100644
--- a/arch/x86_64/kernel/vsyscall.c
+++ b/arch/x86_64/kernel/vsyscall.c
@@ -9,30 +9,14 @@
* a different vsyscall implementation for Linux/IA32 and for the name.
*
* vsyscall 1 is located at -10Mbyte, vsyscall 2 is located
- * at virtual address -10Mbyte+1024bytes etc... There are at max 8192
+ * at virtual address -10Mbyte+1024bytes etc... There are at max 4
* vsyscalls. One vsyscall can reserve more than 1 slot to avoid
- * jumping out of line if necessary.
+ * jumping out of line if necessary. We cannot add more with this
+ * mechanism because older kernels won't return -ENOSYS.
+ * If we want more than four we need a vDSO.
*
- * Note: the concept clashes with user mode linux. If you use UML just
- * set the kernel.vsyscall sysctl to 0.
- */
-
-/*
- * TODO 2001-03-20:
- *
- * 1) make page fault handler detect faults on page1-page-last of the vsyscall
- * virtual space, and make it increase %rip and write -ENOSYS in %rax (so
- * we'll be able to upgrade to a new glibc without upgrading kernel after
- * we add more vsyscalls.
- * 2) Possibly we need a fixmap table for the vsyscalls too if we want
- * to avoid SIGSEGV and we want to return -EFAULT from the vsyscalls as well.
- * Can we segfault inside a "syscall"? We can fix this anytime and those fixes
- * won't be visible for userspace. Not fixing this is a noop for correct programs,
- * broken programs will segfault and there's no security risk until we choose to
- * fix it.
- *
- * These are not urgent things that we need to address only before shipping the first
- * production binary kernels.
+ * Note: the concept clashes with user mode linux. If you use UML and
+ * want per guest time just set the kernel.vsyscall64 sysctl to 0.
*/
#include <linux/time.h>
@@ -41,6 +25,7 @@
#include <linux/timer.h>
#include <linux/seqlock.h>
#include <linux/jiffies.h>
+#include <linux/sysctl.h>
#include <asm/vsyscall.h>
#include <asm/pgtable.h>
@@ -62,8 +47,7 @@ static force_inline void timeval_normalize(struct timeval * tv)
time_t __sec;
__sec = tv->tv_usec / 1000000;
- if (__sec)
- {
+ if (__sec) {
tv->tv_usec %= 1000000;
tv->tv_sec += __sec;
}
@@ -84,10 +68,11 @@ static force_inline void do_vgettimeofday(struct timeval * tv)
if (__vxtime.mode == VXTIME_TSC) {
sync_core();
rdtscll(t);
- if (t < __vxtime.last_tsc) t = __vxtime.last_tsc;
+ if (t < __vxtime.last_tsc)
+ t = __vxtime.last_tsc;
usec += ((t - __vxtime.last_tsc) *
__vxtime.tsc_quot) >> 32;
- /* See comment in x86_64 do_gettimeofday. */
+ /* See comment in x86_64 do_gettimeofday. */
} else {
usec += ((readl((void *)fix_to_virt(VSYSCALL_HPET) + 0xf0) -
__vxtime.last) * __vxtime.quot) >> 32;
@@ -101,14 +86,13 @@ static force_inline void do_vgettimeofday(struct timeval * tv)
/* RED-PEN may want to readd seq locking, but then the variable should be write-once. */
static force_inline void do_get_tz(struct timezone * tz)
{
- *tz = __sys_tz;
+ *tz = __sys_tz;
}
-
static force_inline int gettimeofday(struct timeval *tv, struct timezone *tz)
{
int ret;
- asm volatile("syscall"
+ asm volatile("vsysc2: syscall"
: "=a" (ret)
: "0" (__NR_gettimeofday),"D" (tv),"S" (tz) : __syscall_clobber );
return ret;
@@ -117,7 +101,7 @@ static force_inline int gettimeofday(struct timeval *tv, struct timezone *tz)
static force_inline long time_syscall(long *t)
{
long secs;
- asm volatile("syscall"
+ asm volatile("vsysc1: syscall"
: "=a" (secs)
: "0" (__NR_time),"D" (t) : __syscall_clobber);
return secs;
@@ -126,7 +110,7 @@ static force_inline long time_syscall(long *t)
static int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
{
if (unlikely(!__sysctl_vsyscall))
- return gettimeofday(tv,tz);
+ return gettimeofday(tv,tz);
if (tv)
do_vgettimeofday(tv);
if (tz)
@@ -153,9 +137,71 @@ static long __vsyscall(2) venosys_0(void)
static long __vsyscall(3) venosys_1(void)
{
return -ENOSYS;
+}
+
+#ifdef CONFIG_SYSCTL
+
+#define SYSCALL 0x050f
+#define NOP2 0x9090
+/*
+ * NOP out syscall in vsyscall page when not needed.
+ */
+static int vsyscall_sysctl_change(ctl_table *ctl, int write, struct file * filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ extern u16 vsysc1, vsysc2;
+ u16 *map1, *map2;
+ int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
+ if (!write)
+ return ret;
+ /* gcc has some trouble with __va(__pa()), so just do it this
+ way. */
+ map1 = ioremap(__pa_symbol(&vsysc1), 2);
+ if (!map1)
+ return -ENOMEM;
+ map2 = ioremap(__pa_symbol(&vsysc2), 2);
+ if (!map2) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ if (!sysctl_vsyscall) {
+ *map1 = SYSCALL;
+ *map2 = SYSCALL;
+ } else {
+ *map1 = NOP2;
+ *map2 = NOP2;
+ }
+ iounmap(map2);
+out:
+ iounmap(map1);
+ return ret;
}
+static int vsyscall_sysctl_nostrat(ctl_table *t, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen,
+ void **context)
+{
+ return -ENOSYS;
+}
+
+static ctl_table kernel_table2[] = {
+ { .ctl_name = 99, .procname = "vsyscall64",
+ .data = &sysctl_vsyscall, .maxlen = sizeof(int), .mode = 0644,
+ .strategy = vsyscall_sysctl_nostrat,
+ .proc_handler = vsyscall_sysctl_change },
+ { 0, }
+};
+
+static ctl_table kernel_root_table2[] = {
+ { .ctl_name = CTL_KERN, .procname = "kernel", .mode = 0555,
+ .child = kernel_table2 },
+ { 0 },
+};
+
+#endif
+
static void __init map_vsyscall(void)
{
extern char __vsyscall_0;
@@ -166,13 +212,13 @@ static void __init map_vsyscall(void)
static int __init vsyscall_init(void)
{
- BUG_ON(((unsigned long) &vgettimeofday !=
- VSYSCALL_ADDR(__NR_vgettimeofday)));
+ BUG_ON(((unsigned long) &vgettimeofday !=
+ VSYSCALL_ADDR(__NR_vgettimeofday)));
BUG_ON((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime));
BUG_ON((VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE)));
map_vsyscall();
- sysctl_vsyscall = 1;
-
+ sysctl_vsyscall = 1;
+ register_sysctl_table(kernel_root_table2, 0);
return 0;
}
diff --git a/arch/x86_64/lib/bitops.c b/arch/x86_64/lib/bitops.c
index 994d766503dd9..a29fb75b33ac4 100644
--- a/arch/x86_64/lib/bitops.c
+++ b/arch/x86_64/lib/bitops.c
@@ -1,4 +1,3 @@
-#include <linux/module.h>
#include <linux/bitops.h>
#undef find_first_zero_bit
@@ -134,6 +133,8 @@ long find_next_bit(const unsigned long * addr, long size, long offset)
return (offset + set + res);
}
+#include <linux/module.h>
+
EXPORT_SYMBOL(find_next_bit);
EXPORT_SYMBOL(find_first_bit);
EXPORT_SYMBOL(find_first_zero_bit);
diff --git a/arch/x86_64/lib/delay.c b/arch/x86_64/lib/delay.c
index 05689cc549017..6e2d66472eb19 100644
--- a/arch/x86_64/lib/delay.c
+++ b/arch/x86_64/lib/delay.c
@@ -21,7 +21,7 @@ int x86_udelay_tsc = 0; /* Delay via TSC */
void __delay(unsigned long loops)
{
- unsigned long bclock, now;
+ unsigned bclock, now;
rdtscl(bclock);
do
diff --git a/arch/x86_64/lib/getuser.S b/arch/x86_64/lib/getuser.S
index 61a1f75aba878..f94ea8a440515 100644
--- a/arch/x86_64/lib/getuser.S
+++ b/arch/x86_64/lib/getuser.S
@@ -2,6 +2,7 @@
* __get_user functions.
*
* (C) Copyright 1998 Linus Torvalds
+ * (C) Copyright 2005 Andi Kleen
*
* These functions have a non-standard call interface
* to make them more efficient, especially as they
@@ -12,12 +13,14 @@
/*
* __get_user_X
*
- * Inputs: %rax contains the address
+ * Inputs: %rcx contains the address.
+ * The register is modified, but all changes are undone
+ * before returning because the C code doesn't know about it.
*
* Outputs: %rax is error code (0 or -EFAULT)
* %rdx contains zero-extended value
*
- * %rbx is destroyed.
+ * %r8 is destroyed.
*
* These functions should not modify any other registers,
* as they get called from within inline assembly.
@@ -33,52 +36,60 @@
.p2align 4
.globl __get_user_1
__get_user_1:
- GET_THREAD_INFO(%rbx)
- cmpq threadinfo_addr_limit(%rbx),%rax
+ GET_THREAD_INFO(%r8)
+ cmpq threadinfo_addr_limit(%r8),%rcx
jae bad_get_user
-1: movzb (%rax),%edx
- xorq %rax,%rax
+1: movzb (%rcx),%edx
+ xorl %eax,%eax
ret
.p2align 4
.globl __get_user_2
__get_user_2:
- GET_THREAD_INFO(%rbx)
- addq $1,%rax
- jc bad_get_user
- cmpq threadinfo_addr_limit(%rbx),%rax
- jae bad_get_user
-2: movzwl -1(%rax),%edx
- xorq %rax,%rax
+ GET_THREAD_INFO(%r8)
+ addq $1,%rcx
+ jc 20f
+ cmpq threadinfo_addr_limit(%r8),%rcx
+ jae 20f
+ decq %rcx
+2: movzwl (%rcx),%edx
+ xorl %eax,%eax
ret
+20: decq %rcx
+ jmp bad_get_user
.p2align 4
.globl __get_user_4
__get_user_4:
- GET_THREAD_INFO(%rbx)
- addq $3,%rax
- jc bad_get_user
- cmpq threadinfo_addr_limit(%rbx),%rax
- jae bad_get_user
-3: movl -3(%rax),%edx
- xorq %rax,%rax
+ GET_THREAD_INFO(%r8)
+ addq $3,%rcx
+ jc 30f
+ cmpq threadinfo_addr_limit(%r8),%rcx
+ jae 30f
+ subq $3,%rcx
+3: movl (%rcx),%edx
+ xorl %eax,%eax
ret
+30: subq $3,%rcx
+ jmp bad_get_user
.p2align 4
.globl __get_user_8
__get_user_8:
- GET_THREAD_INFO(%rbx)
- addq $7,%rax
+ GET_THREAD_INFO(%r8)
+ addq $7,%rcx
jc bad_get_user
- cmpq threadinfo_addr_limit(%rbx),%rax
+ cmpq threadinfo_addr_limit(%r8),%rcx
jae bad_get_user
-4: movq -7(%rax),%rdx
- xorq %rax,%rax
+ subq $7,%rcx
+4: movq (%rcx),%rdx
+ xorl %eax,%eax
ret
+40: subq $7,%rcx
+ jmp bad_get_user
-ENTRY(bad_get_user)
bad_get_user:
- xorq %rdx,%rdx
+ xorl %edx,%edx
movq $(-EFAULT),%rax
ret
diff --git a/arch/x86_64/lib/putuser.S b/arch/x86_64/lib/putuser.S
index 4d287ceeab73c..0dee1fdcb1628 100644
--- a/arch/x86_64/lib/putuser.S
+++ b/arch/x86_64/lib/putuser.S
@@ -2,80 +2,81 @@
* __put_user functions.
*
* (C) Copyright 1998 Linus Torvalds
+ * (C) Copyright 2005 Andi Kleen
*
* These functions have a non-standard call interface
- * to make them more efficient.
+ * to make them more efficient, especially as they
+ * return an error value in addition to the "real"
+ * return value.
*/
/*
* __put_user_X
*
- * Inputs: %rax contains the address
- * %rdx contains the value
+ * Inputs: %rcx contains the address
+ * %rdx contains new value
*
* Outputs: %rax is error code (0 or -EFAULT)
- * %rbx is corrupted (will contain "current_task").
+ *
+ * %r8 is destroyed.
*
* These functions should not modify any other registers,
* as they get called from within inline assembly.
*/
-/* FIXME: putuser.S should be really merged with getuser.S, and preprocessor should be used to keep code duplication lower */
-
#include <linux/linkage.h>
#include <asm/page.h>
#include <asm/errno.h>
#include <asm/offset.h>
#include <asm/thread_info.h>
-.text
-.p2align
+ .text
+ .p2align 4
.globl __put_user_1
__put_user_1:
- GET_THREAD_INFO(%rbx)
- cmpq threadinfo_addr_limit(%rbx),%rax
+ GET_THREAD_INFO(%r8)
+ cmpq threadinfo_addr_limit(%r8),%rcx
jae bad_put_user
-1: movb %dl,(%rax)
- xorq %rax,%rax
+1: movb %dl,(%rcx)
+ xorl %eax,%eax
ret
-.p2align
+ .p2align 4
.globl __put_user_2
__put_user_2:
- GET_THREAD_INFO(%rbx)
- addq $1,%rax
- jc bad_put_user
- cmpq threadinfo_addr_limit(%rbx),%rax
- jae bad_put_user
-2: movw %dx,-1(%rax)
- xorq %rax,%rax
+ GET_THREAD_INFO(%r8)
+ addq $1,%rcx
+ jc bad_put_user
+ cmpq threadinfo_addr_limit(%r8),%rcx
+ jae bad_put_user
+2: movw %dx,-1(%rcx)
+ xorl %eax,%eax
ret
-.p2align
+ .p2align 4
.globl __put_user_4
__put_user_4:
- GET_THREAD_INFO(%rbx)
- addq $3,%rax
- jc bad_put_user
- cmpq threadinfo_addr_limit(%rbx),%rax
- jae bad_put_user
-3: movl %edx,-3(%rax)
- xorq %rax,%rax
+ GET_THREAD_INFO(%r8)
+ addq $3,%rcx
+ jc bad_put_user
+ cmpq threadinfo_addr_limit(%r8),%rcx
+ jae bad_put_user
+3: movl %edx,-3(%rcx)
+ xorl %eax,%eax
ret
-.p2align
+ .p2align 4
.globl __put_user_8
__put_user_8:
- GET_THREAD_INFO(%rbx)
- addq $7,%rax
- jc bad_put_user
- cmpq threadinfo_addr_limit(%rbx),%rax
- jae bad_put_user
-4: movq %rdx,-7(%rax)
- xorq %rax,%rax
+ GET_THREAD_INFO(%r8)
+ addq $7,%rcx
+ jc bad_put_user
+ cmpq threadinfo_addr_limit(%r8),%rcx
+ jae bad_put_user
+4: movq %rdx,-7(%rcx)
+ xorl %eax,%eax
ret
-ENTRY(bad_put_user)
bad_put_user:
movq $(-EFAULT),%rax
ret
@@ -84,5 +85,5 @@ bad_put_user:
.quad 1b,bad_put_user
.quad 2b,bad_put_user
.quad 3b,bad_put_user
- .quad 4b,bad_put_user
+ .quad 4b,bad_put_user
.previous
diff --git a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c
index f3fad903503e9..74ec8554b195d 100644
--- a/arch/x86_64/mm/ioremap.c
+++ b/arch/x86_64/mm/ioremap.c
@@ -18,6 +18,9 @@
#include <asm/tlbflush.h>
#include <asm/proto.h>
+#define ISA_START_ADDRESS 0xa0000
+#define ISA_END_ADDRESS 0x100000
+
static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
unsigned long phys_addr, unsigned long flags)
{
@@ -172,7 +175,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
/*
* Don't remap the low PCI/ISA area, it's always mapped..
*/
- if (phys_addr >= 0xA0000 && last_addr < 0x100000)
+ if (phys_addr >= ISA_START_ADDRESS && last_addr < ISA_END_ADDRESS)
return (__force void __iomem *)phys_to_virt(phys_addr);
#ifndef CONFIG_DISCONTIGMEM
@@ -252,6 +255,9 @@ void iounmap(volatile void __iomem *addr)
if (addr <= high_memory)
return;
+ if (addr >= phys_to_virt(ISA_START_ADDRESS) &&
+ addr < phys_to_virt(ISA_END_ADDRESS))
+ return;
write_lock(&vmlist_lock);
for (p = vmlist, pprev = &vmlist; p != NULL; pprev = &p->next, p = *pprev)
diff --git a/arch/x86_64/pci/k8-bus.c b/arch/x86_64/pci/k8-bus.c
index d1c728acddd76..62349c78db574 100644
--- a/arch/x86_64/pci/k8-bus.c
+++ b/arch/x86_64/pci/k8-bus.c
@@ -29,7 +29,7 @@ __init static int
fill_mp_bus_to_cpumask(void)
{
struct pci_dev *nb_dev = NULL;
- int i, j;
+ int i, j, printed;
u32 ldtbus, nid;
static int lbnr[3] = {
LDT_BUS_NUMBER_REGISTER_0,
@@ -60,11 +60,15 @@ fill_mp_bus_to_cpumask(void)
}
/* quick sanity check */
+ printed = 0;
for (i = 0; i < 256; i++) {
if (cpus_empty(pci_bus_to_cpumask[i])) {
- printk(KERN_ERR
- "k8-bus.c: bus %i has empty cpu mask\n", i);
pci_bus_to_cpumask[i] = CPU_MASK_ALL;
+ if (printed)
+ continue;
+ printk(KERN_ERR
+ "k8-bus.c: some busses have empty cpu mask\n");
+ printed = 1;
}
}
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 607cfddc753a6..fd7c5a0649afd 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -84,10 +84,11 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
u32 sec, min, hr;
u32 day, mo, yr;
unsigned char rtc_control = 0;
+ unsigned long flags;
ACPI_FUNCTION_TRACE("acpi_system_alarm_seq_show");
- spin_lock(&rtc_lock);
+ spin_lock_irqsave(&rtc_lock, flags);
sec = CMOS_READ(RTC_SECONDS_ALARM);
min = CMOS_READ(RTC_MINUTES_ALARM);
@@ -109,7 +110,7 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
else
yr = CMOS_READ(RTC_YEAR);
- spin_unlock(&rtc_lock);
+ spin_unlock_irqrestore(&rtc_lock, flags);
if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
BCD_TO_BIN(sec);
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index 2c0946c49d5d9..423bbf2000d2f 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -2700,10 +2700,8 @@ DAC960_DetectController(struct pci_dev *PCI_Device,
Controller->PCIDevice = PCI_Device;
strcpy(Controller->FullModelName, "DAC960");
- if (pci_enable_device(PCI_Device)) {
- kfree(Controller);
+ if (pci_enable_device(PCI_Device))
goto Failure;
- }
switch (Controller->HardwareType)
{
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index c297be0c036a9..e83a1e2e8b15c 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -6,7 +6,7 @@ menu "Block devices"
config BLK_DEV_FD
tristate "Normal floppy disk support"
- depends on (!ARCH_S390 && !M68K && !IA64 && !USERMODE) || Q40 || (SUN3X && BROKEN)
+ depends on (!ARCH_S390 && !M68K && !IA64 && !UML) || Q40 || (SUN3X && BROKEN)
---help---
If you want to use the floppy disk drive(s) of your PC under Linux,
say Y. Information about this driver, especially important for IBM
@@ -210,7 +210,7 @@ config BLK_DEV_UMEM
config BLK_DEV_UBD
bool "Virtual block device"
- depends on USERMODE
+ depends on UML
---help---
The User-Mode Linux port includes a driver called UBD which will let
you access arbitrary files on the host computer as block devices.
@@ -243,7 +243,7 @@ config BLK_DEV_COW_COMMON
config MMAPPER
tristate "Example IO memory driver (BROKEN)"
- depends on USERMODE && BROKEN
+ depends on UML && BROKEN
---help---
The User-Mode Linux port can provide support for IO Memory
emulation with this option. This allows a host file to be
@@ -455,7 +455,7 @@ config INITRAMFS_ROOT_GID
#for instance.
config LBD
bool "Support for Large Block Devices"
- depends on X86 || MIPS32 || PPC32 || ARCH_S390_31 || SUPERH || USERMODE
+ depends on X86 || MIPS32 || PPC32 || ARCH_S390_31 || SUPERH || UML
help
Say Y here if you want to attach large (bigger than 2TB) discs to
your machine, or if you want to have a raid or loopback device
@@ -463,7 +463,7 @@ config LBD
config CDROM_PKTCDVD
tristate "Packet writing on CD/DVD media"
- depends on !USERMODE
+ depends on !UML
help
If you have a CDROM drive that supports packet writing, say Y to
include preliminary support. It should work with any MMC/Mt Fuji
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index f9b386be129ad..8f7c1a1ed7f44 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -304,7 +304,7 @@ cciss_proc_write(struct file *file, const char __user *buffer,
if (copy_from_user(cmd, buffer, count)) return -EFAULT;
cmd[count] = '\0';
len = strlen(cmd); // above 3 lines ensure safety
- if (cmd[len-1] == '\n')
+ if (len && cmd[len-1] == '\n')
cmd[--len] = '\0';
# ifdef CONFIG_CISS_SCSI_TAPE
if (strcmp("engage scsi", cmd)==0) {
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 0014c48476dfa..1a1fa3ccb9137 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -1421,8 +1421,8 @@ static int pkt_set_write_settings(struct pktcdvd_device *pd)
char buffer[128];
int ret, size;
- /* doesn't apply to DVD+RW */
- if (pd->mmc3_profile == 0x1a)
+ /* doesn't apply to DVD+RW or DVD-RAM */
+ if ((pd->mmc3_profile == 0x1a) || (pd->mmc3_profile == 0x12))
return 0;
memset(buffer, 0, sizeof(buffer));
@@ -1536,6 +1536,7 @@ static int pkt_good_disc(struct pktcdvd_device *pd, disc_information *di)
break;
case 0x1a: /* DVD+RW */
case 0x13: /* DVD-RW */
+ case 0x12: /* DVD-RAM */
return 0;
default:
printk("pktcdvd: Wrong disc profile (%x)\n", pd->mmc3_profile);
@@ -1601,6 +1602,9 @@ static int pkt_probe_settings(struct pktcdvd_device *pd)
case 0x13: /* DVD-RW */
printk("pktcdvd: inserted media is DVD-RW\n");
break;
+ case 0x12: /* DVD-RAM */
+ printk("pktcdvd: inserted media is DVD-RAM\n");
+ break;
default:
printk("pktcdvd: inserted media is CD-R%s\n", di.erasable ? "W" : "");
break;
@@ -1893,6 +1897,7 @@ static int pkt_open_write(struct pktcdvd_device *pd)
switch (pd->mmc3_profile) {
case 0x13: /* DVD-RW */
case 0x1a: /* DVD+RW */
+ case 0x12: /* DVD-RAM */
DPRINTK("pktcdvd: write speed %ukB/s\n", write_speed);
break;
default:
@@ -2624,7 +2629,7 @@ static struct miscdevice pkt_misc = {
.fops = &pkt_ctl_fops
};
-static int pkt_init(void)
+static int __init pkt_init(void)
{
int ret;
@@ -2660,7 +2665,7 @@ out2:
return ret;
}
-static void pkt_exit(void)
+static void __exit pkt_exit(void)
{
remove_proc_entry("pktcdvd", proc_root_driver);
misc_deregister(&pkt_misc);
diff --git a/drivers/cdrom/Kconfig b/drivers/cdrom/Kconfig
index 455a9a19ff198..ff5652d40619e 100644
--- a/drivers/cdrom/Kconfig
+++ b/drivers/cdrom/Kconfig
@@ -103,60 +103,14 @@ config SBPCD
To compile this driver as a module, choose M here: the
module will be called sbpcd.
-config MCD
- tristate "Mitsumi (standard) [no XA/Multisession] CDROM support"
- depends on CD_NO_IDESCSI && BROKEN
- ---help---
- This is the older of the two drivers for the older Mitsumi models
- LU-005, FX-001 and FX-001D. This is not the right driver for the
- FX-001DE and the triple or quad speed models (all these are
- IDE/ATAPI models). Please also the file
- <file:Documentation/cdrom/mcd>.
-
- With the old LU-005 model, the whole drive chassis slides out for cd
- insertion. The FX-xxx models use a motorized tray type mechanism.
- Note that this driver does not support XA or MultiSession CDs
- (PhotoCDs). There is a new driver (next question) which can do
- this. If you want that one, say N here.
-
- If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
- file system support" below, because that's the file system used on
- CD-ROMs.
-
- To compile this driver as a module, choose M here: the
- module will be called mcd.
-
-config MCD_IRQ
- int "MCD IRQ"
- depends on MCD
- default "11"
- help
- This allows you to specify the default value of the IRQ used by the
- driver. This setting can be overridden by passing the "mcd="
- parameter to the kernel at boot time (or at module load time if you
- said M to "Standard Mitsumi CD-ROM support").
-
-config MCD_BASE
- hex "MCD I/O base"
- depends on MCD
- default "300"
- help
- This allows you to specify the default value of the I/O base address
- used by the driver. This setting can be overridden by passing the
- "mcd=" parameter to the kernel at boot time (or at module load time
- if you said M to "Standard Mitsumi CD-ROM support").
-
config MCDX
- tristate "Mitsumi [XA/MultiSession] CDROM support"
+ tristate "Mitsumi CDROM support"
depends on CD_NO_IDESCSI
---help---
- Use this driver if you want to be able to read XA or MultiSession
- CDs (PhotoCDs) as well as ordinary CDs with your Mitsumi LU-005,
- FX-001 or FX-001D CD-ROM drive. In addition, this driver uses much
- less kernel memory than the old one, if that is a concern. This
- driver is able to support more than one drive, but each drive needs
- a separate interface card. Please read the file
- <file:Documentation/cdrom/mcdx>.
+ Use this driver if you want to be able to use your Mitsumi LU-005,
+ FX-001 or FX-001D CD-ROM drive.
+
+ Please read the file <file:Documentation/cdrom/mcdx>.
If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM
file system support" below, because that's the file system used on
diff --git a/drivers/cdrom/Makefile b/drivers/cdrom/Makefile
index 4a8351753e07c..d1d1e5a4be73b 100644
--- a/drivers/cdrom/Makefile
+++ b/drivers/cdrom/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_CDU31A) += cdu31a.o cdrom.o
obj-$(CONFIG_CM206) += cm206.o cdrom.o
obj-$(CONFIG_GSCD) += gscd.o
obj-$(CONFIG_ISP16_CDI) += isp16.o
-obj-$(CONFIG_MCD) += mcd.o cdrom.o
obj-$(CONFIG_MCDX) += mcdx.o cdrom.o
obj-$(CONFIG_OPTCD) += optcd.o
obj-$(CONFIG_SBPCD) += sbpcd.o cdrom.o
diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
index 44ea989a51fa4..647a71b12a2a3 100644
--- a/drivers/cdrom/cdu31a.c
+++ b/drivers/cdrom/cdu31a.c
@@ -148,10 +148,10 @@
* Ondrej Zary <rainbow@rainbow-software.org>
*/
-#include <linux/major.h>
+#define DEBUG 1
+#include <linux/major.h>
#include <linux/module.h>
-
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
@@ -166,13 +166,13 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/cdrom.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/dma.h>
-#include <linux/cdrom.h>
#include "cdu31a.h"
#define MAJOR_NR CDU31A_CDROM_MAJOR
@@ -180,10 +180,7 @@
#define CDU31A_MAX_CONSECUTIVE_ATTENTIONS 10
-#define DEBUG 1
-
-/* Define the following if you have data corruption problems. */
-#undef SONY_POLL_EACH_BYTE
+#define PFX "CDU31A: "
/*
** Edit the following data to change interrupts, DMA channels, etc.
@@ -267,14 +264,7 @@ static int sony_toc_read = 0; /* Has the TOC been read for
static struct s_sony_subcode last_sony_subcode; /* Points to the last
subcode address read */
-static volatile int sony_inuse = 0; /* Is the drive in use? Only one operation
- at a time allowed */
-
-static DECLARE_WAIT_QUEUE_HEAD(sony_wait); /* Things waiting for the drive */
-
-static struct task_struct *has_cd_task = NULL; /* The task that is currently
- using the CDROM drive, or
- NULL if none. */
+static DECLARE_MUTEX(sony_sem); /* Semaphore for drive hardware access */
static int is_double_speed = 0; /* does the drive support double speed ? */
@@ -303,6 +293,7 @@ module_param(cdu31a_irq, int, 0);
/* The interrupt handler will wake this queue up when it gets an
interrupts. */
DECLARE_WAIT_QUEUE_HEAD(cdu31a_irq_wait);
+static int irq_flag = 0;
static int curr_control_reg = 0; /* Current value of the control register */
@@ -344,13 +335,16 @@ static int scd_media_changed(struct cdrom_device_info *cdi, int disc_nr)
*/
static int scd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
{
- if (CDSL_CURRENT != slot_nr) {
+ if (CDSL_CURRENT != slot_nr)
/* we have no changer support */
return -EINVAL;
- }
- if (scd_spinup() == 0) {
+ if (sony_spun_up)
+ return CDS_DISC_OK;
+ if (down_interruptible(&sony_sem))
+ return -ERESTARTSYS;
+ if (scd_spinup() == 0)
sony_spun_up = 1;
- }
+ up(&sony_sem);
return sony_spun_up ? CDS_DISC_OK : CDS_DRIVE_NOT_READY;
}
@@ -376,17 +370,31 @@ static inline void disable_interrupts(void)
*/
static inline void sony_sleep(void)
{
- unsigned long flags;
-
if (cdu31a_irq <= 0) {
yield();
} else { /* Interrupt driven */
+ DEFINE_WAIT(w);
+ int first = 1;
- save_flags(flags);
- cli();
- enable_interrupts();
- interruptible_sleep_on(&cdu31a_irq_wait);
- restore_flags(flags);
+ while (1) {
+ prepare_to_wait(&cdu31a_irq_wait, &w,
+ TASK_INTERRUPTIBLE);
+ if (first) {
+ enable_interrupts();
+ first = 0;
+ }
+
+ if (irq_flag != 0)
+ break;
+ if (!signal_pending(current)) {
+ schedule();
+ continue;
+ } else
+ disable_interrupts();
+ break;
+ }
+ finish_wait(&cdu31a_irq_wait, &w);
+ irq_flag = 0;
}
}
@@ -397,37 +405,37 @@ static inline void sony_sleep(void)
*/
static inline int is_attention(void)
{
- return ((inb(sony_cd_status_reg) & SONY_ATTN_BIT) != 0);
+ return (inb(sony_cd_status_reg) & SONY_ATTN_BIT) != 0;
}
static inline int is_busy(void)
{
- return ((inb(sony_cd_status_reg) & SONY_BUSY_BIT) != 0);
+ return (inb(sony_cd_status_reg) & SONY_BUSY_BIT) != 0;
}
static inline int is_data_ready(void)
{
- return ((inb(sony_cd_status_reg) & SONY_DATA_RDY_BIT) != 0);
+ return (inb(sony_cd_status_reg) & SONY_DATA_RDY_BIT) != 0;
}
static inline int is_data_requested(void)
{
- return ((inb(sony_cd_status_reg) & SONY_DATA_REQUEST_BIT) != 0);
+ return (inb(sony_cd_status_reg) & SONY_DATA_REQUEST_BIT) != 0;
}
static inline int is_result_ready(void)
{
- return ((inb(sony_cd_status_reg) & SONY_RES_RDY_BIT) != 0);
+ return (inb(sony_cd_status_reg) & SONY_RES_RDY_BIT) != 0;
}
static inline int is_param_write_rdy(void)
{
- return ((inb(sony_cd_fifost_reg) & SONY_PARAM_WRITE_RDY_BIT) != 0);
+ return (inb(sony_cd_fifost_reg) & SONY_PARAM_WRITE_RDY_BIT) != 0;
}
static inline int is_result_reg_not_empty(void)
{
- return ((inb(sony_cd_fifost_reg) & SONY_RES_REG_NOT_EMP_BIT) != 0);
+ return (inb(sony_cd_fifost_reg) & SONY_RES_REG_NOT_EMP_BIT) != 0;
}
static inline void reset_drive(void)
@@ -445,6 +453,8 @@ static int scd_reset(struct cdrom_device_info *cdi)
{
unsigned long retry_count;
+ if (down_interruptible(&sony_sem))
+ return -ERESTARTSYS;
reset_drive();
retry_count = jiffies + SONY_RESET_TIMEOUT;
@@ -452,6 +462,7 @@ static int scd_reset(struct cdrom_device_info *cdi)
sony_sleep();
}
+ up(&sony_sem);
return 0;
}
@@ -478,17 +489,17 @@ static inline void clear_param_reg(void)
static inline unsigned char read_status_register(void)
{
- return (inb(sony_cd_status_reg));
+ return inb(sony_cd_status_reg);
}
static inline unsigned char read_result_register(void)
{
- return (inb(sony_cd_result_reg));
+ return inb(sony_cd_result_reg);
}
static inline unsigned char read_data_register(void)
{
- return (inb(sony_cd_read_reg));
+ return inb(sony_cd_read_reg);
}
static inline void write_param(unsigned char param)
@@ -527,15 +538,17 @@ static irqreturn_t cdu31a_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* If something was waiting, wake it up now. */
if (waitqueue_active(&cdu31a_irq_wait)) {
disable_interrupts();
- wake_up(&cdu31a_irq_wait);
+ irq_flag = 1;
+ wake_up_interruptible(&cdu31a_irq_wait);
}
} else if (waitqueue_active(&cdu31a_irq_wait)) {
disable_interrupts();
- wake_up(&cdu31a_irq_wait);
+ irq_flag = 1;
+ wake_up_interruptible(&cdu31a_irq_wait);
} else {
disable_interrupts();
- printk
- ("CDU31A: Got an interrupt but nothing was waiting\n");
+ printk(KERN_NOTICE PFX
+ "Got an interrupt but nothing was waiting\n");
}
return IRQ_HANDLED;
}
@@ -610,8 +623,8 @@ static void set_drive_params(int want_doublespeed)
do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
params, 2, res_reg, &res_size);
if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
- printk(" Unable to set spin-down time: 0x%2.2x\n",
- res_reg[1]);
+ printk(KERN_NOTICE PFX
+ "Unable to set spin-down time: 0x%2.2x\n", res_reg[1]);
}
params[0] = SONY_SD_MECH_CONTROL;
@@ -627,8 +640,8 @@ static void set_drive_params(int want_doublespeed)
do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
params, 2, res_reg, &res_size);
if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
- printk(" Unable to set mechanical parameters: 0x%2.2x\n",
- res_reg[1]);
+ printk(KERN_NOTICE PFX "Unable to set mechanical "
+ "parameters: 0x%2.2x\n", res_reg[1]);
}
}
@@ -643,7 +656,10 @@ static int scd_select_speed(struct cdrom_device_info *cdi, int speed)
else
sony_speed = speed - 1;
+ if (down_interruptible(&sony_sem))
+ return -ERESTARTSYS;
set_drive_params(sony_speed);
+ up(&sony_sem);
return 0;
}
@@ -658,7 +674,10 @@ static int scd_lock_door(struct cdrom_device_info *cdi, int lock)
} else {
is_auto_eject = 0;
}
+ if (down_interruptible(&sony_sem))
+ return -ERESTARTSYS;
set_drive_params(sony_speed);
+ up(&sony_sem);
return 0;
}
@@ -672,7 +691,7 @@ static void restart_on_error(void)
unsigned long retry_count;
- printk("cdu31a: Resetting drive on error\n");
+ printk(KERN_NOTICE PFX "Resetting drive on error\n");
reset_drive();
retry_count = jiffies + SONY_RESET_TIMEOUT;
while (time_before(jiffies, retry_count) && (!is_attention())) {
@@ -681,7 +700,7 @@ static void restart_on_error(void)
set_drive_params(sony_speed);
do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
- printk("cdu31a: Unable to spin up drive: 0x%2.2x\n",
+ printk(KERN_NOTICE PFX "Unable to spin up drive: 0x%2.2x\n",
res_reg[1]);
}
@@ -741,9 +760,7 @@ get_result(unsigned char *result_buffer, unsigned int *result_size)
while (handle_sony_cd_attention());
}
if (is_busy() || (!(is_result_ready()))) {
-#if DEBUG
- printk("CDU31A timeout out %d\n", __LINE__);
-#endif
+ pr_debug(PFX "timeout out %d\n", __LINE__);
result_buffer[0] = 0x20;
result_buffer[1] = SONY_TIMEOUT_OP_ERR;
*result_size = 2;
@@ -794,10 +811,8 @@ get_result(unsigned char *result_buffer, unsigned int *result_size)
retry_count--;
}
if (!is_result_ready()) {
-#if DEBUG
- printk("CDU31A timeout out %d\n",
+ pr_debug(PFX "timeout out %d\n",
__LINE__);
-#endif
result_buffer[0] = 0x20;
result_buffer[1] =
SONY_TIMEOUT_OP_ERR;
@@ -823,10 +838,8 @@ get_result(unsigned char *result_buffer, unsigned int *result_size)
retry_count--;
}
if (!is_result_ready()) {
-#if DEBUG
- printk("CDU31A timeout out %d\n",
+ pr_debug(PFX "timeout out %d\n",
__LINE__);
-#endif
result_buffer[0] = 0x20;
result_buffer[1] =
SONY_TIMEOUT_OP_ERR;
@@ -857,38 +870,12 @@ do_sony_cd_cmd(unsigned char cmd,
unsigned char *result_buffer, unsigned int *result_size)
{
unsigned long retry_count;
- int num_retries;
- int recursive_call;
- unsigned long flags;
-
-
- save_flags(flags);
- cli();
- if (current != has_cd_task) { /* Allow recursive calls to this routine */
- while (sony_inuse) {
- interruptible_sleep_on(&sony_wait);
- if (signal_pending(current)) {
- result_buffer[0] = 0x20;
- result_buffer[1] = SONY_SIGNAL_OP_ERR;
- *result_size = 2;
- restore_flags(flags);
- return;
- }
- }
- sony_inuse = 1;
- has_cd_task = current;
- recursive_call = 0;
- } else {
- recursive_call = 1;
- }
+ int num_retries = 0;
- num_retries = 0;
retry_cd_operation:
while (handle_sony_cd_attention());
- sti();
-
retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
while (time_before(jiffies, retry_count) && (is_busy())) {
sony_sleep();
@@ -896,9 +883,7 @@ retry_cd_operation:
while (handle_sony_cd_attention());
}
if (is_busy()) {
-#if DEBUG
- printk("CDU31A timeout out %d\n", __LINE__);
-#endif
+ pr_debug(PFX "timeout out %d\n", __LINE__);
result_buffer[0] = 0x20;
result_buffer[1] = SONY_TIMEOUT_OP_ERR;
*result_size = 2;
@@ -918,14 +903,6 @@ retry_cd_operation:
msleep(100);
goto retry_cd_operation;
}
-
- if (!recursive_call) {
- has_cd_task = NULL;
- sony_inuse = 0;
- wake_up_interruptible(&sony_wait);
- }
-
- restore_flags(flags);
}
@@ -945,21 +922,18 @@ static int handle_sony_cd_attention(void)
volatile int val;
-#if 0*DEBUG
- printk("Entering handle_sony_cd_attention\n");
+#if 0
+ pr_debug(PFX "Entering %s\n", __FUNCTION__);
#endif
if (is_attention()) {
if (num_consecutive_attentions >
CDU31A_MAX_CONSECUTIVE_ATTENTIONS) {
- printk
- ("cdu31a: Too many consecutive attentions: %d\n",
- num_consecutive_attentions);
+ printk(KERN_NOTICE PFX "Too many consecutive "
+ "attentions: %d\n", num_consecutive_attentions);
num_consecutive_attentions = 0;
-#if DEBUG
- printk("Leaving handle_sony_cd_attention at %d\n",
+ pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__,
__LINE__);
-#endif
- return (0);
+ return 0;
}
clear_attention();
@@ -999,11 +973,8 @@ static int handle_sony_cd_attention(void)
}
num_consecutive_attentions++;
-#if DEBUG
- printk("Leaving handle_sony_cd_attention at %d\n",
- __LINE__);
-#endif
- return (1);
+ pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
+ return 1;
} else if (abort_read_started) {
while (is_result_reg_not_empty()) {
val = read_result_register();
@@ -1015,18 +986,15 @@ static int handle_sony_cd_attention(void)
val = read_data_register();
}
abort_read_started = 0;
-#if DEBUG
- printk("Leaving handle_sony_cd_attention at %d\n",
- __LINE__);
-#endif
- return (1);
+ pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
+ return 1;
}
num_consecutive_attentions = 0;
-#if 0*DEBUG
- printk("Leaving handle_sony_cd_attention at %d\n", __LINE__);
+#if 0
+ pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
#endif
- return (0);
+ return 0;
}
@@ -1038,14 +1006,14 @@ static inline unsigned int int_to_bcd(unsigned int val)
retval = (val / 10) << 4;
retval = retval | val % 10;
- return (retval);
+ return retval;
}
/* Convert from BCD to an integer from 0-99 */
static unsigned int bcd_to_int(unsigned int bcd)
{
- return ((((bcd >> 4) & 0x0f) * 10) + (bcd & 0x0f));
+ return (((bcd >> 4) & 0x0f) * 10) + (bcd & 0x0f);
}
@@ -1105,9 +1073,7 @@ start_request(unsigned int sector, unsigned int nsect)
unsigned long retry_count;
-#if DEBUG
- printk("Entering start_request\n");
-#endif
+ pr_debug(PFX "Entering %s\n", __FUNCTION__);
log_to_msf(sector, params);
size_to_buf(nsect, &params[3]);
@@ -1125,11 +1091,10 @@ start_request(unsigned int sector, unsigned int nsect)
}
if (is_busy()) {
- printk("CDU31A: Timeout while waiting to issue command\n");
-#if DEBUG
- printk("Leaving start_request at %d\n", __LINE__);
-#endif
- return (1);
+ printk(KERN_NOTICE PFX "Timeout while waiting "
+ "to issue command\n");
+ pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
+ return 1;
} else {
/* Issue the command */
clear_result_ready();
@@ -1140,14 +1105,10 @@ start_request(unsigned int sector, unsigned int nsect)
sony_blocks_left = nsect * 4;
sony_next_block = sector * 4;
-#if DEBUG
- printk("Leaving start_request at %d\n", __LINE__);
-#endif
- return (0);
+ pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
+ return 0;
}
-#if DEBUG
- printk("Leaving start_request at %d\n", __LINE__);
-#endif
+ pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
}
/* Abort a pending read operation. Clear all the drive status variables. */
@@ -1160,7 +1121,7 @@ static void abort_read(void)
do_sony_cd_cmd(SONY_ABORT_CMD, NULL, 0, result_reg, &result_size);
if ((result_reg[0] & 0xf0) == 0x20) {
- printk("CDU31A: Error aborting read, %s error\n",
+ printk(KERN_ERR PFX "Aborting read, %s error\n",
translate_error(result_reg[1]));
}
@@ -1181,15 +1142,9 @@ static void abort_read(void)
pending read operation. */
static void handle_abort_timeout(unsigned long data)
{
- unsigned long flags;
-
-#if DEBUG
- printk("Entering handle_abort_timeout\n");
-#endif
- save_flags(flags);
- cli();
+ pr_debug(PFX "Entering %s\n", __FUNCTION__);
/* If it is in use, ignore it. */
- if (!sony_inuse) {
+ if (down_trylock(&sony_sem) == 0) {
/* We can't use abort_read(), because it will sleep
or schedule in the timer interrupt. Just start
the operation, finish it on the next access to
@@ -1200,20 +1155,16 @@ static void handle_abort_timeout(unsigned long data)
sony_blocks_left = 0;
abort_read_started = 1;
+ up(&sony_sem);
}
- restore_flags(flags);
-#if DEBUG
- printk("Leaving handle_abort_timeout\n");
-#endif
+ pr_debug(PFX "Leaving %s\n", __FUNCTION__);
}
/* Actually get one sector of data from the drive. */
static void
input_data_sector(char *buffer)
{
-#if DEBUG
- printk("Entering input_data_sector\n");
-#endif
+ pr_debug(PFX "Entering %s\n", __FUNCTION__);
/* If an XA disk on a CDU31A, skip the first 12 bytes of data from
the disk. The real data is after that. We can use audio_buffer. */
@@ -1229,9 +1180,7 @@ input_data_sector(char *buffer)
if (sony_xa_mode)
insb(sony_cd_read_reg, audio_buffer, CD_XA_TAIL);
-#if DEBUG
- printk("Leaving input_data_sector\n");
-#endif
+ pr_debug(PFX "Leaving %s\n", __FUNCTION__);
}
/* read data from the drive. Note the nsect must be <= 4. */
@@ -1243,9 +1192,7 @@ read_data_block(char *buffer,
{
unsigned long retry_count;
-#if DEBUG
- printk("Entering read_data_block\n");
-#endif
+ pr_debug(PFX "Entering %s\n", __FUNCTION__);
res_reg[0] = 0;
res_reg[1] = 0;
@@ -1262,18 +1209,15 @@ read_data_block(char *buffer,
if (is_result_ready()) {
get_result(res_reg, res_size);
if ((res_reg[0] & 0xf0) != 0x20) {
- printk
- ("CDU31A: Got result that should have been error: %d\n",
- res_reg[0]);
+ printk(KERN_NOTICE PFX "Got result that should"
+ " have been error: %d\n", res_reg[0]);
res_reg[0] = 0x20;
res_reg[1] = SONY_BAD_DATA_ERR;
*res_size = 2;
}
abort_read();
} else {
-#if DEBUG
- printk("CDU31A timeout out %d\n", __LINE__);
-#endif
+ pr_debug(PFX "timeout out %d\n", __LINE__);
res_reg[0] = 0x20;
res_reg[1] = SONY_TIMEOUT_OP_ERR;
*res_size = 2;
@@ -1294,9 +1238,7 @@ read_data_block(char *buffer,
}
if (!is_result_ready()) {
-#if DEBUG
- printk("CDU31A timeout out %d\n", __LINE__);
-#endif
+ pr_debug(PFX "timeout out %d\n", __LINE__);
res_reg[0] = 0x20;
res_reg[1] = SONY_TIMEOUT_OP_ERR;
*res_size = 2;
@@ -1315,9 +1257,8 @@ read_data_block(char *buffer,
SONY_RECOV_LECC_ERR_BLK_STAT)) {
/* nothing here */
} else {
- printk
- ("CDU31A: Data block error: 0x%x\n",
- res_reg[0]);
+ printk(KERN_ERR PFX "Data block "
+ "error: 0x%x\n", res_reg[0]);
res_reg[0] = 0x20;
res_reg[1] = SONY_BAD_DATA_ERR;
*res_size = 2;
@@ -1330,9 +1271,8 @@ read_data_block(char *buffer,
} else if ((res_reg[0] & 0xf0) != 0x20) {
/* The drive gave me bad status, I don't know what to do.
Reset the driver and return an error. */
- printk
- ("CDU31A: Invalid block status: 0x%x\n",
- res_reg[0]);
+ printk(KERN_ERR PFX "Invalid block "
+ "status: 0x%x\n", res_reg[0]);
restart_on_error();
res_reg[0] = 0x20;
res_reg[1] = SONY_BAD_DATA_ERR;
@@ -1340,9 +1280,7 @@ read_data_block(char *buffer,
}
}
}
-#if DEBUG
- printk("Leaving read_data_block at %d\n", __LINE__);
-#endif
+ pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
}
@@ -1359,32 +1297,14 @@ static void do_cdu31a_request(request_queue_t * q)
int block, nblock, num_retries;
unsigned char res_reg[12];
unsigned int res_size;
- unsigned long flags;
+ pr_debug(PFX "Entering %s\n", __FUNCTION__);
-#if DEBUG
- printk("Entering do_cdu31a_request\n");
-#endif
-
- /*
- * Make sure no one else is using the driver; wait for them
- * to finish if it is so.
- */
- save_flags(flags);
- cli();
- while (sony_inuse) {
- interruptible_sleep_on(&sony_wait);
- if (signal_pending(current)) {
- restore_flags(flags);
-#if DEBUG
- printk("Leaving do_cdu31a_request at %d\n",
- __LINE__);
-#endif
- return;
- }
+ spin_unlock_irq(q->queue_lock);
+ if (down_interruptible(&sony_sem)) {
+ spin_lock_irq(q->queue_lock);
+ return;
}
- sony_inuse = 1;
- has_cd_task = current;
/* Get drive status before doing anything. */
while (handle_sony_cd_attention());
@@ -1392,10 +1312,6 @@ static void do_cdu31a_request(request_queue_t * q)
/* Make sure we have a valid TOC. */
sony_get_toc();
- /*
- * jens: driver has lots of races
- */
- spin_unlock_irq(q->queue_lock);
/* Make sure the timer is cancelled. */
del_timer(&cdu31a_abort_timer);
@@ -1414,12 +1330,10 @@ static void do_cdu31a_request(request_queue_t * q)
block = req->sector;
nblock = req->nr_sectors;
-#if DEBUG
- printk("CDU31A: request at block %d, length %d blocks\n",
+ pr_debug(PFX "request at block %d, length %d blocks\n",
block, nblock);
-#endif
if (!sony_toc_read) {
- printk("CDU31A: TOC not read\n");
+ printk(KERN_NOTICE PFX "TOC not read\n");
end_request(req, 0);
continue;
}
@@ -1431,14 +1345,13 @@ static void do_cdu31a_request(request_queue_t * q)
end_request(req, 0);
continue;
}
- if (rq_data_dir(req) != READ)
- panic("CDU31A: Unknown cmd");
+
/*
* If the block address is invalid or the request goes beyond the end of
* the media, return an error.
*/
if (((block + nblock) / 4) >= sony_toc.lead_out_start_lba) {
- printk("CDU31A: Request past end of media\n");
+ printk(KERN_NOTICE PFX "Request past end of media\n");
end_request(req, 0);
continue;
}
@@ -1451,7 +1364,7 @@ static void do_cdu31a_request(request_queue_t * q)
while (handle_sony_cd_attention());
if (!sony_toc_read) {
- printk("CDU31A: TOC not read\n");
+ printk(KERN_NOTICE PFX "TOC not read\n");
end_request(req, 0);
continue;
}
@@ -1468,18 +1381,16 @@ static void do_cdu31a_request(request_queue_t * q)
the driver, abort the current operation and start a
new one. */
else if (block != sony_next_block) {
-#if DEBUG
- printk("CDU31A Warning: Read for block %d, expected %d\n",
+ pr_debug(PFX "Read for block %d, expected %d\n",
block, sony_next_block);
-#endif
abort_read();
if (!sony_toc_read) {
- printk("CDU31A: TOC not read\n");
+ printk(KERN_NOTICE PFX "TOC not read\n");
end_request(req, 0);
continue;
}
if (start_request(block / 4, nblock / 4)) {
- printk("CDU31a: start request failed\n");
+ printk(KERN_NOTICE PFX "start request failed\n");
end_request(req, 0);
continue;
}
@@ -1507,13 +1418,12 @@ static void do_cdu31a_request(request_queue_t * q)
do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg,
&res_size);
} else {
- printk("CDU31A: %s error for block %d, nblock %d\n",
+ printk(KERN_NOTICE PFX "%s error for block %d, nblock %d\n",
translate_error(res_reg[1]), block, nblock);
}
goto try_read_again;
}
end_do_cdu31a_request:
- spin_lock_irq(q->queue_lock);
#if 0
/* After finished, cancel any pending operations. */
abort_read();
@@ -1524,13 +1434,9 @@ static void do_cdu31a_request(request_queue_t * q)
add_timer(&cdu31a_abort_timer);
#endif
- has_cd_task = NULL;
- sony_inuse = 0;
- wake_up_interruptible(&sony_wait);
- restore_flags(flags);
-#if DEBUG
- printk("Leaving do_cdu31a_request at %d\n", __LINE__);
-#endif
+ up(&sony_sem);
+ spin_lock_irq(q->queue_lock);
+ pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__);
}
@@ -1549,9 +1455,7 @@ static void sony_get_toc(void)
int mint = 99;
int maxt = 0;
-#if DEBUG
- printk("Entering sony_get_toc\n");
-#endif
+ pr_debug(PFX "Entering %s\n", __FUNCTION__);
num_spin_ups = 0;
if (!sony_toc_read) {
@@ -1602,16 +1506,12 @@ static void sony_get_toc(void)
/* This seems to slow things down enough to make it work. This
* appears to be a problem in do_sony_cd_cmd. This printk seems
* to address the symptoms... -Erik */
-#if DEBUG
- printk("cdu31a: Trying session %d\n", session);
-#endif
+ pr_debug(PFX "Trying session %d\n", session);
parms[0] = session;
do_sony_cd_cmd(SONY_READ_TOC_SPEC_CMD,
parms, 1, res_reg, &res_size);
-#if DEBUG
- printk("%2.2x %2.2x\n", res_reg[0], res_reg[1]);
-#endif
+ pr_debug(PFX "%2.2x %2.2x\n", res_reg[0], res_reg[1]);
if ((res_size < 2)
|| ((res_reg[0] & 0xf0) == 0x20)) {
@@ -1621,9 +1521,7 @@ static void sony_get_toc(void)
("Yikes! Couldn't read any sessions!");
break;
}
-#if DEBUG
- printk("Reading session %d\n", session);
-#endif
+ pr_debug(PFX "Reading session %d\n", session);
parms[0] = session;
do_sony_cd_cmd(SONY_REQ_TOC_DATA_SPEC_CMD,
@@ -1634,8 +1532,8 @@ static void sony_get_toc(void)
if ((res_size < 2)
|| ((single_toc.exec_status[0] & 0xf0) ==
0x20)) {
- printk
- ("cdu31a: Error reading session %d: %x %s\n",
+ printk(KERN_ERR PFX "Error reading "
+ "session %d: %x %s\n",
session, single_toc.exec_status[0],
translate_error(single_toc.
exec_status[1]));
@@ -1643,29 +1541,27 @@ static void sony_get_toc(void)
set. */
return;
}
-#if DEBUG
- printk
- ("add0 %01x, con0 %01x, poi0 %02x, 1st trk %d, dsktyp %x, dum0 %x\n",
+ pr_debug(PFX "add0 %01x, con0 %01x, poi0 %02x, "
+ "1st trk %d, dsktyp %x, dum0 %x\n",
single_toc.address0, single_toc.control0,
single_toc.point0,
bcd_to_int(single_toc.first_track_num),
single_toc.disk_type, single_toc.dummy0);
- printk
- ("add1 %01x, con1 %01x, poi1 %02x, lst trk %d, dummy1 %x, dum2 %x\n",
+ pr_debug(PFX "add1 %01x, con1 %01x, poi1 %02x, "
+ "lst trk %d, dummy1 %x, dum2 %x\n",
single_toc.address1, single_toc.control1,
single_toc.point1,
bcd_to_int(single_toc.last_track_num),
single_toc.dummy1, single_toc.dummy2);
- printk
- ("add2 %01x, con2 %01x, poi2 %02x leadout start min %d, sec %d, frame %d\n",
+ pr_debug(PFX "add2 %01x, con2 %01x, poi2 %02x "
+ "leadout start min %d, sec %d, frame %d\n",
single_toc.address2, single_toc.control2,
single_toc.point2,
bcd_to_int(single_toc.lead_out_start_msf[0]),
bcd_to_int(single_toc.lead_out_start_msf[1]),
bcd_to_int(single_toc.lead_out_start_msf[2]));
if (res_size > 18 && single_toc.pointb0 > 0xaf)
- printk
- ("addb0 %01x, conb0 %01x, poib0 %02x, nextsession min %d, sec %d, frame %d\n"
+ pr_debug(PFX "addb0 %01x, conb0 %01x, poib0 %02x, nextsession min %d, sec %d, frame %d\n"
"#mode5_ptrs %02d, max_start_outer_leadout_msf min %d, sec %d, frame %d\n",
single_toc.addressb0,
single_toc.controlb0,
@@ -1690,8 +1586,7 @@ static void sony_get_toc(void)
max_start_outer_leadout_msf
[2]));
if (res_size > 27 && single_toc.pointb1 > 0xaf)
- printk
- ("addb1 %01x, conb1 %01x, poib1 %02x, %x %x %x %x #skipint_ptrs %d, #skiptrkassign %d %x\n",
+ pr_debug(PFX "addb1 %01x, conb1 %01x, poib1 %02x, %x %x %x %x #skipint_ptrs %d, #skiptrkassign %d %x\n",
single_toc.addressb1,
single_toc.controlb1,
single_toc.pointb1,
@@ -1703,8 +1598,7 @@ static void sony_get_toc(void)
single_toc.num_skip_track_assignments,
single_toc.dummyb0_2);
if (res_size > 36 && single_toc.pointb2 > 0xaf)
- printk
- ("addb2 %01x, conb2 %01x, poib2 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
+ pr_debug(PFX "addb2 %01x, conb2 %01x, poib2 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
single_toc.addressb2,
single_toc.controlb2,
single_toc.pointb2,
@@ -1716,8 +1610,7 @@ static void sony_get_toc(void)
single_toc.tracksb2[5],
single_toc.tracksb2[6]);
if (res_size > 45 && single_toc.pointb3 > 0xaf)
- printk
- ("addb3 %01x, conb3 %01x, poib3 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
+ pr_debug(PFX "addb3 %01x, conb3 %01x, poib3 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
single_toc.addressb3,
single_toc.controlb3,
single_toc.pointb3,
@@ -1729,8 +1622,7 @@ static void sony_get_toc(void)
single_toc.tracksb3[5],
single_toc.tracksb3[6]);
if (res_size > 54 && single_toc.pointb4 > 0xaf)
- printk
- ("addb4 %01x, conb4 %01x, poib4 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
+ pr_debug(PFX "addb4 %01x, conb4 %01x, poib4 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
single_toc.addressb4,
single_toc.controlb4,
single_toc.pointb4,
@@ -1742,8 +1634,7 @@ static void sony_get_toc(void)
single_toc.tracksb4[5],
single_toc.tracksb4[6]);
if (res_size > 63 && single_toc.pointc0 > 0xaf)
- printk
- ("addc0 %01x, conc0 %01x, poic0 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
+ pr_debug(PFX "addc0 %01x, conc0 %01x, poic0 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
single_toc.addressc0,
single_toc.controlc0,
single_toc.pointc0,
@@ -1754,7 +1645,6 @@ static void sony_get_toc(void)
single_toc.dummyc0[4],
single_toc.dummyc0[5],
single_toc.dummyc0[6]);
-#endif
#undef DEBUG
#define DEBUG 0
@@ -1823,8 +1713,8 @@ static void sony_get_toc(void)
res_size += 9;
}
#if DEBUG
- printk
- ("start track lba %u, leadout start lba %u\n",
+ printk(PRINT_INFO PFX "start track lba %u, "
+ "leadout start lba %u\n",
single_toc.start_track_lba,
single_toc.lead_out_start_lba);
{
@@ -1836,8 +1726,7 @@ static void sony_get_toc(void)
-
bcd_to_int(single_toc.
first_track_num); i++) {
- printk
- ("trk %02d: add 0x%01x, con 0x%01x, track %02d, start min %02d, sec %02d, frame %02d\n",
+ printk(KERN_INFO PFX "trk %02d: add 0x%01x, con 0x%01x, track %02d, start min %02d, sec %02d, frame %02d\n",
i,
single_toc.tracks[i].address,
single_toc.tracks[i].control,
@@ -1870,8 +1759,8 @@ static void sony_get_toc(void)
tracks[i].
track);
}
- printk
- ("min track number %d, max track number %d\n",
+ printk(KERN_INFO PFX "min track number %d, "
+ "max track number %d\n",
mint, maxt);
}
#endif
@@ -1976,8 +1865,8 @@ static void sony_get_toc(void)
/* Let's not get carried away... */
if (session > 40) {
- printk("cdu31a: too many sessions: %d\n",
- session);
+ printk(KERN_NOTICE PFX "too many sessions: "
+ "%d\n", session);
break;
}
session++;
@@ -1995,17 +1884,13 @@ static void sony_get_toc(void)
sony_toc.lead_out_start_msf[2];
sony_toc_read = 1;
-#undef DEBUG
-#if DEBUG
- printk
- ("Disk session %d, start track: %d, stop track: %d\n",
+
+ pr_debug(PFX "Disk session %d, start track: %d, "
+ "stop track: %d\n",
session, single_toc.start_track_lba,
single_toc.lead_out_start_lba);
-#endif
}
-#if DEBUG
- printk("Leaving sony_get_toc\n");
-#endif
+ pr_debug(PFX "Leaving %s\n", __FUNCTION__);
}
@@ -2019,8 +1904,12 @@ static int scd_get_last_session(struct cdrom_device_info *cdi,
if (ms_info == NULL)
return 1;
- if (!sony_toc_read)
+ if (!sony_toc_read) {
+ if (down_interruptible(&sony_sem))
+ return -ERESTARTSYS;
sony_get_toc();
+ up(&sony_sem);
+ }
ms_info->addr_format = CDROM_LBA;
ms_info->addr.lba = sony_toc.start_track_lba;
@@ -2060,7 +1949,7 @@ static int read_subcode(void)
0, (unsigned char *) &last_sony_subcode, &res_size);
if ((res_size < 2)
|| ((last_sony_subcode.exec_status[0] & 0xf0) == 0x20)) {
- printk("Sony CDROM error %s (read_subcode)\n",
+ printk(KERN_ERR PFX "Sony CDROM error %s (read_subcode)\n",
translate_error(last_sony_subcode.exec_status[1]));
return -EIO;
}
@@ -2098,8 +1987,11 @@ scd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
unsigned int res_size;
memset(mcn->medium_catalog_number, 0, 14);
+ if (down_interruptible(&sony_sem))
+ return -ERESTARTSYS;
do_sony_cd_cmd(SONY_REQ_UPC_EAN_CMD,
NULL, 0, resbuffer, &res_size);
+ up(&sony_sem);
if ((res_size < 2) || ((resbuffer[0] & 0xf0) == 0x20));
else {
/* packed bcd to single ASCII digits */
@@ -2228,8 +2120,8 @@ read_audio_data(char *buffer, unsigned char res_reg[], int *res_size)
}
/* Invalid data from the drive. Shut down the operation. */
else if ((res_reg[0] & 0xf0) != 0x20) {
- printk
- ("CDU31A: Got result that should have been error: %d\n",
+ printk(KERN_WARNING PFX "Got result that "
+ "should have been error: %d\n",
res_reg[0]);
res_reg[0] = 0x20;
res_reg[1] = SONY_BAD_DATA_ERR;
@@ -2237,9 +2129,7 @@ read_audio_data(char *buffer, unsigned char res_reg[], int *res_size)
}
abort_read();
} else {
-#if DEBUG
- printk("CDU31A timeout out %d\n", __LINE__);
-#endif
+ pr_debug(PFX "timeout out %d\n", __LINE__);
res_reg[0] = 0x20;
res_reg[1] = SONY_TIMEOUT_OP_ERR;
*res_size = 2;
@@ -2269,10 +2159,7 @@ read_audio_data(char *buffer, unsigned char res_reg[], int *res_size)
}
if (!is_result_ready()) {
-#if DEBUG
- printk("CDU31A timeout out %d\n",
- __LINE__);
-#endif
+ pr_debug(PFX "timeout out %d\n", __LINE__);
res_reg[0] = 0x20;
res_reg[1] = SONY_TIMEOUT_OP_ERR;
*res_size = 2;
@@ -2290,7 +2177,7 @@ read_audio_data(char *buffer, unsigned char res_reg[], int *res_size)
|| (res_reg[0] == SONY_NO_ERR_DETECTION_STAT)) {
/* Ok, nothing to do. */
} else {
- printk("CDU31A: Data block error: 0x%x\n",
+ printk(KERN_ERR PFX "Data block error: 0x%x\n",
res_reg[0]);
res_reg[0] = 0x20;
res_reg[1] = SONY_BAD_DATA_ERR;
@@ -2299,7 +2186,7 @@ read_audio_data(char *buffer, unsigned char res_reg[], int *res_size)
} else if ((res_reg[0] & 0xf0) != 0x20) {
/* The drive gave me bad status, I don't know what to do.
Reset the driver and return an error. */
- printk("CDU31A: Invalid block status: 0x%x\n",
+ printk(KERN_NOTICE PFX "Invalid block status: 0x%x\n",
res_reg[0]);
restart_on_error();
res_reg[0] = 0x20;
@@ -2318,28 +2205,11 @@ static int read_audio(struct cdrom_read_audio *ra)
unsigned char res_reg[12];
unsigned int res_size;
unsigned int cframe;
- unsigned long flags;
- /*
- * Make sure no one else is using the driver; wait for them
- * to finish if it is so.
- */
- save_flags(flags);
- cli();
- while (sony_inuse) {
- interruptible_sleep_on(&sony_wait);
- if (signal_pending(current)) {
- restore_flags(flags);
- return -EAGAIN;
- }
- }
- sony_inuse = 1;
- has_cd_task = current;
- restore_flags(flags);
-
- if (!sony_spun_up) {
+ if (down_interruptible(&sony_sem))
+ return -ERESTARTSYS;
+ if (!sony_spun_up)
scd_spinup();
- }
/* Set the drive to do raw operations. */
params[0] = SONY_SD_DECODE_PARAM;
@@ -2347,9 +2217,10 @@ static int read_audio(struct cdrom_read_audio *ra)
do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
params, 2, res_reg, &res_size);
if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
- printk("CDU31A: Unable to set decode params: 0x%2.2x\n",
+ printk(KERN_ERR PFX "Unable to set decode params: 0x%2.2x\n",
res_reg[1]);
- return -EIO;
+ retval = -EIO;
+ goto out_up;
}
/* From here down, we have to goto exit_read_audio instead of returning
@@ -2368,8 +2239,8 @@ static int read_audio(struct cdrom_read_audio *ra)
read_audio_data(audio_buffer, res_reg, &res_size);
if ((res_reg[0] & 0xf0) == 0x20) {
if (res_reg[1] == SONY_BAD_DATA_ERR) {
- printk
- ("CDU31A: Data error on audio sector %d\n",
+ printk(KERN_ERR PFX "Data error on audio "
+ "sector %d\n",
ra->addr.lba + cframe);
} else if (res_reg[1] == SONY_ILL_TRACK_R_ERR) {
/* Illegal track type, change track types and start over. */
@@ -2384,8 +2255,8 @@ static int read_audio(struct cdrom_read_audio *ra)
2, res_reg, &res_size);
if ((res_size < 2)
|| ((res_reg[0] & 0xf0) == 0x20)) {
- printk
- ("CDU31A: Unable to set decode params: 0x%2.2x\n",
+ printk(KERN_ERR PFX "Unable to set "
+ "decode params: 0x%2.2x\n",
res_reg[1]);
retval = -EIO;
goto exit_read_audio;
@@ -2407,13 +2278,12 @@ static int read_audio(struct cdrom_read_audio *ra)
if ((res_reg[0] & 0xf0) == 0x20) {
if (res_reg[1] ==
SONY_BAD_DATA_ERR) {
- printk
- ("CDU31A: Data error on audio sector %d\n",
+ printk(KERN_ERR PFX "Data error"
+ " on audio sector %d\n",
ra->addr.lba +
cframe);
} else {
- printk
- ("CDU31A: Error reading audio data on sector %d: %s\n",
+ printk(KERN_ERR PFX "Error reading audio data on sector %d: %s\n",
ra->addr.lba + cframe,
translate_error
(res_reg[1]));
@@ -2429,8 +2299,8 @@ static int read_audio(struct cdrom_read_audio *ra)
goto exit_read_audio;
}
} else {
- printk
- ("CDU31A: Error reading audio data on sector %d: %s\n",
+ printk(KERN_ERR PFX "Error reading audio "
+ "data on sector %d: %s\n",
ra->addr.lba + cframe,
translate_error(res_reg[1]));
retval = -EIO;
@@ -2448,7 +2318,7 @@ static int read_audio(struct cdrom_read_audio *ra)
get_result(res_reg, &res_size);
if ((res_reg[0] & 0xf0) == 0x20) {
- printk("CDU31A: Error return from audio read: %s\n",
+ printk(KERN_ERR PFX "Error return from audio read: %s\n",
translate_error(res_reg[1]));
retval = -EIO;
goto exit_read_audio;
@@ -2466,16 +2336,15 @@ static int read_audio(struct cdrom_read_audio *ra)
do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
params, 2, res_reg, &res_size);
if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
- printk("CDU31A: Unable to reset decode params: 0x%2.2x\n",
+ printk(KERN_ERR PFX "Unable to reset decode params: 0x%2.2x\n",
res_reg[1]);
- return -EIO;
+ retval = -EIO;
}
- has_cd_task = NULL;
- sony_inuse = 0;
- wake_up_interruptible(&sony_wait);
+ out_up:
+ up(&sony_sem);
- return (retval);
+ return retval;
}
static int
@@ -2488,7 +2357,7 @@ do_sony_cd_cmd_chk(const char *name,
do_sony_cd_cmd(cmd, params, num_params, result_buffer,
result_size);
if ((*result_size < 2) || ((result_buffer[0] & 0xf0) == 0x20)) {
- printk("Sony CDROM error %s (CDROM%s)\n",
+ printk(KERN_ERR PFX "Error %s (CDROM%s)\n",
translate_error(result_buffer[1]), name);
return -EIO;
}
@@ -2501,6 +2370,10 @@ do_sony_cd_cmd_chk(const char *name,
*/
static int scd_tray_move(struct cdrom_device_info *cdi, int position)
{
+ int retval;
+
+ if (down_interruptible(&sony_sem))
+ return -ERESTARTSYS;
if (position == 1 /* open tray */ ) {
unsigned char res_reg[12];
unsigned int res_size;
@@ -2511,13 +2384,15 @@ static int scd_tray_move(struct cdrom_device_info *cdi, int position)
&res_size);
sony_audio_status = CDROM_AUDIO_INVALID;
- return do_sony_cd_cmd_chk("EJECT", SONY_EJECT_CMD, NULL, 0,
+ retval = do_sony_cd_cmd_chk("EJECT", SONY_EJECT_CMD, NULL, 0,
res_reg, &res_size);
} else {
if (0 == scd_spinup())
sony_spun_up = 1;
- return 0;
+ retval = 0;
}
+ up(&sony_sem);
+ return retval;
}
/*
@@ -2529,12 +2404,13 @@ static int scd_audio_ioctl(struct cdrom_device_info *cdi,
unsigned char res_reg[12];
unsigned int res_size;
unsigned char params[7];
- int i;
-
+ int i, retval;
+ if (down_interruptible(&sony_sem))
+ return -ERESTARTSYS;
switch (cmd) {
case CDROMSTART: /* Spin up the drive */
- return do_sony_cd_cmd_chk("START", SONY_SPIN_UP_CMD, NULL,
+ retval = do_sony_cd_cmd_chk("START", SONY_SPIN_UP_CMD, NULL,
0, res_reg, &res_size);
break;
@@ -2547,28 +2423,33 @@ static int scd_audio_ioctl(struct cdrom_device_info *cdi,
* already not spinning.
*/
sony_audio_status = CDROM_AUDIO_NO_STATUS;
- return do_sony_cd_cmd_chk("STOP", SONY_SPIN_DOWN_CMD, NULL,
+ retval = do_sony_cd_cmd_chk("STOP", SONY_SPIN_DOWN_CMD, NULL,
0, res_reg, &res_size);
+ break;
case CDROMPAUSE: /* Pause the drive */
if (do_sony_cd_cmd_chk
("PAUSE", SONY_AUDIO_STOP_CMD, NULL, 0, res_reg,
- &res_size))
- return -EIO;
+ &res_size)) {
+ retval = -EIO;
+ break;
+ }
/* Get the current position and save it for resuming */
if (read_subcode() < 0) {
- return -EIO;
+ retval = -EIO;
+ break;
}
cur_pos_msf[0] = last_sony_subcode.abs_msf[0];
cur_pos_msf[1] = last_sony_subcode.abs_msf[1];
cur_pos_msf[2] = last_sony_subcode.abs_msf[2];
sony_audio_status = CDROM_AUDIO_PAUSED;
- return 0;
+ retval = 0;
break;
case CDROMRESUME: /* Start the drive after being paused */
if (sony_audio_status != CDROM_AUDIO_PAUSED) {
- return -EINVAL;
+ retval = -EINVAL;
+ break;
}
do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg,
@@ -2584,10 +2465,13 @@ static int scd_audio_ioctl(struct cdrom_device_info *cdi,
params[0] = 0x03;
if (do_sony_cd_cmd_chk
("RESUME", SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg,
- &res_size) < 0)
- return -EIO;
+ &res_size) < 0) {
+ retval = -EIO;
+ break;
+ }
sony_audio_status = CDROM_AUDIO_PLAY;
- return 0;
+ retval = 0;
+ break;
case CDROMPLAYMSF: /* Play starting at the given MSF address. */
do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg,
@@ -2601,15 +2485,18 @@ static int scd_audio_ioctl(struct cdrom_device_info *cdi,
params[0] = 0x03;
if (do_sony_cd_cmd_chk
("PLAYMSF", SONY_AUDIO_PLAYBACK_CMD, params, 7,
- res_reg, &res_size) < 0)
- return -EIO;
+ res_reg, &res_size) < 0) {
+ retval = -EIO;
+ break;
+ }
/* Save the final position for pauses and resumes */
final_pos_msf[0] = bcd_to_int(params[4]);
final_pos_msf[1] = bcd_to_int(params[5]);
final_pos_msf[2] = bcd_to_int(params[6]);
sony_audio_status = CDROM_AUDIO_PLAY;
- return 0;
+ retval = 0;
+ break;
case CDROMREADTOCHDR: /* Read the table of contents header */
{
@@ -2617,14 +2504,16 @@ static int scd_audio_ioctl(struct cdrom_device_info *cdi,
sony_get_toc();
if (!sony_toc_read) {
- return -EIO;
+ retval = -EIO;
+ break;
}
hdr = (struct cdrom_tochdr *) arg;
hdr->cdth_trk0 = sony_toc.first_track_num;
hdr->cdth_trk1 = sony_toc.last_track_num;
}
- return 0;
+ retval = 0;
+ break;
case CDROMREADTOCENTRY: /* Read a given table of contents entry */
{
@@ -2634,14 +2523,16 @@ static int scd_audio_ioctl(struct cdrom_device_info *cdi,
sony_get_toc();
if (!sony_toc_read) {
- return -EIO;
+ retval = -EIO;
+ break;
}
entry = (struct cdrom_tocentry *) arg;
track_idx = find_track(entry->cdte_track);
if (track_idx < 0) {
- return -EINVAL;
+ retval = -EINVAL;
+ break;
}
entry->cdte_adr =
@@ -2662,7 +2553,7 @@ static int scd_audio_ioctl(struct cdrom_device_info *cdi,
*(msf_val + 2);
}
}
- return 0;
+ retval = 0;
break;
case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */
@@ -2672,18 +2563,21 @@ static int scd_audio_ioctl(struct cdrom_device_info *cdi,
sony_get_toc();
if (!sony_toc_read) {
- return -EIO;
+ retval = -EIO;
+ break;
}
if ((ti->cdti_trk0 < sony_toc.first_track_num)
|| (ti->cdti_trk0 > sony_toc.last_track_num)
|| (ti->cdti_trk1 < ti->cdti_trk0)) {
- return -EINVAL;
+ retval = -EINVAL;
+ break;
}
track_idx = find_track(ti->cdti_trk0);
if (track_idx < 0) {
- return -EINVAL;
+ retval = -EINVAL;
+ break;
}
params[1] =
int_to_bcd(sony_toc.tracks[track_idx].
@@ -2705,7 +2599,8 @@ static int scd_audio_ioctl(struct cdrom_device_info *cdi,
track_idx = find_track(ti->cdti_trk1 + 1);
}
if (track_idx < 0) {
- return -EINVAL;
+ retval = -EINVAL;
+ break;
}
params[4] =
int_to_bcd(sony_toc.tracks[track_idx].
@@ -2726,14 +2621,16 @@ static int scd_audio_ioctl(struct cdrom_device_info *cdi,
if ((res_size < 2)
|| ((res_reg[0] & 0xf0) == 0x20)) {
- printk("Params: %x %x %x %x %x %x %x\n",
+ printk(KERN_ERR PFX
+ "Params: %x %x %x %x %x %x %x\n",
params[0], params[1], params[2],
params[3], params[4], params[5],
params[6]);
- printk
- ("Sony CDROM error %s (CDROMPLAYTRKIND)\n",
+ printk(KERN_ERR PFX
+ "Error %s (CDROMPLAYTRKIND)\n",
translate_error(res_reg[1]));
- return -EIO;
+ retval = -EIO;
+ break;
}
/* Save the final position for pauses and resumes */
@@ -2741,7 +2638,8 @@ static int scd_audio_ioctl(struct cdrom_device_info *cdi,
final_pos_msf[1] = bcd_to_int(params[5]);
final_pos_msf[2] = bcd_to_int(params[6]);
sony_audio_status = CDROM_AUDIO_PLAY;
- return 0;
+ retval = 0;
+ break;
}
case CDROMVOLCTRL: /* Volume control. What volume does this change, anyway? */
@@ -2752,24 +2650,32 @@ static int scd_audio_ioctl(struct cdrom_device_info *cdi,
params[0] = SONY_SD_AUDIO_VOLUME;
params[1] = volctrl->channel0;
params[2] = volctrl->channel1;
- return do_sony_cd_cmd_chk("VOLCTRL",
+ retval = do_sony_cd_cmd_chk("VOLCTRL",
SONY_SET_DRIVE_PARAM_CMD,
params, 3, res_reg,
&res_size);
+ break;
}
case CDROMSUBCHNL: /* Get subchannel info */
- return sony_get_subchnl_info((struct cdrom_subchnl *) arg);
+ retval = sony_get_subchnl_info((struct cdrom_subchnl *) arg);
+ break;
default:
- return -EINVAL;
+ retval = -EINVAL;
+ break;
}
+ up(&sony_sem);
+ return retval;
}
static int scd_dev_ioctl(struct cdrom_device_info *cdi,
unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
+ int retval;
+ if (down_interruptible(&sony_sem))
+ return -ERESTARTSYS;
switch (cmd) {
case CDROMREADAUDIO: /* Read 2352 byte audio tracks and 2340 byte
raw data tracks. */
@@ -2779,14 +2685,18 @@ static int scd_dev_ioctl(struct cdrom_device_info *cdi,
sony_get_toc();
if (!sony_toc_read) {
- return -EIO;
+ retval = -EIO;
+ break;
}
- if (copy_from_user(&ra, argp, sizeof(ra)))
- return -EFAULT;
+ if (copy_from_user(&ra, argp, sizeof(ra))) {
+ retval = -EFAULT;
+ break;
+ }
if (ra.nframes == 0) {
- return 0;
+ retval = 0;
+ break;
}
if (!access_ok(VERIFY_WRITE, ra.buf,
@@ -2798,13 +2708,15 @@ static int scd_dev_ioctl(struct cdrom_device_info *cdi,
sony_toc.lead_out_start_lba)
|| (ra.addr.lba + ra.nframes >=
sony_toc.lead_out_start_lba)) {
- return -EINVAL;
+ retval = -EINVAL;
+ break;
}
} else if (ra.addr_format == CDROM_MSF) {
if ((ra.addr.msf.minute >= 75)
|| (ra.addr.msf.second >= 60)
|| (ra.addr.msf.frame >= 75)) {
- return -EINVAL;
+ retval = -EINVAL;
+ break;
}
ra.addr.lba = ((ra.addr.msf.minute * 4500)
@@ -2814,7 +2726,8 @@ static int scd_dev_ioctl(struct cdrom_device_info *cdi,
sony_toc.lead_out_start_lba)
|| (ra.addr.lba + ra.nframes >=
sony_toc.lead_out_start_lba)) {
- return -EINVAL;
+ retval = -EINVAL;
+ break;
}
/* I know, this can go negative on an unsigned. However,
@@ -2822,17 +2735,21 @@ static int scd_dev_ioctl(struct cdrom_device_info *cdi,
so this should compensate and allow direct msf access. */
ra.addr.lba -= LOG_START_OFFSET;
} else {
- return -EINVAL;
+ retval = -EINVAL;
+ break;
}
- return (read_audio(&ra));
+ retval = read_audio(&ra);
+ break;
}
- return 0;
+ retval = 0;
break;
default:
- return -EINVAL;
+ retval = -EINVAL;
}
+ up(&sony_sem);
+ return retval;
}
static int scd_spinup(void)
@@ -2849,7 +2766,7 @@ static int scd_spinup(void)
/* The drive sometimes returns error 0. I don't know why, but ignore
it. It seems to mean the drive has already done the operation. */
if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0))) {
- printk("Sony CDROM %s error (scd_open, spin up)\n",
+ printk(KERN_ERR PFX "%s error (scd_open, spin up)\n",
translate_error(res_reg[1]));
return 1;
}
@@ -2873,7 +2790,7 @@ static int scd_spinup(void)
goto respinup_on_open;
}
- printk("Sony CDROM error %s (scd_open, read toc)\n",
+ printk(KERN_ERR PFX "Error %s (scd_open, read toc)\n",
translate_error(res_reg[1]));
do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg,
&res_size);
@@ -2919,9 +2836,8 @@ static int scd_open(struct cdrom_device_info *cdi, int purpose)
params, 2, res_reg, &res_size);
if ((res_size < 2)
|| ((res_reg[0] & 0xf0) == 0x20)) {
- printk
- ("CDU31A: Unable to set XA params: 0x%2.2x\n",
- res_reg[1]);
+ printk(KERN_WARNING PFX "Unable to set "
+ "XA params: 0x%2.2x\n", res_reg[1]);
}
sony_xa_mode = 1;
}
@@ -2933,9 +2849,8 @@ static int scd_open(struct cdrom_device_info *cdi, int purpose)
params, 2, res_reg, &res_size);
if ((res_size < 2)
|| ((res_reg[0] & 0xf0) == 0x20)) {
- printk
- ("CDU31A: Unable to reset XA params: 0x%2.2x\n",
- res_reg[1]);
+ printk(KERN_WARNING PFX "Unable to reset "
+ "XA params: 0x%2.2x\n", res_reg[1]);
}
sony_xa_mode = 0;
}
@@ -3007,6 +2922,8 @@ static int scd_block_release(struct inode *inode, struct file *file)
static int scd_block_ioctl(struct inode *inode, struct file *file,
unsigned cmd, unsigned long arg)
{
+ int retval;
+
/* The eject and close commands should be handled by Uniform CD-ROM
* driver - but I always got hard lockup instead of eject
* until I put this here.
@@ -3014,12 +2931,15 @@ static int scd_block_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case CDROMEJECT:
scd_lock_door(&scd_info, 0);
- return scd_tray_move(&scd_info, 1);
+ retval = scd_tray_move(&scd_info, 1);
+ break;
case CDROMCLOSETRAY:
- return scd_tray_move(&scd_info, 0);
+ retval = scd_tray_move(&scd_info, 0);
+ break;
default:
- return cdrom_ioctl(file, &scd_info, inode, cmd, arg);
+ retval = cdrom_ioctl(file, &scd_info, inode, cmd, arg);
}
+ return retval;
}
static int scd_block_media_changed(struct gendisk *disk)
@@ -3112,7 +3032,6 @@ out_err:
#ifndef MODULE
/*
* Set up base I/O and interrupts, called from main.c.
-
*/
static int __init cdu31a_setup(char *strings)
@@ -3131,7 +3050,7 @@ static int __init cdu31a_setup(char *strings)
if (strcmp(strings, "PAS") == 0) {
sony_pas_init = 1;
} else {
- printk("CDU31A: Unknown interface type: %s\n",
+ printk(KERN_NOTICE PFX "Unknown interface type: %s\n",
strings);
}
}
@@ -3223,9 +3142,8 @@ int __init cdu31a_init(void)
if (request_irq
(cdu31a_irq, cdu31a_interrupt, SA_INTERRUPT,
"cdu31a", NULL)) {
- printk
- ("Unable to grab IRQ%d for the CDU31A driver\n",
- cdu31a_irq);
+ printk(KERN_WARNING PFX "Unable to grab IRQ%d for "
+ "the CDU31A driver\n", cdu31a_irq);
cdu31a_irq = 0;
}
}
@@ -3260,8 +3178,8 @@ int __init cdu31a_init(void)
strcat(msg, buf);
}
strcat(msg, "\n");
- printk("%s",msg);
-
+ printk(KERN_INFO PFX "%s",msg);
+
cdu31a_queue = blk_init_queue(do_cdu31a_request, &cdu31a_lock);
if (!cdu31a_queue)
goto errout0;
@@ -3278,18 +3196,18 @@ int __init cdu31a_init(void)
add_disk(disk);
disk_changed = 1;
- return (0);
+ return 0;
err:
blk_cleanup_queue(cdu31a_queue);
errout0:
if (cdu31a_irq)
free_irq(cdu31a_irq, NULL);
- printk("Unable to register CDU-31a with Uniform cdrom driver\n");
+ printk(KERN_ERR PFX "Unable to register with Uniform cdrom driver\n");
put_disk(disk);
errout1:
if (unregister_blkdev(MAJOR_NR, "cdu31a")) {
- printk("Can't unregister block device for cdu31a\n");
+ printk(KERN_WARNING PFX "Can't unregister block device\n");
}
errout2:
release_region(cdu31a_port, 4);
@@ -3303,12 +3221,12 @@ void __exit cdu31a_exit(void)
del_gendisk(scd_gendisk);
put_disk(scd_gendisk);
if (unregister_cdrom(&scd_info)) {
- printk
- ("Can't unregister cdu31a from Uniform cdrom driver\n");
+ printk(KERN_WARNING PFX "Can't unregister from Uniform "
+ "cdrom driver\n");
return;
}
if ((unregister_blkdev(MAJOR_NR, "cdu31a") == -EINVAL)) {
- printk("Can't unregister cdu31a\n");
+ printk(KERN_WARNING PFX "Can't unregister\n");
return;
}
@@ -3318,7 +3236,7 @@ void __exit cdu31a_exit(void)
free_irq(cdu31a_irq, NULL);
release_region(cdu31a_port, 4);
- printk(KERN_INFO "cdu31a module released.\n");
+ printk(KERN_INFO PFX "module released.\n");
}
#ifdef MODULE
diff --git a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c
deleted file mode 100644
index a204f80f58324..0000000000000
--- a/drivers/cdrom/mcd.c
+++ /dev/null
@@ -1,1565 +0,0 @@
-/*
- linux/kernel/blk_drv/mcd.c - Mitsumi CDROM driver
-
- Copyright (C) 1992 Martin Harriss
- Portions Copyright (C) 2001 Red Hat
-
- martin@bdsi.com (no longer valid - where are you now, Martin?)
-
- 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; 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.
-
- HISTORY
-
- 0.1 First attempt - internal use only
- 0.2 Cleaned up delays and use of timer - alpha release
- 0.3 Audio support added
- 0.3.1 Changes for mitsumi CRMC LU005S march version
- (stud11@cc4.kuleuven.ac.be)
- 0.3.2 bug fixes to the ioctls and merged with ALPHA0.99-pl12
- (Jon Tombs <jon@robots.ox.ac.uk>)
- 0.3.3 Added more #defines and mcd_setup()
- (Jon Tombs <jon@gtex02.us.es>)
-
- October 1993 Bernd Huebner and Ruediger Helsch, Unifix Software GmbH,
- Braunschweig, Germany: rework to speed up data read operation.
- Also enabled definition of irq and address from bootstrap, using the
- environment.
- November 93 added code for FX001 S,D (single & double speed).
- February 94 added code for broken M 5/6 series of 16-bit single speed.
-
-
- 0.4
- Added support for loadable MODULEs, so mcd can now also be loaded by
- insmod and removed by rmmod during runtime.
- Werner Zimmermann (zimmerma@rz.fht-esslingen.de), Mar. 26, 95
-
- 0.5
- I added code for FX001 D to drop from double speed to single speed
- when encountering errors... this helps with some "problematic" CD's
- that are supposedly "OUT OF TOLERANCE" (but are really shitty presses!)
- severely scratched, or possibly slightly warped! I have noticed that
- the Mitsumi 2x/4x drives are just less tolerant and the firmware is
- not smart enough to drop speed, so let's just kludge it with software!
- ****** THE 4X SPEED MITSUMI DRIVES HAVE THE SAME PROBLEM!!!!!! ******
- Anyone want to "DONATE" one to me?! ;) I hear sometimes they are
- even WORSE! ;)
- ** HINT... HINT... TAKE NOTES MITSUMI This could save some hassles with
- certain "large" CD's that have data on the outside edge in your
- DOS DRIVERS .... Accuracy counts... speed is secondary ;)
- 17 June 95 Modifications By Andrew J. Kroll <ag784@freenet.buffalo.edu>
- 07 July 1995 Modifications by Andrew J. Kroll
-
- Bjorn Ekwall <bj0rn@blox.se> added unregister_blkdev to mcd_init()
-
- Michael K. Johnson <johnsonm@redhat.com> added retries on open
- for slow drives which take a while to recognize that they contain
- a CD.
-
- November 1997 -- ported to the Uniform CD-ROM driver by Erik Andersen.
- March 1999 -- made io base and irq CONFIG_ options (Tigran Aivazian).
-
- November 1999 -- Make kernel-parameter implementation work with 2.3.x
- Removed init_module & cleanup_module in favor of
- module_init & module_exit.
- Torben Mathiasen <tmm@image.dk>
-
- September 2001 - Reformatted and cleaned up the code
- Alan Cox <alan@redhat.com>
-*/
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/signal.h>
-#include <linux/mm.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/cdrom.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/config.h>
-
-/* #define REALLY_SLOW_IO */
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/current.h>
-#include <asm/uaccess.h>
-#include <linux/blkdev.h>
-
-#include "mcd.h"
-
-/* I added A flag to drop to 1x speed if too many errors 0 = 1X ; 1 = 2X */
-static int mcdDouble;
-
-/* How many sectors to hold at 1x speed counter */
-static int mcd1xhold;
-
-/* Is the drive connected properly and responding?? */
-static int mcdPresent;
-static struct request_queue *mcd_queue;
-
-#define MAJOR_NR MITSUMI_CDROM_MAJOR
-#define QUEUE (mcd_queue)
-#define CURRENT elv_next_request(mcd_queue)
-
-#define QUICK_LOOP_DELAY udelay(45) /* use udelay */
-#define QUICK_LOOP_COUNT 20
-
-static int current_valid(void)
-{
- return CURRENT &&
- CURRENT->cmd == READ &&
- CURRENT->sector != -1;
-}
-
-#define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA)
-#define MCD_BUF_SIZ 16
-static volatile int mcd_transfer_is_active;
-static char mcd_buf[2048 * MCD_BUF_SIZ]; /* buffer for block size conversion */
-static volatile int mcd_buf_bn[MCD_BUF_SIZ], mcd_next_bn;
-static volatile int mcd_buf_in, mcd_buf_out = -1;
-static volatile int mcd_error;
-static int mcd_open_count;
-enum mcd_state_e {
- MCD_S_IDLE, /* 0 */
- MCD_S_START, /* 1 */
- MCD_S_MODE, /* 2 */
- MCD_S_READ, /* 3 */
- MCD_S_DATA, /* 4 */
- MCD_S_STOP, /* 5 */
- MCD_S_STOPPING /* 6 */
-};
-static volatile enum mcd_state_e mcd_state = MCD_S_IDLE;
-static int mcd_mode = -1;
-static int MCMD_DATA_READ = MCMD_PLAY_READ;
-
-#define READ_TIMEOUT 3000
-
-int mitsumi_bug_93_wait;
-
-static short mcd_port = CONFIG_MCD_BASE; /* used as "mcd" by "insmod" */
-static int mcd_irq = CONFIG_MCD_IRQ; /* must directly follow mcd_port */
-
-static int McdTimeout, McdTries;
-static DECLARE_WAIT_QUEUE_HEAD(mcd_waitq);
-
-static struct mcd_DiskInfo DiskInfo;
-static struct mcd_Toc Toc[MAX_TRACKS];
-static struct mcd_Play_msf mcd_Play;
-
-static int audioStatus;
-static char mcdDiskChanged;
-static char tocUpToDate;
-static char mcdVersion;
-
-static void mcd_transfer(void);
-static void mcd_poll(unsigned long dummy);
-static void mcd_invalidate_buffers(void);
-static void hsg2msf(long hsg, struct msf *msf);
-static void bin2bcd(unsigned char *p);
-static int bcd2bin(unsigned char bcd);
-static int mcdStatus(void);
-static void sendMcdCmd(int cmd, struct mcd_Play_msf *params);
-static int getMcdStatus(int timeout);
-static int GetQChannelInfo(struct mcd_Toc *qp);
-static int updateToc(void);
-static int GetDiskInfo(void);
-static int GetToc(void);
-static int getValue(unsigned char *result);
-static int mcd_open(struct cdrom_device_info *cdi, int purpose);
-static void mcd_release(struct cdrom_device_info *cdi);
-static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr);
-static int mcd_tray_move(struct cdrom_device_info *cdi, int position);
-static DEFINE_SPINLOCK(mcd_spinlock);
-static int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
- void *arg);
-static int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
-
-static struct timer_list mcd_timer = TIMER_INITIALIZER(NULL, 0, 0);
-
-static struct cdrom_device_ops mcd_dops = {
- .open = mcd_open,
- .release = mcd_release,
- .drive_status = mcd_drive_status,
- .media_changed = mcd_media_changed,
- .tray_move = mcd_tray_move,
- .audio_ioctl = mcd_audio_ioctl,
- .capability = CDC_OPEN_TRAY | CDC_MEDIA_CHANGED |
- CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
-};
-
-static struct cdrom_device_info mcd_info = {
- .ops = &mcd_dops,
- .speed = 2,
- .capacity = 1,
- .name = "mcd",
-};
-
-static int mcd_block_open(struct inode *inode, struct file *file)
-{
- return cdrom_open(&mcd_info, inode, file);
-}
-
-static int mcd_block_release(struct inode *inode, struct file *file)
-{
- return cdrom_release(&mcd_info, file);
-}
-
-static int mcd_block_ioctl(struct inode *inode, struct file *file,
- unsigned cmd, unsigned long arg)
-{
- return cdrom_ioctl(file, &mcd_info, inode, cmd, arg);
-}
-
-static int mcd_block_media_changed(struct gendisk *disk)
-{
- return cdrom_media_changed(&mcd_info);
-}
-
-static struct block_device_operations mcd_bdops =
-{
- .owner = THIS_MODULE,
- .open = mcd_block_open,
- .release = mcd_block_release,
- .ioctl = mcd_block_ioctl,
- .media_changed = mcd_block_media_changed,
-};
-
-static struct gendisk *mcd_gendisk;
-
-static int __init mcd_setup(const char *str)
-{
- int ints[9];
-
- (void) get_options(str, ARRAY_SIZE(ints), ints);
-
- if (ints[0] > 0)
- mcd_port = ints[1];
- if (ints[0] > 1)
- mcd_irq = ints[2];
- if (ints[0] > 2)
- mitsumi_bug_93_wait = ints[3];
-
- return 1;
-}
-
-__setup("mcd=", mcd_setup);
-
-#ifdef MODULE
-static int __init param_set_mcd(const char *val, struct kernel_param *kp)
-{
- mcd_setup(val);
- return 0;
-}
-module_param_call(mcd, param_set_mcd, NULL, NULL, 0);
-#endif
-
-static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr)
-{
- return 0;
-}
-
-
-/*
- * Do a 'get status' command and get the result. Only use from the top half
- * because it calls 'getMcdStatus' which sleeps.
- */
-
-static int statusCmd(void)
-{
- int st = -1, retry;
-
- for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
- /* send get-status cmd */
- outb(MCMD_GET_STATUS, MCDPORT(0));
-
- st = getMcdStatus(MCD_STATUS_DELAY);
- if (st != -1)
- break;
- }
-
- return st;
-}
-
-
-/*
- * Send a 'Play' command and get the status. Use only from the top half.
- */
-
-static int mcdPlay(struct mcd_Play_msf *arg)
-{
- int retry, st = -1;
-
- for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
- sendMcdCmd(MCMD_PLAY_READ, arg);
- st = getMcdStatus(2 * MCD_STATUS_DELAY);
- if (st != -1)
- break;
- }
-
- return st;
-}
-
-
-static int mcd_tray_move(struct cdrom_device_info *cdi, int position)
-{
- int i;
- if (position) {
- /* Eject */
- /* all drives can at least stop! */
- if (audioStatus == CDROM_AUDIO_PLAY) {
- outb(MCMD_STOP, MCDPORT(0));
- i = getMcdStatus(MCD_STATUS_DELAY);
- }
-
- audioStatus = CDROM_AUDIO_NO_STATUS;
-
- outb(MCMD_EJECT, MCDPORT(0));
- /*
- * the status (i) shows failure on all but the FX drives.
- * But nothing we can do about that in software!
- * So just read the status and forget it. - Jon.
- */
- i = getMcdStatus(MCD_STATUS_DELAY);
- return 0;
- } else
- return -EINVAL;
-}
-
-long msf2hsg(struct msf *mp)
-{
- return bcd2bin(mp->frame) + bcd2bin(mp->sec) * 75 + bcd2bin(mp->min) * 4500 - 150;
-}
-
-
-int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
- void *arg)
-{
- int i, st;
- struct mcd_Toc qInfo;
- struct cdrom_ti *ti;
- struct cdrom_tochdr *tocHdr;
- struct cdrom_msf *msf;
- struct cdrom_subchnl *subchnl;
- struct cdrom_tocentry *entry;
- struct mcd_Toc *tocPtr;
- struct cdrom_volctrl *volctrl;
-
- st = statusCmd();
- if (st < 0)
- return -EIO;
-
- if (!tocUpToDate) {
- i = updateToc();
- if (i < 0)
- return i; /* error reading TOC */
- }
-
- switch (cmd) {
- case CDROMSTART: /* Spin up the drive */
- /* Don't think we can do this. Even if we could,
- * I think the drive times out and stops after a while
- * anyway. For now, ignore it.
- */
-
- return 0;
-
- case CDROMSTOP: /* Spin down the drive */
- outb(MCMD_STOP, MCDPORT(0));
- i = getMcdStatus(MCD_STATUS_DELAY);
-
- /* should we do anything if it fails? */
-
- audioStatus = CDROM_AUDIO_NO_STATUS;
- return 0;
-
- case CDROMPAUSE: /* Pause the drive */
- if (audioStatus != CDROM_AUDIO_PLAY)
- return -EINVAL;
-
- outb(MCMD_STOP, MCDPORT(0));
- i = getMcdStatus(MCD_STATUS_DELAY);
-
- if (GetQChannelInfo(&qInfo) < 0) {
- /* didn't get q channel info */
-
- audioStatus = CDROM_AUDIO_NO_STATUS;
- return 0;
- }
-
- mcd_Play.start = qInfo.diskTime; /* remember restart point */
-
- audioStatus = CDROM_AUDIO_PAUSED;
- return 0;
-
- case CDROMRESUME: /* Play it again, Sam */
- if (audioStatus != CDROM_AUDIO_PAUSED)
- return -EINVAL;
-
- /* restart the drive at the saved position. */
-
- i = mcdPlay(&mcd_Play);
- if (i < 0) {
- audioStatus = CDROM_AUDIO_ERROR;
- return -EIO;
- }
-
- audioStatus = CDROM_AUDIO_PLAY;
- return 0;
-
- case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */
-
- ti = (struct cdrom_ti *) arg;
-
- if (ti->cdti_trk0 < DiskInfo.first
- || ti->cdti_trk0 > DiskInfo.last
- || ti->cdti_trk1 < ti->cdti_trk0) {
- return -EINVAL;
- }
-
- if (ti->cdti_trk1 > DiskInfo.last)
- ti->cdti_trk1 = DiskInfo.last;
-
- mcd_Play.start = Toc[ti->cdti_trk0].diskTime;
- mcd_Play.end = Toc[ti->cdti_trk1 + 1].diskTime;
-
-#ifdef MCD_DEBUG
- printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
- mcd_Play.start.min, mcd_Play.start.sec,
- mcd_Play.start.frame, mcd_Play.end.min,
- mcd_Play.end.sec, mcd_Play.end.frame);
-#endif
-
- i = mcdPlay(&mcd_Play);
- if (i < 0) {
- audioStatus = CDROM_AUDIO_ERROR;
- return -EIO;
- }
-
- audioStatus = CDROM_AUDIO_PLAY;
- return 0;
-
- case CDROMPLAYMSF: /* Play starting at the given MSF address. */
-
- if (audioStatus == CDROM_AUDIO_PLAY) {
- outb(MCMD_STOP, MCDPORT(0));
- i = getMcdStatus(MCD_STATUS_DELAY);
- audioStatus = CDROM_AUDIO_NO_STATUS;
- }
-
- msf = (struct cdrom_msf *) arg;
-
- /* convert to bcd */
-
- bin2bcd(&msf->cdmsf_min0);
- bin2bcd(&msf->cdmsf_sec0);
- bin2bcd(&msf->cdmsf_frame0);
- bin2bcd(&msf->cdmsf_min1);
- bin2bcd(&msf->cdmsf_sec1);
- bin2bcd(&msf->cdmsf_frame1);
-
- mcd_Play.start.min = msf->cdmsf_min0;
- mcd_Play.start.sec = msf->cdmsf_sec0;
- mcd_Play.start.frame = msf->cdmsf_frame0;
- mcd_Play.end.min = msf->cdmsf_min1;
- mcd_Play.end.sec = msf->cdmsf_sec1;
- mcd_Play.end.frame = msf->cdmsf_frame1;
-
-#ifdef MCD_DEBUG
- printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
- mcd_Play.start.min, mcd_Play.start.sec,
- mcd_Play.start.frame, mcd_Play.end.min,
- mcd_Play.end.sec, mcd_Play.end.frame);
-#endif
-
- i = mcdPlay(&mcd_Play);
- if (i < 0) {
- audioStatus = CDROM_AUDIO_ERROR;
- return -EIO;
- }
-
- audioStatus = CDROM_AUDIO_PLAY;
- return 0;
-
- case CDROMREADTOCHDR: /* Read the table of contents header */
- tocHdr = (struct cdrom_tochdr *) arg;
- tocHdr->cdth_trk0 = DiskInfo.first;
- tocHdr->cdth_trk1 = DiskInfo.last;
- return 0;
-
- case CDROMREADTOCENTRY: /* Read an entry in the table of contents */
- entry = (struct cdrom_tocentry *) arg;
- if (entry->cdte_track == CDROM_LEADOUT)
- tocPtr = &Toc[DiskInfo.last - DiskInfo.first + 1];
-
- else if (entry->cdte_track > DiskInfo.last
- || entry->cdte_track < DiskInfo.first)
- return -EINVAL;
-
- else
- tocPtr = &Toc[entry->cdte_track];
-
- entry->cdte_adr = tocPtr->ctrl_addr;
- entry->cdte_ctrl = tocPtr->ctrl_addr >> 4;
-
- if (entry->cdte_format == CDROM_LBA)
- entry->cdte_addr.lba = msf2hsg(&tocPtr->diskTime);
-
- else if (entry->cdte_format == CDROM_MSF) {
- entry->cdte_addr.msf.minute =
- bcd2bin(tocPtr->diskTime.min);
- entry->cdte_addr.msf.second =
- bcd2bin(tocPtr->diskTime.sec);
- entry->cdte_addr.msf.frame =
- bcd2bin(tocPtr->diskTime.frame);
- }
-
- else
- return -EINVAL;
-
- return 0;
-
- case CDROMSUBCHNL: /* Get subchannel info */
-
- subchnl = (struct cdrom_subchnl *) arg;
- if (GetQChannelInfo(&qInfo) < 0)
- return -EIO;
-
- subchnl->cdsc_audiostatus = audioStatus;
- subchnl->cdsc_adr = qInfo.ctrl_addr;
- subchnl->cdsc_ctrl = qInfo.ctrl_addr >> 4;
- subchnl->cdsc_trk = bcd2bin(qInfo.track);
- subchnl->cdsc_ind = bcd2bin(qInfo.pointIndex);
- subchnl->cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);
- subchnl->cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);
- subchnl->cdsc_absaddr.msf.frame = bcd2bin(qInfo.diskTime.frame);
- subchnl->cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);
- subchnl->cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);
- subchnl->cdsc_reladdr.msf.frame = bcd2bin(qInfo.trackTime.frame);
- return (0);
-
- case CDROMVOLCTRL: /* Volume control */
- volctrl = (struct cdrom_volctrl *) arg;
- outb(MCMD_SET_VOLUME, MCDPORT(0));
- outb(volctrl->channel0, MCDPORT(0));
- outb(255, MCDPORT(0));
- outb(volctrl->channel1, MCDPORT(0));
- outb(255, MCDPORT(0));
-
- i = getMcdStatus(MCD_STATUS_DELAY);
- if (i < 0)
- return -EIO;
-
- {
- char a, b, c, d;
-
- getValue(&a);
- getValue(&b);
- getValue(&c);
- getValue(&d);
- }
-
- return 0;
-
- default:
- return -EINVAL;
- }
-}
-
-/*
- * Take care of the different block sizes between cdrom and Linux.
- * When Linux gets variable block sizes this will probably go away.
- */
-
-static void mcd_transfer(void)
-{
- if (!current_valid())
- return;
-
- while (CURRENT->nr_sectors) {
- int bn = CURRENT->sector / 4;
- int i;
- for (i = 0; i < MCD_BUF_SIZ && mcd_buf_bn[i] != bn; ++i)
- ;
- if (i < MCD_BUF_SIZ) {
- int offs =(i * 4 + (CURRENT->sector & 3)) * 512;
- int nr_sectors = 4 - (CURRENT->sector & 3);
- if (mcd_buf_out != i) {
- mcd_buf_out = i;
- if (mcd_buf_bn[i] != bn) {
- mcd_buf_out = -1;
- continue;
- }
- }
- if (nr_sectors > CURRENT->nr_sectors)
- nr_sectors = CURRENT->nr_sectors;
- memcpy(CURRENT->buffer, mcd_buf + offs, nr_sectors * 512);
- CURRENT->nr_sectors -= nr_sectors;
- CURRENT->sector += nr_sectors;
- CURRENT->buffer += nr_sectors * 512;
- } else {
- mcd_buf_out = -1;
- break;
- }
- }
-}
-
-
-/*
- * We only seem to get interrupts after an error.
- * Just take the interrupt and clear out the status reg.
- */
-
-static irqreturn_t mcd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- int st;
-
- st = inb(MCDPORT(1)) & 0xFF;
- test1(printk("<int1-%02X>", st));
- if (!(st & MFL_STATUS)) {
- st = inb(MCDPORT(0)) & 0xFF;
- test1(printk("<int0-%02X>", st));
- if ((st & 0xFF) != 0xFF)
- mcd_error = st ? st & 0xFF : -1;
- }
- return IRQ_HANDLED;
-}
-
-
-static void do_mcd_request(request_queue_t * q)
-{
- test2(printk(" do_mcd_request(%ld+%ld)\n", CURRENT->sector,
- CURRENT->nr_sectors));
-
- mcd_transfer_is_active = 1;
- while (current_valid()) {
- mcd_transfer();
- if (CURRENT->nr_sectors == 0) {
- end_request(CURRENT, 1);
- } else {
- mcd_buf_out = -1; /* Want to read a block not in buffer */
- if (mcd_state == MCD_S_IDLE) {
- if (!tocUpToDate) {
- if (updateToc() < 0) {
- while (current_valid())
- end_request(CURRENT, 0);
- break;
- }
- }
- mcd_state = MCD_S_START;
- McdTries = 5;
- mcd_timer.function = mcd_poll;
- mod_timer(&mcd_timer, jiffies + 1);
- }
- break;
- }
- }
- mcd_transfer_is_active = 0;
- test2(printk(" do_mcd_request ends\n"));
-}
-
-
-
-static void mcd_poll(unsigned long dummy)
-{
- int st;
-
-
- if (mcd_error) {
- if (mcd_error & 0xA5) {
- printk(KERN_ERR "mcd: I/O error 0x%02x", mcd_error);
- if (mcd_error & 0x80)
- printk(" (Door open)");
- if (mcd_error & 0x20)
- printk(" (Disk changed)");
- if (mcd_error & 0x04) {
- printk(" (Read error)"); /* Bitch about the problem. */
-
- /* Time to get fancy! If at 2x speed and 1 error, drop to 1x speed! */
- /* Interesting how it STAYS at MCD_RETRY_ATTEMPTS on first error! */
- /* But I find that rather HANDY!!! */
- /* Neat! it REALLY WORKS on those LOW QUALITY CD's!!! Smile! :) */
- /* AJK [06/17/95] */
-
- /* Slap the CD down to single speed! */
- if (mcdDouble == 1
- && McdTries == MCD_RETRY_ATTEMPTS
- && MCMD_DATA_READ == MCMD_2X_READ) {
- MCMD_DATA_READ = MCMD_PLAY_READ; /* Uhhh, Ummmm, muhuh-huh! */
- mcd1xhold = SINGLE_HOLD_SECTORS; /* Hey Beavis! */
- printk(" Speed now 1x"); /* Pull my finger! */
- }
- }
- printk("\n");
- mcd_invalidate_buffers();
-#ifdef WARN_IF_READ_FAILURE
- if (McdTries == MCD_RETRY_ATTEMPTS)
- printk(KERN_ERR "mcd: read of block %d failed\n",
- mcd_next_bn);
-#endif
- if (!McdTries--) {
- /* Nuts! This cd is ready for recycling! */
- /* When WAS the last time YOU cleaned it CORRECTLY?! */
- printk(KERN_ERR "mcd: read of block %d failed, giving up\n",
- mcd_next_bn);
- if (mcd_transfer_is_active) {
- McdTries = 0;
- goto ret;
- }
- if (current_valid())
- end_request(CURRENT, 0);
- McdTries = MCD_RETRY_ATTEMPTS;
- }
- }
- mcd_error = 0;
- mcd_state = MCD_S_STOP;
- }
- /* Switch back to Double speed if enough GOOD sectors were read! */
-
- /* Are we a double speed with a crappy CD?! */
- if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS
- && MCMD_DATA_READ == MCMD_PLAY_READ) {
- /* We ARE a double speed and we ARE bitching! */
- if (mcd1xhold == 0) { /* Okay, Like are we STILL at single speed? *//* We need to switch back to double speed now... */
- MCMD_DATA_READ = MCMD_2X_READ; /* Uhhh... BACK You GO! */
- printk(KERN_INFO "mcd: Switching back to 2X speed!\n"); /* Tell 'em! */
- } else
- mcd1xhold--; /* No?! Count down the good reads some more... */
- /* and try, try again! */
- }
-
-immediately:
- switch (mcd_state) {
- case MCD_S_IDLE:
- test3(printk("MCD_S_IDLE\n"));
- goto out;
-
- case MCD_S_START:
- test3(printk("MCD_S_START\n"));
- outb(MCMD_GET_STATUS, MCDPORT(0));
- mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE;
- McdTimeout = 3000;
- break;
-
- case MCD_S_MODE:
- test3(printk("MCD_S_MODE\n"));
- if ((st = mcdStatus()) != -1) {
- if (st & MST_DSK_CHG) {
- mcdDiskChanged = 1;
- tocUpToDate = 0;
- mcd_invalidate_buffers();
- }
-
-set_mode_immediately:
- if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
- mcdDiskChanged = 1;
- tocUpToDate = 0;
- if (mcd_transfer_is_active) {
- mcd_state = MCD_S_START;
- goto immediately;
- }
- printk(KERN_INFO);
- printk((st & MST_DOOR_OPEN) ?
- "mcd: door open\n" :
- "mcd: disk removed\n");
- mcd_state = MCD_S_IDLE;
- while (current_valid())
- end_request(CURRENT, 0);
- goto out;
- }
- outb(MCMD_SET_MODE, MCDPORT(0));
- outb(1, MCDPORT(0));
- mcd_mode = 1;
- mcd_state = MCD_S_READ;
- McdTimeout = 3000;
- }
- break;
-
- case MCD_S_READ:
- test3(printk("MCD_S_READ\n"));
- if ((st = mcdStatus()) != -1) {
- if (st & MST_DSK_CHG) {
- mcdDiskChanged = 1;
- tocUpToDate = 0;
- mcd_invalidate_buffers();
- }
-
-read_immediately:
- if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
- mcdDiskChanged = 1;
- tocUpToDate = 0;
- if (mcd_transfer_is_active) {
- mcd_state = MCD_S_START;
- goto immediately;
- }
- printk(KERN_INFO);
- printk((st & MST_DOOR_OPEN) ?
- "mcd: door open\n" :
- "mcd: disk removed\n");
- mcd_state = MCD_S_IDLE;
- while (current_valid())
- end_request(CURRENT, 0);
- goto out;
- }
-
- if (current_valid()) {
- struct mcd_Play_msf msf;
- mcd_next_bn = CURRENT->sector / 4;
- hsg2msf(mcd_next_bn, &msf.start);
- msf.end.min = ~0;
- msf.end.sec = ~0;
- msf.end.frame = ~0;
- sendMcdCmd(MCMD_DATA_READ, &msf);
- mcd_state = MCD_S_DATA;
- McdTimeout = READ_TIMEOUT;
- } else {
- mcd_state = MCD_S_STOP;
- goto immediately;
- }
-
- }
- break;
-
- case MCD_S_DATA:
- test3(printk("MCD_S_DATA\n"));
- st = inb(MCDPORT(1)) & (MFL_STATUSorDATA);
-data_immediately:
- test5(printk("Status %02x\n", st))
- switch (st) {
- case MFL_DATA:
-#ifdef WARN_IF_READ_FAILURE
- if (McdTries == 5)
- printk(KERN_WARNING "mcd: read of block %d failed\n",
- mcd_next_bn);
-#endif
- if (!McdTries--) {
- printk(KERN_ERR "mcd: read of block %d failed, giving up\n", mcd_next_bn);
- if (mcd_transfer_is_active) {
- McdTries = 0;
- break;
- }
- if (current_valid())
- end_request(CURRENT, 0);
- McdTries = 5;
- }
- mcd_state = MCD_S_START;
- McdTimeout = READ_TIMEOUT;
- goto immediately;
-
- case MFL_STATUSorDATA:
- break;
-
- default:
- McdTries = 5;
- if (!current_valid() && mcd_buf_in == mcd_buf_out) {
- mcd_state = MCD_S_STOP;
- goto immediately;
- }
- mcd_buf_bn[mcd_buf_in] = -1;
- insb(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in,
- 2048);
- mcd_buf_bn[mcd_buf_in] = mcd_next_bn++;
- if (mcd_buf_out == -1)
- mcd_buf_out = mcd_buf_in;
- mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1;
- if (!mcd_transfer_is_active) {
- while (current_valid()) {
- mcd_transfer();
- if (CURRENT->nr_sectors == 0)
- end_request(CURRENT, 1);
- else
- break;
- }
- }
-
- if (current_valid()
- && (CURRENT->sector / 4 < mcd_next_bn ||
- CURRENT->sector / 4 > mcd_next_bn + 16)) {
- mcd_state = MCD_S_STOP;
- goto immediately;
- }
- McdTimeout = READ_TIMEOUT;
- {
- int count = QUICK_LOOP_COUNT;
- while (count--) {
- QUICK_LOOP_DELAY;
- if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) {
- test4(printk(" %d ", QUICK_LOOP_COUNT - count));
- goto data_immediately;
- }
- }
- test4(printk("ended "));
- }
- break;
- }
- break;
-
- case MCD_S_STOP:
- test3(printk("MCD_S_STOP\n"));
- if (!mitsumi_bug_93_wait)
- goto do_not_work_around_mitsumi_bug_93_1;
-
- McdTimeout = mitsumi_bug_93_wait;
- mcd_state = 9 + 3 + 1;
- break;
-
- case 9 + 3 + 1:
- if (McdTimeout)
- break;
-
-do_not_work_around_mitsumi_bug_93_1:
- outb(MCMD_STOP, MCDPORT(0));
- if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
- int i = 4096;
- do {
- inb(MCDPORT(0));
- } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
- outb(MCMD_STOP, MCDPORT(0));
- if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
- i = 4096;
- do {
- inb(MCDPORT(0));
- } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
- outb(MCMD_STOP, MCDPORT(0));
- }
- }
-
- mcd_state = MCD_S_STOPPING;
- McdTimeout = 1000;
- break;
-
- case MCD_S_STOPPING:
- test3(printk("MCD_S_STOPPING\n"));
- if ((st = mcdStatus()) == -1 && McdTimeout)
- break;
-
- if ((st != -1) && (st & MST_DSK_CHG)) {
- mcdDiskChanged = 1;
- tocUpToDate = 0;
- mcd_invalidate_buffers();
- }
- if (!mitsumi_bug_93_wait)
- goto do_not_work_around_mitsumi_bug_93_2;
-
- McdTimeout = mitsumi_bug_93_wait;
- mcd_state = 9 + 3 + 2;
- break;
-
- case 9 + 3 + 2:
- if (McdTimeout)
- break;
- st = -1;
-
-do_not_work_around_mitsumi_bug_93_2:
- test3(printk("CURRENT_VALID %d mcd_mode %d\n", current_valid(),
- mcd_mode));
- if (current_valid()) {
- if (st != -1) {
- if (mcd_mode == 1)
- goto read_immediately;
- else
- goto set_mode_immediately;
- } else {
- mcd_state = MCD_S_START;
- McdTimeout = 1;
- }
- } else {
- mcd_state = MCD_S_IDLE;
- goto out;
- }
- break;
- default:
- printk(KERN_ERR "mcd: invalid state %d\n", mcd_state);
- goto out;
- }
-ret:
- if (!McdTimeout--) {
- printk(KERN_WARNING "mcd: timeout in state %d\n", mcd_state);
- mcd_state = MCD_S_STOP;
- }
- mcd_timer.function = mcd_poll;
- mod_timer(&mcd_timer, jiffies + 1);
-out:
- return;
-}
-
-static void mcd_invalidate_buffers(void)
-{
- int i;
- for (i = 0; i < MCD_BUF_SIZ; ++i)
- mcd_buf_bn[i] = -1;
- mcd_buf_out = -1;
-}
-
-/*
- * Open the device special file. Check that a disk is in.
- */
-static int mcd_open(struct cdrom_device_info *cdi, int purpose)
-{
- int st, count = 0;
- if (mcdPresent == 0)
- return -ENXIO; /* no hardware */
-
- if (mcd_open_count || mcd_state != MCD_S_IDLE)
- goto bump_count;
-
- mcd_invalidate_buffers();
- do {
- st = statusCmd(); /* check drive status */
- if (st == -1)
- goto err_out; /* drive doesn't respond */
- if ((st & MST_READY) == 0) /* no disk? wait a sec... */
- msleep(1000);
-
- } while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS);
-
- if (updateToc() < 0)
- goto err_out;
-
-bump_count:
- ++mcd_open_count;
- return 0;
-
-err_out:
- return -EIO;
-}
-
-
-/*
- * On close, we flush all mcd blocks from the buffer cache.
- */
-static void mcd_release(struct cdrom_device_info *cdi)
-{
- if (!--mcd_open_count) {
- mcd_invalidate_buffers();
- }
-}
-
-/*
- * Test for presence of drive and initialize it. Called at boot time.
- */
-
-int __init mcd_init(void)
-{
- struct gendisk *disk = alloc_disk(1);
- int count;
- unsigned char result[3];
- char msg[80];
-
- if (!disk) {
- printk(KERN_INFO "mcd: can't allocated disk.\n");
- return -ENOMEM;
- }
- if (mcd_port <= 0 || mcd_irq <= 0) {
- printk(KERN_INFO "mcd: not probing.\n");
- put_disk(disk);
- return -EIO;
- }
- if (register_blkdev(MAJOR_NR, "mcd")) {
- put_disk(disk);
- return -EIO;
- }
- if (!request_region(mcd_port, 4, "mcd")) {
- printk(KERN_ERR "mcd: Initialization failed, I/O port (%X) already in use\n", mcd_port);
- goto out_region;
- }
-
- mcd_queue = blk_init_queue(do_mcd_request, &mcd_spinlock);
- if (!mcd_queue)
- goto out_queue;
-
- /* check for card */
-
- outb(0, MCDPORT(1)); /* send reset */
- for (count = 0; count < 2000000; count++)
- (void) inb(MCDPORT(1)); /* delay a bit */
-
- outb(0x40, MCDPORT(0)); /* send get-stat cmd */
- for (count = 0; count < 2000000; count++)
- if (!(inb(MCDPORT(1)) & MFL_STATUS))
- break;
-
- if (count >= 2000000) {
- printk(KERN_INFO "mcd: initialisation failed - No mcd device at 0x%x irq %d\n",
- mcd_port, mcd_irq);
- goto out_probe;
- }
- count = inb(MCDPORT(0)); /* pick up the status */
-
- outb(MCMD_GET_VERSION, MCDPORT(0));
- for (count = 0; count < 3; count++)
- if (getValue(result + count)) {
- printk(KERN_ERR "mcd: mitsumi get version failed at 0x%x\n",
- mcd_port);
- goto out_probe;
- }
-
- if (result[0] == result[1] && result[1] == result[2])
- goto out_probe;
-
- mcdVersion = result[2];
-
- if (mcdVersion >= 4)
- outb(4, MCDPORT(2)); /* magic happens */
-
- /* don't get the IRQ until we know for sure the drive is there */
-
- if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL)) {
- printk(KERN_ERR "mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
- goto out_probe;
- }
-
- if (result[1] == 'D') {
- MCMD_DATA_READ = MCMD_2X_READ;
- /* Added flag to drop to 1x speed if too many errors */
- mcdDouble = 1;
- } else
- mcd_info.speed = 1;
- sprintf(msg, " mcd: Mitsumi %s Speed CD-ROM at port=0x%x,"
- " irq=%d\n", mcd_info.speed == 1 ? "Single" : "Double",
- mcd_port, mcd_irq);
-
- outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
- outb(0x02, MCDPORT(0));
- outb(0x00, MCDPORT(0));
- getValue(result);
-
- outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
- outb(0x10, MCDPORT(0));
- outb(0x04, MCDPORT(0));
- getValue(result);
-
- mcd_invalidate_buffers();
- mcdPresent = 1;
-
- disk->major = MAJOR_NR;
- disk->first_minor = 0;
- sprintf(disk->disk_name, "mcd");
- disk->fops = &mcd_bdops;
- disk->flags = GENHD_FL_CD;
- mcd_gendisk = disk;
-
- if (register_cdrom(&mcd_info) != 0) {
- printk(KERN_ERR "mcd: Unable to register Mitsumi CD-ROM.\n");
- goto out_cdrom;
- }
- disk->queue = mcd_queue;
- add_disk(disk);
- printk(msg);
- return 0;
-
-out_cdrom:
- free_irq(mcd_irq, NULL);
-out_queue:
- release_region(mcd_port, 4);
-out_probe:
- blk_cleanup_queue(mcd_queue);
-out_region:
- unregister_blkdev(MAJOR_NR, "mcd");
- put_disk(disk);
- return -EIO;
-}
-
-
-static void hsg2msf(long hsg, struct msf *msf)
-{
- hsg += 150;
- msf->min = hsg / 4500;
- hsg %= 4500;
- msf->sec = hsg / 75;
- msf->frame = hsg % 75;
-
- bin2bcd(&msf->min); /* convert to BCD */
- bin2bcd(&msf->sec);
- bin2bcd(&msf->frame);
-}
-
-
-static void bin2bcd(unsigned char *p)
-{
- int u, t;
-
- u = *p % 10;
- t = *p / 10;
- *p = u | (t << 4);
-}
-
-static int bcd2bin(unsigned char bcd)
-{
- return (bcd >> 4) * 10 + (bcd & 0xF);
-}
-
-
-/*
- * See if a status is ready from the drive and return it
- * if it is ready.
- */
-
-static int mcdStatus(void)
-{
- int i;
- int st;
-
- st = inb(MCDPORT(1)) & MFL_STATUS;
- if (!st) {
- i = inb(MCDPORT(0)) & 0xFF;
- return i;
- } else
- return -1;
-}
-
-
-/*
- * Send a play or read command to the drive
- */
-
-static void sendMcdCmd(int cmd, struct mcd_Play_msf *params)
-{
- outb(cmd, MCDPORT(0));
- outb(params->start.min, MCDPORT(0));
- outb(params->start.sec, MCDPORT(0));
- outb(params->start.frame, MCDPORT(0));
- outb(params->end.min, MCDPORT(0));
- outb(params->end.sec, MCDPORT(0));
- outb(params->end.frame, MCDPORT(0));
-}
-
-
-/*
- * Timer interrupt routine to test for status ready from the drive.
- * (see the next routine)
- */
-
-static void mcdStatTimer(unsigned long dummy)
-{
- if (!(inb(MCDPORT(1)) & MFL_STATUS)) {
- wake_up(&mcd_waitq);
- return;
- }
-
- McdTimeout--;
- if (McdTimeout <= 0) {
- wake_up(&mcd_waitq);
- return;
- }
- mcd_timer.function = mcdStatTimer;
- mod_timer(&mcd_timer, jiffies + 1);
-}
-
-
-/*
- * Wait for a status to be returned from the drive. The actual test
- * (see routine above) is done by the timer interrupt to avoid
- * excessive rescheduling.
- */
-
-static int getMcdStatus(int timeout)
-{
- int st;
-
- McdTimeout = timeout;
- mcd_timer.function = mcdStatTimer;
- mod_timer(&mcd_timer, jiffies + 1);
- sleep_on(&mcd_waitq);
- if (McdTimeout <= 0)
- return -1;
-
- st = inb(MCDPORT(0)) & 0xFF;
- if (st == 0xFF)
- return -1;
-
- if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
- /* XXX might be an error? look at q-channel? */
- audioStatus = CDROM_AUDIO_COMPLETED;
-
- if (st & MST_DSK_CHG) {
- mcdDiskChanged = 1;
- tocUpToDate = 0;
- audioStatus = CDROM_AUDIO_NO_STATUS;
- }
-
- return st;
-}
-
-
-/* gives current state of the drive This function is quite unreliable,
- and should probably be rewritten by someone, eventually... */
-
-int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
-{
- int st;
-
- st = statusCmd(); /* check drive status */
- if (st == -1)
- return -EIO; /* drive doesn't respond */
- if ((st & MST_READY))
- return CDS_DISC_OK;
- if ((st & MST_DOOR_OPEN))
- return CDS_TRAY_OPEN;
- if ((st & MST_DSK_CHG))
- return CDS_NO_DISC;
- if ((st & MST_BUSY))
- return CDS_DRIVE_NOT_READY;
- return -EIO;
-}
-
-
-/*
- * Read a value from the drive.
- */
-
-static int getValue(unsigned char *result)
-{
- int count;
- int s;
-
- for (count = 0; count < 2000; count++)
- if (!(inb(MCDPORT(1)) & MFL_STATUS))
- break;
-
- if (count >= 2000) {
- printk("mcd: getValue timeout\n");
- return -1;
- }
-
- s = inb(MCDPORT(0)) & 0xFF;
- *result = (unsigned char) s;
- return 0;
-}
-
-/*
- * Read the current Q-channel info. Also used for reading the
- * table of contents.
- */
-
-int GetQChannelInfo(struct mcd_Toc *qp)
-{
- unsigned char notUsed;
- int retry;
-
- for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
- outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
- if (getMcdStatus(MCD_STATUS_DELAY) != -1)
- break;
- }
-
- if (retry >= MCD_RETRY_ATTEMPTS)
- return -1;
-
- if (getValue(&qp->ctrl_addr) < 0)
- return -1;
- if (getValue(&qp->track) < 0)
- return -1;
- if (getValue(&qp->pointIndex) < 0)
- return -1;
- if (getValue(&qp->trackTime.min) < 0)
- return -1;
- if (getValue(&qp->trackTime.sec) < 0)
- return -1;
- if (getValue(&qp->trackTime.frame) < 0)
- return -1;
- if (getValue(&notUsed) < 0)
- return -1;
- if (getValue(&qp->diskTime.min) < 0)
- return -1;
- if (getValue(&qp->diskTime.sec) < 0)
- return -1;
- if (getValue(&qp->diskTime.frame) < 0)
- return -1;
-
- return 0;
-}
-
-/*
- * Read the table of contents (TOC) and TOC header if necessary
- */
-
-static int updateToc(void)
-{
- if (tocUpToDate)
- return 0;
-
- if (GetDiskInfo() < 0)
- return -EIO;
-
- if (GetToc() < 0)
- return -EIO;
-
- tocUpToDate = 1;
- return 0;
-}
-
-/*
- * Read the table of contents header
- */
-
-static int GetDiskInfo(void)
-{
- int retry;
-
- for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
- outb(MCMD_GET_DISK_INFO, MCDPORT(0));
- if (getMcdStatus(MCD_STATUS_DELAY) != -1)
- break;
- }
-
- if (retry >= MCD_RETRY_ATTEMPTS)
- return -1;
-
- if (getValue(&DiskInfo.first) < 0)
- return -1;
- if (getValue(&DiskInfo.last) < 0)
- return -1;
-
- DiskInfo.first = bcd2bin(DiskInfo.first);
- DiskInfo.last = bcd2bin(DiskInfo.last);
-
-#ifdef MCD_DEBUG
- printk
- ("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
- DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min,
- DiskInfo.diskLength.sec, DiskInfo.diskLength.frame,
- DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec,
- DiskInfo.firstTrack.frame);
-#endif
-
- if (getValue(&DiskInfo.diskLength.min) < 0)
- return -1;
- if (getValue(&DiskInfo.diskLength.sec) < 0)
- return -1;
- if (getValue(&DiskInfo.diskLength.frame) < 0)
- return -1;
- if (getValue(&DiskInfo.firstTrack.min) < 0)
- return -1;
- if (getValue(&DiskInfo.firstTrack.sec) < 0)
- return -1;
- if (getValue(&DiskInfo.firstTrack.frame) < 0)
- return -1;
-
- return 0;
-}
-
-/*
- * Read the table of contents (TOC)
- */
-
-static int GetToc(void)
-{
- int i, px;
- int limit;
- int retry;
- struct mcd_Toc qInfo;
-
- for (i = 0; i < MAX_TRACKS; i++)
- Toc[i].pointIndex = 0;
-
- i = DiskInfo.last + 3;
-
- for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
- outb(MCMD_STOP, MCDPORT(0));
- if (getMcdStatus(MCD_STATUS_DELAY) != -1)
- break;
- }
-
- if (retry >= MCD_RETRY_ATTEMPTS)
- return -1;
-
- for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
- outb(MCMD_SET_MODE, MCDPORT(0));
- outb(0x05, MCDPORT(0)); /* mode: toc */
- mcd_mode = 0x05;
- if (getMcdStatus(MCD_STATUS_DELAY) != -1)
- break;
- }
-
- if (retry >= MCD_RETRY_ATTEMPTS)
- return -1;
-
- for (limit = 300; limit > 0; limit--) {
- if (GetQChannelInfo(&qInfo) < 0)
- break;
-
- px = bcd2bin(qInfo.pointIndex);
- if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
- if (Toc[px].pointIndex == 0) {
- Toc[px] = qInfo;
- i--;
- }
-
- if (i <= 0)
- break;
- }
-
- Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
-
- for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
- outb(MCMD_SET_MODE, MCDPORT(0));
- outb(0x01, MCDPORT(0));
- mcd_mode = 1;
- if (getMcdStatus(MCD_STATUS_DELAY) != -1)
- break;
- }
-
-#ifdef MCD_DEBUG
- for (i = 1; i <= DiskInfo.last; i++)
- printk
- ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n",
- i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
- Toc[i].trackTime.min, Toc[i].trackTime.sec,
- Toc[i].trackTime.frame, Toc[i].diskTime.min,
- Toc[i].diskTime.sec, Toc[i].diskTime.frame);
- for (i = 100; i < 103; i++)
- printk
- ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n",
- i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
- Toc[i].trackTime.min, Toc[i].trackTime.sec,
- Toc[i].trackTime.frame, Toc[i].diskTime.min,
- Toc[i].diskTime.sec, Toc[i].diskTime.frame);
-#endif
-
- return limit > 0 ? 0 : -1;
-}
-
-void __exit mcd_exit(void)
-{
- del_gendisk(mcd_gendisk);
- put_disk(mcd_gendisk);
- if (unregister_cdrom(&mcd_info)) {
- printk(KERN_WARNING "Can't unregister cdrom mcd\n");
- return;
- }
- free_irq(mcd_irq, NULL);
- release_region(mcd_port, 4);
- if (unregister_blkdev(MAJOR_NR, "mcd")) {
- printk(KERN_WARNING "Can't unregister major mcd\n");
- return;
- }
- blk_cleanup_queue(mcd_queue);
- del_timer_sync(&mcd_timer);
-}
-
-#ifdef MODULE
-module_init(mcd_init);
-#endif
-module_exit(mcd_exit);
-
-MODULE_AUTHOR("Martin Harriss");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_CDROM_MAJOR);
diff --git a/drivers/cdrom/mcd.h b/drivers/cdrom/mcd.h
deleted file mode 100644
index 1e36c4192bb06..0000000000000
--- a/drivers/cdrom/mcd.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Definitions for a Mitsumi CD-ROM interface
- *
- * Copyright (C) 1992 Martin Harriss
- *
- * martin@bdsi.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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/* Increase this if you get lots of timeouts */
-#define MCD_STATUS_DELAY 1000
-
-/* number of times to retry a command before giving up */
-#define MCD_RETRY_ATTEMPTS 10
-
-/* port access macro */
-#define MCDPORT(x) (mcd_port + (x))
-
-/* How many sectors to read at 1x when an error at 2x speed occurs. */
-/* You can change this to anything from 2 to 32767, but 30 seems to */
-/* work best for me. I have found that when the drive has problems */
-/* reading one sector, it will have troubles reading the next few. */
-#define SINGLE_HOLD_SECTORS 30
-
-#define MCMD_2X_READ 0xC1 /* Double Speed Read DON'T TOUCH! */
-
-/* status bits */
-
-#define MST_CMD_CHECK 0x01 /* command error */
-#define MST_BUSY 0x02 /* now playing */
-#define MST_READ_ERR 0x04 /* read error */
-#define MST_DSK_TYPE 0x08
-#define MST_SERVO_CHECK 0x10
-#define MST_DSK_CHG 0x20 /* disk removed or changed */
-#define MST_READY 0x40 /* disk in the drive */
-#define MST_DOOR_OPEN 0x80 /* door is open */
-
-/* flag bits */
-
-#define MFL_DATA 0x02 /* data available */
-#define MFL_STATUS 0x04 /* status available */
-
-/* commands */
-
-#define MCMD_GET_DISK_INFO 0x10 /* read info from disk */
-#define MCMD_GET_Q_CHANNEL 0x20 /* read info from q channel */
-#define MCMD_GET_STATUS 0x40
-#define MCMD_SET_MODE 0x50
-#define MCMD_SOFT_RESET 0x60
-#define MCMD_STOP 0x70 /* stop play */
-#define MCMD_CONFIG_DRIVE 0x90
-#define MCMD_SET_VOLUME 0xAE /* set audio level */
-#define MCMD_PLAY_READ 0xC0 /* play or read data */
-#define MCMD_GET_VERSION 0xDC
-#define MCMD_EJECT 0xF6 /* eject (FX drive) */
-
-/* borrowed from hd.c */
-
-#define MAX_TRACKS 104
-
-struct msf {
- unsigned char min;
- unsigned char sec;
- unsigned char frame;
-};
-
-struct mcd_Play_msf {
- struct msf start;
- struct msf end;
-};
-
-struct mcd_DiskInfo {
- unsigned char first;
- unsigned char last;
- struct msf diskLength;
- struct msf firstTrack;
-};
-
-struct mcd_Toc {
- unsigned char ctrl_addr;
- unsigned char track;
- unsigned char pointIndex;
- struct msf trackTime;
- struct msf diskTime;
-};
-
-#define test1(x)
-#define test2(x)
-#define test3(x)
-#define test4(x)
-#define test5(x)
-
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 7bd34d93f809b..3dfcaffd37ccd 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -59,7 +59,7 @@ config VT_CONSOLE
config HW_CONSOLE
bool
- depends on VT && !S390 && !USERMODE
+ depends on VT && !S390 && !UML
default y
config SERIAL_NONSTANDARD
@@ -247,7 +247,7 @@ config RISCOM8
config SPECIALIX
tristate "Specialix IO8+ card support"
- depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP
+ depends on SERIAL_NONSTANDARD
help
This is a driver for the Specialix IO8+ multiport card (both the
ISA and the PCI version) which gives you many serial ports. You
@@ -765,6 +765,10 @@ config S3C2410_RTC
Samsung S3C2410. This can provide periodic interrupt rates
from 1Hz to 64Hz for user programs, and wakeup from Alarm.
+config RTC_VR41XX
+ tristate "NEC VR4100 series Real Time Clock Support"
+ depends on CPU_VR41XX
+
config COBALT_LCD
bool "Support for Cobalt LCD"
depends on MIPS_COBALT
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 68b1eeb27d47f..54ed76af1a478 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -63,6 +63,7 @@ obj-$(CONFIG_SGI_DS1286) += ds1286.o
obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
obj-$(CONFIG_DS1302) += ds1302.o
obj-$(CONFIG_S3C2410_RTC) += s3c2410-rtc.o
+obj-$(CONFIG_RTC_VR41XX) += vr41xx_rtc.o
ifeq ($(CONFIG_GENERIC_NVRAM),y)
obj-$(CONFIG_NVRAM) += generic_nvram.o
else
diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c
index fcba54b11dee4..f633623ac802f 100644
--- a/drivers/char/agp/frontend.c
+++ b/drivers/char/agp/frontend.c
@@ -628,7 +628,7 @@ static int agp_mmap(struct file *file, struct vm_area_struct *vma)
DBG("client vm_ops=%p", kerninfo.vm_ops);
if (kerninfo.vm_ops) {
vma->vm_ops = kerninfo.vm_ops;
- } else if (remap_pfn_range(vma, vma->vm_start,
+ } else if (io_remap_pfn_range(vma, vma->vm_start,
(kerninfo.aper_base + offset) >> PAGE_SHIFT,
size, vma->vm_page_prot)) {
goto out_again;
@@ -644,7 +644,7 @@ static int agp_mmap(struct file *file, struct vm_area_struct *vma)
DBG("controller vm_ops=%p", kerninfo.vm_ops);
if (kerninfo.vm_ops) {
vma->vm_ops = kerninfo.vm_ops;
- } else if (remap_pfn_range(vma, vma->vm_start,
+ } else if (io_remap_pfn_range(vma, vma->vm_start,
kerninfo.aper_base >> PAGE_SHIFT,
size, vma->vm_page_prot)) {
goto out_again;
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 05a248d5a9fba..c321a924e38a8 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -36,6 +36,7 @@
#include <linux/pm.h>
#include <linux/agp_backend.h>
#include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <asm/cacheflush.h>
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index d9a661cd62574..fc72f30f312b9 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -625,12 +625,12 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
#endif
offset = dev->driver->get_reg_ofs(dev);
#ifdef __sparc__
- if (io_remap_page_range(DRM_RPR_ARG(vma) vma->vm_start,
- VM_OFFSET(vma) + offset,
+ if (io_remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start,
+ (VM_OFFSET(vma) + offset) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
- vma->vm_page_prot, 0))
+ vma->vm_page_prot))
#else
- if (remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start,
+ if (io_remap_pfn_range(vma, vma->vm_start,
(VM_OFFSET(vma) + offset) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index 37024e676d335..24857cc6c23b3 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -119,7 +119,7 @@ int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
buf_priv->currently_mapped = I810_BUF_MAPPED;
unlock_kernel();
- if (remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start,
+ if (io_remap_pfn_range(vma, vma->vm_start,
VM_OFFSET(vma) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot)) return -EAGAIN;
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index b46af10bc291c..98adccf8e4341 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -121,7 +121,7 @@ int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
buf_priv->currently_mapped = I830_BUF_MAPPED;
unlock_kernel();
- if (remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start,
+ if (io_remap_pfn_range(vma, vma->vm_start,
VM_OFFSET(vma) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot)) return -EAGAIN;
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index 71435d1cb069e..5c8600b8dbe6b 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -26,6 +26,7 @@
#include <linux/mm.h>
#include <linux/generic_serial.h>
#include <linux/interrupt.h>
+#include <linux/tty_flip.h>
#include <linux/delay.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
@@ -45,8 +46,8 @@ static int gs_debug;
#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter %s\n", __FUNCTION__)
#define func_exit() gs_dprintk (GS_DEBUG_FLOW, "gs: exit %s\n", __FUNCTION__)
-
-#ifdef NEW_WRITE_LOCKING
+#define NEW_WRITE_LOCKING 1
+#if NEW_WRITE_LOCKING
#define DECL /* Nothing */
#define LOCKIT down (& port->port_write_sem);
#define RELEASEIT up (&port->port_write_sem);
@@ -208,7 +209,7 @@ int gs_write(struct tty_struct * tty,
if (!port || !port->xmit_buf || !tmp_buf)
return -EIO;
- save_flags(flags);
+ local_save_flags(flags);
while (1) {
cli();
c = count;
@@ -227,14 +228,14 @@ int gs_write(struct tty_struct * tty,
/* Can't copy more? break out! */
if (c <= 0) {
- restore_flags(flags);
+ local_restore_flags(flags);
break;
}
memcpy(port->xmit_buf + port->xmit_head, buf, c);
port->xmit_head = ((port->xmit_head + c) &
(SERIAL_XMIT_SIZE-1));
port->xmit_cnt += c;
- restore_flags(flags);
+ local_restore_flags(flags);
buf += c;
count -= c;
total += c;
@@ -380,9 +381,9 @@ void gs_flush_buffer(struct tty_struct *tty)
if (!port) return;
/* XXX Would the write semaphore do? */
- save_flags(flags); cli();
+ spin_lock_irqsave (&port->driver_lock, flags);
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- restore_flags(flags);
+ spin_unlock_irqrestore (&port->driver_lock, flags);
wake_up_interruptible(&tty->write_wait);
tty_wakeup(tty);
@@ -468,8 +469,7 @@ static void gs_shutdown_port (struct gs_port *port)
if (!(port->flags & ASYNC_INITIALIZED))
return;
- save_flags (flags);
- cli ();
+ spin_lock_irqsave(&port->driver_lock, flags);
if (port->xmit_buf) {
free_page((unsigned long) port->xmit_buf);
@@ -482,7 +482,7 @@ static void gs_shutdown_port (struct gs_port *port)
port->rd->shutdown_port (port);
port->flags &= ~ASYNC_INITIALIZED;
- restore_flags (flags);
+ spin_unlock_irqrestore(&port->driver_lock, flags);
func_exit();
}
@@ -519,6 +519,7 @@ int gs_block_til_ready(void *port_, struct file * filp)
int do_clocal = 0;
int CD;
struct tty_struct *tty;
+ unsigned long flags;
func_enter ();
@@ -570,10 +571,11 @@ int gs_block_til_ready(void *port_, struct file * filp)
add_wait_queue(&port->open_wait, &wait);
gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n");
- cli();
- if (!tty_hung_up_p(filp))
+ spin_lock_irqsave(&port->driver_lock, flags);
+ if (!tty_hung_up_p(filp)) {
port->count--;
- sti();
+ }
+ spin_unlock_irqrestore(&port->driver_lock, flags);
port->blocked_open++;
while (1) {
CD = port->rd->get_CD (port);
@@ -602,8 +604,9 @@ int gs_block_til_ready(void *port_, struct file * filp)
port->blocked_open);
set_current_state (TASK_RUNNING);
remove_wait_queue(&port->open_wait, &wait);
- if (!tty_hung_up_p(filp))
+ if (!tty_hung_up_p(filp)) {
port->count++;
+ }
port->blocked_open--;
if (retval)
return retval;
@@ -633,27 +636,29 @@ void gs_close(struct tty_struct * tty, struct file * filp)
port->tty = tty;
}
- save_flags(flags); cli();
+ spin_lock_irqsave(&port->driver_lock, flags);
if (tty_hung_up_p(filp)) {
- restore_flags(flags);
- port->rd->hungup (port);
+ spin_unlock_irqrestore(&port->driver_lock, flags);
+ if (port->rd->hungup)
+ port->rd->hungup (port);
func_exit ();
return;
}
if ((tty->count == 1) && (port->count != 1)) {
- printk(KERN_ERR "gs: gs_close: bad port count;"
- " tty->count is 1, port count is %d\n", port->count);
+ printk(KERN_ERR "gs: gs_close port %p: bad port count;"
+ " tty->count is 1, port count is %d\n", port, port->count);
port->count = 1;
}
if (--port->count < 0) {
- printk(KERN_ERR "gs: gs_close: bad port count: %d\n", port->count);
+ printk(KERN_ERR "gs: gs_close port %p: bad port count: %d\n", port, port->count);
port->count = 0;
}
+
if (port->count) {
- gs_dprintk(GS_DEBUG_CLOSE, "gs_close: count: %d\n", port->count);
- restore_flags(flags);
+ gs_dprintk(GS_DEBUG_CLOSE, "gs_close port %p: count: %d\n", port, port->count);
+ spin_unlock_irqrestore(&port->driver_lock, flags);
func_exit ();
return;
}
@@ -675,16 +680,17 @@ void gs_close(struct tty_struct * tty, struct file * filp)
*/
port->rd->disable_rx_interrupts (port);
+ spin_unlock_irqrestore(&port->driver_lock, flags);
/* close has no way of returning "EINTR", so discard return value */
if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
- gs_wait_tx_flushed (port, port->closing_wait);
+ gs_wait_tx_flushed (port, port->closing_wait);
port->flags &= ~GS_ACTIVE;
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
-
+
tty_ldisc_flush(tty);
tty->closing = 0;
@@ -695,14 +701,15 @@ void gs_close(struct tty_struct * tty, struct file * filp)
if (port->blocked_open) {
if (port->close_delay) {
+ spin_unlock_irqrestore(&port->driver_lock, flags);
msleep_interruptible(jiffies_to_msecs(port->close_delay));
+ spin_lock_irqsave(&port->driver_lock, flags);
}
wake_up_interruptible(&port->open_wait);
}
port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING | ASYNC_INITIALIZED);
wake_up_interruptible(&port->close_wait);
- restore_flags(flags);
func_exit ();
}
@@ -727,6 +734,12 @@ void gs_set_termios (struct tty_struct * tty,
port = tty->driver_data;
if (!port) return;
+ if (!port->tty) {
+ /* This seems to happen when this is called after gs_close. */
+ gs_dprintk (GS_DEBUG_TERMIOS, "gs: Odd: port->tty is NULL\n");
+ port->tty = tty;
+ }
+
tiosp = tty->termios;
@@ -821,7 +834,7 @@ void gs_set_termios (struct tty_struct * tty,
if (!(old_termios->c_cflag & CLOCAL) &&
(tty->termios->c_cflag & CLOCAL))
- wake_up_interruptible(&info->open_wait);
+ wake_up_interruptible(&port->gs.open_wait);
#endif
func_exit();
@@ -836,56 +849,56 @@ int gs_init_port(struct gs_port *port)
unsigned long flags;
unsigned long page;
- save_flags (flags);
- if (!tmp_buf) {
- page = get_zeroed_page(GFP_KERNEL);
+ func_enter ();
- cli (); /* Don't expect this to make a difference. */
+ if (!tmp_buf) {
+ page = get_zeroed_page(GFP_KERNEL);
+ spin_lock_irqsave (&port->driver_lock, flags); /* Don't expect this to make a difference. */
if (tmp_buf)
free_page(page);
else
tmp_buf = (unsigned char *) page;
- restore_flags (flags);
-
+ spin_unlock_irqrestore (&port->driver_lock, flags);
if (!tmp_buf) {
+ func_exit ();
return -ENOMEM;
}
}
- if (port->flags & ASYNC_INITIALIZED)
+ if (port->flags & ASYNC_INITIALIZED) {
+ func_exit ();
return 0;
-
+ }
if (!port->xmit_buf) {
/* We may sleep in get_zeroed_page() */
unsigned long tmp;
tmp = get_zeroed_page(GFP_KERNEL);
-
- /* Spinlock? */
- cli ();
+ spin_lock_irqsave (&port->driver_lock, flags);
if (port->xmit_buf)
free_page (tmp);
else
port->xmit_buf = (unsigned char *) tmp;
- restore_flags (flags);
-
- if (!port->xmit_buf)
+ spin_unlock_irqrestore(&port->driver_lock, flags);
+ if (!port->xmit_buf) {
+ func_exit ();
return -ENOMEM;
+ }
}
- cli();
-
+ spin_lock_irqsave (&port->driver_lock, flags);
if (port->tty)
clear_bit(TTY_IO_ERROR, &port->tty->flags);
-
+ init_MUTEX(&port->port_write_sem);
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
-
+ spin_unlock_irqrestore(&port->driver_lock, flags);
gs_set_termios(port->tty, NULL);
-
+ spin_lock_irqsave (&port->driver_lock, flags);
port->flags |= ASYNC_INITIALIZED;
port->flags &= ~GS_TX_INTEN;
- restore_flags(flags);
+ spin_unlock_irqrestore(&port->driver_lock, flags);
+ func_exit ();
return 0;
}
@@ -956,13 +969,15 @@ int gs_getserial(struct gs_port *port, struct serial_struct __user *sp)
void gs_got_break(struct gs_port *port)
{
+ func_enter ();
+
+ tty_insert_flip_char(port->tty, 0, TTY_BREAK);
+ tty_schedule_flip(port->tty);
if (port->flags & ASYNC_SAK) {
do_SAK (port->tty);
}
- *(port->tty->flip.flag_buf_ptr) = TTY_BREAK;
- port->tty->flip.flag_buf_ptr++;
- port->tty->flip.char_buf_ptr++;
- port->tty->flip.count++;
+
+ func_exit ();
}
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index a266632e9b70b..5ec732e6ca922 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -76,6 +76,7 @@ struct hpet_dev {
struct hpets {
struct hpets *hp_next;
struct hpet __iomem *hp_hpet;
+ unsigned long hp_hpet_phys;
struct time_interpolator *hp_interpolator;
unsigned long hp_period;
unsigned long hp_delta;
@@ -265,7 +266,7 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
return -EINVAL;
devp = file->private_data;
- addr = (unsigned long)devp->hd_hpet;
+ addr = devp->hd_hpets->hp_hpet_phys;
if (addr & (PAGE_SIZE - 1))
return -ENOSYS;
@@ -274,7 +275,7 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
addr = __pa(addr);
- if (remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
+ if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
PAGE_SIZE, vma->vm_page_prot)) {
printk(KERN_ERR "remap_pfn_range failed in hpet.c\n");
return -EAGAIN;
@@ -795,6 +796,7 @@ int hpet_alloc(struct hpet_data *hdp)
hpetp->hp_which = hpet_nhpet++;
hpetp->hp_hpet = hdp->hd_address;
+ hpetp->hp_hpet_phys = hdp->hd_phys_address;
hpetp->hp_ntimer = hdp->hd_nirqs;
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 2b5d0e084b171..29de259a981e5 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -1477,6 +1477,11 @@ static int try_init_acpi(int intf_num, struct smi_info **new_info)
if (!is_new_interface(-1, addr_space, spmi->addr.address))
return -ENODEV;
+ if (!spmi->addr.register_bit_width) {
+ acpi_failure = 1;
+ return -ENODEV;
+ }
+
/* Figure out the interface type. */
switch (spmi->InterfaceType)
{
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index f305a143a09a3..601c7fccb4cfb 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -151,9 +151,6 @@ MODULE_DEVICE_TABLE(pci, isicom_pci_tbl);
static int prev_card = 3; /* start servicing isi_card[0] */
static struct tty_driver *isicom_normal;
-static struct isi_board isi_card[BOARD_COUNT];
-static struct isi_port isi_ports[PORT_COUNT];
-
static struct timer_list tx;
static char re_schedule = 1;
#ifdef ISICOM_DEBUG
@@ -210,6 +207,9 @@ struct isi_port {
int xmit_cnt;
};
+static struct isi_board isi_card[BOARD_COUNT];
+static struct isi_port isi_ports[PORT_COUNT];
+
/*
* Locking functions for card level locking. We need to own both
* the kernel lock for the card and have the card in a position that
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 2d8c1b8435495..4d159c610f7f3 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -76,14 +76,6 @@ static inline int uncached_access(struct file *file, unsigned long addr)
* On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases.
*/
return !(efi_mem_attributes(addr) & EFI_MEMORY_WB);
-#elif defined(CONFIG_PPC64)
- /* On PPC64, we always do non-cacheable access to the IO hole and
- * cacheable elsewhere. Cache paradox can checkstop the CPU and
- * the high_memory heuristic below is wrong on machines with memory
- * above the IO hole... Ah, and of course, XFree86 doesn't pass
- * O_SYNC when mapping us to tap IO space. Surprised ?
- */
- return !page_is_ram(addr >> PAGE_SHIFT);
#else
/*
* Accessing memory above the top the kernel knows about or through a file pointer
@@ -238,7 +230,13 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
static int mmap_mem(struct file * file, struct vm_area_struct * vma)
{
-#ifdef pgprot_noncached
+#if defined(__HAVE_PHYS_MEM_ACCESS_PROT)
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ vma->vm_page_prot = phys_mem_access_prot(file, offset,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+#elif defined(pgprot_noncached)
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
int uncached;
@@ -257,6 +255,23 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
return 0;
}
+static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
+{
+ unsigned long long val;
+ /*
+ * RED-PEN: on some architectures there is more mapped memory
+ * than available in mem_map which pfn_valid checks
+ * for. Perhaps should add a new macro here.
+ *
+ * RED-PEN: vmalloc is not supported right now.
+ */
+ if (!pfn_valid(vma->vm_pgoff))
+ return -EIO;
+ val = (u64)vma->vm_pgoff << PAGE_SHIFT;
+ vma->vm_pgoff = __pa(val) >> PAGE_SHIFT;
+ return mmap_mem(file, vma);
+}
+
extern long vread(char *buf, char *addr, unsigned long count);
extern long vwrite(char *buf, char *addr, unsigned long count);
@@ -698,7 +713,6 @@ static int open_port(struct inode * inode, struct file * filp)
return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
}
-#define mmap_kmem mmap_mem
#define zero_lseek null_lseek
#define full_lseek null_lseek
#define write_zero write_null
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index ae09412cc3179..edba5a35bf217 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -606,9 +606,11 @@ static inline void n_tty_receive_overrun(struct tty_struct *tty)
char buf[64];
tty->num_overrun++;
- if (time_before(tty->overrun_time, jiffies - HZ)) {
- printk(KERN_WARNING "%s: %d input overrun(s)\n", tty_name(tty, buf),
- tty->num_overrun);
+ if (time_before(tty->overrun_time, jiffies - HZ) ||
+ time_after(tty->overrun_time, jiffies)) {
+ printk(KERN_WARNING "%s: %d input overrun(s)\n",
+ tty_name(tty, buf),
+ tty->num_overrun);
tty->overrun_time = jiffies;
tty->num_overrun = 0;
}
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 5e9d8d87cf97e..c789d5ceac761 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -66,7 +66,7 @@
*
*/
-#define VERSION "1.10"
+#define VERSION "1.11"
/*
@@ -99,6 +99,44 @@
#include "cd1865.h"
+/*
+ This driver can spew a whole lot of debugging output at you. If you
+ need maximum performance, you should disable the DEBUG define. To
+ aid in debugging in the field, I'm leaving the compile-time debug
+ features enabled, and disable them "runtime". That allows me to
+ instruct people with problems to enable debugging without requiring
+ them to recompile...
+*/
+#define DEBUG
+
+static int sx_debug;
+static int sx_rxfifo = SPECIALIX_RXFIFO;
+
+#ifdef DEBUG
+#define dprintk(f, str...) if (sx_debug & f) printk (str)
+#else
+#define dprintk(f, str...) /* nothing */
+#endif
+
+#define SX_DEBUG_FLOW 0x0001
+#define SX_DEBUG_DATA 0x0002
+#define SX_DEBUG_PROBE 0x0004
+#define SX_DEBUG_CHAN 0x0008
+#define SX_DEBUG_INIT 0x0010
+#define SX_DEBUG_RX 0x0020
+#define SX_DEBUG_TX 0x0040
+#define SX_DEBUG_IRQ 0x0080
+#define SX_DEBUG_OPEN 0x0100
+#define SX_DEBUG_TERMIOS 0x0200
+#define SX_DEBUG_SIGNALS 0x0400
+#define SX_DEBUG_FIFO 0x0800
+
+
+#define func_enter() dprintk (SX_DEBUG_FLOW, "io8: enter %s\n",__FUNCTION__)
+#define func_exit() dprintk (SX_DEBUG_FLOW, "io8: exit %s\n", __FUNCTION__)
+
+#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1)
+
/* Configurable options: */
@@ -110,6 +148,12 @@
requiring attention, the timer doesn't help either. */
#undef SPECIALIX_TIMER
+#ifdef SPECIALIX_TIMER
+static int sx_poll = HZ;
+#endif
+
+
+
/*
* The following defines are mostly for testing purposes. But if you need
* some nice reporting in your syslog, you can define them also.
@@ -254,11 +298,17 @@ static inline void sx_out_off(struct specialix_board * bp, unsigned short reg,
/* Wait for Channel Command Register ready */
static inline void sx_wait_CCR(struct specialix_board * bp)
{
- unsigned long delay;
-
- for (delay = SX_CCR_TIMEOUT; delay; delay--)
- if (!sx_in(bp, CD186x_CCR))
+ unsigned long delay, flags;
+ unsigned char ccr;
+
+ for (delay = SX_CCR_TIMEOUT; delay; delay--) {
+ spin_lock_irqsave(&bp->lock, flags);
+ ccr = sx_in(bp, CD186x_CCR);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ if (!ccr)
return;
+ udelay (1);
+ }
printk(KERN_ERR "sx%d: Timeout waiting for CCR.\n", board_No(bp));
}
@@ -268,10 +318,17 @@ static inline void sx_wait_CCR(struct specialix_board * bp)
static inline void sx_wait_CCR_off(struct specialix_board * bp)
{
unsigned long delay;
+ unsigned char crr;
+ unsigned long flags;
- for (delay = SX_CCR_TIMEOUT; delay; delay--)
- if (!sx_in_off(bp, CD186x_CCR))
+ for (delay = SX_CCR_TIMEOUT; delay; delay--) {
+ spin_lock_irqsave(&bp->lock, flags);
+ crr = sx_in_off(bp, CD186x_CCR);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ if (!crr)
return;
+ udelay (1);
+ }
printk(KERN_ERR "sx%d: Timeout waiting for CCR.\n", board_No(bp));
}
@@ -319,6 +376,7 @@ static int sx_set_irq ( struct specialix_board *bp)
{
int virq;
int i;
+ unsigned long flags;
if (bp->flags & SX_BOARD_IS_PCI)
return 1;
@@ -331,11 +389,12 @@ static int sx_set_irq ( struct specialix_board *bp)
default: printk (KERN_ERR "Speclialix: cannot set irq to %d.\n", bp->irq);
return 0;
}
-
+ spin_lock_irqsave(&bp->lock, flags);
for (i=0;i<2;i++) {
sx_out(bp, CD186x_CAR, i);
sx_out(bp, CD186x_MSVRTS, ((virq >> i) & 0x1)? MSVR_RTS:0);
}
+ spin_unlock_irqrestore(&bp->lock, flags);
return 1;
}
@@ -346,14 +405,14 @@ static int sx_init_CD186x(struct specialix_board * bp)
unsigned long flags;
int scaler;
int rv = 1;
-
- save_flags(flags); cli();
+ func_enter();
sx_wait_CCR_off(bp); /* Wait for CCR ready */
+ spin_lock_irqsave(&bp->lock, flags);
sx_out_off(bp, CD186x_CCR, CCR_HARDRESET); /* Reset CD186x chip */
- sti();
+ spin_unlock_irqrestore(&bp->lock, flags);
sx_long_delay(HZ/20); /* Delay 0.05 sec */
- cli();
+ spin_lock_irqsave(&bp->lock, flags);
sx_out_off(bp, CD186x_GIVR, SX_ID); /* Set ID for this chip */
sx_out_off(bp, CD186x_GICR, 0); /* Clear all bits */
sx_out_off(bp, CD186x_PILR1, SX_ACK_MINT); /* Prio for modem intr */
@@ -367,6 +426,7 @@ static int sx_init_CD186x(struct specialix_board * bp)
sx_out_off(bp, CD186x_PPRH, scaler >> 8);
sx_out_off(bp, CD186x_PPRL, scaler & 0xff);
+ spin_unlock_irqrestore(&bp->lock, flags);
if (!sx_set_irq (bp)) {
/* Figure out how to pass this along... */
@@ -374,7 +434,7 @@ static int sx_init_CD186x(struct specialix_board * bp)
rv = 0;
}
- restore_flags(flags);
+ func_exit();
return rv;
}
@@ -383,12 +443,16 @@ static int read_cross_byte (struct specialix_board *bp, int reg, int bit)
{
int i;
int t;
+ unsigned long flags;
+ spin_lock_irqsave(&bp->lock, flags);
for (i=0, t=0;i<8;i++) {
sx_out_off (bp, CD186x_CAR, i);
if (sx_in_off (bp, reg) & bit)
t |= 1 << i;
}
+ spin_unlock_irqrestore(&bp->lock, flags);
+
return t;
}
@@ -396,15 +460,22 @@ static int read_cross_byte (struct specialix_board *bp, int reg, int bit)
#ifdef SPECIALIX_TIMER
void missed_irq (unsigned long data)
{
- if (sx_in ((struct specialix_board *)data, CD186x_SRSR) &
+ unsigned char irq;
+ unsigned long flags;
+ struct specialix_board *bp = (struct specialix_board *)data;
+
+ spin_lock_irqsave(&bp->lock, flags);
+ irq = sx_in ((struct specialix_board *)data, CD186x_SRSR) &
(SRSR_RREQint |
SRSR_TREQint |
- SRSR_MREQint)) {
+ SRSR_MREQint);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ if (irq) {
printk (KERN_INFO "Missed interrupt... Calling int from timer. \n");
sx_interrupt (((struct specialix_board *)data)->irq,
- NULL, NULL);
+ (void*)data, NULL);
}
- missed_irq_timer.expires = jiffies + HZ;
+ missed_irq_timer.expires = jiffies + sx_poll;
add_timer (&missed_irq_timer);
}
#endif
@@ -422,8 +493,12 @@ static int sx_probe(struct specialix_board *bp)
int rev;
int chip;
- if (sx_check_io_range(bp))
+ func_enter();
+
+ if (sx_check_io_range(bp)) {
+ func_exit();
return 1;
+ }
/* Are the I/O ports here ? */
sx_out_off(bp, CD186x_PPRL, 0x5a);
@@ -438,6 +513,7 @@ static int sx_probe(struct specialix_board *bp)
if ((val1 != 0x5a) || (val2 != 0xa5)) {
printk(KERN_INFO "sx%d: specialix IO8+ Board at 0x%03x not found.\n",
board_No(bp), bp->base);
+ func_exit();
return 1;
}
@@ -445,10 +521,9 @@ static int sx_probe(struct specialix_board *bp)
identification */
val1 = read_cross_byte (bp, CD186x_MSVR, MSVR_DSR);
val2 = read_cross_byte (bp, CD186x_MSVR, MSVR_RTS);
-#ifdef SPECIALIX_DEBUG
- printk (KERN_DEBUG "sx%d: DSR lines are: %02x, rts lines are: %02x\n",
+ dprintk (SX_DEBUG_INIT, "sx%d: DSR lines are: %02x, rts lines are: %02x\n",
board_No(bp), val1, val2);
-#endif
+
/* They managed to switch the bit order between the docs and
the IO8+ card. The new PCI card now conforms to old docs.
They changed the PCI docs to reflect the situation on the
@@ -457,6 +532,7 @@ static int sx_probe(struct specialix_board *bp)
if (val1 != val2) {
printk(KERN_INFO "sx%d: specialix IO8+ ID %02x at 0x%03x not found (%02x).\n",
board_No(bp), val2, bp->base, val1);
+ func_exit();
return 1;
}
@@ -473,21 +549,19 @@ static int sx_probe(struct specialix_board *bp)
sx_long_delay(HZ/20);
irqs = probe_irq_off(irqs);
-#if SPECIALIX_DEBUG > 2
- printk (KERN_DEBUG "SRSR = %02x, ", sx_in(bp, CD186x_SRSR));
- printk ( "TRAR = %02x, ", sx_in(bp, CD186x_TRAR));
- printk ( "GIVR = %02x, ", sx_in(bp, CD186x_GIVR));
- printk ( "GICR = %02x, ", sx_in(bp, CD186x_GICR));
- printk ( "\n");
-#endif
+ dprintk (SX_DEBUG_INIT, "SRSR = %02x, ", sx_in(bp, CD186x_SRSR));
+ dprintk (SX_DEBUG_INIT, "TRAR = %02x, ", sx_in(bp, CD186x_TRAR));
+ dprintk (SX_DEBUG_INIT, "GIVR = %02x, ", sx_in(bp, CD186x_GIVR));
+ dprintk (SX_DEBUG_INIT, "GICR = %02x, ", sx_in(bp, CD186x_GICR));
+ dprintk (SX_DEBUG_INIT, "\n");
+
/* Reset CD186x again */
if (!sx_init_CD186x(bp)) {
/* Hmmm. This is dead code anyway. */
}
-#if SPECIALIX_DEBUG > 2
- printk (KERN_DEBUG "val1 = %02x, val2 = %02x, val3 = %02x.\n",
+
+ dprintk (SX_DEBUG_INIT "val1 = %02x, val2 = %02x, val3 = %02x.\n",
val1, val2, val3);
-#endif
}
@@ -495,6 +569,7 @@ static int sx_probe(struct specialix_board *bp)
if (irqs <= 0) {
printk(KERN_ERR "sx%d: Can't find IRQ for specialix IO8+ board at 0x%03x.\n",
board_No(bp), bp->base);
+ func_exit();
return 1;
}
#endif
@@ -504,6 +579,7 @@ static int sx_probe(struct specialix_board *bp)
#endif
/* Reset CD186x again */
if (!sx_init_CD186x(bp)) {
+ func_exit();
return -EIO;
}
@@ -528,15 +604,13 @@ static int sx_probe(struct specialix_board *bp)
default:chip=-1;rev='x';
}
-#if SPECIALIX_DEBUG > 2
- printk (KERN_DEBUG " GFCR = 0x%02x\n", sx_in_off(bp, CD186x_GFRCR) );
-#endif
+ dprintk (SX_DEBUG_INIT, " GFCR = 0x%02x\n", sx_in_off(bp, CD186x_GFRCR) );
#ifdef SPECIALIX_TIMER
init_timer (&missed_irq_timer);
missed_irq_timer.function = missed_irq;
missed_irq_timer.data = (unsigned long) bp;
- missed_irq_timer.expires = jiffies + HZ;
+ missed_irq_timer.expires = jiffies + sx_poll;
add_timer (&missed_irq_timer);
#endif
@@ -545,6 +619,7 @@ static int sx_probe(struct specialix_board *bp)
bp->base, bp->irq,
chip, rev);
+ func_exit();
return 0;
}
@@ -555,8 +630,12 @@ static int sx_probe(struct specialix_board *bp)
static inline void sx_mark_event(struct specialix_port * port, int event)
{
+ func_enter();
+
set_bit(event, &port->event);
schedule_work(&port->tqueue);
+
+ func_exit();
}
@@ -564,12 +643,17 @@ static inline struct specialix_port * sx_get_port(struct specialix_board * bp,
unsigned char const * what)
{
unsigned char channel;
- struct specialix_port * port;
-
+ struct specialix_port * port = NULL;
+
channel = sx_in(bp, CD186x_GICR) >> GICR_CHAN_OFF;
+ dprintk (SX_DEBUG_CHAN, "channel: %d\n", channel);
if (channel < CD186x_NCH) {
port = &sx_port[board_No(bp) * SX_NPORT + channel];
+ dprintk (SX_DEBUG_CHAN, "port: %d %p flags: 0x%x\n",board_No(bp) * SX_NPORT + channel, port, port->flags & ASYNC_INITIALIZED);
+
if (port->flags & ASYNC_INITIALIZED) {
+ dprintk (SX_DEBUG_CHAN, "port: %d %p\n", channel, port);
+ func_exit();
return port;
}
}
@@ -586,43 +670,51 @@ static inline void sx_receive_exc(struct specialix_board * bp)
unsigned char status;
unsigned char ch;
- if (!(port = sx_get_port(bp, "Receive")))
- return;
+ func_enter();
- tty = port->tty;
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
- printk(KERN_INFO "sx%d: port %d: Working around flip buffer overflow.\n",
- board_No(bp), port_No(port));
+ port = sx_get_port(bp, "Receive");
+ if (!port) {
+ dprintk (SX_DEBUG_RX, "Hmm, couldn't find port.\n");
+ func_exit();
return;
}
+ tty = port->tty;
+ dprintk (SX_DEBUG_RX, "port: %p count: %d BUFF_SIZE: %d\n",
+ port, tty->flip.count, TTY_FLIPBUF_SIZE);
-#ifdef SX_REPORT_OVERRUN
status = sx_in(bp, CD186x_RCSR);
+
+ dprintk (SX_DEBUG_RX, "status: 0x%x\n", status);
if (status & RCSR_OE) {
port->overrun++;
-#if SPECIALIX_DEBUG
- printk(KERN_DEBUG "sx%d: port %d: Overrun. Total %ld overruns.\n",
+ dprintk(SX_DEBUG_FIFO, "sx%d: port %d: Overrun. Total %ld overruns.\n",
board_No(bp), port_No(port), port->overrun);
-#endif
}
status &= port->mark_mask;
-#else
- status = sx_in(bp, CD186x_RCSR) & port->mark_mask;
-#endif
+
+ /* This flip buffer check needs to be below the reading of the
+ status register to reset the chip's IRQ.... */
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ dprintk(SX_DEBUG_FIFO, "sx%d: port %d: Working around flip buffer overflow.\n",
+ board_No(bp), port_No(port));
+ func_exit();
+ return;
+ }
+
ch = sx_in(bp, CD186x_RDR);
if (!status) {
+ func_exit();
return;
}
if (status & RCSR_TOUT) {
printk(KERN_INFO "sx%d: port %d: Receiver timeout. Hardware problems ?\n",
board_No(bp), port_No(port));
+ func_exit();
return;
} else if (status & RCSR_BREAK) {
-#ifdef SPECIALIX_DEBUG
- printk(KERN_DEBUG "sx%d: port %d: Handling break...\n",
+ dprintk(SX_DEBUG_RX, "sx%d: port %d: Handling break...\n",
board_No(bp), port_No(port));
-#endif
*tty->flip.flag_buf_ptr++ = TTY_BREAK;
if (port->flags & ASYNC_SAK)
do_SAK(tty);
@@ -642,6 +734,8 @@ static inline void sx_receive_exc(struct specialix_board * bp)
*tty->flip.char_buf_ptr++ = ch;
tty->flip.count++;
schedule_delayed_work(&tty->flip.work, 1);
+
+ func_exit();
}
@@ -650,17 +744,19 @@ static inline void sx_receive(struct specialix_board * bp)
struct specialix_port *port;
struct tty_struct *tty;
unsigned char count;
+
+ func_enter();
- if (!(port = sx_get_port(bp, "Receive")))
+ if (!(port = sx_get_port(bp, "Receive"))) {
+ dprintk (SX_DEBUG_RX, "Hmm, couldn't find port.\n");
+ func_exit();
return;
-
+ }
tty = port->tty;
count = sx_in(bp, CD186x_RDCR);
-
-#ifdef SX_REPORT_FIFO
+ dprintk (SX_DEBUG_RX, "port: %p: count: %d\n", port, count);
port->hits[count > 8 ? 9 : count]++;
-#endif
while (count--) {
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
@@ -673,6 +769,8 @@ static inline void sx_receive(struct specialix_board * bp)
tty->flip.count++;
}
schedule_delayed_work(&tty->flip.work, 1);
+
+ func_exit();
}
@@ -681,11 +779,13 @@ static inline void sx_transmit(struct specialix_board * bp)
struct specialix_port *port;
struct tty_struct *tty;
unsigned char count;
-
-
- if (!(port = sx_get_port(bp, "Transmit")))
+
+ func_enter();
+ if (!(port = sx_get_port(bp, "Transmit"))) {
+ func_exit();
return;
-
+ }
+ dprintk (SX_DEBUG_TX, "port: %p\n", port);
tty = port->tty;
if (port->IER & IER_TXEMPTY) {
@@ -693,6 +793,7 @@ static inline void sx_transmit(struct specialix_board * bp)
sx_out(bp, CD186x_CAR, port_No(port));
port->IER &= ~IER_TXEMPTY;
sx_out(bp, CD186x_IER, port->IER);
+ func_exit();
return;
}
@@ -701,6 +802,7 @@ static inline void sx_transmit(struct specialix_board * bp)
sx_out(bp, CD186x_CAR, port_No(port));
port->IER &= ~IER_TXRDY;
sx_out(bp, CD186x_IER, port->IER);
+ func_exit();
return;
}
@@ -725,6 +827,8 @@ static inline void sx_transmit(struct specialix_board * bp)
sx_out(bp, CD186x_CCR, CCR_CORCHG2);
port->break_length = 0;
}
+
+ func_exit();
return;
}
@@ -743,6 +847,8 @@ static inline void sx_transmit(struct specialix_board * bp)
}
if (port->xmit_cnt <= port->wakeup_chars)
sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+
+ func_exit();
}
@@ -751,10 +857,9 @@ static inline void sx_check_modem(struct specialix_board * bp)
struct specialix_port *port;
struct tty_struct *tty;
unsigned char mcr;
+ int msvr_cd;
-#ifdef SPECIALIX_DEBUG
- printk (KERN_DEBUG "Modem intr. ");
-#endif
+ dprintk (SX_DEBUG_SIGNALS, "Modem intr. ");
if (!(port = sx_get_port(bp, "Modem")))
return;
@@ -764,18 +869,13 @@ static inline void sx_check_modem(struct specialix_board * bp)
printk ("mcr = %02x.\n", mcr);
if ((mcr & MCR_CDCHG)) {
-#ifdef SPECIALIX_DEBUG
- printk (KERN_DEBUG "CD just changed... ");
-#endif
- if (sx_in(bp, CD186x_MSVR) & MSVR_CD) {
-#ifdef SPECIALIX_DEBUG
- printk ( "Waking up guys in open.\n");
-#endif
+ dprintk (SX_DEBUG_SIGNALS, "CD just changed... ");
+ msvr_cd = sx_in(bp, CD186x_MSVR) & MSVR_CD;
+ if (msvr_cd) {
+ dprintk (SX_DEBUG_SIGNALS, "Waking up guys in open.\n");
wake_up_interruptible(&port->open_wait);
} else {
-#ifdef SPECIALIX_DEBUG
- printk ( "Sending HUP.\n");
-#endif
+ dprintk (SX_DEBUG_SIGNALS, "Sending HUP.\n");
schedule_work(&port->tqueue_hangup);
}
}
@@ -820,13 +920,18 @@ static irqreturn_t sx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
struct specialix_board *bp;
unsigned long loop = 0;
int saved_reg;
+ unsigned long flags;
+
+ func_enter();
bp = dev_id;
-
+ spin_lock_irqsave(&bp->lock, flags);
+
+ dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __FUNCTION__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1);
if (!bp || !(bp->flags & SX_BOARD_ACTIVE)) {
-#ifdef SPECIALIX_DEBUG
- printk (KERN_DEBUG "sx: False interrupt. irq %d.\n", irq);
-#endif
+ dprintk (SX_DEBUG_IRQ, "sx: False interrupt. irq %d.\n", irq);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ func_exit();
return IRQ_NONE;
}
@@ -844,8 +949,8 @@ static irqreturn_t sx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
else if (ack == (SX_ID | GIVR_IT_REXC))
sx_receive_exc(bp);
else
- printk(KERN_ERR "sx%d: Bad receive ack 0x%02x.\n",
- board_No(bp), ack);
+ printk(KERN_ERR "sx%d: status: 0x%x Bad receive ack 0x%02x.\n",
+ board_No(bp), status, ack);
} else if (status & SRSR_TREQint) {
ack = sx_in(bp, CD186x_TRAR);
@@ -853,16 +958,16 @@ static irqreturn_t sx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (ack == (SX_ID | GIVR_IT_TX))
sx_transmit(bp);
else
- printk(KERN_ERR "sx%d: Bad transmit ack 0x%02x.\n",
- board_No(bp), ack);
+ printk(KERN_ERR "sx%d: status: 0x%x Bad transmit ack 0x%02x. port: %d\n",
+ board_No(bp), status, ack, port_No (sx_get_port (bp, "Int")));
} else if (status & SRSR_MREQint) {
ack = sx_in(bp, CD186x_MRAR);
if (ack == (SX_ID | GIVR_IT_MODEM))
sx_check_modem(bp);
else
- printk(KERN_ERR "sx%d: Bad modem ack 0x%02x.\n",
- board_No(bp), ack);
+ printk(KERN_ERR "sx%d: status: 0x%x Bad modem ack 0x%02x.\n",
+ board_No(bp), status, ack);
}
@@ -870,6 +975,8 @@ static irqreturn_t sx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
bp->reg = saved_reg;
outb (bp->reg, bp->base + SX_ADDR_REG);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ func_exit();
return IRQ_HANDLED;
}
@@ -880,21 +987,37 @@ static irqreturn_t sx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static void turn_ints_off (struct specialix_board *bp)
{
+ unsigned long flags;
+
+ func_enter();
if (bp->flags & SX_BOARD_IS_PCI) {
/* This was intended for enabeling the interrupt on the
* PCI card. However it seems that it's already enabled
* and as PCI interrupts can be shared, there is no real
* reason to have to turn it off. */
}
+
+ spin_lock_irqsave(&bp->lock, flags);
(void) sx_in_off (bp, 0); /* Turn off interrupts. */
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+ func_exit();
}
static void turn_ints_on (struct specialix_board *bp)
{
+ unsigned long flags;
+
+ func_enter();
+
if (bp->flags & SX_BOARD_IS_PCI) {
/* play with the PCI chip. See comment above. */
}
+ spin_lock_irqsave(&bp->lock, flags);
(void) sx_in (bp, 0); /* Turn ON interrupts. */
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+ func_exit();
}
@@ -924,18 +1047,23 @@ static inline int sx_setup_board(struct specialix_board * bp)
/* Called with disabled interrupts */
static inline void sx_shutdown_board(struct specialix_board *bp)
{
- if (!(bp->flags & SX_BOARD_ACTIVE))
+ func_enter();
+
+ if (!(bp->flags & SX_BOARD_ACTIVE)) {
+ func_exit();
return;
-
+ }
+
bp->flags &= ~SX_BOARD_ACTIVE;
-#if SPECIALIX_DEBUG > 2
- printk ("Freeing IRQ%d for board %d.\n", bp->irq, board_No (bp));
-#endif
+ dprintk (SX_DEBUG_IRQ, "Freeing IRQ%d for board %d.\n",
+ bp->irq, board_No (bp));
free_irq(bp->irq, bp);
turn_ints_off (bp);
+
+ func_exit();
}
@@ -951,13 +1079,19 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
unsigned char cor1 = 0, cor3 = 0;
unsigned char mcor1 = 0, mcor2 = 0;
static unsigned long again;
-
- if (!(tty = port->tty) || !tty->termios)
+ unsigned long flags;
+
+ func_enter();
+
+ if (!(tty = port->tty) || !tty->termios) {
+ func_exit();
return;
+ }
port->IER = 0;
port->COR2 = 0;
/* Select port on the board */
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
/* The Specialix board doens't implement the RTS lines.
@@ -966,9 +1100,8 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
port->MSVR = MSVR_DTR | (sx_in(bp, CD186x_MSVR) & MSVR_RTS);
else
port->MSVR = (sx_in(bp, CD186x_MSVR) & MSVR_RTS);
-#ifdef DEBUG_SPECIALIX
- printk (KERN_DEBUG "sx: got MSVR=%02x.\n", port->MSVR);
-#endif
+ spin_unlock_irqrestore(&bp->lock, flags);
+ dprintk (SX_DEBUG_TERMIOS, "sx: got MSVR=%02x.\n", port->MSVR);
baud = C_BAUD(tty);
if (baud & CBAUDEX) {
@@ -988,17 +1121,15 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
if (!baud_table[baud]) {
/* Drop DTR & exit */
-#ifdef SPECIALIX_DEBUG
- printk (KERN_DEBUG "Dropping DTR... Hmm....\n");
-#endif
+ dprintk (SX_DEBUG_TERMIOS, "Dropping DTR... Hmm....\n");
if (!SX_CRTSCTS (tty)) {
port -> MSVR &= ~ MSVR_DTR;
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_MSVR, port->MSVR );
+ spin_unlock_irqrestore(&bp->lock, flags);
}
-#ifdef DEBUG_SPECIALIX
else
- printk (KERN_DEBUG "Can't drop DTR: no DTR.\n");
-#endif
+ dprintk (SX_DEBUG_TERMIOS, "Can't drop DTR: no DTR.\n");
return;
} else {
/* Set DTR on */
@@ -1037,12 +1168,12 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
port_No (port), tmp);
}
}
-
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_RBPRH, (tmp >> 8) & 0xff);
sx_out(bp, CD186x_TBPRH, (tmp >> 8) & 0xff);
sx_out(bp, CD186x_RBPRL, tmp & 0xff);
sx_out(bp, CD186x_TBPRL, tmp & 0xff);
-
+ spin_unlock_irqrestore(&bp->lock, flags);
if (port->custom_divisor) {
baud = (SX_OSCFREQ + port->custom_divisor/2) / port->custom_divisor;
baud = ( baud + 5 ) / 10;
@@ -1057,8 +1188,9 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
/* Receiver timeout will be transmission time for 1.5 chars */
tmp = (SPECIALIX_TPS + SPECIALIX_TPS/2 + baud/2) / baud;
tmp = (tmp > 0xff) ? 0xff : tmp;
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_RTPR, tmp);
-
+ spin_unlock_irqrestore(&bp->lock, flags);
switch (C_CSIZE(tty)) {
case CS5:
cor1 |= COR1_5BITS;
@@ -1105,7 +1237,9 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
port->IER |= IER_DSR | IER_CTS;
mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
+ spin_lock_irqsave(&bp->lock, flags);
tty->hw_stopped = !(sx_in(bp, CD186x_MSVR) & (MSVR_CTS|MSVR_DSR));
+ spin_unlock_irqrestore(&bp->lock, flags);
#else
port->COR2 |= COR2_CTSAE;
#endif
@@ -1117,10 +1251,12 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
cor3 |= (COR3_FCT | COR3_SCDE);
if (I_IXANY(tty))
port->COR2 |= COR2_IXM;
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_SCHR1, START_CHAR(tty));
sx_out(bp, CD186x_SCHR2, STOP_CHAR(tty));
sx_out(bp, CD186x_SCHR3, START_CHAR(tty));
sx_out(bp, CD186x_SCHR4, STOP_CHAR(tty));
+ spin_unlock_irqrestore(&bp->lock, flags);
}
if (!C_CLOCAL(tty)) {
/* Enable CD check */
@@ -1134,27 +1270,33 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
port->IER |= IER_RXD;
/* Set input FIFO size (1-8 bytes) */
- cor3 |= SPECIALIX_RXFIFO;
+ cor3 |= sx_rxfifo;
/* Setting up CD186x channel registers */
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_COR1, cor1);
sx_out(bp, CD186x_COR2, port->COR2);
sx_out(bp, CD186x_COR3, cor3);
+ spin_unlock_irqrestore(&bp->lock, flags);
/* Make CD186x know about registers change */
sx_wait_CCR(bp);
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CCR, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
/* Setting up modem option registers */
-#ifdef DEBUG_SPECIALIX
- printk ("Mcor1 = %02x, mcor2 = %02x.\n", mcor1, mcor2);
-#endif
+ dprintk (SX_DEBUG_TERMIOS, "Mcor1 = %02x, mcor2 = %02x.\n", mcor1, mcor2);
sx_out(bp, CD186x_MCOR1, mcor1);
sx_out(bp, CD186x_MCOR2, mcor2);
+ spin_unlock_irqrestore(&bp->lock, flags);
/* Enable CD186x transmitter & receiver */
sx_wait_CCR(bp);
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CCR, CCR_TXEN | CCR_RXEN);
/* Enable interrupts */
sx_out(bp, CD186x_IER, port->IER);
/* And finally set the modem lines... */
sx_out(bp, CD186x_MSVR, port->MSVR);
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+ func_exit();
}
@@ -1162,37 +1304,44 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
static int sx_setup_port(struct specialix_board *bp, struct specialix_port *port)
{
unsigned long flags;
-
- if (port->flags & ASYNC_INITIALIZED)
+
+ func_enter();
+
+ if (port->flags & ASYNC_INITIALIZED) {
+ func_exit();
return 0;
+ }
if (!port->xmit_buf) {
/* We may sleep in get_zeroed_page() */
unsigned long tmp;
- if (!(tmp = get_zeroed_page(GFP_KERNEL)))
+ if (!(tmp = get_zeroed_page(GFP_KERNEL))) {
+ func_exit();
return -ENOMEM;
+ }
if (port->xmit_buf) {
free_page(tmp);
+ func_exit();
return -ERESTARTSYS;
}
port->xmit_buf = (unsigned char *) tmp;
}
- save_flags(flags); cli();
-
+ spin_lock_irqsave(&port->lock, flags);
+
if (port->tty)
clear_bit(TTY_IO_ERROR, &port->tty->flags);
-
- if (port->count == 1)
- bp->count++;
-
+
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
sx_change_speed(bp, port);
port->flags |= ASYNC_INITIALIZED;
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
- restore_flags(flags);
+ func_exit();
return 0;
}
@@ -1201,62 +1350,54 @@ static int sx_setup_port(struct specialix_board *bp, struct specialix_port *port
static void sx_shutdown_port(struct specialix_board *bp, struct specialix_port *port)
{
struct tty_struct *tty;
+ int i;
+ unsigned long flags;
- if (!(port->flags & ASYNC_INITIALIZED))
+ func_enter();
+
+ if (!(port->flags & ASYNC_INITIALIZED)) {
+ func_exit();
return;
+ }
-#ifdef SX_REPORT_OVERRUN
- printk(KERN_INFO "sx%d: port %d: Total %ld overruns were detected.\n",
- board_No(bp), port_No(port), port->overrun);
-#endif
-#ifdef SX_REPORT_FIFO
- {
- int i;
-
- printk(KERN_INFO "sx%d: port %d: FIFO hits [ ",
- board_No(bp), port_No(port));
+ if (sx_debug & SX_DEBUG_FIFO) {
+ dprintk(SX_DEBUG_FIFO, "sx%d: port %d: %ld overruns, FIFO hits [ ",
+ board_No(bp), port_No(port), port->overrun);
for (i = 0; i < 10; i++) {
- printk("%ld ", port->hits[i]);
+ dprintk(SX_DEBUG_FIFO, "%ld ", port->hits[i]);
}
- printk("].\n");
+ dprintk(SX_DEBUG_FIFO, "].\n");
}
-#endif
+
if (port->xmit_buf) {
free_page((unsigned long) port->xmit_buf);
port->xmit_buf = NULL;
}
/* Select port */
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
if (!(tty = port->tty) || C_HUPCL(tty)) {
/* Drop DTR */
sx_out(bp, CD186x_MSVDTR, 0);
}
-
+ spin_unlock_irqrestore(&bp->lock, flags);
/* Reset port */
sx_wait_CCR(bp);
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CCR, CCR_SOFTRESET);
/* Disable all interrupts from this port */
port->IER = 0;
sx_out(bp, CD186x_IER, port->IER);
-
+ spin_unlock_irqrestore(&bp->lock, flags);
if (tty)
set_bit(TTY_IO_ERROR, &tty->flags);
port->flags &= ~ASYNC_INITIALIZED;
- if (--bp->count < 0) {
- printk(KERN_ERR "sx%d: sx_shutdown_port: bad board count: %d\n",
- board_No(bp), bp->count);
- bp->count = 0;
- }
-
- /*
- * If this is the last opened port on the board
- * shutdown whole board
- */
if (!bp->count)
sx_shutdown_board(bp);
+ func_exit();
}
@@ -1268,6 +1409,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
int retval;
int do_clocal = 0;
int CD;
+ unsigned long flags;
+
+ func_enter();
/*
* If the device is in the middle of being closed, then block
@@ -1275,10 +1419,13 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
*/
if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
interruptible_sleep_on(&port->close_wait);
- if (port->flags & ASYNC_HUP_NOTIFY)
+ if (port->flags & ASYNC_HUP_NOTIFY) {
+ func_exit();
return -EAGAIN;
- else
+ } else {
+ func_exit();
return -ERESTARTSYS;
+ }
}
/*
@@ -1288,6 +1435,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
if ((filp->f_flags & O_NONBLOCK) ||
(tty->flags & (1 << TTY_IO_ERROR))) {
port->flags |= ASYNC_NORMAL_ACTIVE;
+ func_exit();
return 0;
}
@@ -1303,13 +1451,14 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
*/
retval = 0;
add_wait_queue(&port->open_wait, &wait);
- cli();
- if (!tty_hung_up_p(filp))
+ spin_lock_irqsave(&port->lock, flags);
+ if (!tty_hung_up_p(filp)) {
port->count--;
- sti();
+ }
+ spin_unlock_irqrestore(&port->lock, flags);
port->blocked_open++;
while (1) {
- cli();
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
CD = sx_in(bp, CD186x_MSVR) & MSVR_CD;
if (SX_CRTSCTS (tty)) {
@@ -1320,8 +1469,8 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
/* Activate DTR */
port->MSVR |= MSVR_DTR;
sx_out (bp, CD186x_MSVR, port->MSVR);
- }
- sti();
+ }
+ spin_unlock_irqrestore(&bp->lock, flags);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(port->flags & ASYNC_INITIALIZED)) {
@@ -1340,15 +1489,22 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
}
schedule();
}
- current->state = TASK_RUNNING;
+
+ set_current_state(TASK_RUNNING);
remove_wait_queue(&port->open_wait, &wait);
- if (!tty_hung_up_p(filp))
+ spin_lock_irqsave(&port->lock, flags);
+ if (!tty_hung_up_p(filp)) {
port->count++;
+ }
port->blocked_open--;
- if (retval)
+ spin_unlock_irqrestore(&port->lock, flags);
+ if (retval) {
+ func_exit();
return retval;
-
+ }
+
port->flags |= ASYNC_NORMAL_ACTIVE;
+ func_exit();
return 0;
}
@@ -1359,36 +1515,55 @@ static int sx_open(struct tty_struct * tty, struct file * filp)
int error;
struct specialix_port * port;
struct specialix_board * bp;
-
+ int i;
+ unsigned long flags;
+
+ func_enter();
+
board = SX_BOARD(tty->index);
- if (board >= SX_NBOARD || !(sx_board[board].flags & SX_BOARD_PRESENT))
+ if (board >= SX_NBOARD || !(sx_board[board].flags & SX_BOARD_PRESENT)) {
+ func_exit();
return -ENODEV;
+ }
bp = &sx_board[board];
port = sx_port + board * SX_NPORT + SX_PORT(tty->index);
+ port->overrun = 0;
+ for (i = 0; i < 10; i++)
+ port->hits[i]=0;
-#ifdef DEBUG_SPECIALIX
- printk (KERN_DEBUG "Board = %d, bp = %p, port = %p, portno = %d.\n",
+ dprintk (SX_DEBUG_OPEN, "Board = %d, bp = %p, port = %p, portno = %d.\n",
board, bp, port, SX_PORT(tty->index));
-#endif
- if (sx_paranoia_check(port, tty->name, "sx_open"))
+ if (sx_paranoia_check(port, tty->name, "sx_open")) {
+ func_enter();
return -ENODEV;
+ }
- if ((error = sx_setup_board(bp)))
+ if ((error = sx_setup_board(bp))) {
+ func_exit();
return error;
+ }
+ spin_lock_irqsave(&bp->lock, flags);
port->count++;
+ bp->count++;
tty->driver_data = port;
port->tty = tty;
+ spin_unlock_irqrestore(&bp->lock, flags);
- if ((error = sx_setup_port(bp, port)))
+ if ((error = sx_setup_port(bp, port))) {
+ func_enter();
return error;
+ }
- if ((error = block_til_ready(tty, filp, port)))
+ if ((error = block_til_ready(tty, filp, port))) {
+ func_enter();
return error;
+ }
+ func_exit();
return 0;
}
@@ -1400,12 +1575,16 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
unsigned long flags;
unsigned long timeout;
- if (!port || sx_paranoia_check(port, tty->name, "close"))
+ func_enter();
+ if (!port || sx_paranoia_check(port, tty->name, "close")) {
+ func_exit();
return;
-
- save_flags(flags); cli();
+ }
+ spin_lock_irqsave(&port->lock, flags);
+
if (tty_hung_up_p(filp)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
+ func_exit();
return;
}
@@ -1416,13 +1595,14 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
board_No(bp), port->count);
port->count = 1;
}
- if (--port->count < 0) {
- printk(KERN_ERR "sx%d: sx_close: bad port count for tty%d: %d\n",
- board_No(bp), port_No(port), port->count);
- port->count = 0;
- }
- if (port->count) {
- restore_flags(flags);
+
+ if (port->count > 1) {
+ port->count--;
+ bp->count--;
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ func_exit();
return;
}
port->flags |= ASYNC_CLOSING;
@@ -1431,20 +1611,26 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
- if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ spin_unlock_irqrestore(&port->lock, flags);
+ dprintk (SX_DEBUG_OPEN, "Closing\n");
+ if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
tty_wait_until_sent(tty, port->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.
*/
+ dprintk (SX_DEBUG_OPEN, "Closed\n");
port->IER &= ~IER_RXD;
if (port->flags & ASYNC_INITIALIZED) {
port->IER &= ~IER_TXRDY;
port->IER |= IER_TXEMPTY;
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
sx_out(bp, CD186x_IER, port->IER);
+ spin_unlock_irqrestore(&bp->lock, flags);
/*
* Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially
@@ -1452,6 +1638,7 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
*/
timeout = jiffies+HZ;
while(port->IER & IER_TXEMPTY) {
+ set_current_state (TASK_INTERRUPTIBLE);
msleep_interruptible(jiffies_to_msecs(port->timeout));
if (time_after(jiffies, timeout)) {
printk (KERN_INFO "Timeout waiting for close\n");
@@ -1460,13 +1647,27 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
}
}
+
+ if (--bp->count < 0) {
+ printk(KERN_ERR "sx%d: sx_shutdown_port: bad board count: %d port: %d\n",
+ board_No(bp), bp->count, tty->index);
+ bp->count = 0;
+ }
+ if (--port->count < 0) {
+ printk(KERN_ERR "sx%d: sx_close: bad port count for tty%d: %d\n",
+ board_No(bp), port_No(port), port->count);
+ port->count = 0;
+ }
+
sx_shutdown_port(bp, port);
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
tty_ldisc_flush(tty);
+ spin_lock_irqsave(&port->lock, flags);
tty->closing = 0;
port->event = 0;
port->tty = NULL;
+ spin_unlock_irqrestore(&port->lock, flags);
if (port->blocked_open) {
if (port->close_delay) {
msleep_interruptible(jiffies_to_msecs(port->close_delay));
@@ -1475,7 +1676,8 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
}
port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&port->close_wait);
- restore_flags(flags);
+
+ func_exit();
}
@@ -1486,42 +1688,48 @@ static int sx_write(struct tty_struct * tty,
struct specialix_board *bp;
int c, total = 0;
unsigned long flags;
-
- if (sx_paranoia_check(port, tty->name, "sx_write"))
+
+ func_enter();
+ if (sx_paranoia_check(port, tty->name, "sx_write")) {
+ func_exit();
return 0;
+ }
bp = port_Board(port);
- if (!tty || !port->xmit_buf || !tmp_buf)
+ if (!tty || !port->xmit_buf || !tmp_buf) {
+ func_exit();
return 0;
+ }
- save_flags(flags);
while (1) {
- cli();
+ spin_lock_irqsave(&port->lock, flags);
c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
SERIAL_XMIT_SIZE - port->xmit_head));
if (c <= 0) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
break;
}
memcpy(port->xmit_buf + port->xmit_head, buf, c);
port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
port->xmit_cnt += c;
- restore_flags(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
buf += c;
count -= c;
total += c;
}
- cli();
+ spin_lock_irqsave(&bp->lock, flags);
if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
!(port->IER & IER_TXRDY)) {
port->IER |= IER_TXRDY;
sx_out(bp, CD186x_CAR, port_No(port));
sx_out(bp, CD186x_IER, port->IER);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ func_exit();
+
return total;
}
@@ -1530,24 +1738,36 @@ static void sx_put_char(struct tty_struct * tty, unsigned char ch)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
unsigned long flags;
+ struct specialix_board * bp;
- if (sx_paranoia_check(port, tty->name, "sx_put_char"))
- return;
+ func_enter();
- if (!tty || !port->xmit_buf)
+ if (sx_paranoia_check(port, tty->name, "sx_put_char")) {
+ func_exit();
return;
-
- save_flags(flags); cli();
-
- if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
- restore_flags(flags);
+ }
+ dprintk (SX_DEBUG_TX, "check tty: %p %p\n", tty, port->xmit_buf);
+ if (!tty || !port->xmit_buf) {
+ func_exit();
return;
}
+ bp = port_Board(port);
+ spin_lock_irqsave(&port->lock, flags);
+ dprintk (SX_DEBUG_TX, "xmit_cnt: %d xmit_buf: %p\n", port->xmit_cnt, port->xmit_buf);
+ if ((port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) || (!port->xmit_buf)) {
+ spin_unlock_irqrestore(&port->lock, flags);
+ dprintk (SX_DEBUG_TX, "Exit size\n");
+ func_exit();
+ return;
+ }
+ dprintk (SX_DEBUG_TX, "Handle xmit: %p %p\n", port, port->xmit_buf);
port->xmit_buf[port->xmit_head++] = ch;
port->xmit_head &= SERIAL_XMIT_SIZE - 1;
port->xmit_cnt++;
- restore_flags(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ func_exit();
}
@@ -1555,19 +1775,26 @@ static void sx_flush_chars(struct tty_struct * tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
unsigned long flags;
-
- if (sx_paranoia_check(port, tty->name, "sx_flush_chars"))
+ struct specialix_board * bp = port_Board(port);
+
+ func_enter();
+
+ if (sx_paranoia_check(port, tty->name, "sx_flush_chars")) {
+ func_exit();
return;
-
+ }
if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
- !port->xmit_buf)
+ !port->xmit_buf) {
+ func_exit();
return;
-
- save_flags(flags); cli();
+ }
+ spin_lock_irqsave(&bp->lock, flags);
port->IER |= IER_TXRDY;
sx_out(port_Board(port), CD186x_CAR, port_No(port));
sx_out(port_Board(port), CD186x_IER, port->IER);
- restore_flags(flags);
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+ func_exit();
}
@@ -1575,13 +1802,19 @@ static int sx_write_room(struct tty_struct * tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
int ret;
-
- if (sx_paranoia_check(port, tty->name, "sx_write_room"))
+
+ func_enter();
+
+ if (sx_paranoia_check(port, tty->name, "sx_write_room")) {
+ func_exit();
return 0;
+ }
ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
if (ret < 0)
ret = 0;
+
+ func_exit();
return ret;
}
@@ -1589,10 +1822,14 @@ static int sx_write_room(struct tty_struct * tty)
static int sx_chars_in_buffer(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
-
- if (sx_paranoia_check(port, tty->name, "sx_chars_in_buffer"))
- return 0;
+
+ func_enter();
+ if (sx_paranoia_check(port, tty->name, "sx_chars_in_buffer")) {
+ func_exit();
+ return 0;
+ }
+ func_exit();
return port->xmit_cnt;
}
@@ -1601,16 +1838,22 @@ static void sx_flush_buffer(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
unsigned long flags;
-
- if (sx_paranoia_check(port, tty->name, "sx_flush_buffer"))
+ struct specialix_board * bp;
+
+ func_enter();
+
+ if (sx_paranoia_check(port, tty->name, "sx_flush_buffer")) {
+ func_exit();
return;
+ }
- save_flags(flags); cli();
+ bp = port_Board(port);
+ spin_lock_irqsave(&port->lock, flags);
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&port->lock, flags);
tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
+
+ func_exit();
}
@@ -1622,19 +1865,21 @@ static int sx_tiocmget(struct tty_struct *tty, struct file *file)
unsigned int result;
unsigned long flags;
- if (sx_paranoia_check(port, tty->name, __FUNCTION__))
+ func_enter();
+
+ if (sx_paranoia_check(port, tty->name, __FUNCTION__)) {
+ func_exit();
return -ENODEV;
+ }
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave (&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
status = sx_in(bp, CD186x_MSVR);
- restore_flags(flags);
-#ifdef DEBUG_SPECIALIX
- printk (KERN_DEBUG "Got msvr[%d] = %02x, car = %d.\n",
+ spin_unlock_irqrestore(&bp->lock, flags);
+ dprintk (SX_DEBUG_INIT, "Got msvr[%d] = %02x, car = %d.\n",
port_No(port), status, sx_in (bp, CD186x_CAR));
- printk (KERN_DEBUG "sx_port = %p, port = %p\n", sx_port, port);
-#endif
+ dprintk (SX_DEBUG_INIT, "sx_port = %p, port = %p\n", sx_port, port);
if (SX_CRTSCTS(port->tty)) {
result = /* (status & MSVR_RTS) ? */ TIOCM_DTR /* : 0) */
| ((status & MSVR_DTR) ? TIOCM_RTS : 0)
@@ -1649,6 +1894,8 @@ static int sx_tiocmget(struct tty_struct *tty, struct file *file)
| ((status & MSVR_CTS) ? TIOCM_CTS : 0);
}
+ func_exit();
+
return result;
}
@@ -1660,12 +1907,16 @@ static int sx_tiocmset(struct tty_struct *tty, struct file *file,
unsigned long flags;
struct specialix_board *bp;
- if (sx_paranoia_check(port, tty->name, __FUNCTION__))
+ func_enter();
+
+ if (sx_paranoia_check(port, tty->name, __FUNCTION__)) {
+ func_exit();
return -ENODEV;
+ }
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave(&port->lock, flags);
/* if (set & TIOCM_RTS)
port->MSVR |= MSVR_RTS; */
/* if (set & TIOCM_DTR)
@@ -1690,10 +1941,12 @@ static int sx_tiocmset(struct tty_struct *tty, struct file *file,
if (clear & TIOCM_DTR)
port->MSVR &= ~MSVR_DTR;
}
-
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
sx_out(bp, CD186x_MSVR, port->MSVR);
- restore_flags(flags);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ spin_unlock_irqrestore(&port->lock, flags);
+ func_exit();
return 0;
}
@@ -1703,17 +1956,25 @@ static inline void sx_send_break(struct specialix_port * port, unsigned long len
struct specialix_board *bp = port_Board(port);
unsigned long flags;
- save_flags(flags); cli();
+ func_enter();
+
+ spin_lock_irqsave (&port->lock, flags);
port->break_length = SPECIALIX_TPS / HZ * length;
port->COR2 |= COR2_ETC;
port->IER |= IER_TXRDY;
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
sx_out(bp, CD186x_COR2, port->COR2);
sx_out(bp, CD186x_IER, port->IER);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ spin_unlock_irqrestore (&port->lock, flags);
sx_wait_CCR(bp);
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CCR, CCR_CORCHG2);
+ spin_unlock_irqrestore(&bp->lock, flags);
sx_wait_CCR(bp);
- restore_flags(flags);
+
+ func_exit();
}
@@ -1723,10 +1984,19 @@ static inline int sx_set_serial_info(struct specialix_port * port,
struct serial_struct tmp;
struct specialix_board *bp = port_Board(port);
int change_speed;
- unsigned long flags;
-
- if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
+
+ func_enter();
+ /*
+ error = verify_area(VERIFY_READ, (void *) newinfo, sizeof(tmp));
+ if (error) {
+ func_exit();
+ return error;
+ }
+ */
+ if (copy_from_user(&tmp, newinfo, sizeof(tmp))) {
+ func_enter();
return -EFAULT;
+ }
#if 0
if ((tmp.irq != bp->irq) ||
@@ -1735,8 +2005,10 @@ static inline int sx_set_serial_info(struct specialix_port * port,
(tmp.baud_base != (SX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC) ||
(tmp.custom_divisor != 0) ||
(tmp.xmit_fifo_size != CD186x_NFIFO) ||
- (tmp.flags & ~SPECIALIX_LEGAL_FLAGS))
+ (tmp.flags & ~SPECIALIX_LEGAL_FLAGS)) {
+ func_exit();
return -EINVAL;
+ }
#endif
change_speed = ((port->flags & ASYNC_SPD_MASK) !=
@@ -1747,8 +2019,10 @@ static inline int sx_set_serial_info(struct specialix_port * port,
if ((tmp.close_delay != port->close_delay) ||
(tmp.closing_wait != port->closing_wait) ||
((tmp.flags & ~ASYNC_USR_MASK) !=
- (port->flags & ~ASYNC_USR_MASK)))
+ (port->flags & ~ASYNC_USR_MASK))) {
+ func_exit();
return -EPERM;
+ }
port->flags = ((port->flags & ~ASYNC_USR_MASK) |
(tmp.flags & ASYNC_USR_MASK));
port->custom_divisor = tmp.custom_divisor;
@@ -1760,10 +2034,9 @@ static inline int sx_set_serial_info(struct specialix_port * port,
port->custom_divisor = tmp.custom_divisor;
}
if (change_speed) {
- save_flags(flags); cli();
sx_change_speed(bp, port);
- restore_flags(flags);
}
+ func_exit();
return 0;
}
@@ -1773,7 +2046,16 @@ static inline int sx_get_serial_info(struct specialix_port * port,
{
struct serial_struct tmp;
struct specialix_board *bp = port_Board(port);
+ // int error;
+ func_enter();
+
+ /*
+ error = verify_area(VERIFY_WRITE, (void *) retinfo, sizeof(tmp));
+ if (error)
+ return error;
+ */
+
memset(&tmp, 0, sizeof(tmp));
tmp.type = PORT_CIRRUS;
tmp.line = port - sx_port;
@@ -1785,8 +2067,12 @@ static inline int sx_get_serial_info(struct specialix_port * port,
tmp.closing_wait = port->closing_wait * HZ/100;
tmp.custom_divisor = port->custom_divisor;
tmp.xmit_fifo_size = CD186x_NFIFO;
- if (copy_to_user(retinfo, &tmp, sizeof(tmp)))
+ if (copy_to_user(retinfo, &tmp, sizeof(tmp))) {
+ func_exit();
return -EFAULT;
+ }
+
+ func_exit();
return 0;
}
@@ -1797,44 +2083,63 @@ static int sx_ioctl(struct tty_struct * tty, struct file * filp,
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
int retval;
void __user *argp = (void __user *)arg;
-
- if (sx_paranoia_check(port, tty->name, "sx_ioctl"))
+
+ func_enter();
+
+ if (sx_paranoia_check(port, tty->name, "sx_ioctl")) {
+ func_exit();
return -ENODEV;
+ }
switch (cmd) {
case TCSBRK: /* SVID version: non-zero arg --> no break */
retval = tty_check_change(tty);
- if (retval)
+ if (retval) {
+ func_exit();
return retval;
+ }
tty_wait_until_sent(tty, 0);
if (!arg)
sx_send_break(port, HZ/4); /* 1/4 second */
return 0;
case TCSBRKP: /* support for POSIX tcsendbreak() */
retval = tty_check_change(tty);
- if (retval)
+ if (retval) {
+ func_exit();
return retval;
+ }
tty_wait_until_sent(tty, 0);
sx_send_break(port, arg ? arg*(HZ/10) : HZ/4);
+ func_exit();
return 0;
case TIOCGSOFTCAR:
- if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)argp))
- return -EFAULT;
+ if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)argp)) {
+ func_exit();
+ return -EFAULT;
+ }
+ func_exit();
return 0;
case TIOCSSOFTCAR:
- if (get_user(arg, (unsigned long __user *) argp))
- return -EFAULT;
+ if (get_user(arg, (unsigned long __user *) argp)) {
+ func_exit();
+ return -EFAULT;
+ }
tty->termios->c_cflag =
((tty->termios->c_cflag & ~CLOCAL) |
(arg ? CLOCAL : 0));
+ func_exit();
return 0;
- case TIOCGSERIAL:
+ case TIOCGSERIAL:
+ func_exit();
return sx_get_serial_info(port, argp);
case TIOCSSERIAL:
+ func_exit();
return sx_set_serial_info(port, argp);
default:
+ func_exit();
return -ENOIOCTLCMD;
}
+ func_exit();
return 0;
}
@@ -1844,14 +2149,16 @@ static void sx_throttle(struct tty_struct * tty)
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp;
unsigned long flags;
-
- if (sx_paranoia_check(port, tty->name, "sx_throttle"))
+
+ func_enter();
+
+ if (sx_paranoia_check(port, tty->name, "sx_throttle")) {
+ func_exit();
return;
+ }
bp = port_Board(port);
- save_flags(flags); cli();
-
/* Use DTR instead of RTS ! */
if (SX_CRTSCTS (tty))
port->MSVR &= ~MSVR_DTR;
@@ -1863,14 +2170,22 @@ static void sx_throttle(struct tty_struct * tty)
printk (KERN_ERR "sx%d: Need to throttle, but can't (hardware hs is off)\n",
port_No (port));
}
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
+ spin_unlock_irqrestore(&bp->lock, flags);
if (I_IXOFF(tty)) {
+ spin_unlock_irqrestore(&bp->lock, flags);
sx_wait_CCR(bp);
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CCR, CCR_SSCH2);
+ spin_unlock_irqrestore(&bp->lock, flags);
sx_wait_CCR(bp);
}
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_MSVR, port->MSVR);
- restore_flags(flags);
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+ func_exit();
}
@@ -1879,26 +2194,39 @@ static void sx_unthrottle(struct tty_struct * tty)
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp;
unsigned long flags;
+
+ func_enter();
- if (sx_paranoia_check(port, tty->name, "sx_unthrottle"))
+ if (sx_paranoia_check(port, tty->name, "sx_unthrottle")) {
+ func_exit();
return;
+ }
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave(&port->lock, flags);
/* XXXX Use DTR INSTEAD???? */
if (SX_CRTSCTS(tty)) {
port->MSVR |= MSVR_DTR;
} /* Else clause: see remark in "sx_throttle"... */
-
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
+ spin_unlock_irqrestore(&bp->lock, flags);
if (I_IXOFF(tty)) {
+ spin_unlock_irqrestore(&port->lock, flags);
sx_wait_CCR(bp);
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CCR, CCR_SSCH1);
+ spin_unlock_irqrestore(&bp->lock, flags);
sx_wait_CCR(bp);
+ spin_lock_irqsave(&port->lock, flags);
}
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_MSVR, port->MSVR);
- restore_flags(flags);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ func_exit();
}
@@ -1907,17 +2235,25 @@ static void sx_stop(struct tty_struct * tty)
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp;
unsigned long flags;
-
- if (sx_paranoia_check(port, tty->name, "sx_stop"))
- return;
+
+ func_enter();
+ if (sx_paranoia_check(port, tty->name, "sx_stop")) {
+ func_exit();
+ return;
+ }
+
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave(&port->lock, flags);
port->IER &= ~IER_TXRDY;
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
sx_out(bp, CD186x_IER, port->IER);
- restore_flags(flags);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ func_exit();
}
@@ -1926,19 +2262,27 @@ static void sx_start(struct tty_struct * tty)
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp;
unsigned long flags;
+
+ func_enter();
- if (sx_paranoia_check(port, tty->name, "sx_start"))
+ if (sx_paranoia_check(port, tty->name, "sx_start")) {
+ func_exit();
return;
+ }
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave(&port->lock, flags);
if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
port->IER |= IER_TXRDY;
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
sx_out(bp, CD186x_IER, port->IER);
+ spin_unlock_irqrestore(&bp->lock, flags);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ func_exit();
}
@@ -1956,9 +2300,13 @@ static void do_sx_hangup(void *private_)
struct specialix_port *port = (struct specialix_port *) private_;
struct tty_struct *tty;
+ func_enter();
+
tty = port->tty;
if (tty)
tty_hangup(tty); /* FIXME: module removal race here */
+
+ func_exit();
}
@@ -1966,18 +2314,33 @@ static void sx_hangup(struct tty_struct * tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp;
-
- if (sx_paranoia_check(port, tty->name, "sx_hangup"))
+ unsigned long flags;
+
+ func_enter();
+
+ if (sx_paranoia_check(port, tty->name, "sx_hangup")) {
+ func_exit();
return;
+ }
bp = port_Board(port);
sx_shutdown_port(bp, port);
+ spin_lock_irqsave(&port->lock, flags);
port->event = 0;
+ bp->count -= port->count;
+ if (bp->count < 0) {
+ printk(KERN_ERR "sx%d: sx_hangup: bad board count: %d port: %d\n",
+ board_No(bp), bp->count, tty->index);
+ bp->count = 0;
+ }
port->count = 0;
port->flags &= ~ASYNC_NORMAL_ACTIVE;
port->tty = NULL;
+ spin_unlock_irqrestore(&port->lock, flags);
wake_up_interruptible(&port->open_wait);
+
+ func_exit();
}
@@ -1985,6 +2348,7 @@ static void sx_set_termios(struct tty_struct * tty, struct termios * old_termios
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
unsigned long flags;
+ struct specialix_board * bp;
if (sx_paranoia_check(port, tty->name, "sx_set_termios"))
return;
@@ -1993,9 +2357,10 @@ static void sx_set_termios(struct tty_struct * tty, struct termios * old_termios
tty->termios->c_iflag == old_termios->c_iflag)
return;
- save_flags(flags); cli();
+ bp = port_Board(port);
+ spin_lock_irqsave(&port->lock, flags);
sx_change_speed(port_Board(port), port);
- restore_flags(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
@@ -2009,12 +2374,20 @@ static void do_softint(void *private_)
{
struct specialix_port *port = (struct specialix_port *) private_;
struct tty_struct *tty;
-
- if(!(tty = port->tty))
+
+ func_enter();
+
+ if(!(tty = port->tty)) {
+ func_exit();
return;
+ }
- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event))
- tty_wakeup(tty);
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
+ tty_wakeup(tty);
+ //wake_up_interruptible(&tty->write_wait);
+ }
+
+ func_exit();
}
static struct tty_operations sx_ops = {
@@ -2042,15 +2415,19 @@ static int sx_init_drivers(void)
int error;
int i;
+ func_enter();
+
specialix_driver = alloc_tty_driver(SX_NBOARD * SX_NPORT);
if (!specialix_driver) {
printk(KERN_ERR "sx: Couldn't allocate tty_driver.\n");
+ func_exit();
return 1;
}
if (!(tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL))) {
printk(KERN_ERR "sx: Couldn't get free page.\n");
put_tty_driver(specialix_driver);
+ func_exit();
return 1;
}
specialix_driver->owner = THIS_MODULE;
@@ -2069,6 +2446,7 @@ static int sx_init_drivers(void)
free_page((unsigned long)tmp_buf);
printk(KERN_ERR "sx: Couldn't register specialix IO8+ driver, error = %d\n",
error);
+ func_exit();
return 1;
}
memset(sx_port, 0, sizeof(sx_port));
@@ -2080,16 +2458,21 @@ static int sx_init_drivers(void)
sx_port[i].closing_wait = 3000 * HZ/100;
init_waitqueue_head(&sx_port[i].open_wait);
init_waitqueue_head(&sx_port[i].close_wait);
+ spin_lock_init(&sx_port[i].lock);
}
+ func_exit();
return 0;
}
static void sx_release_drivers(void)
{
+ func_enter();
+
free_page((unsigned long)tmp_buf);
tty_unregister_driver(specialix_driver);
put_tty_driver(specialix_driver);
+ func_exit();
}
/*
@@ -2100,6 +2483,8 @@ static int __init specialix_init(void)
int i;
int found = 0;
+ func_enter();
+
printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997/1998.\n");
printk(KERN_INFO "sx: derived from work (c) D.Gorodchanin 1994-1996.\n");
#ifdef CONFIG_SPECIALIX_RTSCTS
@@ -2108,8 +2493,13 @@ static int __init specialix_init(void)
printk (KERN_INFO "sx: DTR/RTS pin is RTS when CRTSCTS is on.\n");
#endif
- if (sx_init_drivers())
+ for (i = 0; i < SX_NBOARD; i++)
+ sx_board[i].lock = SPIN_LOCK_UNLOCKED;
+
+ if (sx_init_drivers()) {
+ func_exit();
return -EIO;
+ }
for (i = 0; i < SX_NBOARD; i++)
if (sx_board[i].base && !sx_probe(&sx_board[i]))
@@ -2147,9 +2537,11 @@ static int __init specialix_init(void)
if (!found) {
sx_release_drivers();
printk(KERN_INFO "sx: No specialix IO8+ boards detected.\n");
+ func_exit();
return -EIO;
}
+ func_exit();
return 0;
}
@@ -2159,6 +2551,11 @@ static int irq [SX_NBOARD] = {0,};
module_param_array(iobase, int, NULL, 0);
module_param_array(irq, int, NULL, 0);
+module_param(sx_debug, int, 0);
+module_param(sx_rxfifo, int, 0);
+#ifdef SPECIALIX_TIMER
+module_param(sx_poll, int, 0);
+#endif
/*
* You can setup up to 4 boards.
@@ -2173,13 +2570,20 @@ static int __init specialix_init_module(void)
{
int i;
+ func_enter();
+
+ init_MUTEX(&tmp_buf_sem); /* Init de the semaphore - pvdl */
+
if (iobase[0] || iobase[1] || iobase[2] || iobase[3]) {
for(i = 0; i < SX_NBOARD; i++) {
sx_board[i].base = iobase[i];
sx_board[i].irq = irq[i];
+ sx_board[i].count= 0;
}
}
+ func_exit();
+
return specialix_init();
}
@@ -2187,6 +2591,8 @@ static void __exit specialix_exit_module(void)
{
int i;
+ func_enter();
+
sx_release_drivers();
for (i = 0; i < SX_NBOARD; i++)
if (sx_board[i].flags & SX_BOARD_PRESENT)
@@ -2194,7 +2600,8 @@ static void __exit specialix_exit_module(void)
#ifdef SPECIALIX_TIMER
del_timer (&missed_irq_timer);
#endif
-
+
+ func_exit();
}
module_init(specialix_init_module);
diff --git a/drivers/char/specialix_io8.h b/drivers/char/specialix_io8.h
index 948ab1489e7a0..895bd90de3631 100644
--- a/drivers/char/specialix_io8.h
+++ b/drivers/char/specialix_io8.h
@@ -93,9 +93,11 @@ struct specialix_board {
unsigned long flags;
unsigned short base;
unsigned char irq;
- signed char count;
+ //signed char count;
+ int count;
unsigned char DTR;
int reg;
+ spinlock_t lock;
};
#define SX_BOARD_PRESENT 0x00000001
@@ -129,12 +131,9 @@ struct specialix_port {
unsigned char IER;
unsigned char MSVR;
unsigned char COR2;
-#ifdef SX_REPORT_OVERRUN
unsigned long overrun;
-#endif
-#ifdef SX_REPORT_FIFO
unsigned long hits[10];
-#endif
+ spinlock_t lock;
};
#endif /* __KERNEL__ */
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 4203a4f75669a..de166608c59e5 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -232,13 +232,12 @@ static char *stl_brdnames[] = {
/*****************************************************************************/
-#ifdef MODULE
/*
* Define some string labels for arguments passed from the module
* load line. These allow for easy board definitions, and easy
* modification of the io, memory and irq resoucres.
*/
-
+static int stl_nargs = 0;
static char *board0[4];
static char *board1[4];
static char *board2[4];
@@ -299,17 +298,15 @@ MODULE_AUTHOR("Greg Ungerer");
MODULE_DESCRIPTION("Stallion Multiport Serial Driver");
MODULE_LICENSE("GPL");
-MODULE_PARM(board0, "1-4s");
+module_param_array(board0, charp, &stl_nargs, 0);
MODULE_PARM_DESC(board0, "Board 0 config -> name[,ioaddr[,ioaddr2][,irq]]");
-MODULE_PARM(board1, "1-4s");
+module_param_array(board1, charp, &stl_nargs, 0);
MODULE_PARM_DESC(board1, "Board 1 config -> name[,ioaddr[,ioaddr2][,irq]]");
-MODULE_PARM(board2, "1-4s");
+module_param_array(board2, charp, &stl_nargs, 0);
MODULE_PARM_DESC(board2, "Board 2 config -> name[,ioaddr[,ioaddr2][,irq]]");
-MODULE_PARM(board3, "1-4s");
+module_param_array(board3, charp, &stl_nargs, 0);
MODULE_PARM_DESC(board3, "Board 3 config -> name[,ioaddr[,ioaddr2][,irq]]");
-#endif
-
/*****************************************************************************/
/*
@@ -464,12 +461,10 @@ static unsigned int stl_baudrates[] = {
* Declare all those functions in this driver!
*/
-#ifdef MODULE
static void stl_argbrds(void);
static int stl_parsebrd(stlconf_t *confp, char **argp);
static unsigned long stl_atol(char *str);
-#endif
int stl_init(void);
static int stl_open(struct tty_struct *tty, struct file *filp);
@@ -726,8 +721,6 @@ static struct file_operations stl_fsiomem = {
static struct class_simple *stallion_class;
-#ifdef MODULE
-
/*
* Loadable module initialization stuff.
*/
@@ -842,15 +835,13 @@ static void stl_argbrds(void)
{
stlconf_t conf;
stlbrd_t *brdp;
- int nrargs, i;
+ int i;
#ifdef DEBUG
printk("stl_argbrds()\n");
#endif
- nrargs = sizeof(stl_brdsp) / sizeof(char **);
-
- for (i = stl_nrbrds; (i < nrargs); i++) {
+ for (i = stl_nrbrds; (i < stl_nargs); i++) {
memset(&conf, 0, sizeof(conf));
if (stl_parsebrd(&conf, stl_brdsp[i]) == 0)
continue;
@@ -950,8 +941,6 @@ static int stl_parsebrd(stlconf_t *confp, char **argp)
return(1);
}
-#endif
-
/*****************************************************************************/
/*
@@ -2787,9 +2776,7 @@ static inline int stl_initbrds(void)
*/
for (i = 0; (i < stl_nrbrds); i++) {
confp = &stl_brdconf[i];
-#ifdef MODULE
stl_parsebrd(confp, stl_brdsp[i]);
-#endif
if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL)
return(-ENOMEM);
brdp->brdnr = i;
@@ -2805,9 +2792,7 @@ static inline int stl_initbrds(void)
* Find any dynamically supported boards. That is via module load
* line options or auto-detected on the PCI bus.
*/
-#ifdef MODULE
stl_argbrds();
-#endif
#ifdef CONFIG_PCI
stl_findpcibrds();
#endif
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index aeb2403fcd274..8318268169d67 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -39,7 +39,7 @@
#define PCI_GEN2_DEC 0xEC
static LIST_HEAD(tpm_chip_list);
-static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(driver_lock);
static int dev_mask[32];
static void user_reader_timeout(unsigned long ptr)
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 47ed70402bc2b..575cf5aed41a5 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -22,6 +22,7 @@
#include <linux/version.h>
#include <linux/pci.h>
#include <linux/delay.h>
+#include <linux/fs.h>
#include <linux/miscdevice.h>
#define TPM_TIMEOUT msecs_to_jiffies(5)
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 932951c57f5c8..06e5a3f1836db 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -2630,6 +2630,7 @@ static void initialize_tty_struct(struct tty_struct *tty)
tty->magic = TTY_MAGIC;
tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
tty->pgrp = -1;
+ tty->overrun_time = jiffies;
tty->flip.char_buf_ptr = tty->flip.char_buf;
tty->flip.flag_buf_ptr = tty->flip.flag_buf;
INIT_WORK(&tty->flip.work, flush_to_ldisc, tty);
diff --git a/drivers/char/vr41xx_rtc.c b/drivers/char/vr41xx_rtc.c
new file mode 100644
index 0000000000000..a6dbe4da030c7
--- /dev/null
+++ b/drivers/char/vr41xx_rtc.c
@@ -0,0 +1,709 @@
+/*
+ * Driver for NEC VR4100 series Real Time Clock unit.
+ *
+ * Copyright (C) 2003-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *
+ * 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/device.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/mc146818rtc.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/rtc.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#include <asm/div64.h>
+#include <asm/io.h>
+#include <asm/time.h>
+#include <asm/uaccess.h>
+#include <asm/vr41xx/vr41xx.h>
+
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@hh.iij4u.or.jp>");
+MODULE_DESCRIPTION("NEC VR4100 series RTC driver");
+MODULE_LICENSE("GPL");
+
+#define RTC1_TYPE1_START 0x0b0000c0UL
+#define RTC1_TYPE1_END 0x0b0000dfUL
+#define RTC2_TYPE1_START 0x0b0001c0UL
+#define RTC2_TYPE1_END 0x0b0001dfUL
+
+#define RTC1_TYPE2_START 0x0f000100UL
+#define RTC1_TYPE2_END 0x0f00011fUL
+#define RTC2_TYPE2_START 0x0f000120UL
+#define RTC2_TYPE2_END 0x0f00013fUL
+
+#define RTC1_SIZE 0x20
+#define RTC2_SIZE 0x20
+
+/* RTC 1 registers */
+#define ETIMELREG 0x00
+#define ETIMEMREG 0x02
+#define ETIMEHREG 0x04
+/* RFU */
+#define ECMPLREG 0x08
+#define ECMPMREG 0x0a
+#define ECMPHREG 0x0c
+/* RFU */
+#define RTCL1LREG 0x10
+#define RTCL1HREG 0x12
+#define RTCL1CNTLREG 0x14
+#define RTCL1CNTHREG 0x16
+#define RTCL2LREG 0x18
+#define RTCL2HREG 0x1a
+#define RTCL2CNTLREG 0x1c
+#define RTCL2CNTHREG 0x1e
+
+/* RTC 2 registers */
+#define TCLKLREG 0x00
+#define TCLKHREG 0x02
+#define TCLKCNTLREG 0x04
+#define TCLKCNTHREG 0x06
+/* RFU */
+#define RTCINTREG 0x1e
+ #define TCLOCK_INT 0x08
+ #define RTCLONG2_INT 0x04
+ #define RTCLONG1_INT 0x02
+ #define ELAPSEDTIME_INT 0x01
+
+#define RTC_FREQUENCY 32768
+#define MAX_PERIODIC_RATE 6553
+#define MAX_USER_PERIODIC_RATE 64
+
+static void __iomem *rtc1_base;
+static void __iomem *rtc2_base;
+
+#define rtc1_read(offset) readw(rtc1_base + (offset))
+#define rtc1_write(offset, value) writew((value), rtc1_base + (offset))
+
+#define rtc2_read(offset) readw(rtc2_base + (offset))
+#define rtc2_write(offset, value) writew((value), rtc2_base + (offset))
+
+static unsigned long epoch = 1970; /* Jan 1 1970 00:00:00 */
+
+static spinlock_t rtc_task_lock;
+static wait_queue_head_t rtc_wait;
+static unsigned long rtc_irq_data;
+static struct fasync_struct *rtc_async_queue;
+static rtc_task_t *rtc_callback;
+static char rtc_name[] = "RTC";
+static unsigned long periodic_frequency;
+static unsigned long periodic_count;
+
+typedef enum {
+ RTC_RELEASE,
+ RTC_OPEN,
+} rtc_status_t;
+
+static rtc_status_t rtc_status;
+
+typedef enum {
+ FUNCTION_RTC_IOCTL,
+ FUNCTION_RTC_CONTROL,
+} rtc_callfrom_t;
+
+struct resource rtc_resource[2] = {
+ { .name = rtc_name,
+ .flags = IORESOURCE_MEM, },
+ { .name = rtc_name,
+ .flags = IORESOURCE_MEM, },
+};
+
+#define RTC_NUM_RESOURCES sizeof(rtc_resource) / sizeof(struct resource)
+
+static inline unsigned long read_elapsed_second(void)
+{
+ unsigned long first_low, first_mid, first_high;
+ unsigned long second_low, second_mid, second_high;
+
+ do {
+ first_low = rtc1_read(ETIMELREG);
+ first_mid = rtc1_read(ETIMEMREG);
+ first_high = rtc1_read(ETIMEHREG);
+ second_low = rtc1_read(ETIMELREG);
+ second_mid = rtc1_read(ETIMEMREG);
+ second_high = rtc1_read(ETIMEHREG);
+ } while (first_low != second_low || first_mid != second_mid ||
+ first_high != second_high);
+
+ return (first_high << 17) | (first_mid << 1) | (first_low >> 15);
+}
+
+static inline void write_elapsed_second(unsigned long sec)
+{
+ spin_lock_irq(&rtc_lock);
+
+ rtc1_write(ETIMELREG, (uint16_t)(sec << 15));
+ rtc1_write(ETIMEMREG, (uint16_t)(sec >> 1));
+ rtc1_write(ETIMEHREG, (uint16_t)(sec >> 17));
+
+ spin_unlock_irq(&rtc_lock);
+}
+
+static void set_alarm(struct rtc_time *time)
+{
+ unsigned long alarm_sec;
+
+ alarm_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
+ time->tm_hour, time->tm_min, time->tm_sec);
+
+ spin_lock_irq(&rtc_lock);
+
+ rtc1_write(ECMPLREG, (uint16_t)(alarm_sec << 15));
+ rtc1_write(ECMPMREG, (uint16_t)(alarm_sec >> 1));
+ rtc1_write(ECMPHREG, (uint16_t)(alarm_sec >> 17));
+
+ spin_unlock_irq(&rtc_lock);
+}
+
+static void read_alarm(struct rtc_time *time)
+{
+ unsigned long low, mid, high;
+
+ spin_lock_irq(&rtc_lock);
+
+ low = rtc1_read(ECMPLREG);
+ mid = rtc1_read(ECMPMREG);
+ high = rtc1_read(ECMPHREG);
+
+ spin_unlock_irq(&rtc_lock);
+
+ to_tm((high << 17) | (mid << 1) | (low >> 15), time);
+ time->tm_year -= 1900;
+}
+
+static void read_time(struct rtc_time *time)
+{
+ unsigned long epoch_sec, elapsed_sec;
+
+ epoch_sec = mktime(epoch, 1, 1, 0, 0, 0);
+ elapsed_sec = read_elapsed_second();
+
+ to_tm(epoch_sec + elapsed_sec, time);
+ time->tm_year -= 1900;
+}
+
+static void set_time(struct rtc_time *time)
+{
+ unsigned long epoch_sec, current_sec;
+
+ epoch_sec = mktime(epoch, 1, 1, 0, 0, 0);
+ current_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
+ time->tm_hour, time->tm_min, time->tm_sec);
+
+ write_elapsed_second(current_sec - epoch_sec);
+}
+
+static ssize_t rtc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long irq_data;
+ int retval = 0;
+
+ if (count != sizeof(unsigned int) && count != sizeof(unsigned long))
+ return -EINVAL;
+
+ add_wait_queue(&rtc_wait, &wait);
+
+ do {
+ __set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irq(&rtc_lock);
+ irq_data = rtc_irq_data;
+ rtc_irq_data = 0;
+ spin_unlock_irq(&rtc_lock);
+
+ if (irq_data != 0)
+ break;
+
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ break;
+ }
+
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ } while (1);
+
+ if (retval == 0) {
+ if (count == sizeof(unsigned int)) {
+ retval = put_user(irq_data, (unsigned int __user *)buf);
+ if (retval == 0)
+ retval = sizeof(unsigned int);
+ } else {
+ retval = put_user(irq_data, (unsigned long __user *)buf);
+ if (retval == 0)
+ retval = sizeof(unsigned long);
+ }
+
+ }
+
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&rtc_wait, &wait);
+
+ return retval;
+}
+
+static unsigned int rtc_poll(struct file *file, struct poll_table_struct *table)
+{
+ poll_wait(file, &rtc_wait, table);
+
+ if (rtc_irq_data != 0)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, rtc_callfrom_t from)
+{
+ struct rtc_time time;
+ unsigned long count;
+
+ switch (cmd) {
+ case RTC_AIE_ON:
+ enable_irq(ELAPSEDTIME_IRQ);
+ break;
+ case RTC_AIE_OFF:
+ disable_irq(ELAPSEDTIME_IRQ);
+ break;
+ case RTC_PIE_ON:
+ enable_irq(RTCLONG1_IRQ);
+ break;
+ case RTC_PIE_OFF:
+ disable_irq(RTCLONG1_IRQ);
+ break;
+ case RTC_ALM_SET:
+ if (copy_from_user(&time, (struct rtc_time __user *)arg,
+ sizeof(struct rtc_time)))
+ return -EFAULT;
+
+ set_alarm(&time);
+ break;
+ case RTC_ALM_READ:
+ memset(&time, 0, sizeof(struct rtc_time));
+ read_alarm(&time);
+ break;
+ case RTC_RD_TIME:
+ memset(&time, 0, sizeof(struct rtc_time));
+ read_time(&time);
+ if (copy_to_user((void __user *)arg, &time, sizeof(struct rtc_time)))
+ return -EFAULT;
+ break;
+ case RTC_SET_TIME:
+ if (capable(CAP_SYS_TIME) == 0)
+ return -EACCES;
+
+ if (copy_from_user(&time, (struct rtc_time __user *)arg,
+ sizeof(struct rtc_time)))
+ return -EFAULT;
+
+ set_time(&time);
+ break;
+ case RTC_IRQP_READ:
+ return put_user(periodic_frequency, (unsigned long __user *)arg);
+ break;
+ case RTC_IRQP_SET:
+ if (arg > MAX_PERIODIC_RATE)
+ return -EINVAL;
+
+ if (from == FUNCTION_RTC_IOCTL && arg > MAX_USER_PERIODIC_RATE &&
+ capable(CAP_SYS_RESOURCE) == 0)
+ return -EACCES;
+
+ periodic_frequency = arg;
+
+ count = RTC_FREQUENCY;
+ do_div(count, arg);
+
+ periodic_count = count;
+
+ spin_lock_irq(&rtc_lock);
+
+ rtc1_write(RTCL1LREG, count);
+ rtc1_write(RTCL1HREG, count >> 16);
+
+ spin_unlock_irq(&rtc_lock);
+ break;
+ case RTC_EPOCH_READ:
+ return put_user(epoch, (unsigned long __user *)arg);
+ case RTC_EPOCH_SET:
+ /* Doesn't support before 1900 */
+ if (arg < 1900)
+ return -EINVAL;
+
+ if (capable(CAP_SYS_TIME) == 0)
+ return -EACCES;
+
+ epoch = arg;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return rtc_do_ioctl(cmd, arg, FUNCTION_RTC_IOCTL);
+}
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+ spin_lock_irq(&rtc_lock);
+
+ if (rtc_status == RTC_OPEN) {
+ spin_unlock_irq(&rtc_lock);
+ return -EBUSY;
+ }
+
+ rtc_status = RTC_OPEN;
+ rtc_irq_data = 0;
+
+ spin_unlock_irq(&rtc_lock);
+
+ return 0;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+ if (file->f_flags & FASYNC)
+ (void)fasync_helper(-1, file, 0, &rtc_async_queue);
+
+ spin_lock_irq(&rtc_lock);
+
+ rtc1_write(ECMPLREG, 0);
+ rtc1_write(ECMPMREG, 0);
+ rtc1_write(ECMPHREG, 0);
+ rtc1_write(RTCL1LREG, 0);
+ rtc1_write(RTCL1HREG, 0);
+
+ rtc_status = RTC_RELEASE;
+
+ spin_unlock_irq(&rtc_lock);
+
+ disable_irq(ELAPSEDTIME_IRQ);
+ disable_irq(RTCLONG1_IRQ);
+
+ return 0;
+}
+
+static int rtc_fasync(int fd, struct file *file, int on)
+{
+ return fasync_helper(fd, file, on, &rtc_async_queue);
+}
+
+static struct file_operations rtc_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = rtc_read,
+ .poll = rtc_poll,
+ .ioctl = rtc_ioctl,
+ .open = rtc_open,
+ .release = rtc_release,
+ .fasync = rtc_fasync,
+};
+
+static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ spin_lock(&rtc_lock);
+ rtc2_write(RTCINTREG, ELAPSEDTIME_INT);
+
+ rtc_irq_data += 0x100;
+ rtc_irq_data &= ~0xff;
+ rtc_irq_data |= RTC_AF;
+ spin_unlock(&rtc_lock);
+
+ spin_lock(&rtc_lock);
+ if (rtc_callback)
+ rtc_callback->func(rtc_callback->private_data);
+ spin_unlock(&rtc_lock);
+
+ wake_up_interruptible(&rtc_wait);
+
+ kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t rtclong1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long count = periodic_count;
+
+ spin_lock(&rtc_lock);
+ rtc2_write(RTCINTREG, RTCLONG1_INT);
+
+ rtc1_write(RTCL1LREG, count);
+ rtc1_write(RTCL1HREG, count >> 16);
+
+ rtc_irq_data += 0x100;
+ rtc_irq_data &= ~0xff;
+ rtc_irq_data |= RTC_PF;
+ spin_unlock(&rtc_lock);
+
+ spin_lock(&rtc_task_lock);
+ if (rtc_callback)
+ rtc_callback->func(rtc_callback->private_data);
+ spin_unlock(&rtc_task_lock);
+
+ wake_up_interruptible(&rtc_wait);
+
+ kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
+
+ return IRQ_HANDLED;
+}
+
+int rtc_register(rtc_task_t *task)
+{
+ if (task == NULL || task->func == NULL)
+ return -EINVAL;
+
+ spin_lock_irq(&rtc_lock);
+ if (rtc_status == RTC_OPEN) {
+ spin_unlock_irq(&rtc_lock);
+ return -EBUSY;
+ }
+
+ spin_lock(&rtc_task_lock);
+ if (rtc_callback != NULL) {
+ spin_unlock(&rtc_task_lock);
+ spin_unlock_irq(&rtc_task_lock);
+ return -EBUSY;
+ }
+
+ rtc_callback = task;
+ spin_unlock(&rtc_task_lock);
+
+ rtc_status = RTC_OPEN;
+
+ spin_unlock_irq(&rtc_lock);
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(rtc_register);
+
+int rtc_unregister(rtc_task_t *task)
+{
+ spin_lock_irq(&rtc_task_lock);
+ if (task == NULL || rtc_callback != task) {
+ spin_unlock_irq(&rtc_task_lock);
+ return -ENXIO;
+ }
+
+ spin_lock(&rtc_lock);
+
+ rtc1_write(ECMPLREG, 0);
+ rtc1_write(ECMPMREG, 0);
+ rtc1_write(ECMPHREG, 0);
+ rtc1_write(RTCL1LREG, 0);
+ rtc1_write(RTCL1HREG, 0);
+
+ rtc_status = RTC_RELEASE;
+
+ spin_unlock(&rtc_lock);
+
+ rtc_callback = NULL;
+
+ spin_unlock_irq(&rtc_task_lock);
+
+ disable_irq(ELAPSEDTIME_IRQ);
+ disable_irq(RTCLONG1_IRQ);
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(rtc_unregister);
+
+int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+
+ spin_lock_irq(&rtc_task_lock);
+
+ if (rtc_callback != task)
+ retval = -ENXIO;
+ else
+ rtc_do_ioctl(cmd, arg, FUNCTION_RTC_CONTROL);
+
+ spin_unlock_irq(&rtc_task_lock);
+
+ return retval;
+}
+
+EXPORT_SYMBOL_GPL(rtc_control);
+
+static struct miscdevice rtc_miscdevice = {
+ .minor = RTC_MINOR,
+ .name = rtc_name,
+ .fops = &rtc_fops,
+};
+
+static int rtc_probe(struct device *dev)
+{
+ struct platform_device *pdev;
+ unsigned int irq;
+ int retval;
+
+ pdev = to_platform_device(dev);
+ if (pdev->num_resources != 2)
+ return -EBUSY;
+
+ rtc1_base = ioremap(pdev->resource[0].start, RTC1_SIZE);
+ if (rtc1_base == NULL)
+ return -EBUSY;
+
+ rtc2_base = ioremap(pdev->resource[1].start, RTC2_SIZE);
+ if (rtc2_base == NULL) {
+ iounmap(rtc1_base);
+ rtc1_base = NULL;
+ return -EBUSY;
+ }
+
+ retval = misc_register(&rtc_miscdevice);
+ if (retval < 0) {
+ iounmap(rtc1_base);
+ iounmap(rtc2_base);
+ rtc1_base = NULL;
+ rtc2_base = NULL;
+ return retval;
+ }
+
+ spin_lock_irq(&rtc_lock);
+
+ rtc1_write(ECMPLREG, 0);
+ rtc1_write(ECMPMREG, 0);
+ rtc1_write(ECMPHREG, 0);
+ rtc1_write(RTCL1LREG, 0);
+ rtc1_write(RTCL1HREG, 0);
+
+ rtc_status = RTC_RELEASE;
+ rtc_irq_data = 0;
+
+ spin_unlock_irq(&rtc_lock);
+
+ init_waitqueue_head(&rtc_wait);
+
+ irq = ELAPSEDTIME_IRQ;
+ retval = request_irq(irq, elapsedtime_interrupt, SA_INTERRUPT,
+ "elapsed_time", NULL);
+ if (retval == 0) {
+ irq = RTCLONG1_IRQ;
+ retval = request_irq(irq, rtclong1_interrupt, SA_INTERRUPT,
+ "rtclong1", NULL);
+ }
+
+ if (retval < 0) {
+ printk(KERN_ERR "rtc: IRQ%d is busy\n", irq);
+ if (irq == RTCLONG1_IRQ)
+ free_irq(ELAPSEDTIME_IRQ, NULL);
+ iounmap(rtc1_base);
+ iounmap(rtc2_base);
+ rtc1_base = NULL;
+ rtc2_base = NULL;
+ return retval;
+ }
+
+ disable_irq(ELAPSEDTIME_IRQ);
+ disable_irq(RTCLONG1_IRQ);
+
+ spin_lock_init(&rtc_task_lock);
+
+ printk(KERN_INFO "rtc: Real Time Clock of NEC VR4100 series\n");
+
+ return 0;
+}
+
+static int rtc_remove(struct device *dev)
+{
+ int retval;
+
+ retval = misc_deregister(&rtc_miscdevice);
+ if (retval < 0)
+ return retval;
+
+ free_irq(ELAPSEDTIME_IRQ, NULL);
+ free_irq(RTCLONG1_IRQ, NULL);
+ if (rtc1_base != NULL)
+ iounmap(rtc1_base);
+ if (rtc2_base != NULL)
+ iounmap(rtc2_base);
+
+ return 0;
+}
+
+static struct platform_device *rtc_platform_device;
+
+static struct device_driver rtc_device_driver = {
+ .name = rtc_name,
+ .bus = &platform_bus_type,
+ .probe = rtc_probe,
+ .remove = rtc_remove,
+};
+
+static int __devinit vr41xx_rtc_init(void)
+{
+ int retval;
+
+ switch (current_cpu_data.cputype) {
+ case CPU_VR4111:
+ case CPU_VR4121:
+ rtc_resource[0].start = RTC1_TYPE1_START;
+ rtc_resource[0].end = RTC1_TYPE1_END;
+ rtc_resource[1].start = RTC2_TYPE1_START;
+ rtc_resource[1].end = RTC2_TYPE1_END;
+ break;
+ case CPU_VR4122:
+ case CPU_VR4131:
+ case CPU_VR4133:
+ rtc_resource[0].start = RTC1_TYPE2_START;
+ rtc_resource[0].end = RTC1_TYPE2_END;
+ rtc_resource[1].start = RTC2_TYPE2_START;
+ rtc_resource[1].end = RTC2_TYPE2_END;
+ break;
+ default:
+ return -ENODEV;
+ break;
+ }
+
+ rtc_platform_device = platform_device_register_simple("RTC", -1, rtc_resource, RTC_NUM_RESOURCES);
+ if (IS_ERR(rtc_platform_device))
+ return PTR_ERR(rtc_platform_device);
+
+ retval = driver_register(&rtc_device_driver);
+ if (retval < 0)
+ platform_device_unregister(rtc_platform_device);
+
+ return retval;
+}
+
+static void __devexit vr41xx_rtc_exit(void)
+{
+ driver_unregister(&rtc_device_driver);
+
+ platform_device_unregister(rtc_platform_device);
+}
+
+module_init(vr41xx_rtc_init);
+module_exit(vr41xx_rtc_exit);
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 93bab3e4427c9..6229dd04ac314 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -221,9 +221,6 @@ enum {
#define DO_UPDATE(vc) CON_IS_VISIBLE(vc)
#endif
-static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data);
-static struct pm_dev *pm_con;
-
static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed)
{
unsigned short *p;
@@ -723,12 +720,6 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
}
vc->vc_kmalloced = 1;
vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
-
- if (!pm_con) {
- pm_con = pm_register(PM_SYS_DEV,
- PM_SYS_VGA,
- pm_con_request);
- }
}
return 0;
}
@@ -3218,24 +3209,6 @@ void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org)
}
}
-static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data)
-{
- switch (rqst)
- {
- case PM_RESUME:
- acquire_console_sem();
- unblank_screen();
- release_console_sem();
- break;
- case PM_SUSPEND:
- acquire_console_sem();
- do_blank_screen(0);
- release_console_sem();
- break;
- }
- return 0;
-}
-
/*
* Visible symbols for modules
*/
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index cfb509516e502..4ec7fff29b5d6 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -646,7 +646,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
struct ib_smp *smp,
struct ib_send_wr *send_wr)
{
- int ret, alloc_flags, solicited;
+ int ret, solicited;
unsigned long flags;
struct ib_mad_local_private *local;
struct ib_mad_private *mad_priv;
@@ -666,11 +666,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
if (!ret || !device->process_mad)
goto out;
- if (in_atomic() || irqs_disabled())
- alloc_flags = GFP_ATOMIC;
- else
- alloc_flags = GFP_KERNEL;
- local = kmalloc(sizeof *local, alloc_flags);
+ local = kmalloc(sizeof *local, GFP_ATOMIC);
if (!local) {
ret = -ENOMEM;
printk(KERN_ERR PFX "No memory for ib_mad_local_private\n");
@@ -678,7 +674,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
}
local->mad_priv = NULL;
local->recv_mad_agent = NULL;
- mad_priv = kmem_cache_alloc(ib_mad_cache, alloc_flags);
+ mad_priv = kmem_cache_alloc(ib_mad_cache, GFP_ATOMIC);
if (!mad_priv) {
ret = -ENOMEM;
printk(KERN_ERR PFX "No memory for local response MAD\n");
@@ -860,9 +856,7 @@ int ib_post_send_mad(struct ib_mad_agent *mad_agent,
}
/* Allocate MAD send WR tracking structure */
- mad_send_wr = kmalloc(sizeof *mad_send_wr,
- (in_atomic() || irqs_disabled()) ?
- GFP_ATOMIC : GFP_KERNEL);
+ mad_send_wr = kmalloc(sizeof *mad_send_wr, GFP_ATOMIC);
if (!mad_send_wr) {
printk(KERN_ERR PFX "No memory for "
"ib_mad_send_wr_private\n");
diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c
index c2e73933c62dd..c243cb6fdfc4a 100644
--- a/drivers/input/serio/hil_mlc.c
+++ b/drivers/input/serio/hil_mlc.c
@@ -72,7 +72,7 @@ EXPORT_SYMBOL(hil_mlc_unregister);
#define PREFIX "HIL MLC: "
static LIST_HEAD(hil_mlcs);
-static rwlock_t hil_mlcs_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(hil_mlcs_lock);
static struct timer_list hil_mlcs_kicker;
static int hil_mlcs_probe;
@@ -848,7 +848,7 @@ int hil_mlc_register(hil_mlc *mlc) {
mlc->istarted = 0;
mlc->ostarted = 0;
- mlc->lock = RW_LOCK_UNLOCKED;
+ rwlock_init(&mlc->lock);
init_MUTEX(&(mlc->osem));
init_MUTEX(&(mlc->isem));
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index e011f83fa5350..7629452dd64b0 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -779,10 +779,10 @@ static int __init hp_sdc_init(void)
uint8_t ts_sync[6];
struct semaphore s_sync;
- hp_sdc.lock = RW_LOCK_UNLOCKED;
- hp_sdc.ibf_lock = RW_LOCK_UNLOCKED;
- hp_sdc.rtq_lock = RW_LOCK_UNLOCKED;
- hp_sdc.hook_lock = RW_LOCK_UNLOCKED;
+ rwlock_init(&hp_sdc.lock);
+ rwlock_init(&hp_sdc.ibf_lock);
+ rwlock_init(&hp_sdc.rtq_lock);
+ rwlock_init(&hp_sdc.hook_lock);
hp_sdc.timer = NULL;
hp_sdc.hil = NULL;
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index 21271465bd2f2..4d7a0250d7e20 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -838,7 +838,7 @@ static struct pci_dev *dev_qs1000 __devinitdata = NULL;
static struct pci_dev *dev_qs3000 __devinitdata = NULL;
#ifdef __ISAPNP__
-static struct isapnp_device_id elsa_ids[] __initdata = {
+static struct isapnp_device_id elsa_ids[] __devinitdata = {
{ ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133),
ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133),
(unsigned long) "Elsa QS1000" },
@@ -848,7 +848,7 @@ static struct isapnp_device_id elsa_ids[] __initdata = {
{ 0, }
};
-static struct isapnp_device_id *ipid __initdata = &elsa_ids[0];
+static struct isapnp_device_id *ipid __devinitdata = &elsa_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
index 685fcc2d72567..a307fcb6c6349 100644
--- a/drivers/isdn/hisax/hfc_sx.c
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -1382,14 +1382,14 @@ hfcsx_card_msg(struct IsdnCardState *cs, int mt, void *arg)
}
#ifdef __ISAPNP__
-static struct isapnp_device_id hfc_ids[] __initdata = {
+static struct isapnp_device_id hfc_ids[] __devinitdata = {
{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620),
ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620),
(unsigned long) "Teles 16.3c2" },
{ 0, }
};
-static struct isapnp_device_id *ipid __initdata = &hfc_ids[0];
+static struct isapnp_device_id *ipid __devinitdata = &hfc_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index 3393370ce09e0..8390f16068534 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -516,7 +516,7 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
static struct pci_dev *dev_sedl __devinitdata = NULL;
#ifdef __ISAPNP__
-static struct isapnp_device_id sedl_ids[] __initdata = {
+static struct isapnp_device_id sedl_ids[] __devinitdata = {
{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
(unsigned long) "Speed win" },
@@ -526,7 +526,7 @@ static struct isapnp_device_id sedl_ids[] __initdata = {
{ 0, }
};
-static struct isapnp_device_id *ipid __initdata = &sedl_ids[0];
+static struct isapnp_device_id *ipid __devinitdata = &sedl_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c
index 81cb3b55e1b6a..c5b1f65f7275a 100644
--- a/drivers/isdn/hisax/teles3.c
+++ b/drivers/isdn/hisax/teles3.c
@@ -254,7 +254,7 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
#ifdef __ISAPNP__
-static struct isapnp_device_id teles_ids[] __initdata = {
+static struct isapnp_device_id teles_ids[] __devinitdata = {
{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
(unsigned long) "Teles 16.3 PnP" },
@@ -267,7 +267,7 @@ static struct isapnp_device_id teles_ids[] __initdata = {
{ 0, }
};
-static struct isapnp_device_id *ipid __initdata = &teles_ids[0];
+static struct isapnp_device_id *ipid __devinitdata = &teles_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index 36cfc4a482896..d2b6b8e72980d 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -49,7 +49,7 @@ static char *W6692Ver[] __initdata =
{"W6692 V00", "W6692 V01", "W6692 V10",
"W6692 V11"};
-static void
+static void __init
W6692Version(struct IsdnCardState *cs, char *s)
{
int val;
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index 9acb1bf40ba94..9f6c19ac12853 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -20,11 +20,9 @@
#include <media/saa7146.h>
-/* global variables */
-struct list_head saa7146_devices;
-struct semaphore saa7146_devices_lock;
+LIST_HEAD(saa7146_devices);
+DECLARE_MUTEX(saa7146_devices_lock);
-static int initialized = 0;
static int saa7146_num = 0;
unsigned int saa7146_debug = 0;
@@ -48,21 +46,15 @@ static void dump_registers(struct saa7146_dev* dev)
* gpio and debi helper functions
****************************************************************************/
-/* write "data" to the gpio-pin "pin" -- unused */
-void saa7146_set_gpio(struct saa7146_dev *dev, u8 pin, u8 data)
+void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
{
u32 value = 0;
- /* sanity check */
- if(pin > 3)
- return;
-
- /* read old register contents */
- value = saa7146_read(dev, GPIO_CTRL );
-
- value &= ~(0xff << (8*pin));
- value |= (data << (8*pin));
+ BUG_ON(port > 3);
+ value = saa7146_read(dev, GPIO_CTRL);
+ value &= ~(0xff << (8*port));
+ value |= (data << (8*port));
saa7146_write(dev, GPIO_CTRL, value);
}
@@ -238,19 +230,6 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt
}
/********************************************************************************/
-/* gpio functions */
-
-void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
-{
- u32 val = 0;
-
- val=saa7146_read(dev,GPIO_CTRL);
- val&=~(0xff << (8*(port)));
- val|=(data)<<(8*(port));
- saa7146_write(dev, GPIO_CTRL, val);
-}
-
-/********************************************************************************/
/* interrupt handler */
static irqreturn_t interrupt_hw(int irq, void *dev_id, struct pt_regs *regs)
{
@@ -527,12 +506,6 @@ int saa7146_register_extension(struct saa7146_extension* ext)
{
DEB_EE(("ext:%p\n",ext));
- if( 0 == initialized ) {
- INIT_LIST_HEAD(&saa7146_devices);
- init_MUTEX(&saa7146_devices_lock);
- initialized = 1;
- }
-
ext->driver.name = ext->name;
ext->driver.id_table = ext->pci_tbl;
ext->driver.probe = saa7146_init_one;
@@ -550,23 +523,6 @@ int saa7146_unregister_extension(struct saa7146_extension* ext)
return 0;
}
-static int __init saa7146_init_module(void)
-{
- if( 0 == initialized ) {
- INIT_LIST_HEAD(&saa7146_devices);
- init_MUTEX(&saa7146_devices_lock);
- initialized = 1;
- }
- return 0;
-}
-
-static void __exit saa7146_cleanup_module(void)
-{
-}
-
-module_init(saa7146_init_module);
-module_exit(saa7146_cleanup_module);
-
EXPORT_SYMBOL_GPL(saa7146_register_extension);
EXPORT_SYMBOL_GPL(saa7146_unregister_extension);
diff --git a/drivers/media/dvb/b2c2/b2c2-common.c b/drivers/media/dvb/b2c2/b2c2-common.c
index cb42d44f4f986..000d60c405e37 100644
--- a/drivers/media/dvb/b2c2/b2c2-common.c
+++ b/drivers/media/dvb/b2c2/b2c2-common.c
@@ -158,7 +158,7 @@ static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
return 0;
}
-int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
{
u32 div;
unsigned char bs = 0;
diff --git a/drivers/media/dvb/b2c2/skystar2.c b/drivers/media/dvb/b2c2/skystar2.c
index fba10993d4e47..336c178fcd5fc 100644
--- a/drivers/media/dvb/b2c2/skystar2.c
+++ b/drivers/media/dvb/b2c2/skystar2.c
@@ -5,14 +5,14 @@
* Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
*
* FIX: DISEQC Tone Burst in flexcop_diseqc_ioctl()
- * FIX: FULL soft DiSEqC for skystar2 (FlexCopII rev 130) VP310 equipped
+ * FIX: FULL soft DiSEqC for skystar2 (FlexCopII rev 130) VP310 equipped
* Vincenzo Di Massa, hawk.it at tiscalinet.it
- *
+ *
* Converted to Linux coding style
* Misc reorganization, polishing, restyling
- * Roberto Ragusa, r.ragusa at libero.it
- *
- * Added hardware filtering support,
+ * Roberto Ragusa, skystar2-c5b8 at robertoragusa dot it
+ *
+ * Added hardware filtering support,
* Niklas Peinecke, peinecke at gdv.uni-hannover.de
*
*
@@ -231,8 +231,8 @@ static void fixchipaddr(u32 device, u32 bus, u32 addr, u32 *ret)
{
if (device == 0x20000000)
*ret = bus | ((addr >> 8) & 3);
-
- *ret = bus;
+ else
+ *ret = bus;
}
static u32 flex_i2c_read(struct adapter *adapter, u32 device, u32 bus, u32 addr, u8 *buf, u32 len)
@@ -1968,7 +1968,7 @@ static int driver_initialize(struct pci_dev *pdev)
ctrl_enable_mac(adapter, 1);
}
- adapter->lock = SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&adapter->lock);
out:
return ret;
@@ -1996,10 +1996,6 @@ static void driver_halt(struct pci_dev *pdev)
free_adapter_object(adapter);
pci_set_drvdata(pdev, NULL);
-
- pci_disable_device(pdev);
- pci_release_region(pdev, 1);
- pci_release_region(pdev, 0);
}
static int dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
@@ -2356,7 +2352,7 @@ static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
return 0;
}
-int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
{
u32 div;
unsigned char bs = 0;
@@ -2633,7 +2629,7 @@ static struct pci_driver skystar2_pci_driver = {
static int skystar2_init(void)
{
- return pci_module_init(&skystar2_pci_driver);
+ return pci_register_driver(&skystar2_pci_driver);
}
static void skystar2_cleanup(void)
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index bc7b48ed176ec..e7d11e0667a8b 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -5,9 +5,11 @@ config DVB_BT8XX
select DVB_SP887X
select DVB_NXT6000
select DVB_CX24110
+ select DVB_OR51211
help
Support for PCI cards based on the Bt8xx PCI bridge. Examples are
- the Nebula cards, the Pinnacle PCTV cards and Twinhan DST cards.
+ the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards and
+ pcHDTV HD2000 cards.
Since these cards have no MPEG decoder onboard, they transmit
only compressed MPEG data over the PCI bus, so you need
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index 7968bfef30455..213ff79020242 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -55,10 +55,10 @@ static unsigned int bt878_verbose = 1;
static unsigned int bt878_debug;
module_param_named(verbose, bt878_verbose, int, 0444);
-MODULE_PARM_DESC(bt878_verbose,
+MODULE_PARM_DESC(verbose,
"verbose startup messages, default is 1 (yes)");
module_param_named(debug, bt878_debug, int, 0644);
-MODULE_PARM_DESC(bt878_debug, "Turn on/off debugging (default:off).");
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
int bt878_num;
struct bt878 bt878[BT878_MAX];
@@ -381,21 +381,6 @@ bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *
EXPORT_SYMBOL(bt878_device_control);
-struct bt878 *bt878_find_by_i2c_adap(struct i2c_adapter *adapter)
-{
- unsigned int card_nr;
-
- printk("bt878 find by dvb adap: checking \"%s\"\n",adapter->name);
- for (card_nr = 0; card_nr < bt878_num; card_nr++) {
- if (bt878[card_nr].adapter == adapter)
- return &bt878[card_nr];
- }
- printk("bt878 find by dvb adap: NOT found \"%s\"\n",adapter->name);
- return NULL;
-}
-
-EXPORT_SYMBOL(bt878_find_by_i2c_adap);
-
/***********************/
/* PCI device handling */
/***********************/
@@ -578,7 +563,7 @@ static int bt878_init_module(void)
/* later we register inside of bt878_find_audio_dma()
* because we may want to ignore certain cards */
bt878_pci_driver_registered = 1;
- return pci_module_init(&bt878_pci_driver);
+ return pci_register_driver(&bt878_pci_driver);
}
static void bt878_cleanup_module(void)
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 859946703d4b3..eac83768dfd0e 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -998,7 +998,7 @@ struct dvb_frontend* dst_attach(const struct dst_config* config,
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/bt8xx/dst_priv.h b/drivers/media/dvb/bt8xx/dst_priv.h
index b3d5e6fc6d13d..80488aa628b40 100644
--- a/drivers/media/dvb/bt8xx/dst_priv.h
+++ b/drivers/media/dvb/bt8xx/dst_priv.h
@@ -34,4 +34,3 @@ struct bt878;
int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp);
-struct bt878 *bt878_find_by_i2c_adap(struct i2c_adapter *adap);
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index 0f8614cebd53b..b735397f59aad 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -133,7 +133,7 @@ static int thomson_dtt7579_demod_init(struct dvb_frontend* fe)
static u8 mt352_reset [] = { 0x50, 0x80 };
static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 };
- static u8 mt352_gpp_ctl_cfg [] = { 0x75, 0x33 };
+ static u8 mt352_gpp_ctl_cfg [] = { 0x8C, 0x33 };
static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
@@ -369,6 +369,63 @@ static struct dst_config dst_config = {
};
+static int or51211_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+ struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv;
+
+ return request_firmware(fw, name, &bt->bt->dev->dev);
+}
+
+static void or51211_setmode(struct dvb_frontend * fe, int mode)
+{
+ struct dvb_bt8xx_card *bt = fe->dvb->priv;
+ bttv_write_gpio(bt->bttv_nr, 0x0002, mode); /* Reset */
+ msleep(20);
+}
+
+static void or51211_reset(struct dvb_frontend * fe)
+{
+ struct dvb_bt8xx_card *bt = fe->dvb->priv;
+
+ /* RESET DEVICE
+ * reset is controled by GPIO-0
+ * when set to 0 causes reset and when to 1 for normal op
+ * must remain reset for 128 clock cycles on a 50Mhz clock
+ * also PRM1 PRM2 & PRM4 are controled by GPIO-1,GPIO-2 & GPIO-4
+ * We assume that the reset has be held low long enough or we
+ * have been reset by a power on. When the driver is unloaded
+ * reset set to 0 so if reloaded we have been reset.
+ */
+ /* reset & PRM1,2&4 are outputs */
+ int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F);
+ if (ret != 0) {
+ printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR "
+ "(%i)\n", ret);
+ }
+ bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000); /* Reset */
+ msleep(20);
+ /* Now set for normal operation */
+ bttv_write_gpio(bt->bttv_nr, 0x0001F, 0x0001);
+ /* wait for operation to begin */
+ msleep(500);
+}
+
+static void or51211_sleep(struct dvb_frontend * fe)
+{
+ struct dvb_bt8xx_card *bt = fe->dvb->priv;
+ bttv_write_gpio(bt->bttv_nr, 0x0001, 0x0000);
+}
+
+static struct or51211_config or51211_config = {
+
+ .demod_address = 0x15,
+ .request_firmware = or51211_request_firmware,
+ .setmode = or51211_setmode,
+ .reset = or51211_reset,
+ .sleep = or51211_sleep,
+};
+
+
static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
@@ -458,6 +515,13 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
break;
}
break;
+
+ case BTTV_PC_HDTV:
+ card->fe = or51211_attach(&or51211_config, card->i2c_adapter);
+ if (card->fe != NULL) {
+ break;
+ }
+ break;
}
if (card->fe == NULL) {
@@ -637,6 +701,12 @@ static int dvb_bt8xx_probe(struct device *dev)
* RISC+FIFO ENABLE */
break;
+ case BTTV_PC_HDTV:
+ card->gpio_mode = 0x0100EC7B;
+ card->op_sync_orin = 0;
+ card->irq_err_ignore = 0;
+ break;
+
default:
printk(KERN_WARNING "dvb_bt8xx: Unknown bttv card type: %d.\n",
sub->core->type);
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
index f9bf4e2e4f308..80ef189f930f3 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
@@ -34,6 +34,7 @@
#include "dst.h"
#include "nxt6000.h"
#include "cx24110.h"
+#include "or51211.h"
struct dvb_bt8xx_card {
struct semaphore lock;
diff --git a/drivers/media/dvb/dibusb/Kconfig b/drivers/media/dvb/dibusb/Kconfig
index 1352ceba82bdc..74dfc73ae5b01 100644
--- a/drivers/media/dvb/dibusb/Kconfig
+++ b/drivers/media/dvb/dibusb/Kconfig
@@ -13,7 +13,7 @@ config DVB_DIBUSB
TwinhanDTV USB-Ter (VP7041)
TwinhanDTV Magic Box (VP7041e)
- KWorld V-Stream XPERT DTV - DVB-T USB
+ KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
Hama DVB-T USB-Box
DiBcom reference devices (non-public)
Ultima Electronic/Artec T1 USB TVBOX
@@ -23,6 +23,7 @@ config DVB_DIBUSB
Artec T1 USB1.1 and USB2.0 boxes
Yakumo/Typhoon DVB-T USB2.0
Hanftek UMT-010 USB2.0
+ Hauppauge WinTV NOVA-T USB2
The VP7041 seems to be identical to "CTS Portable" (Chinese
Television System).
diff --git a/drivers/media/dvb/dibusb/Makefile b/drivers/media/dvb/dibusb/Makefile
index a0319f8cbeaea..e941c508624ef 100644
--- a/drivers/media/dvb/dibusb/Makefile
+++ b/drivers/media/dvb/dibusb/Makefile
@@ -4,7 +4,7 @@ dvb-dibusb-objs = dvb-dibusb-core.o \
dvb-dibusb-firmware.o \
dvb-dibusb-remote.o \
dvb-dibusb-usb.o \
- dvb-dibusb-pid.o
+ dvb-fe-dtt200u.o
obj-$(CONFIG_DVB_DIBUSB) += dvb-dibusb.o
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-core.c b/drivers/media/dvb/dibusb/dvb-dibusb-core.c
index 503ca57c11986..26235f9247e45 100644
--- a/drivers/media/dvb/dibusb/dvb-dibusb-core.c
+++ b/drivers/media/dvb/dibusb/dvb-dibusb-core.c
@@ -42,11 +42,16 @@ static int pid_parse;
module_param(pid_parse, int, 0644);
MODULE_PARM_DESC(pid_parse, "enable pid parsing (filtering) when running at USB2.0");
-static int rc_query_interval;
+static int rc_query_interval = 100;
module_param(rc_query_interval, int, 0644);
MODULE_PARM_DESC(rc_query_interval, "interval in msecs for remote control query (default: 100; min: 40)");
+static int rc_key_repeat_count = 2;
+module_param(rc_key_repeat_count, int, 0644);
+MODULE_PARM_DESC(rc_key_repeat_count, "how many key repeats will be dropped before passing the key event again (default: 2)");
+
/* Vendor IDs */
+#define USB_VID_ADSTECH 0x06e1
#define USB_VID_ANCHOR 0x0547
#define USB_VID_AVERMEDIA 0x14aa
#define USB_VID_COMPRO 0x185b
@@ -55,13 +60,16 @@ MODULE_PARM_DESC(rc_query_interval, "interval in msecs for remote control query
#define USB_VID_DIBCOM 0x10b8
#define USB_VID_EMPIA 0xeb1a
#define USB_VID_GRANDTEC 0x5032
-#define USB_VID_HYPER_PALTEK 0x1025
#define USB_VID_HANFTEK 0x15f4
+#define USB_VID_HAUPPAUGE 0x2040
+#define USB_VID_HYPER_PALTEK 0x1025
#define USB_VID_IMC_NETWORKS 0x13d3
#define USB_VID_TWINHAN 0x1822
#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
/* Product IDs */
+#define USB_PID_ADSTECH_USB2_COLD 0xa333
+#define USB_PID_ADSTECH_USB2_WARM 0xa334
#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001
#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002
#define USB_PID_COMPRO_DVBU2000_COLD 0xd000
@@ -90,9 +98,11 @@ MODULE_PARM_DESC(rc_query_interval, "interval in msecs for remote control query
#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e
#define USB_PID_UNK_HYPER_PALTEK_WARM 0x005f
#define USB_PID_HANFTEK_UMT_010_COLD 0x0001
-#define USB_PID_HANFTEK_UMT_010_WARM 0x0025
+#define USB_PID_HANFTEK_UMT_010_WARM 0x0015
#define USB_PID_YAKUMO_DTT200U_COLD 0x0201
#define USB_PID_YAKUMO_DTT200U_WARM 0x0301
+#define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300
+#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301
/* USB Driver stuff
* table of devices that this driver is working with
@@ -109,10 +119,6 @@ static struct usb_device_id dib_table [] = {
/* 00 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB_COLD)},
/* 01 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB_WARM)},
/* 02 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_YAKUMO_DTT200U_COLD) },
-
-/* the following device is actually not supported, but when loading the
- * correct firmware (ie. its usb ids will change) everything works fine then
- */
/* 03 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_YAKUMO_DTT200U_WARM) },
/* 04 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) },
@@ -143,16 +149,20 @@ static struct usb_device_id dib_table [] = {
/* 28 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) },
/* 29 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) },
+/* 30 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_COLD) },
+/* 31 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_WARM) },
+/* 32 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_COLD) },
+/* 33 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) },
/*
* activate the following define when you have one of the devices and want to
* build it from build-2.6 in dvb-kernel
*/
-// #define CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
+// #define CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
-/* 30 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
-/* 31 */ { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ULTIMA_TVBOX_USB2_FX_COLD) },
-/* 32 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_USB2_FX_WARM) },
-/* 33 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_DIBCOM_ANCHOR_2135_COLD) },
+/* 34 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
+/* 35 */ { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ULTIMA_TVBOX_USB2_FX_COLD) },
+/* 36 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_USB2_FX_WARM) },
+/* 37 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_DIBCOM_ANCHOR_2135_COLD) },
#endif
{ } /* Terminating entry */
};
@@ -193,13 +203,17 @@ static struct dibusb_demod dibusb_demod[] = {
254,
{ 0xf, 0 },
},
+ { DTT200U_FE,
+ 8,
+ { 0xff,0 }, /* there is no i2c bus in this device */
+ }
};
static struct dibusb_device_class dibusb_device_classes[] = {
{ .id = DIBUSB1_1, .usb_ctrl = &dibusb_usb_ctrl[0],
.firmware = "dvb-dibusb-5.0.0.11.fw",
.pipe_cmd = 0x01, .pipe_data = 0x02,
- .urb_count = 3, .urb_buffer_size = 4096,
+ .urb_count = 7, .urb_buffer_size = 4096,
DIBUSB_RC_NEC_PROTOCOL,
&dibusb_demod[DIBUSB_DIB3000MB],
&dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON],
@@ -207,7 +221,7 @@ static struct dibusb_device_class dibusb_device_classes[] = {
{ DIBUSB1_1_AN2235, &dibusb_usb_ctrl[1],
"dvb-dibusb-an2235-1.fw",
0x01, 0x02,
- 3, 4096,
+ 7, 4096,
DIBUSB_RC_NEC_PROTOCOL,
&dibusb_demod[DIBUSB_DIB3000MB],
&dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON],
@@ -215,20 +229,43 @@ static struct dibusb_device_class dibusb_device_classes[] = {
{ DIBUSB2_0,&dibusb_usb_ctrl[2],
"dvb-dibusb-6.0.0.5.fw",
0x01, 0x06,
- 3, 188*210,
+ 7, 4096,
DIBUSB_RC_NEC_PROTOCOL,
&dibusb_demod[DIBUSB_DIB3000MC],
&dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5],
},
{ UMT2_0, &dibusb_usb_ctrl[2],
- "dvb-dibusb-umt-1.fw",
- 0x01, 0x02,
- 15, 188*21,
+ "dvb-dibusb-umt-2.fw",
+ 0x01, 0x06,
+ 20, 512,
DIBUSB_RC_NO,
&dibusb_demod[DIBUSB_MT352],
-// &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5],
&dibusb_tuner[DIBUSB_TUNER_CABLE_LG_TDTP_E102P],
},
+ { DIBUSB2_0B,&dibusb_usb_ctrl[2],
+ "dvb-dibusb-adstech-usb2-1.fw",
+ 0x01, 0x06,
+ 7, 4096,
+ DIBUSB_RC_NEC_PROTOCOL,
+ &dibusb_demod[DIBUSB_DIB3000MB],
+ &dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON],
+ },
+ { NOVAT_USB2,&dibusb_usb_ctrl[2],
+ "dvb-dibusb-nova-t-1.fw",
+ 0x01, 0x06,
+ 7, 4096,
+ DIBUSB_RC_HAUPPAUGE_PROTO,
+ &dibusb_demod[DIBUSB_DIB3000MC],
+ &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5],
+ },
+ { DTT200U,&dibusb_usb_ctrl[2],
+ "dvb-dtt200u-1.fw",
+ 0x01, 0x02,
+ 7, 4096,
+ DIBUSB_RC_NO,
+ &dibusb_demod[DTT200U_FE],
+ NULL, /* no explicit tuner/pll-programming necessary (it has the ENV57H1XD5) */
+ },
};
static struct dibusb_usb_device dibusb_devices[] = {
@@ -287,30 +324,40 @@ static struct dibusb_usb_device dibusb_devices[] = {
{ &dib_table[27], NULL },
{ NULL },
},
- { "AVermedia/Yakumo/Hama/Typhoon DVB-T USB2.0",
- &dibusb_device_classes[UMT2_0],
+ { "Hauppauge WinTV NOVA-T USB2",
+ &dibusb_device_classes[NOVAT_USB2],
+ { &dib_table[30], NULL },
+ { &dib_table[31], NULL },
+ },
+ { "DTT200U (Yakumo/Hama/Typhoon) DVB-T USB2.0",
+ &dibusb_device_classes[DTT200U],
{ &dib_table[2], NULL },
- { NULL },
+ { &dib_table[3], NULL },
},
{ "Hanftek UMT-010 DVB-T USB2.0",
&dibusb_device_classes[UMT2_0],
{ &dib_table[28], NULL },
{ &dib_table[29], NULL },
},
+ { "KWorld/ADSTech Instant DVB-T USB 2.0",
+ &dibusb_device_classes[DIBUSB2_0B],
+ { &dib_table[32], NULL },
+ { &dib_table[33], NULL }, /* device ID with default DIBUSB2_0-firmware */
+ },
#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
{ "Artec T1 USB1.1 TVBOX with AN2235 (misdesigned)",
&dibusb_device_classes[DIBUSB1_1_AN2235],
- { &dib_table[30], NULL },
+ { &dib_table[34], NULL },
{ NULL },
},
{ "Artec T1 USB2.0 TVBOX with FX2 IDs (misdesigned, please report the warm ID)",
- &dibusb_device_classes[DIBUSB2_0],
- { &dib_table[31], NULL },
- { &dib_table[32], NULL }, /* undefined, it could be that the device will get another USB ID in warm state */
+ &dibusb_device_classes[DTT200U],
+ { &dib_table[35], NULL },
+ { &dib_table[36], NULL }, /* undefined, it could be that the device will get another USB ID in warm state */
},
{ "DiBcom USB1.1 DVB-T reference design (MOD3000) with AN2135 default IDs",
&dibusb_device_classes[DIBUSB1_1],
- { &dib_table[33], NULL },
+ { &dib_table[37], NULL },
{ NULL },
},
#endif
@@ -322,7 +369,6 @@ static int dibusb_exit(struct usb_dibusb *dib)
dibusb_remote_exit(dib);
dibusb_fe_exit(dib);
dibusb_i2c_exit(dib);
- dibusb_pid_list_exit(dib);
dibusb_dvb_exit(dib);
dibusb_urb_exit(dib);
deb_info("init_state should be zero now: %x\n",dib->init_state);
@@ -341,7 +387,6 @@ static int dibusb_init(struct usb_dibusb *dib)
if ((ret = dibusb_urb_init(dib)) ||
(ret = dibusb_dvb_init(dib)) ||
- (ret = dibusb_pid_list_init(dib)) ||
(ret = dibusb_i2c_init(dib))) {
dibusb_exit(dib);
return ret;
@@ -356,30 +401,62 @@ static int dibusb_init(struct usb_dibusb *dib)
return 0;
}
+static struct dibusb_usb_device * dibusb_device_class_quirk(struct usb_device *udev, struct dibusb_usb_device *dev)
+{
+ int i;
+
+ /* Quirk for the Kworld/ADSTech Instant USB2.0 device. It has the same USB
+ * IDs like the USB1.1 KWorld after loading the firmware. Which is a bad
+ * idea and make this quirk necessary.
+ */
+ if (dev->dev_cl->id == DIBUSB1_1 && udev->speed == USB_SPEED_HIGH) {
+ info("this seems to be the Kworld/ADSTech Instant USB2.0 device or equal.");
+ for (i = 0; i < sizeof(dibusb_devices)/sizeof(struct dibusb_usb_device); i++) {
+ if (dibusb_devices[i].dev_cl->id == DIBUSB2_0B) {
+ dev = &dibusb_devices[i];
+ break;
+ }
+ }
+ }
+
+ return dev;
+}
+
static struct dibusb_usb_device * dibusb_find_device (struct usb_device *udev,int *cold)
{
int i,j;
+ struct dibusb_usb_device *dev = NULL;
*cold = -1;
+
for (i = 0; i < sizeof(dibusb_devices)/sizeof(struct dibusb_usb_device); i++) {
for (j = 0; j < DIBUSB_ID_MAX_NUM && dibusb_devices[i].cold_ids[j] != NULL; j++) {
deb_info("check for cold %x %x\n",dibusb_devices[i].cold_ids[j]->idVendor, dibusb_devices[i].cold_ids[j]->idProduct);
if (dibusb_devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
dibusb_devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
*cold = 1;
- return &dibusb_devices[i];
+ dev = &dibusb_devices[i];
+ break;
}
}
+ if (dev != NULL)
+ break;
+
for (j = 0; j < DIBUSB_ID_MAX_NUM && dibusb_devices[i].warm_ids[j] != NULL; j++) {
deb_info("check for warm %x %x\n",dibusb_devices[i].warm_ids[j]->idVendor, dibusb_devices[i].warm_ids[j]->idProduct);
if (dibusb_devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
dibusb_devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
*cold = 0;
- return &dibusb_devices[i];
+ dev = &dibusb_devices[i];
+ break;
}
}
}
- return NULL;
+
+ if (dev != NULL)
+ dev = dibusb_device_class_quirk(udev,dev);
+
+ return dev;
}
/*
@@ -418,6 +495,7 @@ static int dibusb_probe(struct usb_interface *intf,
/* store parameters to structures */
dib->rc_query_interval = rc_query_interval;
dib->pid_parse = pid_parse;
+ dib->rc_key_repeat_count = rc_key_repeat_count;
usb_set_intfdata(intf, dib);
@@ -446,7 +524,7 @@ static void dibusb_disconnect(struct usb_interface *intf)
}
/* usb specific object needed to register this driver with the usb subsystem */
-struct usb_driver dibusb_driver = {
+static struct usb_driver dibusb_driver = {
.owner = THIS_MODULE,
.name = DRIVER_DESC,
.probe = dibusb_probe,
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c b/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c
index d7dd6e747c5d4..04e54ec093f0b 100644
--- a/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c
+++ b/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c
@@ -22,46 +22,34 @@ static u32 urb_compl_count;
void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
{
struct usb_dibusb *dib = urb->context;
- int ret;
deb_ts("urb complete feedcount: %d, status: %d, length: %d\n",dib->feedcount,urb->status,
urb->actual_length);
urb_compl_count++;
- if (urb_compl_count % 500 == 0)
+ if (urb_compl_count % 1000 == 0)
deb_info("%d urbs completed so far.\n",urb_compl_count);
switch (urb->status) {
case 0: /* success */
case -ETIMEDOUT: /* NAK */
break;
- case -ECONNRESET: /* unlink */
+ case -ECONNRESET: /* kill */
case -ENOENT:
case -ESHUTDOWN:
return;
default: /* error */
- warn("urb completition error %d.", urb->status);
+ deb_ts("urb completition error %d.", urb->status);
+ break;
}
- if (dib->feedcount > 0) {
- deb_ts("URB return len: %d\n",urb->actual_length);
- if (urb->actual_length % 188)
- deb_ts("TS Packets: %d, %d\n", urb->actual_length/188,urb->actual_length % 188);
-
- /* Francois recommends to drop not full-filled packets, even if they may
- * contain valid TS packets, at least for USB1.1
- *
- * if (urb->actual_length == dib->dibdev->parm->default_size && dib->dvb_is_ready) */
+ if (dib->feedcount > 0 && urb->actual_length > 0) {
if (dib->init_state & DIBUSB_STATE_DVB)
dvb_dmx_swfilter(&dib->demux, (u8*) urb->transfer_buffer,urb->actual_length);
- else
- deb_ts("URB dropped because of the "
- "actual_length or !dvb_is_ready (%d).\n",dib->init_state & DIBUSB_STATE_DVB);
} else
deb_ts("URB dropped because of feedcount.\n");
- ret = usb_submit_urb(urb,GFP_ATOMIC);
- deb_ts("urb resubmitted, (%d)\n",ret);
+ usb_submit_urb(urb,GFP_ATOMIC);
}
static int dibusb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
@@ -77,7 +65,6 @@ static int dibusb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
/*
* stop feed before setting a new pid if there will be no pid anymore
*/
-// if ((dib->dibdev->parm->firmware_bug && dib->feedcount) ||
if (newfeedcount == 0) {
deb_ts("stop feeding\n");
if (dib->xfer_ops.fifo_ctrl != NULL) {
@@ -86,23 +73,20 @@ static int dibusb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
return -ENODEV;
}
}
+ dibusb_streaming(dib,0);
}
dib->feedcount = newfeedcount;
- /* get a free pid from the list and activate it on the device
- * specific pid_filter
- */
- if (dib->pid_parse)
- dibusb_ctrl_pid(dib,dvbdmxfeed,onoff);
+ /* activate the pid on the device specific pid_filter */
+ deb_ts("setting pid: %5d %04x at index %d '%s'\n",dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ? "on" : "off");
+ if (dib->pid_parse && dib->xfer_ops.pid_ctrl != NULL)
+ dib->xfer_ops.pid_ctrl(dib->fe,dvbdmxfeed->index,dvbdmxfeed->pid,onoff);
/*
- * start the feed, either if there is the firmware bug or
- * if this was the first pid to set and there is still a pid for
- * reception.
+ * start the feed if this was the first pid to set and there is still a pid
+ * for reception.
*/
-
-// if ((dib->dibdev->parm->firmware_bug)
if (dib->feedcount == onoff && dib->feedcount > 0) {
deb_ts("controlling pid parser\n");
@@ -142,12 +126,8 @@ int dibusb_dvb_init(struct usb_dibusb *dib)
urb_compl_count = 0;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,4)
- if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC)) < 0) {
-#else
- if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC ,
+ if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC,
THIS_MODULE)) < 0) {
-#endif
deb_info("dvb_register_adapter failed: error %d", ret);
goto err;
}
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c b/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c
index 30e777521bf30..2ed89488c7c49 100644
--- a/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c
+++ b/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c
@@ -14,7 +14,7 @@
#include <linux/usb.h>
-int dibusb_i2c_msg(struct usb_dibusb *dib, u8 addr,
+static int dibusb_i2c_msg(struct usb_dibusb *dib, u8 addr,
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
{
u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */
@@ -125,27 +125,6 @@ static int dibusb_tuner_quirk(struct usb_dibusb *dib)
return 0;
}
-/* there is a ugly pid_filter in the firmware of the umt devices, it is accessible
- * by i2c address 0x8. Don't know how to deactivate it and how many rows it has.
- */
-static int dibusb_umt_pid_control(struct dvb_frontend *fe, int index, int pid, int onoff)
-{
- struct usb_dibusb *dib = fe->dvb->priv;
- u8 b[3];
- b[0] = index;
- if (onoff) {
- b[1] = (pid >> 8) & 0xff;
- b[2] = pid & 0xff;
- } else {
- b[1] = 0;
- b[2] = 0;
- }
- dibusb_i2c_msg(dib, 0x8, b, 3, NULL,0);
- dibusb_set_streaming_mode(dib,0);
- dibusb_set_streaming_mode(dib,1);
- return 0;
-}
-
int dibusb_fe_init(struct usb_dibusb* dib)
{
struct dib3000_config demod_cfg;
@@ -160,6 +139,8 @@ int dibusb_fe_init(struct usb_dibusb* dib)
demod_cfg.pll_set = dibusb_general_pll_set;
demod_cfg.pll_init = dibusb_general_pll_init;
+ deb_info("demod id: %d %d\n",dib->dibdev->dev_cl->demod->id,DTT200U_FE);
+
switch (dib->dibdev->dev_cl->demod->id) {
case DIBUSB_DIB3000MB:
dib->fe = dib3000mb_attach(&demod_cfg,&dib->i2c_adap,&dib->xfer_ops);
@@ -170,7 +151,9 @@ int dibusb_fe_init(struct usb_dibusb* dib)
case DIBUSB_MT352:
mt352_hanftek_umt_010_config.demod_address = dib->dibdev->dev_cl->demod->i2c_addrs[i];
dib->fe = mt352_attach(&mt352_hanftek_umt_010_config, &dib->i2c_adap);
- dib->xfer_ops.pid_ctrl = dibusb_umt_pid_control;
+ break;
+ case DTT200U_FE:
+ dib->fe = dtt200u_fe_attach(dib,&dib->xfer_ops);
break;
}
if (dib->fe != NULL) {
@@ -178,6 +161,8 @@ int dibusb_fe_init(struct usb_dibusb* dib)
break;
}
}
+ /* if a frontend was found */
+ if (dib->fe != NULL) {
if (dib->fe->ops->sleep != NULL)
dib->fe_sleep = dib->fe->ops->sleep;
dib->fe->ops->sleep = dibusb_hw_sleep;
@@ -192,6 +177,7 @@ int dibusb_fe_init(struct usb_dibusb* dib)
/* check which tuner is mounted on this device, in case this is unsure */
dibusb_tuner_quirk(dib);
}
+ }
if (dib->fe == NULL) {
err("A frontend driver was not found for device '%s'.",
dib->dibdev->name);
@@ -205,6 +191,7 @@ int dibusb_fe_init(struct usb_dibusb* dib)
return -ENODEV;
}
}
+
return 0;
}
@@ -274,10 +261,10 @@ static int thomson_cable_eu_pll_set(struct dvb_frontend_parameters *fep, u8 pllb
static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend_parameters *fep, u8 pllbuf[4])
{
- u32 freq = fep->frequency;
- u32 tfreq = ((freq + 36125000)*6 + 500000) / 1000000;
+ u32 freq_khz = fep->frequency / 1000;
+ u32 tfreq = ((freq_khz + 36125)*6 + 500) / 1000;
u8 TA, T210, R210, ctrl1, cp210, p4321;
- if (freq > 858000000) {
+ if (freq_khz > 858000) {
err("frequency cannot be larger than 858 MHz.");
return -EINVAL;
}
@@ -289,17 +276,17 @@ static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend_parameters *fe
ctrl1 = (1 << 7) | (TA << 6) | (T210 << 3) | R210;
// ******** CHARGE PUMP CONFIG vs RF FREQUENCIES *****************
- if (freq < 470000000)
+ if (freq_khz < 470000)
cp210 = 2; // VHF Low and High band ch E12 to E4 to E12
- else if (freq < 526000000)
+ else if (freq_khz < 526000)
cp210 = 4; // UHF band Ch E21 to E27
else // if (freq < 862000000)
cp210 = 5; // UHF band ch E28 to E69
//********************* BW select *******************************
- if (freq < 153000000)
+ if (freq_khz < 153000)
p4321 = 1; // BW selected for VHF low
- else if (freq < 470000000)
+ else if (freq_khz < 470000)
p4321 = 2; // BW selected for VHF high E5 to E12
else // if (freq < 862000000)
p4321 = 4; // BW selection for UHF E21 to E69
@@ -341,8 +328,6 @@ static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend_parameters *fe
* BSn = 0 corresponding port is off, high-impedance state (at power-on)
* BSn = 1 corresponding port is on
*/
-
-
static int panasonic_cofdm_env77h11d5_tda6650_init(struct dvb_frontend *fe, u8 pllbuf[4])
{
pllbuf[0] = 0x0b;
@@ -437,55 +422,54 @@ static int panasonic_cofdm_env77h11d5_tda6650_set (struct dvb_frontend_parameter
* 0 1 c2 (always valid)
* 1 0 c4
* 1 1 c6
- *
- *
- *
*/
-
static int lg_tdtp_e102p_tua6034(struct dvb_frontend_parameters* fep, u8 pllbuf[4])
{
u32 div;
- u8 p3210, p4;
+ u8 p210, p3;
#define TUNER_MUL 62500
div = (fep->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL;
+// div = ((fep->frequency/1000 + 36166) * 6) / 1000;
if (fep->frequency < 174500000)
- p3210 = 1; // not supported by the tdtp_e102p
+ p210 = 1; // not supported by the tdtp_e102p
else if (fep->frequency < 230000000) // VHF
- p3210 = 2;
+ p210 = 2;
else
- p3210 = 4;
+ p210 = 4;
if (fep->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
- p4 = 0;
+ p3 = 0;
else
- p4 = 1;
+ p3 = 1;
pllbuf[0] = (div >> 8) & 0x7f;
pllbuf[1] = div & 0xff;
pllbuf[2] = 0xce;
- pllbuf[3] = (p4 << 4) | p3210;
+// pllbuf[2] = 0xcc;
+ pllbuf[3] = (p3 << 3) | p210;
return 0;
}
static int lg_tdtp_e102p_mt352_demod_init(struct dvb_frontend *fe)
{
- static u8 mt352_clock_config[] = { 0x89, 0xb0, 0x2d };
+ static u8 mt352_clock_config[] = { 0x89, 0xb8, 0x2d };
static u8 mt352_reset[] = { 0x50, 0x80 };
static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 };
static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
- static u8 mt352_agc_cfg[] = { 0x67, 0x14, 0x22 };
- static u8 mt352_sec_agc_cfg[] = { 0x69, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x40, 0x40 };
-
- static u8 mt352_unk [] = { 0xb5, 0x7a };
+ static u8 mt352_agc_cfg[] = { 0x67, 0x10, 0xa0 };
- static u8 mt352_acq_ctl[] = { 0x53, 0x5f };
- static u8 mt352_input_freq_1[] = { 0x56, 0xf1, 0x05 };
+ static u8 mt352_sec_agc_cfg1[] = { 0x6a, 0xff };
+ static u8 mt352_sec_agc_cfg2[] = { 0x6d, 0xff };
+ static u8 mt352_sec_agc_cfg3[] = { 0x70, 0x40 };
+ static u8 mt352_sec_agc_cfg4[] = { 0x7b, 0x03 };
+ static u8 mt352_sec_agc_cfg5[] = { 0x7d, 0x0f };
-// static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
+ static u8 mt352_acq_ctl[] = { 0x53, 0x50 };
+ static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x06 };
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
udelay(2000);
@@ -495,15 +479,15 @@ static int lg_tdtp_e102p_mt352_demod_init(struct dvb_frontend *fe)
mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
- mt352_write(fe, mt352_sec_agc_cfg, sizeof(mt352_sec_agc_cfg));
-
- mt352_write(fe, mt352_unk, sizeof(mt352_unk));
+ mt352_write(fe, mt352_sec_agc_cfg1, sizeof(mt352_sec_agc_cfg1));
+ mt352_write(fe, mt352_sec_agc_cfg2, sizeof(mt352_sec_agc_cfg2));
+ mt352_write(fe, mt352_sec_agc_cfg3, sizeof(mt352_sec_agc_cfg3));
+ mt352_write(fe, mt352_sec_agc_cfg4, sizeof(mt352_sec_agc_cfg4));
+ mt352_write(fe, mt352_sec_agc_cfg5, sizeof(mt352_sec_agc_cfg5));
mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl));
mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1));
-// mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
-
return 0;
}
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c b/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c
index 708ec73701424..504ba47afdf37 100644
--- a/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c
+++ b/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c
@@ -30,11 +30,13 @@ int dibusb_loadfirmware(struct usb_device *udev, struct dibusb_usb_device *dibde
int ret = 0,i;
if ((ret = request_firmware(&fw, dibdev->dev_cl->firmware, &udev->dev)) != 0) {
- err("did not find a valid firmware file. (%s) "
+ err("did not find the firmware file. (%s) "
"Please see linux/Documentation/dvb/ for more details on firmware-problems.",
dibdev->dev_cl->firmware);
return ret;
}
+
+ info("downloading firmware from file '%s'.",dibdev->dev_cl->firmware);
p = kmalloc(fw->size,GFP_KERNEL);
if (p != NULL) {
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-pid.c b/drivers/media/dvb/dibusb/dvb-dibusb-pid.c
deleted file mode 100644
index 91a39541d5242..0000000000000
--- a/drivers/media/dvb/dibusb/dvb-dibusb-pid.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * dvb-dibusb-pid.c is part of the driver for mobile USB Budget DVB-T devices
- * based on reference design made by DiBcom (http://www.dibcom.fr/)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * see dvb-dibusb-core.c for more copyright details.
- *
- * This file contains functions for initializing and handling the internal
- * pid-list. This pid-list mirrors the information currently stored in the
- * devices pid-list.
- */
-#include "dvb-dibusb.h"
-
-int dibusb_pid_list_init(struct usb_dibusb *dib)
-{
- int i;
- dib->pid_list = kmalloc(sizeof(struct dibusb_pid) * dib->dibdev->dev_cl->demod->pid_filter_count,GFP_KERNEL);
- if (dib->pid_list == NULL)
- return -ENOMEM;
-
- deb_xfer("initializing %d pids for the pid_list.\n",dib->dibdev->dev_cl->demod->pid_filter_count);
-
- dib->pid_list_lock = SPIN_LOCK_UNLOCKED;
- memset(dib->pid_list,0,dib->dibdev->dev_cl->demod->pid_filter_count*(sizeof(struct dibusb_pid)));
- for (i=0; i < dib->dibdev->dev_cl->demod->pid_filter_count; i++) {
- dib->pid_list[i].index = i;
- dib->pid_list[i].pid = 0;
- dib->pid_list[i].active = 0;
- }
-
- dib->init_state |= DIBUSB_STATE_PIDLIST;
- return 0;
-}
-
-void dibusb_pid_list_exit(struct usb_dibusb *dib)
-{
- if (dib->init_state & DIBUSB_STATE_PIDLIST)
- kfree(dib->pid_list);
- dib->init_state &= ~DIBUSB_STATE_PIDLIST;
-}
-
-/* fetch a pid from pid_list and set it on or off */
-int dibusb_ctrl_pid(struct usb_dibusb *dib, struct dvb_demux_feed *dvbdmxfeed , int onoff)
-{
- int i,ret = -1;
- unsigned long flags;
- u16 pid = dvbdmxfeed->pid;
-
- if (onoff) {
- spin_lock_irqsave(&dib->pid_list_lock,flags);
- for (i=0; i < dib->dibdev->dev_cl->demod->pid_filter_count; i++)
- if (!dib->pid_list[i].active) {
- dib->pid_list[i].pid = pid;
- dib->pid_list[i].active = 1;
- ret = i;
- break;
- }
- dvbdmxfeed->priv = &dib->pid_list[ret];
- spin_unlock_irqrestore(&dib->pid_list_lock,flags);
-
- if (dib->xfer_ops.pid_ctrl != NULL)
- dib->xfer_ops.pid_ctrl(dib->fe,dib->pid_list[ret].index,dib->pid_list[ret].pid,1);
- } else {
- struct dibusb_pid *dpid = dvbdmxfeed->priv;
-
- if (dib->xfer_ops.pid_ctrl != NULL)
- dib->xfer_ops.pid_ctrl(dib->fe,dpid->index,0,0);
-
- dpid->pid = 0;
- dpid->active = 0;
- ret = dpid->index;
- }
-
- /* a free pid from the list */
- deb_info("setting pid: %5d %04x at index %d '%s'\n",pid,pid,ret,onoff ? "on" : "off");
-
- return ret;
-}
-
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-remote.c b/drivers/media/dvb/dibusb/dvb-dibusb-remote.c
index b3b6f24135e4e..9dc8b15517b7c 100644
--- a/drivers/media/dvb/dibusb/dvb-dibusb-remote.c
+++ b/drivers/media/dvb/dibusb/dvb-dibusb-remote.c
@@ -13,7 +13,7 @@
/* Table to map raw key codes to key events. This should not be hard-wired
into the kernel. */
-static const struct { u8 c0, c1, c2; uint32_t key; } rc_keys [] =
+static const struct { u8 c0, c1, c2; uint32_t key; } nec_rc_keys [] =
{
/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
{ 0x00, 0xff, 0x16, KEY_POWER },
@@ -83,18 +83,58 @@ static const struct { u8 c0, c1, c2; uint32_t key; } rc_keys [] =
{ 0x86, 0x6b, 0x1b, KEY_RIGHT },
};
-/*
- * Read the remote control and feed the appropriate event.
- * NEC protocol is used for remote controls
- */
-static int dibusb_read_remote_control(struct usb_dibusb *dib)
+/* Hauppauge NOVA-T USB2 keys */
+static const struct { u16 raw; uint32_t key; } haupp_rc_keys [] = {
+ { 0xddf, KEY_GOTO },
+ { 0xdef, KEY_POWER },
+ { 0xce7, KEY_TV },
+ { 0xcc7, KEY_VIDEO },
+ { 0xccf, KEY_AUDIO },
+ { 0xcd7, KEY_MEDIA },
+ { 0xcdf, KEY_EPG },
+ { 0xca7, KEY_UP },
+ { 0xc67, KEY_RADIO },
+ { 0xcb7, KEY_LEFT },
+ { 0xd2f, KEY_OK },
+ { 0xcbf, KEY_RIGHT },
+ { 0xcff, KEY_BACK },
+ { 0xcaf, KEY_DOWN },
+ { 0xc6f, KEY_MENU },
+ { 0xc87, KEY_VOLUMEUP },
+ { 0xc8f, KEY_VOLUMEDOWN },
+ { 0xc97, KEY_CHANNEL },
+ { 0xc7f, KEY_MUTE },
+ { 0xd07, KEY_CHANNELUP },
+ { 0xd0f, KEY_CHANNELDOWN },
+ { 0xdbf, KEY_RECORD },
+ { 0xdb7, KEY_STOP },
+ { 0xd97, KEY_REWIND },
+ { 0xdaf, KEY_PLAY },
+ { 0xda7, KEY_FASTFORWARD },
+ { 0xd27, KEY_LAST }, /* Skip backwards */
+ { 0xd87, KEY_PAUSE },
+ { 0xcf7, KEY_NEXT },
+ { 0xc07, KEY_0 },
+ { 0xc0f, KEY_1 },
+ { 0xc17, KEY_2 },
+ { 0xc1f, KEY_3 },
+ { 0xc27, KEY_4 },
+ { 0xc2f, KEY_5 },
+ { 0xc37, KEY_6 },
+ { 0xc3f, KEY_7 },
+ { 0xc47, KEY_8 },
+ { 0xc4f, KEY_9 },
+ { 0xc57, KEY_KPASTERISK },
+ { 0xc77, KEY_GRAVE }, /* # */
+ { 0xc5f, KEY_RED },
+ { 0xd77, KEY_GREEN },
+ { 0xdc7, KEY_YELLOW },
+ { 0xd4f, KEY_BLUE},
+};
+
+static int dibusb_key2event_nec(struct usb_dibusb *dib,u8 rb[5])
{
- u8 b[1] = { DIBUSB_REQ_POLL_REMOTE }, rb[5];
- int ret;
int i;
- if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5)))
- return ret;
-
switch (rb[0]) {
case DIBUSB_RC_NEC_KEY_PRESSED:
/* rb[1-3] is the actual key, rb[4] is a checksum */
@@ -107,30 +147,100 @@ static int dibusb_read_remote_control(struct usb_dibusb *dib)
}
/* See if we can match the raw key code. */
- for (i = 0; i < sizeof(rc_keys)/sizeof(rc_keys[0]); i++) {
- if (rc_keys[i].c0 == rb[1] &&
- rc_keys[i].c1 == rb[2] &&
- rc_keys[i].c2 == rb[3]) {
- dib->rc_input_event = rc_keys[i].key;
- deb_rc("Translated key 0x%04x\n", dib->rc_input_event);
- /* Signal down and up events for this key. */
- input_report_key(&dib->rc_input_dev, dib->rc_input_event, 1);
- input_report_key(&dib->rc_input_dev, dib->rc_input_event, 0);
- input_sync(&dib->rc_input_dev);
- break;
+ for (i = 0; i < sizeof(nec_rc_keys)/sizeof(nec_rc_keys[0]); i++) {
+ if (nec_rc_keys[i].c0 == rb[1] &&
+ nec_rc_keys[i].c1 == rb[2] &&
+ nec_rc_keys[i].c2 == rb[3]) {
+
+ dib->last_event = nec_rc_keys[i].key;
+ return 1;
}
}
break;
- case DIBUSB_RC_NEC_EMPTY: /* No (more) remote control keys. */
- break;
case DIBUSB_RC_NEC_KEY_REPEATED:
/* rb[1]..rb[4] are always zero.*/
/* Repeats often seem to occur so for the moment just ignore this. */
- deb_rc("Key repeat\n");
+ return 0;
+ case DIBUSB_RC_NEC_EMPTY: /* No (more) remote control keys. */
+ default:
+ break;
+ }
+ return -1;
+}
+
+static int dibusb_key2event_hauppauge(struct usb_dibusb *dib,u8 rb[4])
+{
+ u16 raw;
+ int i,state;
+ switch (rb[0]) {
+ case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED:
+ raw = ((rb[1] & 0x0f) << 8) | rb[2];
+
+ state = !!(rb[1] & 0x40);
+
+ deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to %04x state: %d\n",rb[1],rb[2],rb[3],raw,state);
+ for (i = 0; i < sizeof(haupp_rc_keys)/sizeof(haupp_rc_keys[0]); i++) {
+ if (haupp_rc_keys[i].raw == raw) {
+ if (dib->last_event == haupp_rc_keys[i].key &&
+ dib->last_state == state) {
+ deb_rc("key repeat\n");
+ return 0;
+ } else {
+ dib->last_event = haupp_rc_keys[i].key;
+ dib->last_state = state;
+ return 1;
+ }
+ }
+ }
+
+ break;
+ case DIBUSB_RC_HAUPPAUGE_KEY_EMPTY:
+ default:
+ break;
+ }
+ return -1;
+}
+
+/*
+ * Read the remote control and feed the appropriate event.
+ * NEC protocol is used for remote controls
+ */
+static int dibusb_read_remote_control(struct usb_dibusb *dib)
+{
+ u8 b[1] = { DIBUSB_REQ_POLL_REMOTE }, rb[5];
+ int ret,event = 0;
+
+ if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5)))
+ return ret;
+
+ switch (dib->dibdev->dev_cl->remote_type) {
+ case DIBUSB_RC_NEC_PROTOCOL:
+ event = dibusb_key2event_nec(dib,rb);
break;
+ case DIBUSB_RC_HAUPPAUGE_PROTO:
+ event = dibusb_key2event_hauppauge(dib,rb);
default:
break;
}
+
+ /* key repeat */
+ if (event == 0)
+ if (++dib->repeat_key_count < dib->rc_key_repeat_count) {
+ deb_rc("key repeat dropped. (%d)\n",dib->repeat_key_count);
+ event = -1; /* skip this key repeat */
+ }
+
+ if (event == 1 || event == 0) {
+ deb_rc("Translated key 0x%04x\n",event);
+
+ /* Signal down and up events for this key. */
+ input_report_key(&dib->rc_input_dev, dib->last_event, 1);
+ input_report_key(&dib->rc_input_dev, dib->last_event, 0);
+ input_sync(&dib->rc_input_dev);
+
+ if (event == 1)
+ dib->repeat_key_count = 0;
+ }
return 0;
}
@@ -161,12 +271,21 @@ int dibusb_remote_init(struct usb_dibusb *dib)
dib->rc_input_dev.keycodemax = KEY_MAX;
dib->rc_input_dev.name = DRIVER_DESC " remote control";
- for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i++)
- set_bit(rc_keys[i].key, dib->rc_input_dev.keybit);
+ switch (dib->dibdev->dev_cl->remote_type) {
+ case DIBUSB_RC_NEC_PROTOCOL:
+ for (i=0; i<sizeof(nec_rc_keys)/sizeof(nec_rc_keys[0]); i++)
+ set_bit(nec_rc_keys[i].key, dib->rc_input_dev.keybit);
+ break;
+ case DIBUSB_RC_HAUPPAUGE_PROTO:
+ for (i=0; i<sizeof(haupp_rc_keys)/sizeof(haupp_rc_keys[0]); i++)
+ set_bit(haupp_rc_keys[i].key, dib->rc_input_dev.keybit);
+ break;
+ default:
+ break;
+ }
- input_register_device(&dib->rc_input_dev);
- dib->rc_input_event = KEY_MAX;
+ input_register_device(&dib->rc_input_dev);
INIT_WORK(&dib->rc_query_work, dibusb_remote_query, dib);
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-usb.c b/drivers/media/dvb/dibusb/dvb-dibusb-usb.c
index 656a0115c101e..642f0596a5ba9 100644
--- a/drivers/media/dvb/dibusb/dvb-dibusb-usb.c
+++ b/drivers/media/dvb/dibusb/dvb-dibusb-usb.c
@@ -1,12 +1,12 @@
/*
- * dvb-dibusb-usb.c is part of the driver for mobile USB Budget DVB-T devices
+ * dvb-dibusb-usb.c is part of the driver for mobile USB Budget DVB-T devices
* based on reference design made by DiBcom (http://www.dibcom.fr/)
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* see dvb-dibusb-core.c for more copyright details.
*
- * This file contains functions for initializing and handling the
+ * This file contains functions for initializing and handling the
* usb specific stuff.
*/
#include "dvb-dibusb.h"
@@ -25,18 +25,12 @@ int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf,
if ((ret = down_interruptible(&dib->usb_sem)))
return ret;
- if (dib->feedcount &&
- wbuf[0] == DIBUSB_REQ_I2C_WRITE &&
- dib->dibdev->dev_cl->id == DIBUSB1_1)
- deb_err("BUG: writing to i2c, while TS-streaming destroys the stream."
- "(%x reg: %x %x)\n", wbuf[0],wbuf[2],wbuf[3]);
-
debug_dump(wbuf,wlen);
ret = usb_bulk_msg(dib->udev,usb_sndbulkpipe(dib->udev,
dib->dibdev->dev_cl->pipe_cmd), wbuf,wlen,&actlen,
DIBUSB_I2C_TIMEOUT);
-
+
if (ret)
err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
else
@@ -55,7 +49,7 @@ int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf,
debug_dump(rbuf,actlen);
}
}
-
+
up(&dib->usb_sem);
return ret;
}
@@ -63,15 +57,18 @@ int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf,
/*
* Cypress controls
*/
+int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
+{
+ return dibusb_readwrite_usb(dib,buf,len,NULL,0);
+}
#if 0
-/*
- * #if 0'ing the following functions as they are not in use _now_,
+/*
+ * #if 0'ing the following functions as they are not in use _now_,
* but probably will be sometime.
*/
-
/*
- * do not use this, just a workaround for a bug,
+ * do not use this, just a workaround for a bug,
* which will hopefully never occur :).
*/
int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
@@ -79,15 +76,10 @@ int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
u8 b[1] = { DIBUSB_REQ_INTR_READ };
return dibusb_write_usb(dib,b,1);
}
-
-#endif
-static int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
-{
- return dibusb_readwrite_usb(dib,buf,len,NULL,0);
-}
+#endif
/*
- * ioctl for the firmware
+ * ioctl for the firmware
*/
static int dibusb_ioctl_cmd(struct usb_dibusb *dib, u8 cmd, u8 *param, int plen)
{
@@ -111,11 +103,18 @@ int dibusb_hw_wakeup(struct dvb_frontend *fe)
struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
u8 b[1] = { DIBUSB_IOCTL_POWER_WAKEUP };
deb_info("dibusb-device is getting up.\n");
- dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
-
+
+ switch (dib->dibdev->dev_cl->id) {
+ case DTT200U:
+ break;
+ default:
+ dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
+ break;
+ }
+
if (dib->fe_init)
return dib->fe_init(fe);
-
+
return 0;
}
@@ -124,11 +123,19 @@ int dibusb_hw_sleep(struct dvb_frontend *fe)
struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP };
deb_info("dibusb-device is going to bed.\n");
- dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
-
+ /* workaround, something is wrong, when dibusb 1.1 device are going to bed too late */
+ switch (dib->dibdev->dev_cl->id) {
+ case DIBUSB1_1:
+ case NOVAT_USB2:
+ case DTT200U:
+ break;
+ default:
+ dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
+ break;
+ }
if (dib->fe_sleep)
return dib->fe_sleep(fe);
-
+
return 0;
}
@@ -138,18 +145,57 @@ int dibusb_set_streaming_mode(struct usb_dibusb *dib,u8 mode)
return dibusb_readwrite_usb(dib,b,2,NULL,0);
}
+static int dibusb_urb_kill(struct usb_dibusb *dib)
+{
+ int i;
+deb_info("trying to kill urbs\n");
+ if (dib->init_state & DIBUSB_STATE_URB_SUBMIT) {
+ for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
+ deb_info("killing URB no. %d.\n",i);
+
+ /* stop the URB */
+ usb_kill_urb(dib->urb_list[i]);
+ }
+ } else
+ deb_info(" URBs not killed.\n");
+ dib->init_state &= ~DIBUSB_STATE_URB_SUBMIT;
+ return 0;
+}
+
+static int dibusb_urb_submit(struct usb_dibusb *dib)
+{
+ int i,ret;
+ if (dib->init_state & DIBUSB_STATE_URB_INIT) {
+ for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
+ deb_info("submitting URB no. %d\n",i);
+ if ((ret = usb_submit_urb(dib->urb_list[i],GFP_ATOMIC))) {
+ err("could not submit buffer urb no. %d - get them all back\n",i);
+ dibusb_urb_kill(dib);
+ return ret;
+ }
+ dib->init_state |= DIBUSB_STATE_URB_SUBMIT;
+ }
+ }
+ return 0;
+}
+
int dibusb_streaming(struct usb_dibusb *dib,int onoff)
{
+ if (onoff)
+ dibusb_urb_submit(dib);
+ else
+ dibusb_urb_kill(dib);
+
switch (dib->dibdev->dev_cl->id) {
case DIBUSB2_0:
+ case DIBUSB2_0B:
+ case NOVAT_USB2:
+ case UMT2_0:
if (onoff)
return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_ENABLE_STREAM,NULL,0);
else
return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_DISABLE_STREAM,NULL,0);
break;
- case UMT2_0:
- return dibusb_set_streaming_mode(dib,onoff);
- break;
default:
break;
}
@@ -158,10 +204,10 @@ int dibusb_streaming(struct usb_dibusb *dib,int onoff)
int dibusb_urb_init(struct usb_dibusb *dib)
{
- int ret,i,bufsize,def_pid_parse = 1;
-
+ int i,bufsize,def_pid_parse = 1;
+
/*
- * when reloading the driver w/o replugging the device
+ * when reloading the driver w/o replugging the device
* a timeout occures, this helps
*/
usb_clear_halt(dib->udev,usb_sndbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd));
@@ -175,7 +221,7 @@ int dibusb_urb_init(struct usb_dibusb *dib)
memset(dib->urb_list,0,dib->dibdev->dev_cl->urb_count*sizeof(struct urb *));
dib->init_state |= DIBUSB_STATE_URB_LIST;
-
+
bufsize = dib->dibdev->dev_cl->urb_count*dib->dibdev->dev_cl->urb_buffer_size;
deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize);
/* allocate the actual buffer for the URBs */
@@ -185,7 +231,7 @@ int dibusb_urb_init(struct usb_dibusb *dib)
}
deb_info("allocation complete\n");
memset(dib->buffer,0,bufsize);
-
+
dib->init_state |= DIBUSB_STATE_URB_BUF;
/* allocate and submit the URBs */
@@ -193,55 +239,49 @@ int dibusb_urb_init(struct usb_dibusb *dib)
if (!(dib->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) {
return -ENOMEM;
}
- deb_info("submitting URB no. %d\n",i);
-
- usb_fill_bulk_urb( dib->urb_list[i], dib->udev,
+
+ usb_fill_bulk_urb( dib->urb_list[i], dib->udev,
usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data),
- &dib->buffer[i*dib->dibdev->dev_cl->urb_buffer_size],
- dib->dibdev->dev_cl->urb_buffer_size,
+ &dib->buffer[i*dib->dibdev->dev_cl->urb_buffer_size],
+ dib->dibdev->dev_cl->urb_buffer_size,
dibusb_urb_complete, dib);
-
+
dib->urb_list[i]->transfer_flags = 0;
- if ((ret = usb_submit_urb(dib->urb_list[i],GFP_ATOMIC))) {
- err("could not submit buffer urb no. %d\n",i);
- return ret;
- }
- dib->init_state |= DIBUSB_STATE_URB_SUBMIT;
+ dib->init_state |= DIBUSB_STATE_URB_INIT;
}
/* dib->pid_parse here contains the value of the module parameter */
/* decide if pid parsing can be deactivated:
- * is possible (by speed) and wanted (by user)
+ * is possible (by device type) and wanted (by user)
*/
switch (dib->dibdev->dev_cl->id) {
case DIBUSB2_0:
+ case DIBUSB2_0B:
if (dib->udev->speed == USB_SPEED_HIGH && !dib->pid_parse) {
def_pid_parse = 0;
info("running at HIGH speed, will deliver the complete TS.");
} else
info("will use pid_parsing.");
break;
- default:
+ default:
break;
}
/* from here on it contains the device and user decision */
dib->pid_parse = def_pid_parse;
-
+
return 0;
}
int dibusb_urb_exit(struct usb_dibusb *dib)
{
int i;
+
+ dibusb_urb_kill(dib);
+
if (dib->init_state & DIBUSB_STATE_URB_LIST) {
for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
if (dib->urb_list[i] != NULL) {
- deb_info("killing URB no. %d.\n",i);
-
- /* stop the URBs */
- usb_kill_urb(dib->urb_list[i]);
-
deb_info("freeing URB no. %d.\n",i);
/* free the URBs */
usb_free_urb(dib->urb_list[i]);
@@ -249,7 +289,6 @@ int dibusb_urb_exit(struct usb_dibusb *dib)
}
/* free the urb array */
kfree(dib->urb_list);
- dib->init_state &= ~DIBUSB_STATE_URB_SUBMIT;
dib->init_state &= ~DIBUSB_STATE_URB_LIST;
}
@@ -259,5 +298,6 @@ int dibusb_urb_exit(struct usb_dibusb *dib)
dib->buffer,dib->dma_handle);
dib->init_state &= ~DIBUSB_STATE_URB_BUF;
+ dib->init_state &= ~DIBUSB_STATE_URB_INIT;
return 0;
}
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb.h b/drivers/media/dvb/dibusb/dvb-dibusb.h
index 19362c75abef2..52cd35dd9d838 100644
--- a/drivers/media/dvb/dibusb/dvb-dibusb.h
+++ b/drivers/media/dvb/dibusb/dvb-dibusb.h
@@ -44,7 +44,7 @@ extern int dvb_dibusb_debug;
/* Version information */
#define DRIVER_VERSION "0.3"
-#define DRIVER_DESC "Driver for DiBcom based USB Budget DVB-T device"
+#define DRIVER_DESC "DiBcom based USB Budget DVB-T device"
#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
#define deb_info(args...) dprintk(0x01,args)
@@ -55,9 +55,12 @@ extern int dvb_dibusb_debug;
#define deb_rc(args...) dprintk(0x20,args)
/* generic log methods - taken from usb.h */
-#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , __FILE__ , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , __FILE__ , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , __FILE__ , ## arg)
+#undef err
+#define err(format, arg...) printk(KERN_ERR "dvb-dibusb: " format "\n" , ## arg)
+#undef info
+#define info(format, arg...) printk(KERN_INFO "dvb-dibusb: " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) printk(KERN_WARNING "dvb-dibusb: " format "\n" , ## arg)
struct dibusb_usb_controller {
const char *name; /* name of the usb controller */
@@ -69,6 +72,9 @@ typedef enum {
DIBUSB1_1_AN2235,
DIBUSB2_0,
UMT2_0,
+ DIBUSB2_0B,
+ NOVAT_USB2,
+ DTT200U,
} dibusb_class_t;
typedef enum {
@@ -82,11 +88,13 @@ typedef enum {
DIBUSB_DIB3000MB = 0,
DIBUSB_DIB3000MC,
DIBUSB_MT352,
+ DTT200U_FE,
} dibusb_demodulator_t;
typedef enum {
DIBUSB_RC_NO = 0,
- DIBUSB_RC_NEC_PROTOCOL = 1,
+ DIBUSB_RC_NEC_PROTOCOL,
+ DIBUSB_RC_HAUPPAUGE_PROTO,
} dibusb_remote_t;
struct dibusb_tuner {
@@ -149,11 +157,11 @@ struct usb_dibusb {
#define DIBUSB_STATE_INIT 0x000
#define DIBUSB_STATE_URB_LIST 0x001
#define DIBUSB_STATE_URB_BUF 0x002
-#define DIBUSB_STATE_URB_SUBMIT 0x004
+#define DIBUSB_STATE_URB_INIT 0x004
#define DIBUSB_STATE_DVB 0x008
#define DIBUSB_STATE_I2C 0x010
#define DIBUSB_STATE_REMOTE 0x020
-#define DIBUSB_STATE_PIDLIST 0x040
+#define DIBUSB_STATE_URB_SUBMIT 0x040
int init_state;
int feedcount;
@@ -172,10 +180,6 @@ struct usb_dibusb {
struct semaphore usb_sem;
struct semaphore i2c_sem;
- /* pid filtering */
- spinlock_t pid_list_lock;
- struct dibusb_pid *pid_list;
-
/* dvb */
struct dvb_adapter *adapter;
struct dmxdev dmxdev;
@@ -189,7 +193,10 @@ struct usb_dibusb {
/* remote control */
struct input_dev rc_input_dev;
struct work_struct rc_query_work;
- int rc_input_event;
+ int last_event;
+ int last_state; /* for Hauppauge RC protocol */
+ int repeat_key_count;
+ int rc_key_repeat_count; /* module parameter */
/* module parameters */
int pid_parse;
@@ -206,8 +213,6 @@ int dibusb_remote_exit(struct usb_dibusb *dib);
int dibusb_remote_init(struct usb_dibusb *dib);
/* dvb-dibusb-fe-i2c.c */
-int dibusb_i2c_msg(struct usb_dibusb *dib, u8 addr,
- u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen);
int dibusb_fe_init(struct usb_dibusb* dib);
int dibusb_fe_exit(struct usb_dibusb *dib);
int dibusb_i2c_init(struct usb_dibusb *dib);
@@ -221,6 +226,7 @@ int dibusb_dvb_exit(struct usb_dibusb *dib);
/* dvb-dibusb-usb.c */
int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf,
u16 rlen);
+int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len);
int dibusb_hw_wakeup(struct dvb_frontend *);
int dibusb_hw_sleep(struct dvb_frontend *);
@@ -230,10 +236,8 @@ int dibusb_streaming(struct usb_dibusb *,int);
int dibusb_urb_init(struct usb_dibusb *);
int dibusb_urb_exit(struct usb_dibusb *);
-/* dvb-dibusb-pid.c */
-int dibusb_pid_list_init(struct usb_dibusb *dib);
-void dibusb_pid_list_exit(struct usb_dibusb *dib);
-int dibusb_ctrl_pid(struct usb_dibusb *dib, struct dvb_demux_feed *dvbdmxfeed , int onoff);
+/* dvb-fe-dtt200u.c */
+struct dvb_frontend* dtt200u_fe_attach(struct usb_dibusb *,struct dib_fe_xfer_ops *);
/* i2c and transfer stuff */
#define DIBUSB_I2C_TIMEOUT 5000
@@ -278,6 +282,10 @@ int dibusb_ctrl_pid(struct usb_dibusb *dib, struct dvb_demux_feed *dvbdmxfeed ,
#define DIBUSB_RC_NEC_KEY_PRESSED 0x01
#define DIBUSB_RC_NEC_KEY_REPEATED 0x02
+/* additional status values for Hauppauge Remote Control Protocol */
+#define DIBUSB_RC_HAUPPAUGE_KEY_PRESSED 0x01
+#define DIBUSB_RC_HAUPPAUGE_KEY_EMPTY 0x03
+
/* streaming mode:
* bulk write: 0x05 mode_byte
*
diff --git a/drivers/media/dvb/dibusb/dvb-fe-dtt200u.c b/drivers/media/dvb/dibusb/dvb-fe-dtt200u.c
new file mode 100644
index 0000000000000..1872aa6d200a0
--- /dev/null
+++ b/drivers/media/dvb/dibusb/dvb-fe-dtt200u.c
@@ -0,0 +1,263 @@
+/*
+ * dvb-dtt200u-fe.c is a driver which implements the frontend-part of the
+ * Yakumo/Typhoon/Hama USB2.0 boxes. It is hard-wired to the dibusb-driver as
+ * it uses the usb-transfer functions directly (maybe creating a
+ * generic-dvb-usb-lib for all usb-drivers will be reduce some more code.)
+ *
+ * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
+ *
+ * see dvb-dibusb-core.c for copyright details.
+ */
+
+/* guessed protocol description (reverse engineered):
+ * read
+ * 00 - USB type 0x02 for usb2.0, 0x01 for usb1.1
+ * 81 - <TS_LOCK> <current frequency divided by 250000>
+ * 82 - crash - do not touch
+ * 83 - crash - do not touch
+ * 84 - remote control
+ * 85 - crash - do not touch (OK, stop testing here)
+ * 88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
+ * 89 - noise-to-signal
+ * 8a - unkown 1 byte - signal_strength
+ * 8c - ber ???
+ * 8d - ber
+ * 8e - unc
+ *
+ * write
+ * 02 - bandwidth
+ * 03 - frequency (divided by 250000)
+ * 04 - pid table (index pid(7:0) pid(12:8))
+ * 05 - reset the pid table
+ * 08 - demod transfer enabled or not (FX2 transfer is enabled by default)
+ */
+
+#include "dvb-dibusb.h"
+#include "dvb_frontend.h"
+
+struct dtt200u_fe_state {
+ struct usb_dibusb *dib;
+
+ struct dvb_frontend_parameters fep;
+ struct dvb_frontend frontend;
+};
+
+#define moan(which,what) info("unexpected value in '%s' for cmd '%02x' - please report to linux-dvb@linuxtv.org",which,what)
+
+static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
+{
+ struct dtt200u_fe_state *state = fe->demodulator_priv;
+ u8 bw[1] = { 0x81 };
+ u8 br[3] = { 0 };
+// u8 bdeb[5] = { 0 };
+
+ dibusb_readwrite_usb(state->dib,bw,1,br,3);
+ switch (br[0]) {
+ case 0x01:
+ *stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+ break;
+ case 0x00:
+ *stat = 0;
+ break;
+ default:
+ moan("br[0]",0x81);
+ break;
+ }
+
+// bw[0] = 0x88;
+// dibusb_readwrite_usb(state->dib,bw,1,bdeb,5);
+
+// deb_info("%02x: %02x %02x %02x %02x %02x\n",bw[0],bdeb[0],bdeb[1],bdeb[2],bdeb[3],bdeb[4]);
+
+ return 0;
+}
+static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+ struct dtt200u_fe_state *state = fe->demodulator_priv;
+ u8 bw[1] = { 0x8d };
+ *ber = 0;
+ dibusb_readwrite_usb(state->dib,bw,1,(u8*) ber, 3);
+ return 0;
+}
+
+static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+ struct dtt200u_fe_state *state = fe->demodulator_priv;
+ u8 bw[1] = { 0x8c };
+ *unc = 0;
+ dibusb_readwrite_usb(state->dib,bw,1,(u8*) unc, 3);
+ return 0;
+}
+
+static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+ struct dtt200u_fe_state *state = fe->demodulator_priv;
+ u8 bw[1] = { 0x8a };
+ u8 b;
+ dibusb_readwrite_usb(state->dib,bw,1,&b, 1);
+ *strength = (b << 8) | b;
+ return 0;
+}
+
+static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+ struct dtt200u_fe_state *state = fe->demodulator_priv;
+ u8 bw[1] = { 0x89 };
+ u8 br[1] = { 0 };
+ dibusb_readwrite_usb(state->dib,bw,1,br,1);
+ *snr = ((0xff - br[0]) << 8) | (0xff - br[0]);
+ return 0;
+}
+
+static int dtt200u_fe_init(struct dvb_frontend* fe)
+{
+ struct dtt200u_fe_state *state = fe->demodulator_priv;
+ u8 b[] = { 0x01 };
+ return dibusb_write_usb(state->dib,b,1);
+}
+
+static int dtt200u_fe_sleep(struct dvb_frontend* fe)
+{
+ return dtt200u_fe_init(fe);
+}
+
+static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+ tune->min_delay_ms = 1500;
+ tune->step_size = 166667;
+ tune->max_drift = 166667 * 2;
+ return 0;
+}
+
+static int dtt200u_fe_set_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct dtt200u_fe_state *state = fe->demodulator_priv;
+ u16 freq = fep->frequency / 250000;
+ u8 bw,bwbuf[2] = { 0x03, 0 }, freqbuf[3] = { 0x02, 0, 0 };
+
+ switch (fep->u.ofdm.bandwidth) {
+ case BANDWIDTH_8_MHZ: bw = 8; break;
+ case BANDWIDTH_7_MHZ: bw = 7; break;
+ case BANDWIDTH_6_MHZ: bw = 6; break;
+ case BANDWIDTH_AUTO: return -EOPNOTSUPP;
+ default:
+ return -EINVAL;
+ }
+ deb_info("set_frontend\n");
+
+ bwbuf[1] = bw;
+ dibusb_write_usb(state->dib,bwbuf,2);
+
+ freqbuf[1] = freq & 0xff;
+ freqbuf[2] = (freq >> 8) & 0xff;
+ dibusb_write_usb(state->dib,freqbuf,3);
+
+ memcpy(&state->fep,fep,sizeof(struct dvb_frontend_parameters));
+
+ return 0;
+}
+
+static int dtt200u_fe_get_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct dtt200u_fe_state *state = fe->demodulator_priv;
+ memcpy(fep,&state->fep,sizeof(struct dvb_frontend_parameters));
+ return 0;
+}
+
+static void dtt200u_fe_release(struct dvb_frontend* fe)
+{
+ struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
+ kfree(state);
+}
+
+static int dtt200u_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff)
+{
+ struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
+ u8 b_pid[4];
+ pid = onoff ? pid : 0;
+
+ b_pid[0] = 0x04;
+ b_pid[1] = index;
+ b_pid[2] = pid & 0xff;
+ b_pid[3] = (pid >> 8) & 0xff;
+
+ dibusb_write_usb(state->dib,b_pid,4);
+ return 0;
+}
+
+static int dtt200u_fifo_control(struct dvb_frontend *fe, int onoff)
+{
+ struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
+ u8 b_streaming[2] = { 0x08, onoff };
+ u8 b_rst_pid[1] = { 0x05 };
+
+ dibusb_write_usb(state->dib,b_streaming,2);
+
+ if (!onoff)
+ dibusb_write_usb(state->dib,b_rst_pid,1);
+ return 0;
+}
+
+static struct dvb_frontend_ops dtt200u_fe_ops;
+
+struct dvb_frontend* dtt200u_fe_attach(struct usb_dibusb *dib, struct dib_fe_xfer_ops *xfer_ops)
+{
+ struct dtt200u_fe_state* state = NULL;
+
+ /* allocate memory for the internal state */
+ state = (struct dtt200u_fe_state*) kmalloc(sizeof(struct dtt200u_fe_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+ memset(state,0,sizeof(struct dtt200u_fe_state));
+
+ deb_info("attaching frontend dtt200u\n");
+
+ state->dib = dib;
+
+ state->frontend.ops = &dtt200u_fe_ops;
+ state->frontend.demodulator_priv = state;
+
+ xfer_ops->fifo_ctrl = dtt200u_fifo_control;
+ xfer_ops->pid_ctrl = dtt200u_pid_control;
+
+ goto success;
+error:
+ return NULL;
+success:
+ return &state->frontend;
+}
+
+static struct dvb_frontend_ops dtt200u_fe_ops = {
+ .info = {
+ .name = "DTT200U (Yakumo/Typhoon/Hama) DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 44250000,
+ .frequency_max = 867250000,
+ .frequency_stepsize = 250000,
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_RECOVER |
+ FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .release = dtt200u_fe_release,
+
+ .init = dtt200u_fe_init,
+ .sleep = dtt200u_fe_sleep,
+
+ .set_frontend = dtt200u_fe_set_frontend,
+ .get_frontend = dtt200u_fe_get_frontend,
+ .get_tune_settings = dtt200u_fe_get_tune_settings,
+
+ .read_status = dtt200u_fe_read_status,
+ .read_ber = dtt200u_fe_read_ber,
+ .read_signal_strength = dtt200u_fe_read_signal_strength,
+ .read_snr = dtt200u_fe_read_snr,
+ .read_ucblocks = dtt200u_fe_read_unc_blocks,
+};
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index d0e01bda833fa..fb55eaa5c8e70 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -298,8 +298,4 @@ struct dmx_demux {
#define DMX_DIR_ENTRY(list) list_entry(list, struct dmx_demux, reg_list)
-int dmx_register_demux (struct dmx_demux* demux);
-int dmx_unregister_demux (struct dmx_demux* demux);
-struct list_head* dmx_get_demuxes (void);
-
#endif /* #ifndef __DEMUX_H */
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 7d26f91e99bae..1863f1dfb00c5 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -304,8 +304,7 @@ static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, unsign
buf->size=size;
buf->pwrite=buf->pread=0;
spin_unlock_irq(&dmxdevfilter->dev->lock);
- if (mem)
- vfree(mem);
+ vfree(mem);
if (buf->size) {
mem=vmalloc(dmxdevfilter->buffer.size);
@@ -1129,15 +1128,10 @@ dvb_dmxdev_release(struct dmxdev *dmxdev)
dvb_unregister_device(dmxdev->dvbdev);
dvb_unregister_device(dmxdev->dvr_dvbdev);
- if (dmxdev->filter) {
- vfree(dmxdev->filter);
- dmxdev->filter=NULL;
- }
-
- if (dmxdev->dvr) {
- vfree(dmxdev->dvr);
- dmxdev->dvr=NULL;
- }
+ vfree(dmxdev->filter);
+ dmxdev->filter=NULL;
+ vfree(dmxdev->dvr);
+ dmxdev->dvr=NULL;
dmxdev->demux->close(dmxdev->demux);
}
EXPORT_SYMBOL(dvb_dmxdev_release);
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 9df998504c8ef..c1ea89f2880ce 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -148,13 +148,13 @@ struct dvb_ca_private {
wait_queue_head_t thread_queue;
/* Flag indicating when thread should exit */
- int exit:1;
+ unsigned int exit:1;
/* Flag indicating if the CA device is open */
- int open:1;
+ unsigned int open:1;
/* Flag indicating the thread should wake up now */
- int wakeup:1;
+ unsigned int wakeup:1;
/* Delay the main thread should use */
unsigned long delay;
@@ -804,8 +804,7 @@ static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot)
down_write(&ca->slot_info[slot].sem);
ca->pub->slot_shutdown(ca->pub, slot);
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
- if (ca->slot_info[slot].rx_buffer.data)
- vfree(ca->slot_info[slot].rx_buffer.data);
+ vfree(ca->slot_info[slot].rx_buffer.data);
ca->slot_info[slot].rx_buffer.data = NULL;
up_write(&ca->slot_info[slot].sem);
@@ -974,7 +973,7 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
if (ca->open) {
if ((!ca->slot_info[slot].da_irq_supported) ||
(!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) {
- delay = HZ / 100;
+ delay = HZ / 10;
}
}
break;
@@ -1733,8 +1732,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
if (ca != NULL) {
if (ca->dvbdev != NULL)
dvb_unregister_device(ca->dvbdev);
- if (ca->slot_info != NULL)
- kfree(ca->slot_info);
+ kfree(ca->slot_info);
kfree(ca);
}
pubca->private = NULL;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 98f4573d2c489..ac9889d222882 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -39,17 +39,17 @@
// #define DVB_DEMUX_SECTION_LOSS_LOG
-LIST_HEAD(dmx_muxs);
+static LIST_HEAD(dmx_muxs);
-int dmx_register_demux(struct dmx_demux *demux)
+static int dmx_register_demux(struct dmx_demux *demux)
{
demux->users = 0;
list_add(&demux->reg_list, &dmx_muxs);
return 0;
}
-int dmx_unregister_demux(struct dmx_demux* demux)
+static int dmx_unregister_demux(struct dmx_demux* demux)
{
struct list_head *pos, *n, *head=&dmx_muxs;
@@ -66,14 +66,6 @@ int dmx_unregister_demux(struct dmx_demux* demux)
}
-struct list_head *dmx_get_demuxes(void)
-{
- if (list_empty(&dmx_muxs))
- return NULL;
-
- return &dmx_muxs;
-}
-
/******************************************************************************
* static inlined helper functions
******************************************************************************/
@@ -105,19 +97,6 @@ static inline u8 payload(const u8 *tsp)
}
-void dvb_set_crc32(u8 *data, int length)
-{
- u32 crc;
-
- crc = crc32_be(~0, data, length);
-
- data[length] = (crc >> 24) & 0xff;
- data[length+1] = (crc >> 16) & 0xff;
- data[length+2] = (crc >> 8) & 0xff;
- data[length+3] = (crc) & 0xff;
-}
-
-
static u32 dvb_dmx_crc32 (struct dvb_demux_feed *f, const u8 *src, size_t len)
{
return (f->feed.sec.crc_val = crc32_be (f->feed.sec.crc_val, src, len));
@@ -424,7 +403,7 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, con
((f)->feed.ts.is_filtering) && \
(((f)->ts_type & (TS_PACKET|TS_PAYLOAD_ONLY)) == TS_PACKET))
-void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
+static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
{
struct dvb_demux_feed *feed;
struct list_head *pos, *head=&demux->feed_list;
@@ -452,7 +431,6 @@ void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
}
}
-EXPORT_SYMBOL(dvb_dmx_swfilter_packet);
void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t count)
{
@@ -1190,7 +1168,7 @@ static struct list_head * dvbdmx_get_frontends(struct dmx_demux *demux)
}
-int dvbdmx_connect_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend)
+static int dvbdmx_connect_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend)
{
struct dvb_demux *dvbdemux = (struct dvb_demux *) demux;
@@ -1204,10 +1182,9 @@ int dvbdmx_connect_frontend(struct dmx_demux *demux, struct dmx_frontend *fronte
up(&dvbdemux->mutex);
return 0;
}
-EXPORT_SYMBOL(dvbdmx_connect_frontend);
-int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
+static int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
{
struct dvb_demux *dvbdemux = (struct dvb_demux *) demux;
@@ -1218,7 +1195,6 @@ int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
up(&dvbdemux->mutex);
return 0;
}
-EXPORT_SYMBOL(dvbdmx_disconnect_frontend);
static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 *pids)
@@ -1250,8 +1226,10 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
dvbdemux->filter[i].state = DMX_STATE_FREE;
dvbdemux->filter[i].index = i;
}
- for (i=0; i<dvbdemux->feednum; i++)
+ for (i=0; i<dvbdemux->feednum; i++) {
dvbdemux->feed[i].state = DMX_STATE_FREE;
+ dvbdemux->feed[i].index = i;
+ }
dvbdemux->frontend_list.next=
dvbdemux->frontend_list.prev=
&dvbdemux->frontend_list;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 904ad580420b9..c09beb3916225 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -98,6 +98,7 @@ struct dvb_demux_feed {
u16 peslen;
struct list_head list_head;
+ int index; /* a unique index for each feed (can be used as hardware pid filter index) */
};
struct dvb_demux {
@@ -138,12 +139,8 @@ struct dvb_demux {
int dvb_dmx_init(struct dvb_demux *dvbdemux);
int dvb_dmx_release(struct dvb_demux *dvbdemux);
-void dvb_dmx_swfilter_packet(struct dvb_demux *dvbdmx, const u8 *buf);
void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, size_t count);
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count);
-int dvbdmx_connect_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend);
-int dvbdmx_disconnect_frontend(struct dmx_demux *demux);
-
#endif /* _DVB_DEMUX_H_ */
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 60c888eb29200..59a9adfae1ebc 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -908,8 +908,7 @@ int dvb_unregister_frontend(struct dvb_frontend* fe)
else
printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops->info.name);
/* fe is invalid now */
- if (fepriv)
- kfree(fepriv);
+ kfree(fepriv);
up (&frontend_mutex);
return 0;
}
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 2a4d70a5e9fa0..44892e7abd3d1 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -217,12 +217,12 @@ static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb,
#define ULE_TEST 0
#define ULE_BRIDGED 1
-int ule_test_sndu( struct dvb_net_priv *p )
+static int ule_test_sndu( struct dvb_net_priv *p )
{
return -1;
}
-int ule_bridged_sndu( struct dvb_net_priv *p )
+static int ule_bridged_sndu( struct dvb_net_priv *p )
{
/* BRIDGE SNDU handling sucks in draft-ietf-ipdvb-ule-03.txt.
* This has to be the last extension header, otherwise it won't work.
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index 57cf77cf6774e..cf4ffe38fda37 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -51,9 +51,10 @@ static const char * const dnames[] = {
"net", "osd"
};
-#define DVB_MAX_IDS 6
-#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type)
-#define MAX_DVB_MINORS (DVB_MAX_IDS*64)
+#define DVB_MAX_ADAPTERS 8
+#define DVB_MAX_IDS 4
+#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type)
+#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)
struct class_simple *dvb_class;
EXPORT_SYMBOL(dvb_class);
@@ -268,7 +269,7 @@ static int dvbdev_get_free_adapter_num (void)
{
int num = 0;
- while (1) {
+ while (num < DVB_MAX_ADAPTERS) {
struct list_head *entry;
list_for_each (entry, &dvb_adapter_list) {
struct dvb_adapter *adap;
@@ -396,9 +397,7 @@ int dvb_usercopy(struct inode *inode, struct file *file,
}
out:
- if (mbuf)
- kfree(mbuf);
-
+ kfree(mbuf);
return err;
}
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index c8acf8f0bbf9a..0bfd4df17d08d 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -108,14 +108,14 @@ config DVB_MT352
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_DIB3000MB
- tristate "DiBcom 3000-MB"
+ tristate "DiBcom 3000M-B"
depends on DVB_CORE
help
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
to support this frontend.
config DVB_DIB3000MC
- tristate "DiBcom 3000-MC/P"
+ tristate "DiBcom 3000P/M-C"
depends on DVB_CORE
help
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
@@ -154,6 +154,7 @@ comment "ATSC (North American/Korean Terresterial DTV) frontends"
config DVB_NXT2002
tristate "Nxt2002 based"
depends on DVB_CORE
+ select FW_LOADER
help
An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
@@ -161,4 +162,11 @@ config DVB_OR51132
tristate "OR51132 based (pcHDTV)"
depends on DVB_CORE
+config DVB_OR51211
+ tristate "or51211 based (pcHDTV HD2000 card)"
+ depends on DVB_CORE
+ select FW_LOADER
+ help
+ An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
+
endmenu
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 863e304468900..7f8784870eab2 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -26,4 +26,5 @@ obj-$(CONFIG_DVB_TDA80XX) += tda80xx.o
obj-$(CONFIG_DVB_TDA10021) += tda10021.o
obj-$(CONFIG_DVB_STV0297) += stv0297.o
obj-$(CONFIG_DVB_NXT2002) += nxt2002.o
+obj-$(CONFIG_DVB_OR51211) += or51211.o
obj-$(CONFIG_DVB_OR51132) += or51132.o
diff --git a/drivers/media/dvb/frontends/at76c651.c b/drivers/media/dvb/frontends/at76c651.c
index 8618767918766..ce2eaa1640e87 100644
--- a/drivers/media/dvb/frontends/at76c651.c
+++ b/drivers/media/dvb/frontends/at76c651.c
@@ -402,7 +402,7 @@ struct dvb_frontend* at76c651_attach(const struct at76c651_config* config,
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c
index 663002da331fa..a212279042b8f 100644
--- a/drivers/media/dvb/frontends/cx22700.c
+++ b/drivers/media/dvb/frontends/cx22700.c
@@ -392,7 +392,7 @@ struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 7bcff1c62da6f..1930b513eefad 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -476,7 +476,7 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index 4bbffaae275c2..6147e580a1536 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -581,7 +581,7 @@ struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/dib3000-common.c b/drivers/media/dvb/frontends/dib3000-common.c
index 1a4f1f7c228a1..47ab02e133d1b 100644
--- a/drivers/media/dvb/frontends/dib3000-common.c
+++ b/drivers/media/dvb/frontends/dib3000-common.c
@@ -73,7 +73,7 @@ u16 dib3000_seq[2][2][2] = /* fft,gua, inv */
};
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de");
-MODULE_DESCRIPTION("Common functions for the dib3000mb/dib3000mc dvb frontend drivers");
+MODULE_DESCRIPTION("Common functions for the dib3000mb/dib3000mc dvb-frontend drivers");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(dib3000_seq);
diff --git a/drivers/media/dvb/frontends/dib3000-common.h b/drivers/media/dvb/frontends/dib3000-common.h
index 2286891da698b..c31d6df15472e 100644
--- a/drivers/media/dvb/frontends/dib3000-common.h
+++ b/drivers/media/dvb/frontends/dib3000-common.h
@@ -1,6 +1,6 @@
/*
* .h-files for the common use of the frontend drivers made by DiBcom
- * DiBcom 3000-MB/MC/P
+ * DiBcom 3000M-B/C, 3000P
*
* DiBcom (http://www.dibcom.fr/)
*
@@ -30,9 +30,9 @@
#include "dib3000.h"
/* info and err, taken from usb.h, if there is anything available like by default. */
-#define err(format, arg...) printk(KERN_ERR "dib3000mX: " format "\n" , ## arg)
-#define info(format, arg...) printk(KERN_INFO "dib3000mX: " format "\n" , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "dib3000mX: " format "\n" , ## arg)
+#define err(format, arg...) printk(KERN_ERR "dib3000: " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO "dib3000: " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "dib3000: " format "\n" , ## arg)
/* frontend state */
struct dib3000_state {
diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h
index a2525e478f629..80687c130836f 100644
--- a/drivers/media/dvb/frontends/dib3000.h
+++ b/drivers/media/dvb/frontends/dib3000.h
@@ -1,6 +1,6 @@
/*
* public header file of the frontend drivers for mobile DVB-T demodulators
- * DiBcom 3000-MB and DiBcom 3000-MC/P (http://www.dibcom.fr/)
+ * DiBcom 3000M-B and DiBcom 3000P/M-C (http://www.dibcom.fr/)
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index 9a3ec43948142..a853d12a26f1e 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -1,5 +1,5 @@
/*
- * Frontend driver for mobile DVB-T demodulator DiBcom 3000-MB
+ * Frontend driver for mobile DVB-T demodulator DiBcom 3000M-B
* DiBcom (http://www.dibcom.fr/)
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
@@ -35,7 +35,7 @@
/* Version information */
#define DRIVER_VERSION "0.1"
-#define DRIVER_DESC "DiBcom 3000-MB DVB-T demodulator driver"
+#define DRIVER_DESC "DiBcom 3000M-B DVB-T demodulator"
#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
#ifdef CONFIG_DVB_DIBCOM_DEBUG
@@ -297,7 +297,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
rd(DIB3000MB_REG_LOCK2_VALUE))) < 0 && as_count++ < 100)
msleep(1);
- deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count);
+ deb_setf("search_state after autosearch %d after %d checks\n",search_state,as_count);
if (search_state == 1) {
struct dvb_frontend_parameters feps;
@@ -319,6 +319,7 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
{
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+ deb_info("dib3000mb is getting up.\n");
wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_UP);
wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC);
@@ -574,16 +575,9 @@ static int dib3000mb_read_status(struct dvb_frontend* fe, fe_status_t *stat)
if (rd(DIB3000MB_REG_TS_SYNC_LOCK))
*stat |= (FE_HAS_SYNC | FE_HAS_LOCK);
- deb_info("actual status is %2x\n",*stat);
+ deb_getf("actual status is %2x\n",*stat);
- deb_getf("tps %x %x %x %x %x\n",
- rd(DIB3000MB_REG_TPS_1),
- rd(DIB3000MB_REG_TPS_2),
- rd(DIB3000MB_REG_TPS_3),
- rd(DIB3000MB_REG_TPS_4),
- rd(DIB3000MB_REG_TPS_5));
-
- deb_info("autoval: tps: %d, qam: %d, hrch: %d, alpha: %d, hp: %d, lp: %d, guard: %d, fft: %d cell: %d\n",
+ deb_getf("autoval: tps: %d, qam: %d, hrch: %d, alpha: %d, hp: %d, lp: %d, guard: %d, fft: %d cell: %d\n",
rd(DIB3000MB_REG_TPS_LOCK),
rd(DIB3000MB_REG_TPS_QAM),
rd(DIB3000MB_REG_TPS_HRCH),
@@ -605,68 +599,22 @@ static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber)
*ber = ((rd(DIB3000MB_REG_BER_MSB) << 16) | rd(DIB3000MB_REG_BER_LSB));
return 0;
}
-/*
- * Amaury:
- * signal strength is measured with dBm (power compared to mW)
- * the standard range is -90dBm(low power) to -10 dBm (strong power),
- * but the calibration is done for -100 dBm to 0dBm
- */
-#define DIB3000MB_AGC_REF_dBm -14
-#define DIB3000MB_GAIN_SLOPE_dBm 100
-#define DIB3000MB_GAIN_DELTA_dBm -2
+/* see dib3000-watch dvb-apps for exact calcuations of signal_strength and snr */
static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
{
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
-/* TODO log10
- u16 sigpow = rd(DIB3000MB_REG_SIGNAL_POWER),
- n_agc_power = rd(DIB3000MB_REG_AGC_POWER),
- rf_power = rd(DIB3000MB_REG_RF_POWER);
- double rf_power_dBm, ad_power_dBm, minar_power_dBm;
-
- if (n_agc_power == 0 )
- n_agc_power = 1 ;
-
- ad_power_dBm = 10 * log10 ( (float)n_agc_power / (float)(1<<16) );
- minor_power_dBm = ad_power_dBm - DIB3000MB_AGC_REF_dBm;
- rf_power_dBm = (-DIB3000MB_GAIN_SLOPE_dBm * (float)rf_power / (float)(1<<16) +
- DIB3000MB_GAIN_DELTA_dBm) + minor_power_dBm;
- // relative rf_power
- *strength = (u16) ((rf_power_dBm + 100) / 100 * 0xffff);
-*/
*strength = rd(DIB3000MB_REG_SIGNAL_POWER) * 0xffff / 0x170;
return 0;
}
-/*
- * Amaury:
- * snr is the signal quality measured in dB.
- * snr = 10*log10(signal power / noise power)
- * the best quality is near 35dB (cable transmission & good modulator)
- * the minimum without errors depend of transmission parameters
- * some indicative values are given in en300744 Annex A
- * ex : 16QAM 2/3 (Gaussian) = 11.1 dB
- *
- * If SNR is above 20dB, BER should be always 0.
- * choose 0dB as the minimum
- */
static int dib3000mb_read_snr(struct dvb_frontend* fe, u16 *snr)
{
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
short sigpow = rd(DIB3000MB_REG_SIGNAL_POWER);
int icipow = ((rd(DIB3000MB_REG_NOISE_POWER_MSB) & 0xff) << 16) |
rd(DIB3000MB_REG_NOISE_POWER_LSB);
-/*
- float snr_dBm=0;
-
- if (sigpow > 0 && icipow > 0)
- snr_dBm = 10.0 * log10( (float) (sigpow<<8) / (float)icipow ) ;
- else if (sigpow > 0)
- snr_dBm = 35;
-
- *snr = (u16) ((snr_dBm / 35) * 0xffff);
-*/
*snr = (sigpow << 8) / ((icipow > 0) ? icipow : 1);
return 0;
}
@@ -682,7 +630,7 @@ static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
static int dib3000mb_sleep(struct dvb_frontend* fe)
{
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
-
+ deb_info("dib3000mb is going to bed.\n");
wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_DOWN);
return 0;
}
@@ -736,8 +684,9 @@ static int dib3000mb_fifo_control(struct dvb_frontend *fe, int onoff)
static int dib3000mb_pid_parse(struct dvb_frontend *fe, int onoff)
{
- //struct dib3000_state *state = fe->demodulator_priv;
- /* switch it off and on */
+ struct dib3000_state *state = fe->demodulator_priv;
+ deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling");
+ wr(DIB3000MB_REG_PID_PARSE,onoff);
return 0;
}
@@ -763,6 +712,7 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
state = (struct dib3000_state*) kmalloc(sizeof(struct dib3000_state), GFP_KERNEL);
if (state == NULL)
goto error;
+ memset(state,0,sizeof(struct dib3000_state));
/* setup the state */
state->i2c = i2c;
@@ -789,15 +739,14 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
return &state->frontend;
error:
- if (state)
- kfree(state);
+ kfree(state);
return NULL;
}
static struct dvb_frontend_ops dib3000mb_ops = {
.info = {
- .name = "DiBcom 3000-MB DVB-T",
+ .name = "DiBcom 3000M-B DVB-T",
.type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index 1d4b988a43b23..4a31c05eaecd1 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -1,5 +1,5 @@
/*
- * Frontend driver for mobile DVB-T demodulator DiBcom 3000-MC/P
+ * Frontend driver for mobile DVB-T demodulator DiBcom 3000P/M-C
* DiBcom (http://www.dibcom.fr/)
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
@@ -34,7 +34,7 @@
/* Version information */
#define DRIVER_VERSION "0.1"
-#define DRIVER_DESC "DiBcom 3000-MC DVB-T demodulator driver"
+#define DRIVER_DESC "DiBcom 3000M-C DVB-T demodulator"
#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
#ifdef CONFIG_DVB_DIBCOM_DEBUG
@@ -794,10 +794,8 @@ static int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling");
if (onoff) {
- deb_xfer("%d %x\n",tmp | DIB3000MC_SMO_MODE_PID_PARSE,tmp | DIB3000MC_SMO_MODE_PID_PARSE);
wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_PID_PARSE);
} else {
- deb_xfer("%d %x\n",tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE);
wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE);
}
return 0;
@@ -849,6 +847,7 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
state = (struct dib3000_state*) kmalloc(sizeof(struct dib3000_state), GFP_KERNEL);
if (state == NULL)
goto error;
+ memset(state,0,sizeof(struct dib3000_state));
/* setup the state */
state->i2c = i2c;
@@ -865,10 +864,10 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
switch (devid) {
case DIB3000MC_DEVICE_ID:
- info("Found a DiBcom 3000-MC, interesting...");
+ info("Found a DiBcom 3000M-C, interesting...");
break;
case DIB3000P_DEVICE_ID:
- info("Found a DiBcom 3000-P.");
+ info("Found a DiBcom 3000P.");
break;
}
@@ -887,15 +886,14 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
return &state->frontend;
error:
- if (state)
- kfree(state);
+ kfree(state);
return NULL;
}
static struct dvb_frontend_ops dib3000mc_ops = {
.info = {
- .name = "DiBcom 3000-MC/P DVB-T",
+ .name = "DiBcom 3000P/M-C DVB-T",
.type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
diff --git a/drivers/media/dvb/frontends/dib3000mc_priv.h b/drivers/media/dvb/frontends/dib3000mc_priv.h
index 2b2342b758eab..2930aac7591b7 100644
--- a/drivers/media/dvb/frontends/dib3000mc_priv.h
+++ b/drivers/media/dvb/frontends/dib3000mc_priv.h
@@ -320,7 +320,7 @@ static u16 dib3000mc_mobile_mode[][5] = {
* pidfilter
* it is not a hardware pidfilter but a filter which drops all pids
* except the ones set. When connected to USB1.1 bandwidth this is important.
- * DiB3000-MC/P can filter up to 32 PIDs
+ * DiB3000P/M-C can filter up to 32 PIDs
*/
#define DIB3000MC_REG_FIRST_PID ( 212)
#define DIB3000MC_NUM_PIDS ( 32)
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c
index 375d6f3b4401a..c05a9b05600c2 100644
--- a/drivers/media/dvb/frontends/dvb_dummy_fe.c
+++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c
@@ -123,7 +123,7 @@ struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void)
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c
index 385b04ee00a83..9ac95de9834d5 100644
--- a/drivers/media/dvb/frontends/l64781.c
+++ b/drivers/media/dvb/frontends/l64781.c
@@ -1,9 +1,8 @@
/*
driver for LSI L64781 COFDM demodulator
- Copyright (C) 2001 Holger Waechtler <holger@convergence.de>
- for Convergence Integrated Media GmbH
- Marko Kohtala <marko.kohtala@nokia.com>
+ Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH
+ Marko Kohtala <marko.kohtala@luukku.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
@@ -560,7 +559,7 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config,
error:
if (reg0x3e >= 0) l64781_writereg (state, 0x3e, reg0x3e); /* restore reg 0x3e */
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/l64781.h b/drivers/media/dvb/frontends/l64781.h
index 259dfffcc8679..7e30fb0fdfa78 100644
--- a/drivers/media/dvb/frontends/l64781.h
+++ b/drivers/media/dvb/frontends/l64781.h
@@ -1,9 +1,8 @@
/*
driver for LSI L64781 COFDM demodulator
- Copyright (C) 2001 Holger Waechtler <holger@convergence.de>
- for Convergence Integrated Media GmbH
- Marko Kohtala <marko.kohtala@nokia.com>
+ Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH
+ Marko Kohtala <marko.kohtala@luukku.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
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
index 9880b3742d059..176a22e3441bf 100644
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb/frontends/mt312.c
@@ -641,8 +641,7 @@ struct dvb_frontend* vp310_attach(const struct mt312_config* config,
return &state->frontend;
error:
- if (state)
- kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
index 06125c54eff7a..50326c7248fa3 100644
--- a/drivers/media/dvb/frontends/mt352.c
+++ b/drivers/media/dvb/frontends/mt352.c
@@ -42,13 +42,11 @@
struct mt352_state {
struct i2c_adapter* i2c;
+ struct dvb_frontend frontend;
struct dvb_frontend_ops ops;
/* configuration settings */
const struct mt352_config* config;
- int s0,s1,s3;
-
- struct dvb_frontend frontend;
};
static int debug;
@@ -59,7 +57,7 @@ static int debug;
static int mt352_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
{
- struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+ struct mt352_state* state = fe->demodulator_priv;
u8 buf[2] = { reg, val };
struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0,
.buf = buf, .len = 2 };
@@ -170,7 +168,7 @@ static void mt352_calc_input_freq(struct mt352_state* state,
static int mt352_set_parameters(struct dvb_frontend* fe,
struct dvb_frontend_parameters *param)
{
- struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+ struct mt352_state* state = fe->demodulator_priv;
unsigned char buf[13];
static unsigned char tuner_go[] = { 0x5d, 0x01 };
static unsigned char fsm_go[] = { 0x5e, 0x01 };
@@ -293,18 +291,6 @@ static int mt352_set_parameters(struct dvb_frontend* fe,
mt352_calc_input_freq(state, buf+6);
state->config->pll_set(fe, param, buf+8);
-#if 0 /* FIXME: should be catched elsewhere ... */
- /* Only send the tuning request if the tuner doesn't have the requested
- * parameters already set. Enhances tuning time and prevents stream
- * breakup when retuning the same transponder. */
- for (i = 1; i < 13; i++)
- if (buf[i] != mt352_read_register(state, i + 0x50))
- break;
- if (13 == i)
- /* no changes */
- return 0;
-#endif
-
mt352_write(fe, buf, sizeof(buf));
if (state->config->no_tuner) {
/* start decoding */
@@ -319,7 +305,7 @@ static int mt352_set_parameters(struct dvb_frontend* fe,
static int mt352_get_parameters(struct dvb_frontend* fe,
struct dvb_frontend_parameters *param)
{
- struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+ struct mt352_state* state = fe->demodulator_priv;
u16 tps;
u16 div;
u8 trl;
@@ -337,9 +323,7 @@ static int mt352_get_parameters(struct dvb_frontend* fe,
};
if ( (mt352_read_register(state,0x00) & 0xC0) != 0xC0 )
- {
return -EINVAL;
- }
/* Use TPS_RECEIVED-registers, not the TPS_CURRENT-registers because
* the mt352 sometimes works with the wrong parameters
@@ -410,17 +394,11 @@ static int mt352_get_parameters(struct dvb_frontend* fe,
param->frequency = ( 500 * (div - IF_FREQUENCYx6) ) / 3 * 1000;
if (trl == 0x72)
- {
op->bandwidth = BANDWIDTH_8_MHZ;
- }
else if (trl == 0x64)
- {
op->bandwidth = BANDWIDTH_7_MHZ;
- }
else
- {
op->bandwidth = BANDWIDTH_6_MHZ;
- }
if (mt352_read_register(state, STATUS_2) & 0x02)
@@ -433,39 +411,38 @@ static int mt352_get_parameters(struct dvb_frontend* fe,
static int mt352_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
- struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
-#if 1
- int val;
-
- if (0 != mt352_read_register(state, INTERRUPT_0)) {
- val = mt352_read_register(state, STATUS_0);
- if (-1 != val)
- state->s0 = val;
- val = mt352_read_register(state, STATUS_1);
- if (-1 != val)
- state->s1 = val;
- val = mt352_read_register(state, STATUS_3);
- if (-1 != val)
- state->s3 = val;
- }
-#else
- state->s0 = mt352_read_register(state, STATUS_0);
- state->s1 = mt352_read_register(state, STATUS_1);
- state->s3 = mt352_read_register(state, STATUS_3);
- if (-1 == state->s0 || -1 == state->s1 || -1 == state->s3)
- return -EIO;
-#endif
+ struct mt352_state* state = fe->demodulator_priv;
+ int s0, s1, s3;
+
+ /* FIXME:
+ *
+ * The MT352 design manual from Zarlink states (page 46-47):
+ *
+ * Notes about the TUNER_GO register:
+ *
+ * If the Read_Tuner_Byte (bit-1) is activated, then the tuner status
+ * byte is copied from the tuner to the STATUS_3 register and
+ * completion of the read operation is indicated by bit-5 of the
+ * INTERRUPT_3 register.
+ */
+
+ if ((s0 = mt352_read_register(state, STATUS_0)) < 0)
+ return -EREMOTEIO;
+ if ((s1 = mt352_read_register(state, STATUS_1)) < 0)
+ return -EREMOTEIO;
+ if ((s3 = mt352_read_register(state, STATUS_3)) < 0)
+ return -EREMOTEIO;
*status = 0;
- if (state->s0 & (1 << 4))
+ if (s0 & (1 << 4))
*status |= FE_HAS_CARRIER;
- if (state->s0 & (1 << 1))
+ if (s0 & (1 << 1))
*status |= FE_HAS_VITERBI;
- if (state->s0 & (1 << 5))
+ if (s0 & (1 << 5))
*status |= FE_HAS_LOCK;
- if (state->s1 & (1 << 1))
+ if (s1 & (1 << 1))
*status |= FE_HAS_SYNC;
- if (state->s3 & (1 << 6))
+ if (s3 & (1 << 6))
*status |= FE_HAS_SIGNAL;
if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
@@ -477,7 +454,7 @@ static int mt352_read_status(struct dvb_frontend* fe, fe_status_t* status)
static int mt352_read_ber(struct dvb_frontend* fe, u32* ber)
{
- struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+ struct mt352_state* state = fe->demodulator_priv;
*ber = (mt352_read_register (state, RS_ERR_CNT_2) << 16) |
(mt352_read_register (state, RS_ERR_CNT_1) << 8) |
@@ -488,10 +465,10 @@ static int mt352_read_ber(struct dvb_frontend* fe, u32* ber)
static int mt352_read_signal_strength(struct dvb_frontend* fe, u16* strength)
{
- struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+ struct mt352_state* state = fe->demodulator_priv;
- u16 signal = (mt352_read_register (state, AGC_GAIN_3) << 8) |
- (mt352_read_register (state, AGC_GAIN_2));
+ u16 signal = ((mt352_read_register(state, AGC_GAIN_1) << 8) & 0x0f) |
+ (mt352_read_register(state, AGC_GAIN_0));
*strength = ~signal;
return 0;
@@ -499,7 +476,7 @@ static int mt352_read_signal_strength(struct dvb_frontend* fe, u16* strength)
static int mt352_read_snr(struct dvb_frontend* fe, u16* snr)
{
- struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+ struct mt352_state* state = fe->demodulator_priv;
u8 _snr = mt352_read_register (state, SNR);
*snr = (_snr << 8) | _snr;
@@ -509,7 +486,7 @@ static int mt352_read_snr(struct dvb_frontend* fe, u16* snr)
static int mt352_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
{
- struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+ struct mt352_state* state = fe->demodulator_priv;
*ucblocks = (mt352_read_register (state, RS_UBC_1) << 8) |
(mt352_read_register (state, RS_UBC_0));
@@ -528,7 +505,7 @@ static int mt352_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_
static int mt352_init(struct dvb_frontend* fe)
{
- struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+ struct mt352_state* state = fe->demodulator_priv;
static u8 mt352_reset_attach [] = { RESET, 0xC0 };
@@ -547,7 +524,7 @@ static int mt352_init(struct dvb_frontend* fe)
static void mt352_release(struct dvb_frontend* fe)
{
- struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+ struct mt352_state* state = fe->demodulator_priv;
kfree(state);
}
@@ -559,7 +536,7 @@ struct dvb_frontend* mt352_attach(const struct mt352_config* config,
struct mt352_state* state = NULL;
/* allocate memory for the internal state */
- state = (struct mt352_state*) kmalloc(sizeof(struct mt352_state), GFP_KERNEL);
+ state = kmalloc(sizeof(struct mt352_state), GFP_KERNEL);
if (state == NULL) goto error;
memset(state,0,sizeof(*state));
@@ -577,7 +554,7 @@ struct dvb_frontend* mt352_attach(const struct mt352_config* config,
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/nxt2002.c b/drivers/media/dvb/frontends/nxt2002.c
index 984163af5f7bb..4743aa17406e0 100644
--- a/drivers/media/dvb/frontends/nxt2002.c
+++ b/drivers/media/dvb/frontends/nxt2002.c
@@ -343,8 +343,21 @@ static int nxt2002_setup_frontend_parameters (struct dvb_frontend* fe,
/* reset the agc now that tuning has been completed */
nxt2002_agc_reset(state);
+
+
/* set target power level */
+ switch (p->u.vsb.modulation) {
+ case QAM_64:
+ case QAM_256:
+ buf[0] = 0x74;
+ break;
+ case VSB_8:
buf[0] = 0x70;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
i2c_writebytes(state,0x42,buf,1);
/* configure sdm */
@@ -357,7 +370,20 @@ static int nxt2002_setup_frontend_parameters (struct dvb_frontend* fe,
nxt2002_writereg_multibyte(state,0x58,buf,2);
/* write sdmx input */
+ switch (p->u.vsb.modulation) {
+ case QAM_64:
+ buf[0] = 0x68;
+ break;
+ case QAM_256:
+ buf[0] = 0x64;
+ break;
+ case VSB_8:
buf[0] = 0x60;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
buf[1] = 0x00;
nxt2002_writereg_multibyte(state,0x5C,buf,2);
@@ -387,7 +413,20 @@ static int nxt2002_setup_frontend_parameters (struct dvb_frontend* fe,
i2c_writebytes(state,0x41,buf,1);
/* write agc ucgp0 */
+ switch (p->u.vsb.modulation) {
+ case QAM_64:
+ buf[0] = 0x02;
+ break;
+ case QAM_256:
+ buf[0] = 0x03;
+ break;
+ case VSB_8:
buf[0] = 0x00;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
i2c_writebytes(state,0x30,buf,1);
/* write agc control reg */
@@ -520,7 +559,7 @@ static int nxt2002_init(struct dvb_frontend* fe)
if (!state->initialised) {
/* request the firmware, this will block until someone uploads it */
- printk("nxt2002: Waiting for firmware upload...\n");
+ printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE);
ret = state->config->request_firmware(fe, &fw, NXT2002_DEFAULT_FIRMWARE);
printk("nxt2002: Waiting for firmware upload(2)...\n");
if (ret) {
@@ -534,6 +573,7 @@ static int nxt2002_init(struct dvb_frontend* fe)
release_firmware(fw);
return ret;
}
+ printk("nxt2002: firmware upload complete\n");
/* Put the micro into reset */
nxt2002_microcontroller_stop(state);
@@ -621,7 +661,7 @@ struct dvb_frontend* nxt2002_attach(const struct nxt2002_config* config,
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
@@ -631,12 +671,12 @@ static struct dvb_frontend_ops nxt2002_ops = {
.name = "Nextwave nxt2002 VSB/QAM frontend",
.type = FE_ATSC,
.frequency_min = 54000000,
- .frequency_max = 803000000,
+ .frequency_max = 860000000,
/* stepsize is just a guess */
.frequency_stepsize = 166666,
.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_8VSB
+ FE_CAN_8VSB | FE_CAN_QAM_64 | FE_CAN_QAM_256
},
.release = nxt2002_release,
diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c
index 9708d4732e17e..a41f7da8b8422 100644
--- a/drivers/media/dvb/frontends/nxt6000.c
+++ b/drivers/media/dvb/frontends/nxt6000.c
@@ -511,7 +511,7 @@ struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index 6bd790fb5736e..df5dee7760a34 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -422,7 +422,7 @@ static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status)
}
/* log10-1 table at .5 increments from 1 to 100.5 */
-unsigned int i100x20log10[] = {
+static unsigned int i100x20log10[] = {
0, 352, 602, 795, 954, 1088, 1204, 1306, 1397, 1480,
1556, 1625, 1690, 1750, 1806, 1858, 1908, 1955, 2000, 2042,
2082, 2121, 2158, 2193, 2227, 2260, 2292, 2322, 2352, 2380,
@@ -445,9 +445,9 @@ unsigned int i100x20log10[] = {
3964, 3969, 3973, 3978, 3982, 3986, 3991, 3995, 4000, 4004,
};
-unsigned int denom[] = {1,1,100,1000,10000,100000,1000000,10000000,100000000};
+static unsigned int denom[] = {1,1,100,1000,10000,100000,1000000,10000000,100000000};
-unsigned int i20Log10(unsigned short val)
+static unsigned int i20Log10(unsigned short val)
{
unsigned int rntval = 100;
unsigned int tmp = val;
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
new file mode 100644
index 0000000000000..ad56a99584043
--- /dev/null
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -0,0 +1,631 @@
+/*
+ * Support for OR51211 (pcHDTV HD-2000) - VSB
+ *
+ * Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com>
+ *
+ * Based on code from Jack Kelliher (kelliher@xmission.com)
+ * Copyright (C) 2002 & pcHDTV, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+/*
+ * This driver needs external firmware. Please use the command
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ */
+#define OR51211_DEFAULT_FIRMWARE "dvb-fe-or51211.fw"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <asm/byteorder.h>
+
+#include "dvb_frontend.h"
+#include "or51211.h"
+
+static int debug;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "or51211: " args); \
+ } while (0)
+
+static u8 run_buf[] = {0x7f,0x01};
+static u8 cmd_buf[] = {0x04,0x01,0x50,0x80,0x06}; // ATSC
+
+struct or51211_state {
+
+ struct i2c_adapter* i2c;
+ struct dvb_frontend_ops ops;
+
+ /* Configuration settings */
+ const struct or51211_config* config;
+
+ struct dvb_frontend frontend;
+ struct bt878* bt;
+
+ /* Demodulator private data */
+ u8 initialized:1;
+
+ /* Tuner private data */
+ u32 current_frequency;
+};
+
+static int i2c_writebytes (struct or51211_state* state, u8 reg, u8 *buf,
+ int len)
+{
+ int err;
+ struct i2c_msg msg;
+ msg.addr = reg;
+ msg.flags = 0;
+ msg.len = len;
+ msg.buf = buf;
+
+ if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+ printk(KERN_WARNING "or51211: i2c_writebytes error "
+ "(addr %02x, err == %i)\n", reg, err);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static u8 i2c_readbytes (struct or51211_state* state, u8 reg, u8* buf, int len)
+{
+ int err;
+ struct i2c_msg msg;
+ msg.addr = reg;
+ msg.flags = I2C_M_RD;
+ msg.len = len;
+ msg.buf = buf;
+
+ if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+ printk(KERN_WARNING "or51211: i2c_readbytes error "
+ "(addr %02x, err == %i)\n", reg, err);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int or51211_load_firmware (struct dvb_frontend* fe,
+ const struct firmware *fw)
+{
+ struct or51211_state* state = fe->demodulator_priv;
+ u8 tudata[585];
+ int i;
+
+ dprintk("Firmware is %d bytes\n",fw->size);
+
+ /* Get eprom data */
+ tudata[0] = 17;
+ if (i2c_writebytes(state,0x50,tudata,1)) {
+ printk(KERN_WARNING "or51211:load_firmware error eprom addr\n");
+ return -1;
+ }
+ if (i2c_readbytes(state,0x50,&tudata[145],192)) {
+ printk(KERN_WARNING "or51211: load_firmware error eprom\n");
+ return -1;
+ }
+
+ /* Create firmware buffer */
+ for (i = 0; i < 145; i++)
+ tudata[i] = fw->data[i];
+
+ for (i = 0; i < 248; i++)
+ tudata[i+337] = fw->data[145+i];
+
+ state->config->reset(fe);
+
+ if (i2c_writebytes(state,state->config->demod_address,tudata,585)) {
+ printk(KERN_WARNING "or51211: load_firmware error 1\n");
+ return -1;
+ }
+ msleep(1);
+
+ if (i2c_writebytes(state,state->config->demod_address,
+ &fw->data[393],8125)) {
+ printk(KERN_WARNING "or51211: load_firmware error 2\n");
+ return -1;
+ }
+ msleep(1);
+
+ if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
+ printk(KERN_WARNING "or51211: load_firmware error 3\n");
+ return -1;
+ }
+
+ /* Wait at least 5 msec */
+ msleep(10);
+ if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
+ printk(KERN_WARNING "or51211: load_firmware error 4\n");
+ return -1;
+ }
+ msleep(10);
+
+ printk("or51211: Done.\n");
+ return 0;
+};
+
+static int or51211_setmode(struct dvb_frontend* fe, int mode)
+{
+ struct or51211_state* state = fe->demodulator_priv;
+ u8 rec_buf[14];
+
+ state->config->setmode(fe, mode);
+
+ if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
+ printk(KERN_WARNING "or51211: setmode error 1\n");
+ return -1;
+ }
+
+ /* Wait at least 5 msec */
+ msleep(10);
+ if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
+ printk(KERN_WARNING "or51211: setmode error 2\n");
+ return -1;
+ }
+
+ msleep(10);
+
+ /* Set operation mode in Receiver 1 register;
+ * type 1:
+ * data 0x50h Automatic sets receiver channel conditions
+ * Automatic NTSC rejection filter
+ * Enable MPEG serial data output
+ * MPEG2tr
+ * High tuner phase noise
+ * normal +/-150kHz Carrier acquisition range
+ */
+ if (i2c_writebytes(state,state->config->demod_address,cmd_buf,3)) {
+ printk(KERN_WARNING "or51211: setmode error 3\n");
+ return -1;
+ }
+
+ rec_buf[0] = 0x04;
+ rec_buf[1] = 0x00;
+ rec_buf[2] = 0x03;
+ rec_buf[3] = 0x00;
+ msleep(20);
+ if (i2c_writebytes(state,state->config->demod_address,rec_buf,3)) {
+ printk(KERN_WARNING "or51211: setmode error 5\n");
+ }
+ msleep(3);
+ if (i2c_readbytes(state,state->config->demod_address,&rec_buf[10],2)) {
+ printk(KERN_WARNING "or51211: setmode error 6");
+ return -1;
+ }
+ dprintk("setmode rec status %02x %02x\n",rec_buf[10],rec_buf[11]);
+
+ return 0;
+}
+
+static int or51211_set_parameters(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *param)
+{
+ struct or51211_state* state = fe->demodulator_priv;
+ u32 freq = 0;
+ u16 tunerfreq = 0;
+ u8 buf[4];
+
+ /* Change only if we are actually changing the channel */
+ if (state->current_frequency != param->frequency) {
+ freq = 44000 + (param->frequency/1000);
+ tunerfreq = freq * 16/1000;
+
+ dprintk("set_parameters frequency = %d (tunerfreq = %d)\n",
+ param->frequency,tunerfreq);
+
+ buf[0] = (tunerfreq >> 8) & 0x7F;
+ buf[1] = (tunerfreq & 0xFF);
+ buf[2] = 0x8E;
+
+ if (param->frequency < 157250000) {
+ buf[3] = 0xA0;
+ dprintk("set_parameters VHF low range\n");
+ } else if (param->frequency < 454000000) {
+ buf[3] = 0x90;
+ dprintk("set_parameters VHF high range\n");
+ } else {
+ buf[3] = 0x30;
+ dprintk("set_parameters UHF range\n");
+ }
+ dprintk("set_parameters tuner bytes: 0x%02x 0x%02x "
+ "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]);
+
+ if (i2c_writebytes(state,0xC2>>1,buf,4))
+ printk(KERN_WARNING "or51211:set_parameters error "
+ "writing to tuner\n");
+
+ /* Set to ATSC mode */
+ or51211_setmode(fe,0);
+
+ /* Update current frequency */
+ state->current_frequency = param->frequency;
+ }
+ return 0;
+}
+
+static int or51211_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct or51211_state* state = fe->demodulator_priv;
+ unsigned char rec_buf[2];
+ unsigned char snd_buf[] = {0x04,0x00,0x03,0x00};
+ *status = 0;
+
+ /* Receiver Status */
+ if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
+ printk(KERN_WARNING "or51132: read_status write error\n");
+ return -1;
+ }
+ msleep(3);
+ if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
+ printk(KERN_WARNING "or51132: read_status read error\n");
+ return -1;
+ }
+ dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]);
+
+ if (rec_buf[0] & 0x01) { /* Receiver Lock */
+ *status |= FE_HAS_SIGNAL;
+ *status |= FE_HAS_CARRIER;
+ *status |= FE_HAS_VITERBI;
+ *status |= FE_HAS_SYNC;
+ *status |= FE_HAS_LOCK;
+ }
+ return 0;
+}
+
+/* log10-1 table at .5 increments from 1 to 100.5 */
+static unsigned int i100x20log10[] = {
+ 0, 352, 602, 795, 954, 1088, 1204, 1306, 1397, 1480,
+ 1556, 1625, 1690, 1750, 1806, 1858, 1908, 1955, 2000, 2042,
+ 2082, 2121, 2158, 2193, 2227, 2260, 2292, 2322, 2352, 2380,
+ 2408, 2434, 2460, 2486, 2510, 2534, 2557, 2580, 2602, 2623,
+ 2644, 2664, 2684, 2704, 2723, 2742, 2760, 2778, 2795, 2813,
+ 2829, 2846, 2862, 2878, 2894, 2909, 2924, 2939, 2954, 2968,
+ 2982, 2996, 3010, 3023, 3037, 3050, 3062, 3075, 3088, 3100,
+ 3112, 3124, 3136, 3148, 3159, 3170, 3182, 3193, 3204, 3214,
+ 3225, 3236, 3246, 3256, 3266, 3276, 3286, 3296, 3306, 3316,
+ 3325, 3334, 3344, 3353, 3362, 3371, 3380, 3389, 3397, 3406,
+ 3415, 3423, 3432, 3440, 3448, 3456, 3464, 3472, 3480, 3488,
+ 3496, 3504, 3511, 3519, 3526, 3534, 3541, 3549, 3556, 3563,
+ 3570, 3577, 3584, 3591, 3598, 3605, 3612, 3619, 3625, 3632,
+ 3639, 3645, 3652, 3658, 3665, 3671, 3677, 3683, 3690, 3696,
+ 3702, 3708, 3714, 3720, 3726, 3732, 3738, 3744, 3750, 3755,
+ 3761, 3767, 3772, 3778, 3784, 3789, 3795, 3800, 3806, 3811,
+ 3816, 3822, 3827, 3832, 3838, 3843, 3848, 3853, 3858, 3863,
+ 3868, 3874, 3879, 3884, 3888, 3893, 3898, 3903, 3908, 3913,
+ 3918, 3922, 3927, 3932, 3936, 3941, 3946, 3950, 3955, 3960,
+ 3964, 3969, 3973, 3978, 3982, 3986, 3991, 3995, 4000, 4004,
+};
+
+static unsigned int denom[] = {1,1,100,1000,10000,100000,1000000,10000000,100000000};
+
+static unsigned int i20Log10(unsigned short val)
+{
+ unsigned int rntval = 100;
+ unsigned int tmp = val;
+ unsigned int exp = 1;
+
+ while(tmp > 100) {tmp /= 100; exp++;}
+
+ val = (2 * val)/denom[exp];
+ if (exp > 1) rntval = 2000*exp;
+
+ rntval += i100x20log10[val];
+ return rntval;
+}
+
+static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ struct or51211_state* state = fe->demodulator_priv;
+ u8 rec_buf[2];
+ u8 snd_buf[4];
+ u8 snr_equ;
+
+ /* SNR after Equalizer */
+ snd_buf[0] = 0x04;
+ snd_buf[1] = 0x00;
+ snd_buf[2] = 0x04;
+ snd_buf[3] = 0x00;
+
+ if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
+ printk(KERN_WARNING "or51211: read_status write error\n");
+ return -1;
+ }
+ msleep(3);
+ if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
+ printk(KERN_WARNING "or51211: read_status read error\n");
+ return -1;
+ }
+ snr_equ = rec_buf[0] & 0xff;
+
+ /* The value reported back from the frontend will be FFFF=100% 0000=0% */
+ *strength = (((5334 - i20Log10(snr_equ))/3+5)*65535)/1000;
+
+ dprintk("read_signal_strength %i\n",*strength);
+
+ return 0;
+}
+
+static int or51211_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct or51211_state* state = fe->demodulator_priv;
+ u8 rec_buf[2];
+ u8 snd_buf[4];
+
+ /* SNR after Equalizer */
+ snd_buf[0] = 0x04;
+ snd_buf[1] = 0x00;
+ snd_buf[2] = 0x04;
+ snd_buf[3] = 0x00;
+
+ if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
+ printk(KERN_WARNING "or51211: read_status write error\n");
+ return -1;
+ }
+ msleep(3);
+ if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
+ printk(KERN_WARNING "or51211: read_status read error\n");
+ return -1;
+ }
+ *snr = rec_buf[0] & 0xff;
+
+ dprintk("read_snr %i\n",*snr);
+
+ return 0;
+}
+
+static int or51211_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ *ber = -ENOSYS;
+ return 0;
+}
+
+static int or51211_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ *ucblocks = -ENOSYS;
+ return 0;
+}
+
+static int or51211_sleep(struct dvb_frontend* fe)
+{
+ return 0;
+}
+
+static int or51211_init(struct dvb_frontend* fe)
+{
+ struct or51211_state* state = fe->demodulator_priv;
+ const struct or51211_config* config = state->config;
+ const struct firmware* fw;
+ unsigned char get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00};
+ unsigned char rec_buf[14];
+ int ret,i;
+
+ if (!state->initialized) {
+ /* Request the firmware, this will block until it uploads */
+ printk(KERN_INFO "or51211: Waiting for firmware upload "
+ "(%s)...\n", OR51211_DEFAULT_FIRMWARE);
+ ret = config->request_firmware(fe, &fw,
+ OR51211_DEFAULT_FIRMWARE);
+ printk(KERN_INFO "or51211:Got Hotplug firmware\n");
+ if (ret) {
+ printk(KERN_WARNING "or51211: No firmware uploaded "
+ "(timeout or file not found?)\n");
+ return ret;
+ }
+
+ ret = or51211_load_firmware(fe, fw);
+ if (ret) {
+ printk(KERN_WARNING "or51211: Writing firmware to "
+ "device failed!\n");
+ release_firmware(fw);
+ return ret;
+ }
+ printk(KERN_INFO "or51211: Firmware upload complete.\n");
+
+ /* Set operation mode in Receiver 1 register;
+ * type 1:
+ * data 0x50h Automatic sets receiver channel conditions
+ * Automatic NTSC rejection filter
+ * Enable MPEG serial data output
+ * MPEG2tr
+ * High tuner phase noise
+ * normal +/-150kHz Carrier acquisition range
+ */
+ if (i2c_writebytes(state,state->config->demod_address,
+ cmd_buf,3)) {
+ printk(KERN_WARNING "or51211: Load DVR Error 5\n");
+ return -1;
+ }
+
+ /* Read back ucode version to besure we loaded correctly */
+ /* and are really up and running */
+ rec_buf[0] = 0x04;
+ rec_buf[1] = 0x00;
+ rec_buf[2] = 0x03;
+ rec_buf[3] = 0x00;
+ msleep(30);
+ if (i2c_writebytes(state,state->config->demod_address,
+ rec_buf,3)) {
+ printk(KERN_WARNING "or51211: Load DVR Error A\n");
+ return -1;
+ }
+ msleep(3);
+ if (i2c_readbytes(state,state->config->demod_address,
+ &rec_buf[10],2)) {
+ printk(KERN_WARNING "or51211: Load DVR Error B\n");
+ return -1;
+ }
+
+ rec_buf[0] = 0x04;
+ rec_buf[1] = 0x00;
+ rec_buf[2] = 0x01;
+ rec_buf[3] = 0x00;
+ msleep(20);
+ if (i2c_writebytes(state,state->config->demod_address,
+ rec_buf,3)) {
+ printk(KERN_WARNING "or51211: Load DVR Error C\n");
+ return -1;
+ }
+ msleep(3);
+ if (i2c_readbytes(state,state->config->demod_address,
+ &rec_buf[12],2)) {
+ printk(KERN_WARNING "or51211: Load DVR Error D\n");
+ return -1;
+ }
+
+ for (i = 0; i < 8; i++)
+ rec_buf[i]=0xed;
+
+ for (i = 0; i < 5; i++) {
+ msleep(30);
+ get_ver_buf[4] = i+1;
+ if (i2c_writebytes(state,state->config->demod_address,
+ get_ver_buf,5)) {
+ printk(KERN_WARNING "or51211:Load DVR Error 6"
+ " - %d\n",i);
+ return -1;
+ }
+ msleep(3);
+
+ if (i2c_readbytes(state,state->config->demod_address,
+ &rec_buf[i*2],2)) {
+ printk(KERN_WARNING "or51211:Load DVR Error 7"
+ " - %d\n",i);
+ return -1;
+ }
+ /* If we didn't receive the right index, try again */
+ if ((int)rec_buf[i*2+1]!=i+1){
+ i--;
+ }
+ }
+ dprintk("read_fwbits %x %x %x %x %x %x %x %x %x %x\n",
+ rec_buf[0], rec_buf[1], rec_buf[2], rec_buf[3],
+ rec_buf[4], rec_buf[5], rec_buf[6], rec_buf[7],
+ rec_buf[8], rec_buf[9]);
+
+ printk(KERN_INFO "or51211: ver TU%02x%02x%02x VSB mode %02x"
+ " Status %02x\n",
+ rec_buf[2], rec_buf[4],rec_buf[6],
+ rec_buf[12],rec_buf[10]);
+
+ rec_buf[0] = 0x04;
+ rec_buf[1] = 0x00;
+ rec_buf[2] = 0x03;
+ rec_buf[3] = 0x00;
+ msleep(20);
+ if (i2c_writebytes(state,state->config->demod_address,
+ rec_buf,3)) {
+ printk(KERN_WARNING "or51211: Load DVR Error 8\n");
+ return -1;
+ }
+ msleep(20);
+ if (i2c_readbytes(state,state->config->demod_address,
+ &rec_buf[8],2)) {
+ printk(KERN_WARNING "or51211: Load DVR Error 9\n");
+ return -1;
+ }
+ state->initialized = 1;
+ }
+
+ return 0;
+}
+
+static int or51211_get_tune_settings(struct dvb_frontend* fe,
+ struct dvb_frontend_tune_settings* fesettings)
+{
+ fesettings->min_delay_ms = 500;
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
+ return 0;
+}
+
+static void or51211_release(struct dvb_frontend* fe)
+{
+ struct or51211_state* state = fe->demodulator_priv;
+ state->config->sleep(fe);
+ kfree(state);
+}
+
+static struct dvb_frontend_ops or51211_ops;
+
+struct dvb_frontend* or51211_attach(const struct or51211_config* config,
+ struct i2c_adapter* i2c)
+{
+ struct or51211_state* state = NULL;
+
+ /* Allocate memory for the internal state */
+ state = kmalloc(sizeof(struct or51211_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* Setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
+ state->initialized = 0;
+ state->current_frequency = 0;
+
+ /* Create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops or51211_ops = {
+
+ .info = {
+ .name = "Oren OR51211 VSB Frontend",
+ .type = FE_ATSC,
+ .frequency_min = 44000000,
+ .frequency_max = 958000000,
+ .frequency_stepsize = 166666,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_8VSB
+ },
+
+ .release = or51211_release,
+
+ .init = or51211_init,
+ .sleep = or51211_sleep,
+
+ .set_frontend = or51211_set_parameters,
+ .get_tune_settings = or51211_get_tune_settings,
+
+ .read_status = or51211_read_status,
+ .read_ber = or51211_read_ber,
+ .read_signal_strength = or51211_read_signal_strength,
+ .read_snr = or51211_read_snr,
+ .read_ucblocks = or51211_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Oren OR51211 VSB [pcHDTV HD-2000] Demodulator Driver");
+MODULE_AUTHOR("Kirk Lapray");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(or51211_attach);
+
diff --git a/drivers/media/dvb/frontends/or51211.h b/drivers/media/dvb/frontends/or51211.h
new file mode 100644
index 0000000000000..13a5a3afbf8b1
--- /dev/null
+++ b/drivers/media/dvb/frontends/or51211.h
@@ -0,0 +1,44 @@
+/*
+ * Support for OR51211 (pcHDTV HD-2000) - VSB
+ *
+ * Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+#ifndef OR51211_H
+#define OR51211_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct or51211_config
+{
+ /* The demodulator's i2c address */
+ u8 demod_address;
+
+ /* Request firmware for device */
+ int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+ void (*setmode)(struct dvb_frontend * fe, int mode);
+ void (*reset)(struct dvb_frontend * fe);
+ void (*sleep)(struct dvb_frontend * fe);
+};
+
+extern struct dvb_frontend* or51211_attach(const struct or51211_config* config,
+ struct i2c_adapter* i2c);
+
+#endif // OR51211_H
+
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c
index 538cb03ee3b57..58ad34ef0a007 100644
--- a/drivers/media/dvb/frontends/sp8870.c
+++ b/drivers/media/dvb/frontends/sp8870.c
@@ -570,7 +570,7 @@ struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
index f34c010d0e2eb..7eae833ece490 100644
--- a/drivers/media/dvb/frontends/sp887x.c
+++ b/drivers/media/dvb/frontends/sp887x.c
@@ -564,7 +564,7 @@ struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
index 65255113f1c6b..502c6403dfc64 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -758,8 +758,7 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config,
return &state->frontend;
error:
- if (state)
- kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index a468f88049483..15b40541b62d1 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -675,7 +675,7 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 1690dfd3b30fa..4e40d95ee95da 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -61,12 +61,12 @@ static int verbose;
#define FIN (XIN >> 4)
-int tda10021_inittab_size = 0x40;
+static int tda10021_inittab_size = 0x40;
static u8 tda10021_inittab[0x40]=
{
0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a,
0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40,
- 0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff,
+ 0xb8, 0x3f, 0xa0, 0x00, 0xcd, 0x01, 0x00, 0xff,
0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00,
0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00,
0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58,
@@ -420,7 +420,7 @@ struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index 80ab328529acd..687ad9cf3384b 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -353,7 +353,7 @@ static int tda10045_fwupload(struct dvb_frontend* fe)
if (tda1004x_check_upload_ok(state, 0x2c) == 0) return 0;
/* request the firmware, this will block until someone uploads it */
- printk("tda1004x: waiting for firmware upload...\n");
+ printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE);
ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
if (ret) {
printk("tda1004x: no firmware upload (timeout or file not found?)\n");
@@ -372,6 +372,7 @@ static int tda10045_fwupload(struct dvb_frontend* fe)
ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN);
if (ret)
return ret;
+ printk("tda1004x: firmware upload complete\n");
/* wait for DSP to initialise */
/* DSPREADY doesn't seem to work on the TDA10045H */
@@ -396,7 +397,7 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
if (tda1004x_check_upload_ok(state, 0x20) == 0) return 0;
/* request the firmware, this will block until someone uploads it */
- printk("tda1004x: waiting for firmware upload...\n");
+ printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10046_DEFAULT_FIRMWARE);
ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
if (ret) {
printk("tda1004x: no firmware upload (timeout or file not found?)\n");
@@ -414,6 +415,7 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
if (ret)
return ret;
+ printk("tda1004x: firmware upload complete\n");
/* wait for DSP to initialise */
timeout = jiffies + HZ;
@@ -1095,7 +1097,7 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c
index db6624b9f036b..da82e90d6d136 100644
--- a/drivers/media/dvb/frontends/tda8083.c
+++ b/drivers/media/dvb/frontends/tda8083.c
@@ -405,7 +405,7 @@ struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/tda80xx.c b/drivers/media/dvb/frontends/tda80xx.c
index 4bf476b34efa3..c99632114283d 100644
--- a/drivers/media/dvb/frontends/tda80xx.c
+++ b/drivers/media/dvb/frontends/tda80xx.c
@@ -683,7 +683,7 @@ struct dvb_frontend* tda80xx_attach(const struct tda80xx_config* config,
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c
index 62945ef1f9661..9c0d23e1d9e5a 100644
--- a/drivers/media/dvb/frontends/ves1820.c
+++ b/drivers/media/dvb/frontends/ves1820.c
@@ -404,7 +404,7 @@ struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c
index 2862c7c79ec01..edcad283aa86e 100644
--- a/drivers/media/dvb/frontends/ves1x93.c
+++ b/drivers/media/dvb/frontends/ves1x93.c
@@ -175,7 +175,7 @@ static int ves1x93_set_symbolrate (struct ves1x93_state* state, u32 srate)
{
u32 BDR;
u32 ratio;
- u8 ADCONF, FCONF, FNR;
+ u8 ADCONF, FCONF, FNR, AGCR;
u32 BDRI;
u32 tmp;
u32 FIN;
@@ -243,10 +243,16 @@ static int ves1x93_set_symbolrate (struct ves1x93_state* state, u32 srate)
ves1x93_writereg (state, 0x20, ADCONF);
ves1x93_writereg (state, 0x21, FCONF);
+ AGCR = state->init_1x93_tab[0x05];
+ if (state->config->invert_pwm)
+ AGCR |= 0x20;
+
if (srate < 6000000)
- ves1x93_writereg (state, 0x05, state->init_1x93_tab[0x05] | 0x80);
+ AGCR |= 0x80;
else
- ves1x93_writereg (state, 0x05, state->init_1x93_tab[0x05] & 0x7f);
+ AGCR &= ~0x80;
+
+ ves1x93_writereg (state, 0x05, AGCR);
/* ves1993 hates this, will lose lock */
if (state->demod_type != DEMOD_VES1993)
@@ -491,7 +497,7 @@ struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index edb9c730ebc92..7ffa2c7315b38 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -10,6 +10,7 @@ config DVB_AV7110
select DVB_TDA8083
select DVB_SP8870
select DVB_STV0297
+ select DVB_L64781
help
Support for SAA7146 and AV7110 based DVB cards as produced
by Fujitsu-Siemens, Technotrend, Hauppauge and others.
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 9e80d593f7198..922c205a26522 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -188,6 +188,15 @@ static void arm_error(struct av7110 *av7110)
recover_arm(av7110);
}
+static void av7110_arm_sync(struct av7110 *av7110)
+{
+ av7110->arm_rmmod = 1;
+ wake_up_interruptible(&av7110->arm_wait);
+
+ while (av7110->arm_thread)
+ msleep(1);
+}
+
static int arm_thread(void *data)
{
struct av7110 *av7110 = data;
@@ -1461,6 +1470,11 @@ static int check_firmware(struct av7110* av7110)
#ifdef CONFIG_DVB_AV7110_FIRMWARE_FILE
#include "av7110_firm.h"
+static void put_firmware(struct av7110* av7110)
+{
+ av7110->bin_fw = NULL;
+}
+
static inline int get_firmware(struct av7110* av7110)
{
av7110->bin_fw = dvb_ttpci_fw;
@@ -1468,6 +1482,11 @@ static inline int get_firmware(struct av7110* av7110)
return check_firmware(av7110);
}
#else
+static void put_firmware(struct av7110* av7110)
+{
+ vfree(av7110->bin_fw);
+}
+
static int get_firmware(struct av7110* av7110)
{
int ret;
@@ -1834,6 +1853,45 @@ static struct stv0297_config nexusca_stv0297_config = {
};
+
+static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ u32 div;
+ u8 cfg, cpump, band_select;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = (36125000 + params->frequency) / 166666;
+
+ cfg = 0x88;
+
+ if (params->frequency < 175000000) cpump = 2;
+ else if (params->frequency < 390000000) cpump = 1;
+ else if (params->frequency < 470000000) cpump = 2;
+ else if (params->frequency < 750000000) cpump = 1;
+ else cpump = 3;
+
+ if (params->frequency < 175000000) band_select = 0x0e;
+ else if (params->frequency < 470000000) band_select = 0x05;
+ else band_select = 0x03;
+
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = ((div >> 10) & 0x60) | cfg;
+ data[3] = (cpump << 6) | band_select;
+
+ if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct l64781_config grundig_29504_401_config = {
+ .demod_address = 0x55,
+ .pll_set = grundig_29504_401_pll_set,
+};
+
+
+
static void av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
{
int synced = (status & FE_HAS_LOCK) ? 1 : 0;
@@ -1960,8 +2018,10 @@ static u8 read_pwm(struct av7110* av7110)
return pwm;
}
-static void frontend_init(struct av7110 *av7110)
+static int frontend_init(struct av7110 *av7110)
{
+ int ret;
+
if (av7110->dev->pci->subsystem_vendor == 0x110a) {
switch(av7110->dev->pci->subsystem_device) {
case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??))
@@ -2039,6 +2099,11 @@ static void frontend_init(struct av7110 *av7110)
}
break;
+ case 0x0008: // Hauppauge/TT DVB-T
+
+ av7110->fe = l64781_attach(&grundig_29504_401_config, &av7110->i2c_adap);
+ break;
+
case 0x000A: // Hauppauge/TT Nexus-CA rev1.X
av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap, 0x7b);
@@ -2054,7 +2119,9 @@ static void frontend_init(struct av7110 *av7110)
}
}
- if (av7110->fe == NULL) {
+ if (!av7110->fe) {
+ /* FIXME: propagate the failure code from the lower layers */
+ ret = -ENOMEM;
printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
av7110->dev->pci->vendor,
av7110->dev->pci->device,
@@ -2071,13 +2138,15 @@ static void frontend_init(struct av7110 *av7110)
FE_FUNC_OVERRIDE(av7110->fe->ops->dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
FE_FUNC_OVERRIDE(av7110->fe->ops->set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
- if (dvb_register_frontend(av7110->dvb_adapter, av7110->fe)) {
+ ret = dvb_register_frontend(av7110->dvb_adapter, av7110->fe);
+ if (ret < 0) {
printk("av7110: Frontend registration failed!\n");
if (av7110->fe->ops->release)
av7110->fe->ops->release(av7110->fe);
av7110->fe = NULL;
}
}
+ return ret;
}
/* Budgetpatch note:
@@ -2147,10 +2216,10 @@ static void frontend_init(struct av7110 *av7110)
*/
static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *pci_ext)
{
- struct av7110 *av7110 = NULL;
- int length = TS_WIDTH * TS_HEIGHT;
- int ret = 0;
- int count = 0;
+ const int length = TS_WIDTH * TS_HEIGHT;
+ struct pci_dev *pdev = dev->pci;
+ struct av7110 *av7110;
+ int ret, count = 0;
dprintk(4, "dev: %p\n", dev);
@@ -2244,7 +2313,8 @@ static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_d
}
/* prepare the av7110 device struct */
- if (!(av7110 = kmalloc (sizeof (struct av7110), GFP_KERNEL))) {
+ av7110 = kmalloc(sizeof(struct av7110), GFP_KERNEL);
+ if (!av7110) {
dprintk(1, "out of memory\n");
return -ENOMEM;
}
@@ -2255,12 +2325,14 @@ static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_d
av7110->dev = dev;
dev->ext_priv = av7110;
- if ((ret = get_firmware(av7110))) {
- kfree(av7110);
- return ret;
- }
+ ret = get_firmware(av7110);
+ if (ret < 0)
+ goto err_kfree_0;
- dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name, THIS_MODULE);
+ ret = dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name,
+ THIS_MODULE);
+ if (ret < 0)
+ goto err_put_firmware_1;
/* the Siemens DVB needs this if you want to have the i2c chips
get recognized before the main driver is fully loaded */
@@ -2275,21 +2347,21 @@ static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_d
saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
- if (i2c_add_adapter(&av7110->i2c_adap) < 0) {
-err_no_mem:
- dvb_unregister_adapter (av7110->dvb_adapter);
- kfree(av7110);
- return -ENOMEM;
- }
+ ret = i2c_add_adapter(&av7110->i2c_adap);
+ if (ret < 0)
+ goto err_dvb_unregister_adapter_2;
- ttpci_eeprom_parse_mac(&av7110->i2c_adap, av7110->dvb_adapter->proposed_mac);
+ ttpci_eeprom_parse_mac(&av7110->i2c_adap,
+ av7110->dvb_adapter->proposed_mac);
+ ret = -ENOMEM;
if (budgetpatch) {
spin_lock_init(&av7110->feedlock1);
- av7110->grabbing = saa7146_vmalloc_build_pgtable(
- dev->pci, length, &av7110->pt);
+ av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length,
+ &av7110->pt);
if (!av7110->grabbing)
- goto err_no_mem;
+ goto err_i2c_del_3;
+
saa7146_write(dev, PCI_BT_V1, 0x1c1f101f);
saa7146_write(dev, BCS_CTRL, 0x80400040);
/* set dd1 stream a & b */
@@ -2396,43 +2468,43 @@ err_no_mem:
av7110->arm_thread = NULL;
/* allocate and init buffers */
- av7110->debi_virt = pci_alloc_consistent(dev->pci, 8192,
- &av7110->debi_bus);
- if (!av7110->debi_virt) {
- ret = -ENOMEM;
- goto err;
- }
+ av7110->debi_virt = pci_alloc_consistent(pdev, 8192, &av7110->debi_bus);
+ if (!av7110->debi_virt)
+ goto err_saa71466_vfree_4;
+
av7110->iobuf = vmalloc(AVOUTLEN+AOUTLEN+BMPLEN+4*IPACKS);
- if (!av7110->iobuf) {
- ret = -ENOMEM;
- goto err;
- }
+ if (!av7110->iobuf)
+ goto err_pci_free_5;
- av7110_av_init(av7110);
+ ret = av7110_av_init(av7110);
+ if (ret < 0)
+ goto err_iobuf_vfree_6;
/* init BMP buffer */
av7110->bmpbuf = av7110->iobuf+AVOUTLEN+AOUTLEN;
init_waitqueue_head(&av7110->bmpq);
- av7110_ca_init(av7110);
+ ret = av7110_ca_init(av7110);
+ if (ret < 0)
+ goto err_av7110_av_exit_7;
/* load firmware into AV7110 cards */
- av7110_bootarm(av7110);
- if (av7110_firmversion(av7110)) {
- ret = -EIO;
- goto err2;
- }
+ ret = av7110_bootarm(av7110);
+ if (ret < 0)
+ goto err_av7110_ca_exit_8;
+
+ ret = av7110_firmversion(av7110);
+ if (ret < 0)
+ goto err_stop_arm_9;
if (FW_VERSION(av7110->arm_app)<0x2501)
printk ("dvb-ttpci: Warning, firmware version 0x%04x is too old. "
"System might be unstable!\n", FW_VERSION(av7110->arm_app));
- if (kernel_thread(arm_thread, (void *) av7110, 0) < 0) {
- printk("dvb-ttpci: failed to start arm_mon kernel thread @ card %d\n",
- av7110->dvb_adapter->num);
- goto err2;
- }
+ ret = kernel_thread(arm_thread, (void *) av7110, 0);
+ if (ret < 0)
+ goto err_stop_arm_9;
/* set initial volume in mixer struct */
av7110->mixer.volume_left = volume;
@@ -2440,56 +2512,65 @@ err_no_mem:
init_av7110_av(av7110);
- av7110_register(av7110);
+ ret = av7110_register(av7110);
+ if (ret < 0)
+ goto err_arm_thread_stop_10;
/* special case DVB-C: these cards have an analog tuner
plus need some special handling, so we have separate
saa7146_ext_vv data for these... */
ret = av7110_init_v4l(av7110);
-
- if (ret)
- goto err3;
+ if (ret < 0)
+ goto err_av7110_unregister_11;
av7110->dvb_adapter->priv = av7110;
- frontend_init(av7110);
+ ret = frontend_init(av7110);
+ if (ret < 0)
+ goto err_av7110_exit_v4l_12;
+#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
+ av7110_ir_init();
+#endif
printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num);
- av7110->device_initialized = 1;
av7110_num++;
- return 0;
+out:
+ return ret;
-err3:
- av7110->arm_rmmod = 1;
- wake_up_interruptible(&av7110->arm_wait);
- while (av7110->arm_thread)
- msleep(1);
-err2:
+err_av7110_exit_v4l_12:
+ av7110_exit_v4l(av7110);
+err_av7110_unregister_11:
+ dvb_unregister(av7110);
+err_arm_thread_stop_10:
+ av7110_arm_sync(av7110);
+err_stop_arm_9:
+ /* Nothing to do. Rejoice. */
+err_av7110_ca_exit_8:
av7110_ca_exit(av7110);
+err_av7110_av_exit_7:
av7110_av_exit(av7110);
-err:
+err_iobuf_vfree_6:
+ vfree(av7110->iobuf);
+err_pci_free_5:
+ pci_free_consistent(pdev, 8192, av7110->debi_virt, av7110->debi_bus);
+err_saa71466_vfree_4:
+ if (!av7110->grabbing)
+ saa7146_pgtable_free(pdev, &av7110->pt);
+err_i2c_del_3:
i2c_del_adapter(&av7110->i2c_adap);
-
+err_dvb_unregister_adapter_2:
dvb_unregister_adapter(av7110->dvb_adapter);
-
- if (NULL != av7110->debi_virt)
- pci_free_consistent(dev->pci, 8192, av7110->debi_virt, av7110->debi_bus);
- if (NULL != av7110->iobuf)
- vfree(av7110->iobuf);
- if (NULL != av7110 ) {
+err_put_firmware_1:
+ put_firmware(av7110);
+err_kfree_0:
kfree(av7110);
- }
-
- return ret;
+ goto out;
}
static int av7110_detach(struct saa7146_dev* saa)
{
- struct av7110 *av7110 = (struct av7110*)saa->ext_priv;
+ struct av7110 *av7110 = saa->ext_priv;
dprintk(4, "%p\n", av7110);
- if (!av7110->device_initialized )
- return 0;
-
if (budgetpatch) {
/* Disable RPS1 */
saa7146_write(saa, MC1, MASK_29);
@@ -2504,11 +2585,7 @@ static int av7110_detach(struct saa7146_dev* saa)
}
av7110_exit_v4l(av7110);
- av7110->arm_rmmod=1;
- wake_up_interruptible(&av7110->arm_wait);
-
- while (av7110->arm_thread)
- msleep(1);
+ av7110_arm_sync(av7110);
tasklet_kill(&av7110->debi_tasklet);
tasklet_kill(&av7110->gpio_tasklet);
@@ -2530,11 +2607,11 @@ static int av7110_detach(struct saa7146_dev* saa)
dvb_unregister_adapter (av7110->dvb_adapter);
av7110_num--;
-#ifndef CONFIG_DVB_AV7110_FIRMWARE_FILE
- if (av7110->bin_fw)
- vfree(av7110->bin_fw);
-#endif
+
+ put_firmware(av7110);
+
kfree(av7110);
+
saa->ext_priv = NULL;
return 0;
@@ -2596,6 +2673,7 @@ MAKE_AV7110_INFO(ttc_1_X, "Technotrend/Hauppauge WinTV Nexus-CA rev1.X");
MAKE_AV7110_INFO(ttc_2_X, "Technotrend/Hauppauge WinTV DVB-C rev2.X");
MAKE_AV7110_INFO(tts_2_X, "Technotrend/Hauppauge WinTV Nexus-S rev2.X");
MAKE_AV7110_INFO(tts_1_3se, "Technotrend/Hauppauge WinTV DVB-S rev1.3 SE");
+MAKE_AV7110_INFO(ttt, "Technotrend/Hauppauge DVB-T");
MAKE_AV7110_INFO(fsc, "Fujitsu Siemens DVB-C");
MAKE_AV7110_INFO(fss, "Fujitsu Siemens DVB-S rev1.6");
@@ -2608,10 +2686,10 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000),
MAKE_EXTENSION_PCI(ttc_1_X, 0x13c2, 0x000a),
MAKE_EXTENSION_PCI(fss, 0x13c2, 0x0006),
+ MAKE_EXTENSION_PCI(ttt, 0x13c2, 0x0008),
/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0004), UNDEFINED CARD */ // Galaxis DVB PC-Sat-Carte
/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1
-/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0008), UNDEFINED CARD */ // TT/Hauppauge WinTV DVB-T v????
/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v????
{
@@ -2640,18 +2718,6 @@ static int __init av7110_init(void)
{
int retval;
retval = saa7146_register_extension(&av7110_extension);
-#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
- if (retval)
- goto failed_saa7146_register;
-
- retval = av7110_ir_init();
- if (retval)
- goto failed_av7110_ir_init;
- return 0;
-failed_av7110_ir_init:
- saa7146_unregister_extension(&av7110_extension);
-failed_saa7146_register:
-#endif
return retval;
}
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index faba99a5cae8d..5070e0523da71 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -31,6 +31,7 @@
#include "tda8083.h"
#include "sp8870.h"
#include "stv0297.h"
+#include "l64781.h"
#include <media/saa7146_vv.h>
@@ -231,8 +232,6 @@ struct av7110 {
u32 ir_config;
/* firmware stuff */
- unsigned int device_initialized;
-
unsigned char *bin_fw;
unsigned long size_fw;
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index f875efcf5de68..d77e8a00688fc 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -1426,25 +1426,34 @@ void av7110_av_unregister(struct av7110 *av7110)
int av7110_av_init(struct av7110 *av7110)
{
+ void (*play[])(u8 *, int, void *) = { play_audio_cb, play_video_cb };
+ int i, ret;
+
av7110->vidmode = VIDEO_MODE_PAL;
- av7110_ipack_init(&av7110->ipack[0], IPACKS, play_audio_cb);
- av7110->ipack[0].data = (void *) av7110;
- av7110_ipack_init(&av7110->ipack[1], IPACKS, play_video_cb);
- av7110->ipack[1].data = (void *) av7110;
+ for (i = 0; i < 2; i++) {
+ struct ipack *ipack = av7110->ipack + i;
+
+ ret = av7110_ipack_init(ipack, IPACKS, play[i]);
+ if (ret < 0) {
+ if (i)
+ av7110_ipack_free(--ipack);
+ goto out;
+ }
+ ipack->data = av7110;
+ }
dvb_ringbuffer_init(&av7110->avout, av7110->iobuf, AVOUTLEN);
dvb_ringbuffer_init(&av7110->aout, av7110->iobuf + AVOUTLEN, AOUTLEN);
av7110->kbuf[0] = (u8 *)(av7110->iobuf + AVOUTLEN + AOUTLEN + BMPLEN);
av7110->kbuf[1] = av7110->kbuf[0] + 2 * IPACKS;
-
- return 0;
+out:
+ return ret;
}
-int av7110_av_exit(struct av7110 *av7110)
+void av7110_av_exit(struct av7110 *av7110)
{
av7110_ipack_free(&av7110->ipack[0]);
av7110_ipack_free(&av7110->ipack[1]);
- return 0;
}
diff --git a/drivers/media/dvb/ttpci/av7110_av.h b/drivers/media/dvb/ttpci/av7110_av.h
index 9bfdf37459db9..cc5e7a7e87c39 100644
--- a/drivers/media/dvb/ttpci/av7110_av.h
+++ b/drivers/media/dvb/ttpci/av7110_av.h
@@ -23,7 +23,7 @@ extern void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7
extern int av7110_av_register(struct av7110 *av7110);
extern void av7110_av_unregister(struct av7110 *av7110);
extern int av7110_av_init(struct av7110 *av7110);
-extern int av7110_av_exit(struct av7110 *av7110);
+extern void av7110_av_exit(struct av7110 *av7110);
#endif /* _AV7110_AV_H_ */
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
index 0bd0da28dfad9..21f7aacf77266 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
@@ -91,8 +91,20 @@ void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len)
static int ci_ll_init(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf, int size)
{
- dvb_ringbuffer_init(cirbuf, vmalloc(size), size);
- dvb_ringbuffer_init(ciwbuf, vmalloc(size), size);
+ struct dvb_ringbuffer *tab[] = { cirbuf, ciwbuf, NULL }, **p;
+ void *data;
+
+ for (p = tab; *p; p++) {
+ data = vmalloc(size);
+ if (!data) {
+ while (p-- != tab) {
+ vfree(p[0]->data);
+ p[0]->data = NULL;
+ }
+ return -ENOMEM;
+ }
+ dvb_ringbuffer_init(*p, data, size);
+ }
return 0;
}
@@ -367,9 +379,9 @@ void av7110_ca_unregister(struct av7110 *av7110)
dvb_unregister_device(av7110->ca_dev);
}
-void av7110_ca_init(struct av7110* av7110)
+int av7110_ca_init(struct av7110* av7110)
{
- ci_ll_init(&av7110->ci_rbuffer, &av7110->ci_wbuffer, 8192);
+ return ci_ll_init(&av7110->ci_rbuffer, &av7110->ci_wbuffer, 8192);
}
void av7110_ca_exit(struct av7110* av7110)
diff --git a/drivers/media/dvb/ttpci/av7110_ca.h b/drivers/media/dvb/ttpci/av7110_ca.h
index f9a0b3d5ef824..70ee855ece1bb 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.h
+++ b/drivers/media/dvb/ttpci/av7110_ca.h
@@ -8,7 +8,7 @@ extern void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len);
extern int av7110_ca_register(struct av7110 *av7110);
extern void av7110_ca_unregister(struct av7110 *av7110);
-extern void av7110_ca_init(struct av7110* av7110);
+extern int av7110_ca_init(struct av7110* av7110);
extern void av7110_ca_exit(struct av7110* av7110);
#endif /* _AV7110_CA_H_ */
diff --git a/drivers/media/dvb/ttpci/av7110_ipack.c b/drivers/media/dvb/ttpci/av7110_ipack.c
index 8879368534bf2..2466407418886 100644
--- a/drivers/media/dvb/ttpci/av7110_ipack.c
+++ b/drivers/media/dvb/ttpci/av7110_ipack.c
@@ -37,7 +37,6 @@ int av7110_ipack_init(struct ipack *p, int size,
void av7110_ipack_free(struct ipack *p)
{
- if (p->buf)
vfree(p->buf);
}
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
index 10df56b54df85..6d2256f1e3542 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -12,6 +12,7 @@
/* enable ir debugging by or'ing av7110_debug with 16 */
+static int ir_initialized;
static struct input_dev input_dev;
static u32 ir_config;
@@ -162,6 +163,9 @@ int __init av7110_ir_init(void)
{
static struct proc_dir_entry *e;
+ if (ir_initialized)
+ return 0;
+
init_timer(&keyup_timer);
keyup_timer.data = 0;
@@ -187,16 +191,20 @@ int __init av7110_ir_init(void)
e->size = 4 + 256 * sizeof(u16);
}
+ ir_initialized = 1;
return 0;
}
void __exit av7110_ir_exit(void)
{
+ if (ir_initialized == 0)
+ return;
del_timer_sync(&keyup_timer);
remove_proc_entry("av7110_ir", NULL);
av7110_unregister_irc_handler(av7110_emit_key);
input_unregister_device(&input_dev);
+ ir_initialized = 0;
}
//MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>");
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index ffbe501d4876e..14e963206b890 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -59,7 +59,7 @@ struct budget_av {
struct dvb_ca_en50221 ca;
};
-int enable_ci = 0;
+static int enable_ci = 0;
/****************************************************************************
@@ -121,6 +121,8 @@ static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int ad
return -EINVAL;
saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
+ udelay(1);
+
result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 0);
if (result == -ETIMEDOUT)
@@ -137,6 +139,8 @@ static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int a
return -EINVAL;
saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
+ udelay(1);
+
result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 0);
if (result == -ETIMEDOUT)
@@ -153,6 +157,8 @@ static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 addre
return -EINVAL;
saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+ udelay(1);
+
result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0);
if (result == -ETIMEDOUT)
@@ -169,6 +175,8 @@ static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 addr
return -EINVAL;
saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+ udelay(1);
+
result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0);
if (result == -ETIMEDOUT)
@@ -180,6 +188,7 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
{
struct budget_av *budget_av = (struct budget_av *) ca->data;
struct saa7146_dev *saa = budget_av->budget.dev;
+ int max = 20;
if (slot != 0)
return -EINVAL;
@@ -190,7 +199,9 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI);
msleep(100);
saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
- msleep(2000); /* horrendous I know, but its the only way to be absolutely sure without an IRQ line! */
+
+ while (--max > 0 && ciintf_read_attribute_mem(ca, slot, 0) != 0x1d)
+ msleep(100);
ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
return 0;
@@ -658,7 +669,7 @@ static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
return request_firmware(fw, name, &budget->dev->pci->dev);
}
-struct tda1004x_config philips_tu1216_config = {
+static struct tda1004x_config philips_tu1216_config = {
.demod_address = 0x8,
.invert = 1,
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index edfa5c1f108de..93a9b40917e43 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -41,7 +41,7 @@
int budget_debug;
module_param_named(debug, budget_debug, int, 0644);
-MODULE_PARM_DESC(budget_debug, "Turn on/off budget debugging (default:off).");
+MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off).");
/****************************************************************************
* TT budget / WinTV Nova
@@ -415,8 +415,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
err:
i2c_del_adapter(&budget->i2c_adap);
- if (budget->grabbing)
- vfree(budget->grabbing);
+ vfree(budget->grabbing);
dvb_unregister_adapter(budget->dvb_adapter);
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index 10653ce69b68b..5d524a4f213f3 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -406,7 +406,7 @@ static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_fronten
return 0;
}
-struct tda8083_config grundig_29504_451_config = {
+static struct tda8083_config grundig_29504_451_config = {
.demod_address = 0x68,
.pll_set = grundig_29504_451_pll_set,
};
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index a6476bad4f2a5..5e6a10f4ad95b 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -444,9 +444,15 @@ static void frontend_init(struct budget *budget)
if (budget->dvb_frontend) break;
break;
- case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI (tda8083/Grundig 29504-451(tsa5522))
+ case 0x4f60: // Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/ALPS BSRU6(tsa5059))
+ budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
+ break;
+ }
+ break;
- // grundig 29504-451
+ case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))
budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
@@ -518,14 +524,16 @@ MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC);
-MAKE_BUDGET_INFO(fsacs, "Fujitsu Siemens Activy Budget-S PCI", BUDGET_FS_ACTIVY);
+MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
+MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003),
MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004),
MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005),
MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
- MAKE_EXTENSION_PCI(fsacs, 0x1131, 0x4f61),
+ MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
+ MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
{
.vendor = 0,
}
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 8b0fe7b20dcd4..4c046ece883a8 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -68,6 +68,7 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
#define TTUSB_MAXFILTER 16 /* ??? */
#endif
+#define TTUSB_REV_2_2 0x22
#define TTUSB_BUDGET_NAME "ttusb_stc_fw"
/**
@@ -79,9 +80,8 @@ struct ttusb {
struct dmxdev dmxdev;
struct dvb_net dvbnet;
- /* our semaphore, for channel allocation/deallocation */
- struct semaphore sem;
/* and one for USB access. */
+ struct semaphore semi2c;
struct semaphore semusb;
struct dvb_adapter *adapter;
@@ -121,18 +121,8 @@ struct ttusb {
u8 last_result[32];
- struct ttusb_channel {
- struct ttusb *ttusb;
- struct dvb_demux_feed *dvbdmxfeed;
+ int revision;
- int active;
- int id;
- int pid;
- int type; /* 1 - TS, 2 - Filter */
-#ifdef TTUSB_HWSECTIONS
- int filterstate[TTUSB_MAXFILTER]; /* 0: not busy, 1: busy */
-#endif
- } channel[TTUSB_MAXCHANNEL];
#if 0
devfs_handle_t stc_devfs_handle;
#endif
@@ -258,7 +248,7 @@ static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num
int i = 0;
int inc;
- if (down_interruptible(&ttusb->sem) < 0)
+ if (down_interruptible(&ttusb->semi2c) < 0)
return -EAGAIN;
while (i < num) {
@@ -292,7 +282,7 @@ static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num
i += inc;
}
- up(&ttusb->sem);
+ up(&ttusb->semi2c);
return i;
}
@@ -445,13 +435,17 @@ static int ttusb_init_controller(struct ttusb *ttusb)
if (memcmp(get_version + 4, "V 0.0", 5) &&
memcmp(get_version + 4, "V 1.1", 5) &&
- memcmp(get_version + 4, "V 2.1", 5)) {
+ memcmp(get_version + 4, "V 2.1", 5) &&
+ memcmp(get_version + 4, "V 2.2", 5)) {
printk
("%s: unknown STC version %c%c%c%c%c, please report!\n",
__FUNCTION__, get_version[4], get_version[5],
get_version[6], get_version[7], get_version[8]);
}
+ ttusb->revision = ((get_version[6] - '0') << 4) |
+ (get_version[8] - '0');
+
err =
ttusb_cmd(ttusb, get_dsp_version, sizeof(get_dsp_version), 1);
if (err)
@@ -491,6 +485,31 @@ static int ttusb_send_diseqc(struct dvb_frontend* fe,
}
#endif
+static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+ struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
+ int ret;
+ u8 data[1];
+ struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ switch(voltage) {
+ case SEC_VOLTAGE_OFF:
+ data[0] = 0x00;
+ break;
+ case SEC_VOLTAGE_13:
+ data[0] = 0x44;
+ break;
+ case SEC_VOLTAGE_18:
+ data[0] = 0x4c;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ ret = i2c_transfer(&ttusb->i2c_adap, &msg, 1);
+ return (ret != 1) ? -EIO : 0;
+}
+
static int ttusb_update_lnb(struct ttusb *ttusb)
{
u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1,
@@ -831,7 +850,7 @@ static void ttusb_stop_iso_xfer(struct ttusb *ttusb)
int i;
for (i = 0; i < ISO_BUF_COUNT; i++)
- usb_unlink_urb(ttusb->iso_urb[i]);
+ usb_kill_urb(ttusb->iso_urb[i]);
ttusb->iso_streaming = 0;
}
@@ -888,15 +907,13 @@ static int ttusb_start_iso_xfer(struct ttusb *ttusb)
}
#ifdef TTUSB_HWSECTIONS
-static void ttusb_handle_ts_data(struct ttusb_channel *channel, const u8 * data,
+static void ttusb_handle_ts_data(struct dvb_demux_feed *dvbdmxfeed, const u8 * data,
int len)
{
- struct dvb_demux_feed *dvbdmxfeed = channel->dvbdmxfeed;
-
dvbdmxfeed->cb.ts(data, len, 0, 0, &dvbdmxfeed->feed.ts, 0);
}
-static void ttusb_handle_sec_data(struct ttusb_channel *channel, const u8 * data,
+static void ttusb_handle_sec_data(struct dvb_demux_feed *dvbdmxfeed, const u8 * data,
int len)
{
// struct dvb_demux_feed *dvbdmxfeed = channel->dvbdmxfeed;
@@ -905,31 +922,10 @@ static void ttusb_handle_sec_data(struct ttusb_channel *channel, const u8 * data
}
#endif
-static struct ttusb_channel *ttusb_channel_allocate(struct ttusb *ttusb)
-{
- int i;
-
- if (down_interruptible(&ttusb->sem))
- return NULL;
-
- /* lock! */
- for (i = 0; i < TTUSB_MAXCHANNEL; ++i) {
- if (!ttusb->channel[i].active) {
- ttusb->channel[i].active = 1;
- up(&ttusb->sem);
- return ttusb->channel + i;
- }
- }
-
- up(&ttusb->sem);
-
- return NULL;
-}
-
static int ttusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
{
struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux;
- struct ttusb_channel *channel;
+ int feed_type = 1;
dprintk("ttusb_start_feed\n");
@@ -949,35 +945,22 @@ static int ttusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
case DMX_TS_PES_TELETEXT:
case DMX_TS_PES_PCR:
case DMX_TS_PES_OTHER:
- channel = ttusb_channel_allocate(ttusb);
break;
default:
return -EINVAL;
}
- } else {
- channel = ttusb_channel_allocate(ttusb);
}
- if (!channel)
- return -EBUSY;
-
- dvbdmxfeed->priv = channel;
- channel->dvbdmxfeed = dvbdmxfeed;
-
- channel->pid = dvbdmxfeed->pid;
-
#ifdef TTUSB_HWSECTIONS
+#error TODO: allocate filters
if (dvbdmxfeed->type == DMX_TYPE_TS) {
- channel->type = 1;
+ feed_type = 1;
} else if (dvbdmxfeed->type == DMX_TYPE_SEC) {
- channel->type = 2;
-#error TODO: allocate filters
+ feed_type = 2;
}
-#else
- channel->type = 1;
#endif
- ttusb_set_channel(ttusb, channel->id, channel->type, channel->pid);
+ ttusb_set_channel(ttusb, dvbdmxfeed->index, feed_type, dvbdmxfeed->pid);
if (0 == ttusb->running_feed_count++)
ttusb_start_iso_xfer(ttusb);
@@ -987,17 +970,13 @@ static int ttusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
static int ttusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
{
- struct ttusb_channel *channel =
- (struct ttusb_channel *) dvbdmxfeed->priv;
struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux;
- ttusb_del_channel(channel->ttusb, channel->id);
+ ttusb_del_channel(ttusb, dvbdmxfeed->index);
if (--ttusb->running_feed_count == 0)
ttusb_stop_iso_xfer(ttusb);
- channel->active = 0;
-
return 0;
}
@@ -1201,10 +1180,51 @@ static struct tda1004x_config philips_tdm1316l_config = {
.request_firmware = philips_tdm1316l_request_firmware,
};
+static u8 alps_bsbe1_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x30,
+ 0x03, 0x00,
+ 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
+ 0x06, 0x40, /* DAC not used, set to high impendance mode */
+ 0x07, 0x00, /* DAC LSB */
+ 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
+ 0x09, 0x00, /* FIFO */
+ 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+ 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
+ 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
+ 0x10, 0x3f, // AGC2 0x3d
+ 0x11, 0x84,
+ 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x15, 0xc9, // lock detector threshold
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
+ 0x29, 0x1e, // 1/2 threshold
+ 0x2a, 0x14, // 2/3 threshold
+ 0x2b, 0x0f, // 3/4 threshold
+ 0x2c, 0x09, // 5/6 threshold
+ 0x2d, 0x05, // 7/8 threshold
+ 0x2e, 0x01,
+ 0x31, 0x1f, // test all FECs
+ 0x32, 0x19, // viterbi and synchro search
+ 0x33, 0xfc, // rs control
+ 0x34, 0x93, // error control
+ 0x0f, 0x92,
+ 0xff, 0xff
+};
static u8 alps_bsru6_inittab[] = {
0x01, 0x15,
- 0x02, 0x00,
+ 0x02, 0x30,
0x03, 0x00,
0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
@@ -1244,7 +1264,7 @@ static u8 alps_bsru6_inittab[] = {
0xff, 0xff
};
-static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
+static int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
{
u8 aclk = 0;
u8 bclk = 0;
@@ -1278,7 +1298,7 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ra
return 0;
}
-static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 buf[4];
@@ -1295,7 +1315,11 @@ static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct dvb_frontend_param
buf[3] = 0xC4;
if (params->frequency > 1530000)
- buf[3] = 0xc0;
+ buf[3] = 0xC0;
+
+ /* BSBE1 wants XCE bit set */
+ if (ttusb->revision == TTUSB_REV_2_2)
+ buf[3] |= 0x20;
if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1)
return -EIO;
@@ -1303,8 +1327,7 @@ static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct dvb_frontend_param
return 0;
}
-static struct stv0299_config alps_bsru6_config = {
-
+static struct stv0299_config alps_stv0299_config = {
.demod_address = 0x68,
.inittab = alps_bsru6_inittab,
.mclk = 88000000UL,
@@ -1314,8 +1337,8 @@ static struct stv0299_config alps_bsru6_config = {
.lock_output = STV0229_LOCKOUTPUT_1,
.volt13_op0_op1 = STV0299_VOLT13_OP1,
.min_delay_ms = 100,
- .set_symbol_rate = alps_bsru6_set_symbol_rate,
- .pll_set = alps_bsru6_pll_set,
+ .set_symbol_rate = alps_stv0299_set_symbol_rate,
+ .pll_set = philips_tsa5059_pll_set,
};
static int ttusb_novas_grundig_29504_491_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
@@ -1349,11 +1372,16 @@ static struct tda8083_config ttusb_novas_grundig_29504_491_config = {
static void frontend_init(struct ttusb* ttusb)
{
switch(le16_to_cpu(ttusb->dev->descriptor.idProduct)) {
- case 0x1003: // Hauppauge/TT Nova-USB-S budget (stv0299/ALPS BSRU6(tsa5059)
- // try the ALPS BSRU6 first
- ttusb->fe = stv0299_attach(&alps_bsru6_config, &ttusb->i2c_adap);
+ case 0x1003: // Hauppauge/TT Nova-USB-S budget (stv0299/ALPS BSRU6|BSBE1(tsa5059))
+ // try the stv0299 based first
+ ttusb->fe = stv0299_attach(&alps_stv0299_config, &ttusb->i2c_adap);
if (ttusb->fe != NULL) {
- ttusb->fe->ops->set_voltage = ttusb_set_voltage;
+ if(ttusb->revision == TTUSB_REV_2_2) { // ALPS BSBE1
+ alps_stv0299_config.inittab = alps_bsbe1_inittab;
+ ttusb->fe->ops->set_voltage = lnbp21_set_voltage;
+ } else { // ALPS BSRU6
+ ttusb->fe->ops->set_voltage = ttusb_set_voltage;
+ }
break;
}
@@ -1406,7 +1434,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
{
struct usb_device *udev;
struct ttusb *ttusb;
- int result, channel;
+ int result;
dprintk("%s: TTUSB DVB connected\n", __FUNCTION__);
@@ -1419,15 +1447,10 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
memset(ttusb, 0, sizeof(struct ttusb));
- for (channel = 0; channel < TTUSB_MAXCHANNEL; ++channel) {
- ttusb->channel[channel].id = channel;
- ttusb->channel[channel].ttusb = ttusb;
- }
-
ttusb->dev = udev;
ttusb->c = 0;
ttusb->mux_state = 0;
- sema_init(&ttusb->sem, 0);
+ sema_init(&ttusb->semi2c, 0);
sema_init(&ttusb->semusb, 1);
ttusb_setup_interfaces(ttusb);
@@ -1436,7 +1459,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
if (ttusb_init_controller(ttusb))
printk("ttusb_init_controller: error\n");
- up(&ttusb->sem);
+ up(&ttusb->semi2c);
dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE);
ttusb->adapter->priv = ttusb;
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 525d275e87e31..64e771bd89078 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -2,6 +2,7 @@
* TTUSB DEC Driver
*
* Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.org>
+ * IR support by Peter Beutner <p.beutner@gmx.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
@@ -32,6 +33,7 @@
#include <linux/firmware.h>
#include <linux/crc32.h>
#include <linux/init.h>
+#include <linux/input.h>
#include "dmxdev.h"
#include "dvb_demux.h"
@@ -42,27 +44,32 @@
static int debug;
static int output_pva;
+static int enable_rc;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
module_param(output_pva, int, 0444);
MODULE_PARM_DESC(output_pva, "Output PVA from dvr device (default:off)");
+module_param(enable_rc, int, 0644);
+MODULE_PARM_DESC(enable_rc, "Turn on/off IR remote control(default: off)");
#define dprintk if (debug) printk
#define DRIVER_NAME "TechnoTrend/Hauppauge DEC USB"
#define COMMAND_PIPE 0x03
-#define RESULT_PIPE 0x84
-#define IN_PIPE 0x88
+#define RESULT_PIPE 0x04
+#define IN_PIPE 0x08
#define OUT_PIPE 0x07
+#define IRQ_PIPE 0x0A
#define COMMAND_PACKET_SIZE 0x3c
#define ARM_PACKET_SIZE 0x1000
+#define IRQ_PACKET_SIZE 0x8
#define ISO_BUF_COUNT 0x04
#define FRAMES_PER_ISO_BUF 0x04
-#define ISO_FRAME_SIZE 0x03FF
+#define ISO_FRAME_SIZE 0x0380
#define MAX_PVA_LENGTH 6144
@@ -107,9 +114,13 @@ struct ttusb_dec {
unsigned int result_pipe;
unsigned int in_pipe;
unsigned int out_pipe;
+ unsigned int irq_pipe;
enum ttusb_dec_interface interface;
struct semaphore usb_sem;
+ void *irq_buffer;
+ struct urb *irq_urb;
+ dma_addr_t irq_dma_handle;
void *iso_buffer;
dma_addr_t iso_dma_handle;
struct urb *iso_urb[ISO_BUF_COUNT];
@@ -142,6 +153,8 @@ struct ttusb_dec {
struct list_head filter_info_list;
spinlock_t filter_info_list_lock;
+ struct input_dev rc_input_dev;
+
int active; /* Loaded successfully */
};
@@ -157,9 +170,83 @@ struct filter_info {
struct list_head filter_info_list;
};
+static u16 rc_keys[] = {
+ KEY_POWER,
+ KEY_MUTE,
+ KEY_1,
+ KEY_2,
+ KEY_3,
+ KEY_4,
+ KEY_5,
+ KEY_6,
+ KEY_7,
+ KEY_8,
+ KEY_9,
+ KEY_0,
+ KEY_CHANNELUP,
+ KEY_VOLUMEDOWN,
+ KEY_OK,
+ KEY_VOLUMEUP,
+ KEY_CHANNELDOWN,
+ KEY_PREVIOUS,
+ KEY_ESC,
+ KEY_RED,
+ KEY_GREEN,
+ KEY_YELLOW,
+ KEY_BLUE,
+ KEY_OPTION,
+ KEY_M,
+ KEY_RADIO
+};
+
static void ttusb_dec_set_model(struct ttusb_dec *dec,
enum ttusb_dec_model model);
+static void ttusb_dec_handle_irq( struct urb *urb, struct pt_regs *regs)
+{
+ struct ttusb_dec * dec = urb->context;
+ char *buffer = dec->irq_buffer;
+ int retval;
+
+ switch(urb->status) {
+ case 0: /*success*/
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ case -ETIMEDOUT:
+ /* this urb is dead, cleanup */
+ dprintk("%s:urb shutting down with status: %d\n",
+ __FUNCTION__, urb->status);
+ return;
+ default:
+ dprintk("%s:nonzero status received: %d\n",
+ __FUNCTION__,urb->status);
+ goto exit;
+ }
+
+ if( (buffer[0] == 0x1) && (buffer[2] == 0x15) ) {
+ /* IR - Event */
+ /* this is an fact a bit too simple implementation;
+ * the box also reports a keyrepeat signal
+ * (with buffer[3] == 0x40) in an intervall of ~100ms.
+ * But to handle this correctly we had to imlemenent some
+ * kind of timer which signals a 'key up' event if no
+ * keyrepeat signal is recieved for lets say 200ms.
+ * this should/could be added later ...
+ * for now lets report each signal as a key down and up*/
+ dprintk("%s:rc signal:%d\n", __FUNCTION__, buffer[4]);
+ input_report_key(&dec->rc_input_dev,rc_keys[buffer[4]-1],1);
+ input_report_key(&dec->rc_input_dev,rc_keys[buffer[4]-1],0);
+ input_sync(&dec->rc_input_dev);
+ }
+
+exit: retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if(retval)
+ printk("%s - usb_commit_urb failed with result: %d\n",
+ __FUNCTION__, retval);
+}
+
static u16 crc16(u16 crc, const u8 *buf, size_t len)
{
u16 tmp;
@@ -781,7 +868,7 @@ static int ttusb_dec_set_interface(struct ttusb_dec *dec,
b, NULL, NULL);
if (result)
return result;
- result = usb_set_interface(dec->udev, 0, 7);
+ result = usb_set_interface(dec->udev, 0, 8);
break;
case TTUSB_DEC_INTERFACE_OUT:
result = usb_set_interface(dec->udev, 0, 1);
@@ -1095,6 +1182,31 @@ static void ttusb_dec_init_tasklet(struct ttusb_dec *dec)
(unsigned long)dec);
}
+static void ttusb_init_rc( struct ttusb_dec *dec)
+{
+ u8 b[] = { 0x00, 0x01 };
+ int i;
+
+ init_input_dev(&dec->rc_input_dev);
+
+ dec->rc_input_dev.name = "ttusb_dec remote control";
+ dec->rc_input_dev.evbit[0] = BIT(EV_KEY);
+ dec->rc_input_dev.keycodesize = sizeof(u16);
+ dec->rc_input_dev.keycodemax = 0x1a;
+ dec->rc_input_dev.keycode = rc_keys;
+
+ for (i = 0; i < sizeof(rc_keys)/sizeof(rc_keys[0]); i++)
+ set_bit(rc_keys[i], dec->rc_input_dev.keybit);
+
+ input_register_device(&dec->rc_input_dev);
+
+ if(usb_submit_urb(dec->irq_urb,GFP_KERNEL)) {
+ printk("%s: usb_submit_urb failed\n",__FUNCTION__);
+ }
+ /* enable irq pipe */
+ ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL);
+}
+
static void ttusb_dec_init_v_pes(struct ttusb_dec *dec)
{
dprintk("%s\n", __FUNCTION__);
@@ -1105,7 +1217,7 @@ static void ttusb_dec_init_v_pes(struct ttusb_dec *dec)
dec->v_pes[3] = 0xe0;
}
-static void ttusb_dec_init_usb(struct ttusb_dec *dec)
+static int ttusb_dec_init_usb(struct ttusb_dec *dec)
{
dprintk("%s\n", __FUNCTION__);
@@ -1116,8 +1228,26 @@ static void ttusb_dec_init_usb(struct ttusb_dec *dec)
dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE);
dec->in_pipe = usb_rcvisocpipe(dec->udev, IN_PIPE);
dec->out_pipe = usb_sndisocpipe(dec->udev, OUT_PIPE);
+ dec->irq_pipe = usb_rcvintpipe(dec->udev, IRQ_PIPE);
+
+ if(enable_rc) {
+ dec->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if(!dec->irq_urb) {
+ return -ENOMEM;
+ }
+ dec->irq_buffer = usb_buffer_alloc(dec->udev,IRQ_PACKET_SIZE,
+ SLAB_ATOMIC, &dec->irq_dma_handle);
+ if(!dec->irq_buffer) {
+ return -ENOMEM;
+ }
+ usb_fill_int_urb(dec->irq_urb, dec->udev,dec->irq_pipe,
+ dec->irq_buffer, IRQ_PACKET_SIZE,
+ ttusb_dec_handle_irq, dec, 1);
+ dec->irq_urb->transfer_dma = dec->irq_dma_handle;
+ dec->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ }
- ttusb_dec_alloc_iso_urbs(dec);
+ return ttusb_dec_alloc_iso_urbs(dec);
}
static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
@@ -1369,6 +1499,26 @@ static void ttusb_dec_exit_dvb(struct ttusb_dec *dec)
dvb_unregister_adapter(dec->adapter);
}
+static void ttusb_dec_exit_rc(struct ttusb_dec *dec)
+{
+
+ dprintk("%s\n", __FUNCTION__);
+ /* we have to check whether the irq URB is already submitted.
+ * As the irq is submitted after the interface is changed,
+ * this is the best method i figured out.
+ * Any others?*/
+ if(dec->interface == TTUSB_DEC_INTERFACE_IN)
+ usb_kill_urb(dec->irq_urb);
+
+ usb_free_urb(dec->irq_urb);
+
+ usb_buffer_free(dec->udev,IRQ_PACKET_SIZE,
+ dec->irq_buffer, dec->irq_dma_handle);
+
+ input_unregister_device(&dec->rc_input_dev);
+}
+
+
static void ttusb_dec_exit_usb(struct ttusb_dec *dec)
{
int i;
@@ -1462,7 +1612,8 @@ static int ttusb_dec_probe(struct usb_interface *intf,
dec->udev = udev;
- ttusb_dec_init_usb(dec);
+ if (ttusb_dec_init_usb(dec))
+ return 0;
if (ttusb_dec_init_stb(dec)) {
ttusb_dec_exit_usb(dec);
return 0;
@@ -1502,6 +1653,9 @@ static int ttusb_dec_probe(struct usb_interface *intf,
ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN);
+ if(enable_rc)
+ ttusb_init_rc(dec);
+
return 0;
}
@@ -1516,6 +1670,8 @@ static void ttusb_dec_disconnect(struct usb_interface *intf)
if (dec->active) {
ttusb_dec_exit_tasklet(dec);
ttusb_dec_exit_filters(dec);
+ if(enable_rc)
+ ttusb_dec_exit_rc(dec);
ttusb_dec_exit_usb(dec);
ttusb_dec_exit_dvb(dec);
}
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
index ff0e5212a1f44..1699cc9f6bb0d 100644
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
@@ -169,7 +169,7 @@ struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* conf
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
@@ -195,7 +195,7 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index b6b670664d4a1..cf0db2554a80d 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -236,7 +236,8 @@ bt819_init (struct i2c_client *client)
init[0x07 * 2 - 1] = timing->hactive & 0xff;
init[0x08 * 2 - 1] = timing->hscale >> 8;
init[0x09 * 2 - 1] = timing->hscale & 0xff;
- init[0x19*2-1] = decoder->norm == 0 ? 115 : 93; /* Chroma burst delay */
+ /* 0x15 in array is address 0x19 */
+ init[0x15 * 2 - 1] = (decoder->norm == 0) ? 115 : 93; /* Chroma burst delay */
/* reset */
bt819_write(client, 0x1f, 0x00);
mdelay(1);
diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c
index 040d9312e37d2..d996ec99caff9 100644
--- a/drivers/media/video/msp3400.c
+++ b/drivers/media/video/msp3400.c
@@ -734,6 +734,7 @@ static int msp34xx_sleep(struct msp3400c *msp, int timeout)
{
DECLARE_WAITQUEUE(wait, current);
+again:
add_wait_queue(&msp->wq, &wait);
if (!kthread_should_stop()) {
if (timeout < 0) {
@@ -749,9 +750,12 @@ static int msp34xx_sleep(struct msp3400c *msp, int timeout)
#endif
}
}
- if (current->flags & PF_FREEZE)
- refrigerator(PF_FREEZE);
+
remove_wait_queue(&msp->wq, &wait);
+
+ if (try_to_freeze(PF_FREEZE))
+ goto again;
+
return msp->restart;
}
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 540a6b1461f7f..065eb4007b1d1 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -286,6 +286,7 @@ static int chip_thread(void *data)
schedule();
}
remove_wait_queue(&chip->wq, &wait);
+ try_to_freeze(PF_FREEZE);
if (chip->done || signal_pending(current))
break;
dprintk("%s: thread wakeup\n", i2c_clientname(&chip->c));
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index c2a0ea8b4386e..7b96506dfac1b 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -135,7 +135,7 @@ endif
#
menu "Ethernet (10 or 100Mbit)"
- depends on NETDEVICES
+ depends on NETDEVICES && !UML
config NET_ETHERNET
bool "Ethernet (10 or 100Mbit)"
@@ -1767,7 +1767,7 @@ endmenu
#
menu "Ethernet (1000 Mbit)"
- depends on NETDEVICES
+ depends on NETDEVICES && !UML
config ACENIC
tristate "Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support"
@@ -2077,7 +2077,7 @@ endmenu
#
menu "Ethernet (10000 Mbit)"
- depends on NETDEVICES
+ depends on NETDEVICES && !UML
config IXGB
tristate "Intel(R) PRO/10GbE support"
@@ -2156,11 +2156,13 @@ config 2BUFF_MODE
endmenu
+if !UML
source "drivers/net/tokenring/Kconfig"
source "drivers/net/wireless/Kconfig"
source "drivers/net/pcmcia/Kconfig"
+endif
source "drivers/net/wan/Kconfig"
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index a6ac2cffd9602..98b3a2fdce90d 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -144,8 +144,8 @@ MODULE_PARM_DESC(full_duplex, "full duplex setting(s) (1)");
MODULE_PARM_DESC(congenb, "Enable congestion control (1)");
MODULE_PARM_DESC(txfifo, "Tx FIFO threshold in 4 byte units, (0-15)");
MODULE_PARM_DESC(rxfifo, "Rx FIFO threshold in 4 byte units, (0-15)");
-MODULE_PARM_DESC(txdmaccount, "Tx DMA burst length; 128 - disable (0-128)");
-MODULE_PARM_DESC(rxdmaccount, "Rx DMA burst length; 128 - disable (0-128)");
+MODULE_PARM_DESC(txdmacount, "Tx DMA burst length; 128 - disable (0-128)");
+MODULE_PARM_DESC(rxdmacount, "Rx DMA burst length; 128 - disable (0-128)");
MODULE_PARM_DESC(rx_copybreak, "copy breakpoint for copy-only-tiny-frames");
MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt");
MODULE_PARM_DESC(multicast_filter_limit, "maximum number of filtered multicast addresses");
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 635c65a0886a9..2951b9084bfd2 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -2733,11 +2733,11 @@ enum parport_pc_pci_cards {
aks_0100,
mobility_pp,
netmos_9705,
+ netmos_9715,
+ netmos_9755,
netmos_9805,
netmos_9815,
netmos_9855,
- netmos_9755,
- netmos_9715
};
@@ -2808,11 +2808,11 @@ static struct parport_pc_pci {
/* aks_0100 */ { 1, { { 0, -1 }, } },
/* mobility_pp */ { 1, { { 0, 1 }, } },
/* netmos_9705 */ { 1, { { 0, -1 }, } }, /* untested */
+ /* netmos_9715 */ { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */
+ /* netmos_9755 */ { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */
/* netmos_9805 */ { 1, { { 0, -1 }, } }, /* untested */
/* netmos_9815 */ { 2, { { 0, -1 }, { 2, -1 }, } }, /* untested */
/* netmos_9855 */ { 2, { { 0, -1 }, { 2, -1 }, } }, /* untested */
- /* netmos_9755 */ { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */
- /* netmos_9715 */ { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */
};
static struct pci_device_id parport_pc_pci_tbl[] = {
@@ -2885,16 +2885,16 @@ static struct pci_device_id parport_pc_pci_tbl[] = {
/* NetMos communication controllers */
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9705,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9705 },
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9715,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9715 },
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9755,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9755 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9805,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9805 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9815,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9815 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9855 },
- { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9755,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9755 },
- { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9715,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9715 },
{ 0, } /* terminate list */
};
MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index 1f17d0124cc7a..6715a17b5d0fe 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -33,8 +33,7 @@
enum parport_pc_pci_cards {
titan_110l = 0,
titan_210l,
- netmos_9735,
- netmos_9835,
+ netmos_9xx5_combo,
avlab_1s1p,
avlab_1s1p_650,
avlab_1s1p_850,
@@ -51,9 +50,8 @@ enum parport_pc_pci_cards {
siig_2s1p_20x,
};
-
/* each element directly indexed from enum list, above */
-static struct parport_pc_pci {
+struct parport_pc_pci {
int numports;
struct { /* BAR (base address registers) numbers in the config
space header */
@@ -65,16 +63,30 @@ static struct parport_pc_pci {
/* If set, this is called immediately after pci_enable_device.
* If it returns non-zero, no probing will take place and the
* ports will not be used. */
- int (*preinit_hook) (struct pci_dev *pdev, int autoirq, int autodma);
+ int (*preinit_hook) (struct pci_dev *pdev, struct parport_pc_pci *card,
+ int autoirq, int autodma);
/* If set, this is called after probing for ports. If 'failed'
* is non-zero we couldn't use any of the ports. */
- void (*postinit_hook) (struct pci_dev *pdev, int failed);
-} cards[] __devinitdata = {
+ void (*postinit_hook) (struct pci_dev *pdev,
+ struct parport_pc_pci *card, int failed);
+};
+
+static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc_pci *card, int autoirq, int autodma)
+{
+ /*
+ * Netmos uses the subdevice ID to indicate the number of parallel
+ * and serial ports. The form is 0x00PS, where <P> is the number of
+ * parallel ports and <S> is the number of serial ports.
+ */
+ card->numports = (dev->subsystem_device & 0xf0) >> 4;
+ return 0;
+}
+
+static struct parport_pc_pci cards[] __devinitdata = {
/* titan_110l */ { 1, { { 3, -1 }, } },
/* titan_210l */ { 1, { { 3, -1 }, } },
- /* netmos_9735 (not tested) */ { 1, { { 2, -1 }, } },
- /* netmos_9835 */ { 1, { { 2, -1 }, } },
+ /* netmos_9xx5_combo */ { 1, { { 2, -1 }, }, netmos_parallel_init },
/* avlab_1s1p */ { 1, { { 1, 2}, } },
/* avlab_1s1p_650 */ { 1, { { 1, 2}, } },
/* avlab_1s1p_850 */ { 1, { { 1, 2}, } },
@@ -98,9 +110,17 @@ static struct pci_device_id parport_serial_pci_tbl[] = {
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_210L,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_210l },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9735,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9735 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9745,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9835 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9845,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
/* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
{ 0x14db, 0x2110, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p},
{ 0x14db, 0x2111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p_650},
@@ -167,6 +187,12 @@ static int __devinit siig20x_init_fn(struct pci_dev *dev, struct pci_board_no_id
return pci_siig20x_fn(dev, enable);
}
+static int __devinit netmos_serial_init(struct pci_dev *dev, struct pci_board_no_ids *board, int enable)
+{
+ board->num_ports = dev->subsystem_device & 0xf;
+ return 0;
+}
+
static struct pci_board_no_ids pci_boards[] __devinitdata = {
/*
* PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
@@ -180,8 +206,7 @@ static struct pci_board_no_ids pci_boards[] __devinitdata = {
/* titan_110l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 1, 921600 },
/* titan_210l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 },
-/* netmos_9735 (n/t)*/ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
-/* netmos_9835 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
+/* netmos_9xx5_combo */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200, 0, 0, netmos_serial_init },
/* avlab_1s1p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
/* avlab_1s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
/* avlab_1s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
@@ -204,6 +229,7 @@ struct parport_serial_private {
struct pci_board_no_ids ser;
int num_par;
struct parport *port[PARPORT_MAX];
+ struct parport_pc_pci par;
};
static int __devinit get_pci_port (struct pci_dev *dev,
@@ -271,14 +297,15 @@ static int __devinit get_pci_port (struct pci_dev *dev,
static int __devinit serial_register (struct pci_dev *dev,
const struct pci_device_id *id)
{
- struct pci_board_no_ids *board = &pci_boards[id->driver_data];
+ struct pci_board_no_ids *board;
struct parport_serial_private *priv = pci_get_drvdata (dev);
struct serial_struct serial_req;
int base_baud;
int k;
int success = 0;
- priv->ser = *board;
+ priv->ser = pci_boards[id->driver_data];
+ board = &priv->ser;
if (board->init_fn && ((board->init_fn) (dev, board, 1) != 0))
return 1;
@@ -289,6 +316,15 @@ static int __devinit serial_register (struct pci_dev *dev,
for (k = 0; k < board->num_ports; k++) {
int line;
+
+ if (priv->num_ser == ARRAY_SIZE (priv->line)) {
+ printk (KERN_WARNING
+ "parport_serial: %s: only %u serial lines "
+ "supported (%d reported)\n", pci_name (dev),
+ ARRAY_SIZE (priv->line), board->num_ports);
+ break;
+ }
+
serial_req.irq = dev->irq;
if (get_pci_port (dev, board, &serial_req, k))
break;
@@ -311,19 +347,31 @@ static int __devinit serial_register (struct pci_dev *dev,
static int __devinit parport_register (struct pci_dev *dev,
const struct pci_device_id *id)
{
+ struct parport_pc_pci *card;
struct parport_serial_private *priv = pci_get_drvdata (dev);
int i = id->driver_data, n;
int success = 0;
- if (cards[i].preinit_hook &&
- cards[i].preinit_hook (dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE))
+ priv->par = cards[id->driver_data];
+ card = &priv->par;
+ if (card->preinit_hook &&
+ card->preinit_hook (dev, card, PARPORT_IRQ_NONE, PARPORT_DMA_NONE))
return -ENODEV;
- for (n = 0; n < cards[i].numports; n++) {
+ for (n = 0; n < card->numports; n++) {
struct parport *port;
- int lo = cards[i].addr[n].lo;
- int hi = cards[i].addr[n].hi;
+ int lo = card->addr[n].lo;
+ int hi = card->addr[n].hi;
unsigned long io_lo, io_hi;
+
+ if (priv->num_par == ARRAY_SIZE (priv->port)) {
+ printk (KERN_WARNING
+ "parport_serial: %s: only %u parallel ports "
+ "supported (%d reported)\n", pci_name (dev),
+ ARRAY_SIZE (priv->port), card->numports);
+ break;
+ }
+
io_lo = pci_resource_start (dev, lo);
io_hi = 0;
if ((hi >= 0) && (hi <= 6))
@@ -345,8 +393,8 @@ static int __devinit parport_register (struct pci_dev *dev,
}
}
- if (cards[i].postinit_hook)
- cards[i].postinit_hook (dev, !success);
+ if (card->postinit_hook)
+ card->postinit_hook (dev, card, !success);
return success ? 0 : 1;
}
diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids
index 99a1a7f7df253..6007a75900541 100644
--- a/drivers/pci/pci.ids
+++ b/drivers/pci/pci.ids
@@ -9572,14 +9572,25 @@
6565 6565
9710 NetMos Technology
7780 USB IRDA-port
- 9815 PCI 9815 Multi-I/O Controller
+ 9705 PCI 9705 Parallel Port
+ 9715 PCI 9715 Dual Parallel Port
+ 9735 PCI 9735 Multi-I/O Controller
+ 1000 0002 0P2S (2 serial)
+ 1000 0012 1P2S (1 parallel + 2 serial)
+ 9745 PCI 9745 Multi-I/O Controller
+ 1000 0002 0P2S (2 serial)
+ 1000 0012 1P2S (1 parallel + 2 serial)
+ 9755 PCI 9755 Parallel Port and ISA Bridge
+ 9805 PCI 9805 Parallel Port
+ 9815 PCI 9815 Dual Parallel Port
1000 0020 2P0S (2 port parallel adaptor)
9835 PCI 9835 Multi-I/O Controller
- 1000 0002 2S (16C550 UART)
+ 1000 0002 0P2S (16C550 UART)
1000 0012 1P2S
9845 PCI 9845 Multi-I/O Controller
1000 0004 0P4S (4 port 16550A serial card)
- 1000 0006 0P6S (6 port 16550a serial card)
+ 1000 0006 0P6S (6 port 16550A serial card)
+ 1000 0014 1P4S (4 port 16550A serial card + parallel)
9855 PCI 9855 Multi-I/O Controller
1000 0014 1P4S
9902 Stargen Inc.
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index ec1af69b0f895..eef35c8a71e59 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -1259,6 +1259,40 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quir
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_pcie_mch );
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_pcie_mch );
+static void __devinit quirk_netmos(struct pci_dev *dev)
+{
+ unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4;
+ unsigned int num_serial = dev->subsystem_device & 0xf;
+
+ /*
+ * These Netmos parts are multiport serial devices with optional
+ * parallel ports. Even when parallel ports are present, they
+ * are identified as class SERIAL, which means the serial driver
+ * will claim them. To prevent this, mark them as class OTHER.
+ * These combo devices should be claimed by parport_serial.
+ *
+ * The subdevice ID is of the form 0x00PS, where <P> is the number
+ * of parallel ports and <S> is the number of serial ports.
+ */
+ switch (dev->device) {
+ case PCI_DEVICE_ID_NETMOS_9735:
+ case PCI_DEVICE_ID_NETMOS_9745:
+ case PCI_DEVICE_ID_NETMOS_9835:
+ case PCI_DEVICE_ID_NETMOS_9845:
+ case PCI_DEVICE_ID_NETMOS_9855:
+ if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL &&
+ num_parallel) {
+ printk(KERN_INFO "PCI: Netmos %04x (%u parallel, "
+ "%u serial); changing class SERIAL to OTHER "
+ "(use parport_serial)\n",
+ dev->device, num_parallel, num_serial);
+ dev->class = (PCI_CLASS_COMMUNICATION_OTHER << 8) |
+ (dev->class & 0xff);
+ }
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, quirk_netmos);
+
static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end)
{
while (f < end) {
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c
index 769a8cc12f9dc..9fa7f15d89e59 100644
--- a/drivers/pcmcia/au1000_generic.c
+++ b/drivers/pcmcia/au1000_generic.c
@@ -156,15 +156,12 @@ static int au1x00_pcmcia_sock_init(struct pcmcia_socket *sock)
static int au1x00_pcmcia_suspend(struct pcmcia_socket *sock)
{
struct au1000_pcmcia_socket *skt = to_au1000_socket(sock);
- int ret;
debug("suspending socket %u\n", skt->nr);
- ret = au1x00_pcmcia_config_skt(skt, &dead_socket);
- if (ret == 0)
- skt->ops->socket_suspend(skt);
+ skt->ops->socket_suspend(skt);
- return ret;
+ return 0;
}
static DEFINE_SPINLOCK(status_lock);
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 236ad9e453b7b..5e095967a0965 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -565,7 +565,9 @@ static int socket_suspend(struct pcmcia_socket *skt)
send_event(skt, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
skt->socket = dead_socket;
- skt->ops->suspend(skt);
+ skt->ops->set_socket(skt, &skt->socket);
+ if (skt->ops->suspend)
+ skt->ops->suspend(skt);
skt->state |= SOCKET_SUSPEND;
return CS_SUCCESS;
@@ -587,6 +589,11 @@ static int socket_resume(struct pcmcia_socket *skt)
skt->ops->init(skt);
skt->ops->set_socket(skt, &skt->socket);
+ if (!(skt->state & SOCKET_PRESENT)) {
+ skt->state &= ~SOCKET_SUSPEND;
+ return socket_insert(skt);
+ }
+
ret = socket_setup(skt, resume_delay);
if (ret == CS_SUCCESS) {
/*
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 767427de8299c..66150d08b5c7c 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -91,8 +91,7 @@ struct pcmcia_bus_socket {
struct pcmcia_callback callback;
int state;
user_info_t *user;
- int req_pending, req_result;
- wait_queue_head_t queue, request;
+ wait_queue_head_t queue;
struct pcmcia_socket *parent;
/* the PCMCIA devices connected to this socket (normally one, more
@@ -673,19 +672,6 @@ static void handle_event(struct pcmcia_bus_socket *s, event_t event)
wake_up_interruptible(&s->queue);
}
-static int handle_request(struct pcmcia_bus_socket *s, event_t event)
-{
- if (s->req_pending != 0)
- return CS_IN_USE;
- if (s->state & DS_SOCKET_BUSY)
- s->req_pending = 1;
- handle_event(s, event);
- if (wait_event_interruptible(s->request, s->req_pending <= 0))
- return CS_IN_USE;
- if (s->state & DS_SOCKET_BUSY)
- return s->req_result;
- return CS_SUCCESS;
-}
/*======================================================================
@@ -767,9 +753,6 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
break;
case CS_EVENT_EJECTION_REQUEST:
- ret = handle_request(s, event);
- if (ret)
- break;
ret = send_event(skt, event, priority);
break;
@@ -1216,8 +1199,6 @@ static int ds_release(struct inode *inode, struct file *file)
/* Unlink user data structure */
if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
s->state &= ~DS_SOCKET_BUSY;
- s->req_pending = 0;
- wake_up_interruptible(&s->request);
}
file->private_data = NULL;
for (link = &s->user; *link; link = &(*link)->next)
@@ -1266,33 +1247,14 @@ static ssize_t ds_read(struct file *file, char __user *buf,
static ssize_t ds_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct pcmcia_bus_socket *s;
- user_info_t *user;
-
ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
-
+
if (count != 4)
return -EINVAL;
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
return -EBADF;
- user = file->private_data;
- if (CHECK_USER(user))
- return -EIO;
-
- s = user->socket;
- if (s->state & DS_SOCKET_DEAD)
- return -EIO;
-
- if (s->req_pending) {
- s->req_pending--;
- get_user(s->req_result, (int __user *)buf);
- if ((s->req_result != 0) || (s->req_pending == 0))
- wake_up_interruptible(&s->request);
- } else
- return -EIO;
-
- return 4;
+ return -EIO;
} /* ds_write */
/*====================================================================*/
@@ -1386,7 +1348,9 @@ static int ds_ioctl(struct inode * inode, struct file * file,
buf->config.Function, &buf->config);
break;
case DS_GET_FIRST_TUPLE:
+ down(&s->parent->skt_sem);
pcmcia_validate_mem(s->parent);
+ up(&s->parent->skt_sem);
ret = pccard_get_first_tuple(s->parent, BIND_FN_ALL, &buf->tuple);
break;
case DS_GET_NEXT_TUPLE:
@@ -1412,7 +1376,9 @@ static int ds_ioctl(struct inode * inode, struct file * file,
ret = pccard_get_status(s->parent, buf->status.Function, &buf->status);
break;
case DS_VALIDATE_CIS:
+ down(&s->parent->skt_sem);
pcmcia_validate_mem(s->parent);
+ up(&s->parent->skt_sem);
ret = pccard_validate_cis(s->parent, BIND_FN_ALL, &buf->cisinfo);
break;
case DS_SUSPEND_CARD:
@@ -1453,7 +1419,7 @@ static int ds_ioctl(struct inode * inode, struct file * file,
printed++;
}
}
- ret = -EINVAL;
+ err = -EINVAL;
goto free_out;
break;
case DS_GET_FIRST_WINDOW:
@@ -1562,7 +1528,6 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev)
msleep(250);
init_waitqueue_head(&s->queue);
- init_waitqueue_head(&s->request);
INIT_LIST_HEAD(&s->devices_list);
/* Set up hotline to Card Services */
diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c
index 48584bb264410..5e6c4ba7d9955 100644
--- a/drivers/pcmcia/hd64465_ss.c
+++ b/drivers/pcmcia/hd64465_ss.c
@@ -353,20 +353,6 @@ static int hs_init(struct pcmcia_socket *s)
/*============================================================*/
-static int hs_suspend(struct pcmcia_socket *s)
-{
-#ifdef HD64465_DEBUG
- hs_socket_t *sp = container_of(s, struct hs_socket_t, socket);
- DPRINTK("hs_suspend(%d)\n", sp->number);
-#endif
-
- /* TODO */
-
- return 0;
-}
-
-/*============================================================*/
-
static int hs_get_status(struct pcmcia_socket *s, u_int *value)
{
@@ -763,7 +749,6 @@ static irqreturn_t hs_interrupt(int irq, void *dev, struct pt_regs *regs)
static struct pccard_operations hs_operations = {
.init = hs_init,
- .suspend = hs_suspend,
.get_status = hs_get_status,
.get_socket = hs_get_socket,
.set_socket = hs_set_socket,
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index a34632d759920..0a20f69fbc095 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -65,7 +65,6 @@ static struct pci_driver i82092aa_pci_drv = {
/* the pccard structure and its functions */
static struct pccard_operations i82092aa_operations = {
.init = i82092aa_init,
- .suspend = i82092aa_suspend,
.get_status = i82092aa_get_status,
.get_socket = i82092aa_get_socket,
.set_socket = i82092aa_set_socket,
@@ -440,15 +439,6 @@ static int i82092aa_init(struct pcmcia_socket *sock)
return 0;
}
-static int i82092aa_suspend(struct pcmcia_socket *sock)
-{
- int retval;
- enter("i82092aa_suspend");
- retval = i82092aa_set_socket(sock, &dead_socket);
- leave("i82092aa_suspend");
- return retval;
-}
-
static int i82092aa_get_status(struct pcmcia_socket *socket, u_int *value)
{
unsigned int sock = container_of(socket, struct socket_info, socket)->number;
diff --git a/drivers/pcmcia/i82092aa.h b/drivers/pcmcia/i82092aa.h
index 0cdd80a1e17e2..b98cac7bda9f5 100644
--- a/drivers/pcmcia/i82092aa.h
+++ b/drivers/pcmcia/i82092aa.h
@@ -34,7 +34,6 @@ static int i82092aa_set_socket(struct pcmcia_socket *socket, socket_state_t *sta
static int i82092aa_set_io_map(struct pcmcia_socket *socket, struct pccard_io_map *io);
static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_map *mem);
static int i82092aa_init(struct pcmcia_socket *socket);
-static int i82092aa_suspend(struct pcmcia_socket *socket);
#endif
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index e9b5eb3ad2e54..7bda91537e3c6 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -1322,14 +1322,8 @@ static int pcic_init(struct pcmcia_socket *s)
return 0;
}
-static int pcic_suspend(struct pcmcia_socket *sock)
-{
- return pcic_set_socket(sock, &dead_socket);
-}
-
static struct pccard_operations pcic_operations = {
.init = pcic_init,
- .suspend = pcic_suspend,
.get_status = pcic_get_status,
.get_socket = pcic_get_socket,
.set_socket = pcic_set_socket,
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
index eab36ffb462d0..b0b7a7a411200 100644
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -732,15 +732,8 @@ static int pcc_init(struct pcmcia_socket *s)
return 0;
}
-static int pcc_suspend(struct pcmcia_socket *sock)
-{
- debug(3, "m32r_cfc: pcc_suspend()\n");
- return pcc_set_socket(sock, &dead_socket);
-}
-
static struct pccard_operations pcc_operations = {
.init = pcc_init,
- .suspend = pcc_suspend,
.get_status = pcc_get_status,
.get_socket = pcc_get_socket,
.set_socket = pcc_set_socket,
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index cbd187d41d809..cafba6f45dfa4 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -685,14 +685,8 @@ static int pcc_init(struct pcmcia_socket *s)
return 0;
}
-static int pcc_suspend(struct pcmcia_socket *sock)
-{
- return pcc_set_socket(sock, &dead_socket);
-}
-
static struct pccard_operations pcc_operations = {
.init = pcc_init,
- .suspend = pcc_suspend,
.get_status = pcc_get_status,
.get_socket = pcc_get_socket,
.set_socket = pcc_set_socket,
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index 545cebb4d952f..9a16e243f183d 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -615,11 +615,6 @@ static int pd6729_set_mem_map(struct pcmcia_socket *sock,
return 0;
}
-static int pd6729_suspend(struct pcmcia_socket *sock)
-{
- return pd6729_set_socket(sock, &dead_socket);
-}
-
static int pd6729_init(struct pcmcia_socket *sock)
{
int i;
@@ -644,7 +639,6 @@ static int pd6729_init(struct pcmcia_socket *sock)
/* the pccard structure and its functions */
static struct pccard_operations pd6729_operations = {
.init = pd6729_init,
- .suspend = pd6729_suspend,
.get_status = pd6729_get_status,
.get_socket = pd6729_get_socket,
.set_socket = pd6729_set_socket,
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index ae5d944022313..5876bab7c14c8 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -474,8 +474,7 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
/*
- * Locking note: this is the only place where we take
- * both rsrc_sem and skt_sem.
+ * Locking note: Must be called with skt_sem held!
*/
static void pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
{
@@ -492,12 +491,8 @@ static void pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
if (probe_mask & ~s_data->rsrc_mem_probe) {
s_data->rsrc_mem_probe |= probe_mask;
- down(&s->skt_sem);
-
if (s->state & SOCKET_PRESENT)
validate_mem(s, probe_mask);
-
- up(&s->skt_sem);
}
up(&rsrc_sem);
@@ -781,6 +776,7 @@ static int nonstatic_init(struct pcmcia_socket *s)
data = kmalloc(sizeof(struct socket_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
+ memset(data, 0, sizeof(struct socket_data));
data->mem_db.next = &data->mem_db;
data->io_db.next = &data->io_db;
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index e8c3f1fb62580..888b70e6a484f 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -197,15 +197,12 @@ static int soc_common_pcmcia_sock_init(struct pcmcia_socket *sock)
static int soc_common_pcmcia_suspend(struct pcmcia_socket *sock)
{
struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
- int ret;
debug(skt, 2, "suspending socket\n");
- ret = soc_common_pcmcia_config_skt(skt, &dead_socket);
- if (ret == 0)
- skt->ops->socket_suspend(skt);
+ skt->ops->socket_suspend(skt);
- return ret;
+ return 0;
}
static DEFINE_SPINLOCK(status_lock);
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index 52d2a383e72b2..6d1b9817f5bd3 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -888,14 +888,8 @@ static int tcic_init(struct pcmcia_socket *s)
return 0;
}
-static int tcic_suspend(struct pcmcia_socket *sock)
-{
- return tcic_set_socket(sock, &dead_socket);
-}
-
static struct pccard_operations tcic_operations = {
.init = tcic_init,
- .suspend = tcic_suspend,
.get_status = tcic_get_status,
.get_socket = tcic_get_socket,
.set_socket = tcic_set_socket,
diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c
index bb49ce19d5762..987bc21ced42b 100644
--- a/drivers/pcmcia/vrc4171_card.c
+++ b/drivers/pcmcia/vrc4171_card.c
@@ -249,11 +249,6 @@ static int pccard_init(struct pcmcia_socket *sock)
return 0;
}
-static int pccard_suspend(struct pcmcia_socket *sock)
-{
- return -EINVAL;
-}
-
static int pccard_get_status(struct pcmcia_socket *sock, u_int *value)
{
unsigned int slot;
@@ -554,7 +549,6 @@ static int pccard_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map
static struct pccard_operations vrc4171_pccard_operations = {
.init = pccard_init,
- .suspend = pccard_suspend,
.get_status = pccard_get_status,
.get_socket = pccard_get_socket,
.set_socket = pccard_set_socket,
diff --git a/drivers/pcmcia/vrc4173_cardu.c b/drivers/pcmcia/vrc4173_cardu.c
index c727087199903..db91259dc50eb 100644
--- a/drivers/pcmcia/vrc4173_cardu.c
+++ b/drivers/pcmcia/vrc4173_cardu.c
@@ -141,11 +141,6 @@ static int cardu_init(unsigned int slot)
return 0;
}
-static int cardu_suspend(unsigned int slot)
-{
- return -EINVAL;
-}
-
static int cardu_register_callback(unsigned int sock,
void (*handler)(void *, unsigned int),
void * info)
@@ -433,7 +428,6 @@ static void cardu_proc_setup(unsigned int sock, struct proc_dir_entry *base)
static struct pccard_operations cardu_operations = {
.init = cardu_init,
- .suspend = cardu_suspend,
.register_callback = cardu_register_callback,
.inquire_socket = cardu_inquire_socket,
.get_status = cardu_get_status,
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 495fb4a1ba34c..557a29e73d0d3 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -506,8 +506,6 @@ static int yenta_sock_suspend(struct pcmcia_socket *sock)
{
struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
- yenta_set_socket(sock, &dead_socket);
-
/* Disable CSC interrupts */
cb_writel(socket, CB_SOCKET_MASK, 0x0);
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 355242f64c99c..0f6330b3af12b 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -180,8 +180,12 @@ static int pnp_dock_thread(void * unused)
* Poll every 2 seconds
*/
msleep_interruptible(2000);
- if(signal_pending(current))
+
+ if(signal_pending(current)) {
+ if (try_to_freeze(PF_FREEZE))
+ continue;
break;
+ }
status = pnp_bios_dock_station_info(&now);
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index cac2c21642038..2d1322dd7e196 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -21,7 +21,6 @@
#include <linux/pnp.h>
#include "base.h"
-static int pnp_skip_pci_scan; /* skip PCI resource scanning */
static int pnp_reserve_irq[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some IRQ */
static int pnp_reserve_dma[8] = { [0 ... 7] = -1 }; /* reserve (don't use) some DMA */
static int pnp_reserve_io[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some I/O region */
@@ -385,9 +384,9 @@ int pnp_check_irq(struct pnp_dev * dev, int idx)
#ifdef CONFIG_PCI
/* check if the resource is being used by a pci device */
- if (!pnp_skip_pci_scan) {
- struct pci_dev * pci = NULL;
- while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) {
+ {
+ struct pci_dev *pci = NULL;
+ for_each_pci_dev(pci) {
if (pci->irq == *irq)
return 0;
}
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 30837596ccaf9..b755bac6ccbca 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -7,7 +7,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
*
- * $Revision: 1.156 $
+ * $Revision: 1.158 $
*/
#include <linux/config.h>
@@ -757,6 +757,17 @@ dasd_start_IO(struct dasd_ccw_req * cqr)
DBF_DEV_EVENT(DBF_ERR, device, "%s",
"start_IO: request timeout, retry later");
break;
+ case -EACCES:
+ /* -EACCES indicates that the request used only a
+ * subset of the available pathes and all these
+ * pathes are gone.
+ * Do a retry with all available pathes.
+ */
+ cqr->lpm = LPM_ANYPATH;
+ DBF_DEV_EVENT(DBF_ERR, device, "%s",
+ "start_IO: selected pathes gone,"
+ " retry on all pathes");
+ break;
case -ENODEV:
case -EIO:
DBF_DEV_EVENT(DBF_ERR, device, "%s",
@@ -1222,7 +1233,9 @@ __dasd_start_head(struct dasd_device * device)
rc = device->discipline->start_IO(cqr);
if (rc == 0)
dasd_set_timer(device, cqr->expires);
- else
+ else if (rc == -EACCES) {
+ dasd_schedule_bh(device);
+ } else
/* Hmpf, try again in 1/2 sec */
dasd_set_timer(device, 50);
}
@@ -1813,8 +1826,8 @@ dasd_generic_set_online (struct ccw_device *cdev,
if (rc) {
printk (KERN_WARNING
"dasd_generic couldn't online device %s "
- "with discipline %s\n",
- cdev->dev.bus_id, discipline->name);
+ "with discipline %s rc=%i\n",
+ cdev->dev.bus_id, discipline->name, rc);
dasd_delete_device(device);
return rc;
}
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index df8902364762d..838aedf78a561 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -7,7 +7,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
- * $Revision: 1.68 $
+ * $Revision: 1.69 $
*/
#include <linux/config.h>
@@ -56,6 +56,7 @@ static struct dasd_discipline dasd_eckd_discipline;
struct dasd_eckd_private {
struct dasd_eckd_characteristics rdc_data;
struct dasd_eckd_confdata conf_data;
+ struct dasd_eckd_path path_data;
struct eckd_count count_area[5];
int init_cqr_status;
int uses_cdl;
@@ -447,12 +448,72 @@ dasd_eckd_cdl_reclen(int recid)
}
static int
+dasd_eckd_read_conf(struct dasd_device *device)
+{
+ void *conf_data;
+ int conf_len, conf_data_saved;
+ int rc;
+ __u8 lpm;
+ struct dasd_eckd_private *private;
+ struct dasd_eckd_path *path_data;
+
+ private = (struct dasd_eckd_private *) device->private;
+ path_data = (struct dasd_eckd_path *) &private->path_data;
+ path_data->opm = ccw_device_get_path_mask(device->cdev);
+ lpm = 0x80;
+ conf_data_saved = 0;
+
+ /* get configuration data per operational path */
+ for (lpm = 0x80; lpm; lpm>>= 1) {
+ if (lpm & path_data->opm){
+ rc = read_conf_data_lpm(device->cdev, &conf_data,
+ &conf_len, lpm);
+ if (rc && rc != -EOPNOTSUPP) { /* -EOPNOTSUPP is ok */
+ MESSAGE(KERN_WARNING,
+ "Read configuration data returned "
+ "error %d", rc);
+ return rc;
+ }
+ if (conf_data == NULL) {
+ MESSAGE(KERN_WARNING, "%s", "No configuration "
+ "data retrieved");
+ continue; /* no errror */
+ }
+ if (conf_len != sizeof (struct dasd_eckd_confdata)) {
+ MESSAGE(KERN_WARNING,
+ "sizes of configuration data mismatch"
+ "%d (read) vs %ld (expected)",
+ conf_len,
+ sizeof (struct dasd_eckd_confdata));
+ kfree(conf_data);
+ continue; /* no errror */
+ }
+ /* save first valid configuration data */
+ if (!conf_data_saved){
+ memcpy(&private->conf_data, conf_data,
+ sizeof (struct dasd_eckd_confdata));
+ conf_data_saved++;
+ }
+ switch (((char *)conf_data)[242] & 0x07){
+ case 0x02:
+ path_data->npm |= lpm;
+ break;
+ case 0x03:
+ path_data->ppm |= lpm;
+ break;
+ }
+ kfree(conf_data);
+ }
+ }
+ return 0;
+}
+
+
+static int
dasd_eckd_check_characteristics(struct dasd_device *device)
{
struct dasd_eckd_private *private;
void *rdc_data;
- void *conf_data;
- int conf_len;
int rc;
private = (struct dasd_eckd_private *) device->private;
@@ -465,6 +526,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
"data");
return -ENOMEM;
}
+ memset(private, 0, sizeof(struct dasd_eckd_private));
device->private = (void *) private;
}
/* Invalidate status of initial analysis. */
@@ -494,30 +556,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
private->rdc_data.sec_per_trk);
/* Read Configuration Data */
- rc = read_conf_data(device->cdev, &conf_data, &conf_len);
- if (rc && rc != -EOPNOTSUPP) { /* -EOPNOTSUPP is ok */
- DEV_MESSAGE(KERN_WARNING, device,
- "Read configuration data returned error %d", rc);
- return rc;
- }
- if (conf_data == NULL) {
- DEV_MESSAGE(KERN_WARNING, device, "%s",
- "No configuration data retrieved");
- return 0; /* no errror */
- }
- if (conf_len != sizeof (struct dasd_eckd_confdata)) {
- DEV_MESSAGE(KERN_WARNING, device,
- "sizes of configuration data mismatch"
- "%d (read) vs %ld (expected)",
- conf_len, sizeof (struct dasd_eckd_confdata));
+ rc = dasd_eckd_read_conf (device);
+ return rc;
- kfree(conf_data); /* allocated by read_conf_data() */
- return 0; /* no errror */
- }
- memcpy(&private->conf_data, conf_data,
- sizeof (struct dasd_eckd_confdata));
- kfree(conf_data); /* allocated by read_conf_data() */
- return 0;
}
static struct dasd_ccw_req *
@@ -1096,7 +1137,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
}
cqr->device = device;
cqr->expires = 5 * 60 * HZ; /* 5 minutes */
- cqr->lpm = LPM_ANYPATH;
+ cqr->lpm = private->path_data.ppm;
cqr->retries = 256;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index 3e1a051d4ab83..b6888c68b2244 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -5,7 +5,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
- * $Revision: 1.9 $
+ * $Revision: 1.10 $
*/
#ifndef DASD_ECKD_H
@@ -326,6 +326,12 @@ struct dasd_eckd_confdata {
} __attribute__ ((packed)) neq;
} __attribute__ ((packed));
+struct dasd_eckd_path {
+ __u8 opm;
+ __u8 ppm;
+ __u8 npm;
+};
+
/*
* Perform Subsystem Function - Prepare for Read Subsystem Data
*/
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
index 82a864719e2e3..7cb98d25f3416 100644
--- a/drivers/s390/block/dasd_erp.c
+++ b/drivers/s390/block/dasd_erp.c
@@ -7,7 +7,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
*
- * $Revision: 1.13 $
+ * $Revision: 1.14 $
*/
#include <linux/config.h>
@@ -95,6 +95,7 @@ dasd_default_erp_action(struct dasd_ccw_req * cqr)
DEV_MESSAGE (KERN_DEBUG, device,
"default ERP called (%i retries left)",
cqr->retries);
+ cqr->lpm = LPM_ANYPATH;
cqr->status = DASD_CQR_QUEUED;
} else {
DEV_MESSAGE (KERN_WARNING, device, "%s",
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 442a5b327c1dc..b35fe12e6bfc5 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -1,7 +1,7 @@
/*
* drivers/s390/cio/chsc.c
* S/390 common I/O routines -- channel subsystem call
- * $Revision: 1.118 $
+ * $Revision: 1.119 $
*
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
@@ -887,6 +887,27 @@ chp_status_write(struct device *dev, const char *buf, size_t count)
static DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write);
+static ssize_t
+chp_type_show(struct device *dev, char *buf)
+{
+ struct channel_path *chp = container_of(dev, struct channel_path, dev);
+
+ if (!chp)
+ return 0;
+ return sprintf(buf, "%x\n", chp->desc.desc);
+}
+
+static DEVICE_ATTR(type, 0444, chp_type_show, NULL);
+
+static struct attribute * chp_attrs[] = {
+ &dev_attr_status.attr,
+ &dev_attr_type.attr,
+ NULL,
+};
+
+static struct attribute_group chp_attr_group = {
+ .attrs = chp_attrs,
+};
static void
chp_release(struct device *dev)
@@ -897,6 +918,68 @@ chp_release(struct device *dev)
kfree(cp);
}
+static int
+chsc_determine_channel_path_description(int chpid,
+ struct channel_path_desc *desc)
+{
+ int ccode, ret;
+
+ struct {
+ struct chsc_header request;
+ u32 : 24;
+ u32 first_chpid : 8;
+ u32 : 24;
+ u32 last_chpid : 8;
+ u32 zeroes1;
+ struct chsc_header response;
+ u32 zeroes2;
+ struct channel_path_desc desc;
+ } *scpd_area;
+
+ scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ if (!scpd_area)
+ return -ENOMEM;
+
+ scpd_area->request = (struct chsc_header) {
+ .length = 0x0010,
+ .code = 0x0002,
+ };
+
+ scpd_area->first_chpid = chpid;
+ scpd_area->last_chpid = chpid;
+
+ ccode = chsc(scpd_area);
+ if (ccode > 0) {
+ ret = (ccode == 3) ? -ENODEV : -EBUSY;
+ goto out;
+ }
+
+ switch (scpd_area->response.code) {
+ case 0x0001: /* Success. */
+ memcpy(desc, &scpd_area->desc,
+ sizeof(struct channel_path_desc));
+ ret = 0;
+ break;
+ case 0x0003: /* Invalid block. */
+ case 0x0007: /* Invalid format. */
+ case 0x0008: /* Other invalid block. */
+ CIO_CRW_EVENT(2, "Error in chsc request block!\n");
+ ret = -EINVAL;
+ break;
+ case 0x0004: /* Command not provided in model. */
+ CIO_CRW_EVENT(2, "Model does not provide scpd\n");
+ ret = -EOPNOTSUPP;
+ break;
+ default:
+ CIO_CRW_EVENT(2, "Unknown CHSC response %d\n",
+ scpd_area->response.code);
+ ret = -EIO;
+ }
+out:
+ free_page((unsigned long)scpd_area);
+ return ret;
+}
+
/*
* Entries for chpids on the system bus.
* This replaces /proc/chpids.
@@ -921,6 +1004,11 @@ new_channel_path(int chpid)
};
snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp0.%x", chpid);
+ /* Obtain channel path description and fill it in. */
+ ret = chsc_determine_channel_path_description(chpid, &chp->desc);
+ if (ret)
+ goto out_free;
+
/* make it known to the system */
ret = device_register(&chp->dev);
if (ret) {
@@ -928,7 +1016,7 @@ new_channel_path(int chpid)
__func__, chpid);
goto out_free;
}
- ret = device_create_file(&chp->dev, &dev_attr_status);
+ ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group);
if (ret) {
device_unregister(&chp->dev);
goto out_free;
@@ -940,6 +1028,23 @@ out_free:
return ret;
}
+void *
+chsc_get_chp_desc(struct subchannel *sch, int chp_no)
+{
+ struct channel_path *chp;
+ struct channel_path_desc *desc;
+
+ chp = chps[sch->schib.pmcw.chpid[chp_no]];
+ if (!chp)
+ return NULL;
+ desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL);
+ if (!desc)
+ return NULL;
+ memcpy(desc, &chp->desc, sizeof(struct channel_path_desc));
+ return desc;
+}
+
+
static int __init
chsc_alloc_sei_area(void)
{
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index b85af9ea2a969..be20da49d147b 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -12,9 +12,21 @@ struct chsc_header {
u16 code;
};
+struct channel_path_desc {
+ u8 flags;
+ u8 lsn;
+ u8 desc;
+ u8 chpid;
+ u8 swla;
+ u8 zeroes;
+ u8 chla;
+ u8 chpp;
+};
+
struct channel_path {
int id;
int state;
+ struct channel_path_desc desc;
struct device dev;
};
@@ -49,4 +61,6 @@ extern struct css_chsc_char css_chsc_characteristics;
extern int chsc_determine_css_characteristics(void);
extern int css_characteristics_avail;
+
+extern void *chsc_get_chp_desc(struct subchannel*, int);
#endif
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 34527b8477efb..11e260e0b9c92 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -24,6 +24,7 @@
#include "cio.h"
#include "cio_debug.h"
#include "css.h"
+#include "chsc.h"
#include "device.h"
#include "qdio.h"
@@ -291,14 +292,14 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
}
static inline int
-__ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic)
+__ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, __u8 lpm)
{
int ret;
struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent);
do {
- ret = cio_start (sch, ccw, 0);
+ ret = cio_start (sch, ccw, lpm);
if ((ret == -EBUSY) || (ret == -EACCES)) {
/* Try again later. */
spin_unlock_irq(&sch->lock);
@@ -388,7 +389,7 @@ read_dev_chars (struct ccw_device *cdev, void **buffer, int length)
ret = -EBUSY;
else
/* 0x00D9C4C3 == ebcdic "RDC" */
- ret = __ccw_device_retry_loop(cdev, rdc_ccw, 0x00D9C4C3);
+ ret = __ccw_device_retry_loop(cdev, rdc_ccw, 0x00D9C4C3, 0);
/* Restore interrupt handler. */
cdev->handler = handler;
@@ -401,10 +402,10 @@ read_dev_chars (struct ccw_device *cdev, void **buffer, int length)
}
/*
- * Read Configuration data
+ * Read Configuration data using path mask
*/
int
-read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
+read_conf_data_lpm (struct ccw_device *cdev, void **buffer, int *length, __u8 lpm)
{
void (*handler)(struct ccw_device *, unsigned long, struct irb *);
struct subchannel *sch;
@@ -457,7 +458,7 @@ read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
ret = -EBUSY;
else
/* 0x00D9C3C4 == ebcdic "RCD" */
- ret = __ccw_device_retry_loop(cdev, rcd_ccw, 0x00D9C3C4);
+ ret = __ccw_device_retry_loop(cdev, rcd_ccw, 0x00D9C3C4, lpm);
/* Restore interrupt handler. */
cdev->handler = handler;
@@ -480,6 +481,15 @@ read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
}
/*
+ * Read Configuration data
+ */
+int
+read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
+{
+ return read_conf_data_lpm (cdev, buffer, length, 0);
+}
+
+/*
* Try to break the lock on a boxed device.
*/
int
@@ -550,6 +560,15 @@ out_unlock:
return ret;
}
+void *
+ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
+{
+ struct subchannel *sch;
+
+ sch = to_subchannel(cdev->dev.parent);
+ return chsc_get_chp_desc(sch, chp_no);
+}
+
// FIXME: these have to go:
int
@@ -580,3 +599,5 @@ EXPORT_SYMBOL(read_conf_data);
EXPORT_SYMBOL(read_dev_chars);
EXPORT_SYMBOL(_ccw_device_get_subchannel_number);
EXPORT_SYMBOL(_ccw_device_get_device_number);
+EXPORT_SYMBOL_GPL(ccw_device_get_chp_desc);
+EXPORT_SYMBOL_GPL(read_conf_data_lpm);
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index 7899560dbfa44..a7efc394515e1 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -50,6 +50,15 @@ config SMSGIUCV
Select this option if you want to be able to receive SMSG messages
from other VM guest systems.
+config CLAW
+ tristate "CLAW device support"
+ depends on NETDEVICES
+ help
+ This driver supports channel attached CLAW devices.
+ CLAW is Common Link Access for Workstation. Common devices
+ that use CLAW are RS/6000s, Cisco Routers (CIP) and 3172 devices.
+ To compile as a module choose M here: The module will be called
+ claw.ko to compile into the kernel choose Y
config QETH
tristate "Gigabit Ethernet device support"
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile
index 2cfd22b2f914d..7cabb80a2e414 100644
--- a/drivers/s390/net/Makefile
+++ b/drivers/s390/net/Makefile
@@ -9,6 +9,6 @@ obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
obj-$(CONFIG_LCS) += lcs.o cu3088.o
-qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o
+qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o qeth_tso.o
qeth-$(CONFIG_PROC_FS) += qeth_proc.o
obj-$(CONFIG_QETH) += qeth.o
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
new file mode 100644
index 0000000000000..06804d39a9c6d
--- /dev/null
+++ b/drivers/s390/net/claw.c
@@ -0,0 +1,4447 @@
+/*
+ * drivers/s390/net/claw.c
+ * ESCON CLAW network driver
+ *
+ * $Revision: 1.35 $ $Date: 2005/03/24 12:25:38 $
+ *
+ * Linux fo zSeries version
+ * Copyright (C) 2002,2005 IBM Corporation
+ * Author(s) Original code written by:
+ * Kazuo Iimura (iimura@jp.ibm.com)
+ * Rewritten by
+ * Andy Richter (richtera@us.ibm.com)
+ * Marc Price (mwprice@us.ibm.com)
+ *
+ * sysfs parms:
+ * group x.x.rrrr,x.x.wwww
+ * read_buffer nnnnnnn
+ * write_buffer nnnnnn
+ * host_name aaaaaaaa
+ * adapter_name aaaaaaaa
+ * api_type aaaaaaaa
+ *
+ * eg.
+ * group 0.0.0200 0.0.0201
+ * read_buffer 25
+ * write_buffer 20
+ * host_name LINUX390
+ * adapter_name RS6K
+ * api_type TCPIP
+ *
+ * where
+ *
+ * The device id is decided by the order entries
+ * are added to the group the first is claw0 the second claw1
+ * up to CLAW_MAX_DEV
+ *
+ * rrrr - the first of 2 consecutive device addresses used for the
+ * CLAW protocol.
+ * The specified address is always used as the input (Read)
+ * channel and the next address is used as the output channel.
+ *
+ * wwww - the second of 2 consecutive device addresses used for
+ * the CLAW protocol.
+ * The specified address is always used as the output
+ * channel and the previous address is used as the input channel.
+ *
+ * read_buffer - specifies number of input buffers to allocate.
+ * write_buffer - specifies number of output buffers to allocate.
+ * host_name - host name
+ * adaptor_name - adaptor name
+ * api_type - API type TCPIP or API will be sent and expected
+ * as ws_name
+ *
+ * Note the following requirements:
+ * 1) host_name must match the configured adapter_name on the remote side
+ * 2) adaptor_name must match the configured host name on the remote side
+ *
+ * Change History
+ * 1.00 Initial release shipped
+ * 1.10 Changes for Buffer allocation
+ * 1.15 Changed for 2.6 Kernel No longer compiles on 2.4 or lower
+ * 1.25 Added Packing support
+ */
+#include <asm/bitops.h>
+#include <asm/ccwdev.h>
+#include <asm/ccwgroup.h>
+#include <asm/debug.h>
+#include <asm/idals.h>
+#include <asm/io.h>
+
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/tcp.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/version.h>
+
+#include "cu3088.h"
+#include "claw.h"
+
+MODULE_AUTHOR("Andy Richter <richtera@us.ibm.com>");
+MODULE_DESCRIPTION("Linux for zSeries CLAW Driver\n" \
+ "Copyright 2000,2005 IBM Corporation\n");
+MODULE_LICENSE("GPL");
+
+/* Debugging is based on DEBUGMSG, IOTRACE, or FUNCTRACE options:
+ DEBUGMSG - Enables output of various debug messages in the code
+ IOTRACE - Enables output of CCW and other IO related traces
+ FUNCTRACE - Enables output of function entry/exit trace
+ Define any combination of above options to enable tracing
+
+ CLAW also uses the s390dbf file system see claw_trace and claw_setup
+*/
+
+/* following enables tracing */
+//#define DEBUGMSG
+//#define IOTRACE
+//#define FUNCTRACE
+
+#ifdef DEBUGMSG
+#define DEBUG
+#endif
+
+#ifdef IOTRACE
+#define DEBUG
+#endif
+
+#ifdef FUNCTRACE
+#define DEBUG
+#endif
+
+ char debug_buffer[255];
+/**
+ * Debug Facility Stuff
+ */
+static debug_info_t *claw_dbf_setup;
+static debug_info_t *claw_dbf_trace;
+
+/**
+ * CLAW Debug Facility functions
+ */
+static void
+claw_unregister_debug_facility(void)
+{
+ if (claw_dbf_setup)
+ debug_unregister(claw_dbf_setup);
+ if (claw_dbf_trace)
+ debug_unregister(claw_dbf_trace);
+}
+
+static int
+claw_register_debug_facility(void)
+{
+ claw_dbf_setup = debug_register("claw_setup", 1, 1, 8);
+ claw_dbf_trace = debug_register("claw_trace", 1, 2, 8);
+ if (claw_dbf_setup == NULL || claw_dbf_trace == NULL) {
+ printk(KERN_WARNING "Not enough memory for debug facility.\n");
+ claw_unregister_debug_facility();
+ return -ENOMEM;
+ }
+ debug_register_view(claw_dbf_setup, &debug_hex_ascii_view);
+ debug_set_level(claw_dbf_setup, 2);
+ debug_register_view(claw_dbf_trace, &debug_hex_ascii_view);
+ debug_set_level(claw_dbf_trace, 2);
+ return 0;
+}
+
+static inline void
+claw_set_busy(struct net_device *dev)
+{
+ ((struct claw_privbk *) dev->priv)->tbusy=1;
+ eieio();
+}
+
+static inline void
+claw_clear_busy(struct net_device *dev)
+{
+ clear_bit(0, &(((struct claw_privbk *) dev->priv)->tbusy));
+ netif_wake_queue(dev);
+ eieio();
+}
+
+static inline int
+claw_check_busy(struct net_device *dev)
+{
+ eieio();
+ return ((struct claw_privbk *) dev->priv)->tbusy;
+}
+
+static inline void
+claw_setbit_busy(int nr,struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ set_bit(nr, (void *)&(((struct claw_privbk *)dev->priv)->tbusy));
+}
+
+static inline void
+claw_clearbit_busy(int nr,struct net_device *dev)
+{
+ clear_bit(nr,(void *)&(((struct claw_privbk *)dev->priv)->tbusy));
+ netif_wake_queue(dev);
+}
+
+static inline int
+claw_test_and_setbit_busy(int nr,struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ return test_and_set_bit(nr,
+ (void *)&(((struct claw_privbk *) dev->priv)->tbusy));
+}
+
+
+/* Functions for the DEV methods */
+
+static int claw_probe(struct ccwgroup_device *cgdev);
+static void claw_remove_device(struct ccwgroup_device *cgdev);
+static void claw_purge_skb_queue(struct sk_buff_head *q);
+static int claw_new_device(struct ccwgroup_device *cgdev);
+static int claw_shutdown_device(struct ccwgroup_device *cgdev);
+static int claw_tx(struct sk_buff *skb, struct net_device *dev);
+static int claw_change_mtu( struct net_device *dev, int new_mtu);
+static int claw_open(struct net_device *dev);
+static void claw_irq_handler(struct ccw_device *cdev,
+ unsigned long intparm, struct irb *irb);
+static void claw_irq_tasklet ( unsigned long data );
+static int claw_release(struct net_device *dev);
+static void claw_write_retry ( struct chbk * p_ch );
+static void claw_write_next ( struct chbk * p_ch );
+static void claw_timer ( struct chbk * p_ch );
+
+/* Functions */
+static int add_claw_reads(struct net_device *dev,
+ struct ccwbk* p_first, struct ccwbk* p_last);
+static void inline ccw_check_return_code (struct ccw_device *cdev,
+ int return_code);
+static void inline ccw_check_unit_check (struct chbk * p_ch,
+ unsigned char sense );
+static int find_link(struct net_device *dev, char *host_name, char *ws_name );
+static int claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid);
+static int init_ccw_bk(struct net_device *dev);
+static void probe_error( struct ccwgroup_device *cgdev);
+static struct net_device_stats *claw_stats(struct net_device *dev);
+static int inline pages_to_order_of_mag(int num_of_pages);
+static struct sk_buff *claw_pack_skb(struct claw_privbk *privptr);
+#ifdef DEBUG
+static void dumpit (char *buf, int len);
+#endif
+/* sysfs Functions */
+static ssize_t claw_hname_show(struct device *dev, char *buf);
+static ssize_t claw_hname_write(struct device *dev,
+ const char *buf, size_t count);
+static ssize_t claw_adname_show(struct device *dev, char *buf);
+static ssize_t claw_adname_write(struct device *dev,
+ const char *buf, size_t count);
+static ssize_t claw_apname_show(struct device *dev, char *buf);
+static ssize_t claw_apname_write(struct device *dev,
+ const char *buf, size_t count);
+static ssize_t claw_wbuff_show(struct device *dev, char *buf);
+static ssize_t claw_wbuff_write(struct device *dev,
+ const char *buf, size_t count);
+static ssize_t claw_rbuff_show(struct device *dev, char *buf);
+static ssize_t claw_rbuff_write(struct device *dev,
+ const char *buf, size_t count);
+static int claw_add_files(struct device *dev);
+static void claw_remove_files(struct device *dev);
+
+/* Functions for System Validate */
+static int claw_process_control( struct net_device *dev, struct ccwbk * p_ccw);
+static int claw_send_control(struct net_device *dev, __u8 type, __u8 link,
+ __u8 correlator, __u8 rc , char *local_name, char *remote_name);
+static int claw_snd_conn_req(struct net_device *dev, __u8 link);
+static int claw_snd_disc(struct net_device *dev, struct clawctl * p_ctl);
+static int claw_snd_sys_validate_rsp(struct net_device *dev,
+ struct clawctl * p_ctl, __u32 return_code);
+static int claw_strt_conn_req(struct net_device *dev );
+static void claw_strt_read ( struct net_device *dev, int lock );
+static void claw_strt_out_IO( struct net_device *dev );
+static void claw_free_wrt_buf( struct net_device *dev );
+
+/* Functions for unpack reads */
+static void unpack_read (struct net_device *dev );
+
+/* ccwgroup table */
+
+static struct ccwgroup_driver claw_group_driver = {
+ .owner = THIS_MODULE,
+ .name = "claw",
+ .max_slaves = 2,
+ .driver_id = 0xC3D3C1E6,
+ .probe = claw_probe,
+ .remove = claw_remove_device,
+ .set_online = claw_new_device,
+ .set_offline = claw_shutdown_device,
+};
+
+/*
+*
+* Key functions
+*/
+
+/*----------------------------------------------------------------*
+ * claw_probe *
+ * this function is called for each CLAW device. *
+ *----------------------------------------------------------------*/
+static int
+claw_probe(struct ccwgroup_device *cgdev)
+{
+ int rc;
+ struct claw_privbk *privptr=NULL;
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s Enter\n",__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(2,setup,"probe");
+ if (!get_device(&cgdev->dev))
+ return -ENODEV;
+#ifdef DEBUGMSG
+ printk(KERN_INFO "claw: variable cgdev =\n");
+ dumpit((char *)cgdev, sizeof(struct ccwgroup_device));
+#endif
+ privptr = kmalloc(sizeof(struct claw_privbk), GFP_KERNEL);
+ if (privptr == NULL) {
+ probe_error(cgdev);
+ put_device(&cgdev->dev);
+ printk(KERN_WARNING "Out of memory %s %s Exit Line %d \n",
+ cgdev->cdev[0]->dev.bus_id,__FUNCTION__,__LINE__);
+ CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM);
+ return -ENOMEM;
+ }
+ memset(privptr,0x00,sizeof(struct claw_privbk));
+ privptr->p_mtc_envelope= kmalloc( MAX_ENVELOPE_SIZE, GFP_KERNEL);
+ privptr->p_env = kmalloc(sizeof(struct claw_env), GFP_KERNEL);
+ if ((privptr->p_mtc_envelope==NULL) || (privptr->p_env==NULL)) {
+ probe_error(cgdev);
+ put_device(&cgdev->dev);
+ printk(KERN_WARNING "Out of memory %s %s Exit Line %d \n",
+ cgdev->cdev[0]->dev.bus_id,__FUNCTION__,__LINE__);
+ CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM);
+ return -ENOMEM;
+ }
+ memset(privptr->p_mtc_envelope, 0x00, MAX_ENVELOPE_SIZE);
+ memset(privptr->p_env, 0x00, sizeof(struct claw_env));
+ memcpy(privptr->p_env->adapter_name,WS_NAME_NOT_DEF,8);
+ memcpy(privptr->p_env->host_name,WS_NAME_NOT_DEF,8);
+ memcpy(privptr->p_env->api_type,WS_NAME_NOT_DEF,8);
+ privptr->p_env->packing = 0;
+ privptr->p_env->write_buffers = 5;
+ privptr->p_env->read_buffers = 5;
+ privptr->p_env->read_size = CLAW_FRAME_SIZE;
+ privptr->p_env->write_size = CLAW_FRAME_SIZE;
+ rc = claw_add_files(&cgdev->dev);
+ if (rc) {
+ probe_error(cgdev);
+ put_device(&cgdev->dev);
+ printk(KERN_WARNING "add_files failed %s %s Exit Line %d \n",
+ cgdev->cdev[0]->dev.bus_id,__FUNCTION__,__LINE__);
+ CLAW_DBF_TEXT_(2,setup,"probex%d",rc);
+ return rc;
+ }
+ printk(KERN_INFO "claw: sysfs files added for %s\n",cgdev->cdev[0]->dev.bus_id);
+ privptr->p_env->p_priv = privptr;
+ cgdev->cdev[0]->handler = claw_irq_handler;
+ cgdev->cdev[1]->handler = claw_irq_handler;
+ cgdev->dev.driver_data = privptr;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "claw:%s exit on line %d, "
+ "rc = 0\n",__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(2,setup,"prbext 0");
+
+ return 0;
+} /* end of claw_probe */
+
+/*-------------------------------------------------------------------*
+ * claw_tx *
+ *-------------------------------------------------------------------*/
+
+static int
+claw_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ int rc;
+ struct claw_privbk *privptr=dev->priv;
+ unsigned long saveflags;
+ struct chbk *p_ch;
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s enter\n",dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"claw_tx");
+ p_ch=&privptr->channel[WRITE];
+ if (skb == NULL) {
+ printk(KERN_WARNING "%s: null pointer passed as sk_buffer\n",
+ dev->name);
+ privptr->stats.tx_dropped++;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s() exit on line %d, rc = EIO\n",
+ dev->name,__FUNCTION__, __LINE__);
+#endif
+ CLAW_DBF_TEXT_(2,trace,"clawtx%d",-EIO);
+ return -EIO;
+ }
+
+#ifdef IOTRACE
+ printk(KERN_INFO "%s: variable sk_buff=\n",dev->name);
+ dumpit((char *) skb, sizeof(struct sk_buff));
+ printk(KERN_INFO "%s: variable dev=\n",dev->name);
+ dumpit((char *) dev, sizeof(struct net_device));
+#endif
+ spin_lock_irqsave(get_ccwdev_lock(p_ch->cdev), saveflags);
+ rc=claw_hw_tx( skb, dev, 1 );
+ spin_unlock_irqrestore(get_ccwdev_lock(p_ch->cdev), saveflags);
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s exit on line %d, rc = %d\n",
+ dev->name, __FUNCTION__, __LINE__, rc);
+#endif
+ CLAW_DBF_TEXT_(4,trace,"clawtx%d",rc);
+ return rc;
+} /* end of claw_tx */
+
+/*------------------------------------------------------------------*
+ * pack the collect queue into an skb and return it *
+ * If not packing just return the top skb from the queue *
+ *------------------------------------------------------------------*/
+
+static struct sk_buff *
+claw_pack_skb(struct claw_privbk *privptr)
+{
+ struct sk_buff *new_skb,*held_skb;
+ struct chbk *p_ch = &privptr->channel[WRITE];
+ struct claw_env *p_env = privptr->p_env;
+ int pkt_cnt,pk_ind,so_far;
+
+ new_skb = NULL; /* assume no dice */
+ pkt_cnt = 0;
+ CLAW_DBF_TEXT(4,trace,"PackSKBe");
+ if (skb_queue_len(&p_ch->collect_queue) > 0) {
+ /* some data */
+ held_skb = skb_dequeue(&p_ch->collect_queue);
+ if (p_env->packing != DO_PACKED)
+ return held_skb;
+ if (held_skb)
+ atomic_dec(&held_skb->users);
+ else
+ return NULL;
+ /* get a new SKB we will pack at least one */
+ new_skb = dev_alloc_skb(p_env->write_size);
+ if (new_skb == NULL) {
+ atomic_inc(&held_skb->users);
+ skb_queue_head(&p_ch->collect_queue,held_skb);
+ return NULL;
+ }
+ /* we have packed packet and a place to put it */
+ pk_ind = 1;
+ so_far = 0;
+ new_skb->cb[1] = 'P'; /* every skb on queue has pack header */
+ while ((pk_ind) && (held_skb != NULL)) {
+ if (held_skb->len+so_far <= p_env->write_size-8) {
+ memcpy(skb_put(new_skb,held_skb->len),
+ held_skb->data,held_skb->len);
+ privptr->stats.tx_packets++;
+ so_far += held_skb->len;
+ pkt_cnt++;
+ dev_kfree_skb_irq(held_skb);
+ held_skb = skb_dequeue(&p_ch->collect_queue);
+ if (held_skb)
+ atomic_dec(&held_skb->users);
+ } else {
+ pk_ind = 0;
+ atomic_inc(&held_skb->users);
+ skb_queue_head(&p_ch->collect_queue,held_skb);
+ }
+ }
+#ifdef IOTRACE
+ printk(KERN_INFO "%s: %s() Packed %d len %d\n",
+ p_env->ndev->name,
+ __FUNCTION__,pkt_cnt,new_skb->len);
+#endif
+ }
+ CLAW_DBF_TEXT(4,trace,"PackSKBx");
+ return new_skb;
+}
+
+/*-------------------------------------------------------------------*
+ * claw_change_mtu *
+ * *
+ *-------------------------------------------------------------------*/
+
+static int
+claw_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct claw_privbk *privptr=dev->priv;
+ int buff_size;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__);
+#endif
+#ifdef DEBUGMSG
+ printk(KERN_INFO "variable dev =\n");
+ dumpit((char *) dev, sizeof(struct net_device));
+ printk(KERN_INFO "variable new_mtu = %d\n", new_mtu);
+#endif
+ CLAW_DBF_TEXT(4,trace,"setmtu");
+ buff_size = privptr->p_env->write_size;
+ if ((new_mtu < 60) || (new_mtu > buff_size)) {
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d, rc=EINVAL\n",
+ dev->name,
+ __FUNCTION__, __LINE__);
+#endif
+ return -EINVAL;
+ }
+ dev->mtu = new_mtu;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",dev->name,
+ __FUNCTION__, __LINE__);
+#endif
+ return 0;
+} /* end of claw_change_mtu */
+
+
+/*-------------------------------------------------------------------*
+ * claw_open *
+ * *
+ *-------------------------------------------------------------------*/
+static int
+claw_open(struct net_device *dev)
+{
+
+ int rc;
+ int i;
+ unsigned long saveflags=0;
+ unsigned long parm;
+ struct claw_privbk *privptr;
+ DECLARE_WAITQUEUE(wait, current);
+ struct timer_list timer;
+ struct ccwbk *p_buf;
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"open");
+ if (!dev | (dev->name[0] == 0x00)) {
+ CLAW_DBF_TEXT(2,trace,"BadDev");
+ printk(KERN_WARNING "claw: Bad device at open failing \n");
+ return -ENODEV;
+ }
+ privptr = (struct claw_privbk *)dev->priv;
+ /* allocate and initialize CCW blocks */
+ if (privptr->buffs_alloc == 0) {
+ rc=init_ccw_bk(dev);
+ if (rc) {
+ printk(KERN_INFO "%s:%s Exit on line %d, rc=ENOMEM\n",
+ dev->name,
+ __FUNCTION__, __LINE__);
+ CLAW_DBF_TEXT(2,trace,"openmem");
+ return -ENOMEM;
+ }
+ }
+ privptr->system_validate_comp=0;
+ privptr->release_pend=0;
+ if(strncmp(privptr->p_env->api_type,WS_APPL_NAME_PACKED,6) == 0) {
+ privptr->p_env->read_size=DEF_PACK_BUFSIZE;
+ privptr->p_env->write_size=DEF_PACK_BUFSIZE;
+ privptr->p_env->packing=PACKING_ASK;
+ } else {
+ privptr->p_env->packing=0;
+ privptr->p_env->read_size=CLAW_FRAME_SIZE;
+ privptr->p_env->write_size=CLAW_FRAME_SIZE;
+ }
+ claw_set_busy(dev);
+ tasklet_init(&privptr->channel[READ].tasklet, claw_irq_tasklet,
+ (unsigned long) &privptr->channel[READ]);
+ for ( i = 0; i < 2; i++) {
+ CLAW_DBF_TEXT_(2,trace,"opn_ch%d",i);
+ init_waitqueue_head(&privptr->channel[i].wait);
+ /* skb_queue_head_init(&p_ch->io_queue); */
+ if (i == WRITE)
+ skb_queue_head_init(
+ &privptr->channel[WRITE].collect_queue);
+ privptr->channel[i].flag_a = 0;
+ privptr->channel[i].IO_active = 0;
+ privptr->channel[i].flag &= ~CLAW_TIMER;
+ init_timer(&timer);
+ timer.function = (void *)claw_timer;
+ timer.data = (unsigned long)(&privptr->channel[i]);
+ timer.expires = jiffies + 15*HZ;
+ add_timer(&timer);
+ spin_lock_irqsave(get_ccwdev_lock(
+ privptr->channel[i].cdev), saveflags);
+ parm = (unsigned long) &privptr->channel[i];
+ privptr->channel[i].claw_state = CLAW_START_HALT_IO;
+ rc = 0;
+ add_wait_queue(&privptr->channel[i].wait, &wait);
+ rc = ccw_device_halt(
+ (struct ccw_device *)privptr->channel[i].cdev,parm);
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_irqrestore(
+ get_ccwdev_lock(privptr->channel[i].cdev), saveflags);
+ schedule();
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&privptr->channel[i].wait, &wait);
+ if(rc != 0)
+ ccw_check_return_code(privptr->channel[i].cdev, rc);
+ if((privptr->channel[i].flag & CLAW_TIMER) == 0x00)
+ del_timer(&timer);
+ }
+ if ((((privptr->channel[READ].last_dstat |
+ privptr->channel[WRITE].last_dstat) &
+ ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) ||
+ (((privptr->channel[READ].flag |
+ privptr->channel[WRITE].flag) & CLAW_TIMER) != 0x00)) {
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: channel problems during open - read:"
+ " %02x - write: %02x\n",
+ dev->name,
+ privptr->channel[READ].last_dstat,
+ privptr->channel[WRITE].last_dstat);
+#endif
+ printk(KERN_INFO "%s: remote side is not ready\n", dev->name);
+ CLAW_DBF_TEXT(2,trace,"notrdy");
+
+ for ( i = 0; i < 2; i++) {
+ spin_lock_irqsave(
+ get_ccwdev_lock(privptr->channel[i].cdev),
+ saveflags);
+ parm = (unsigned long) &privptr->channel[i];
+ privptr->channel[i].claw_state = CLAW_STOP;
+ rc = ccw_device_halt(
+ (struct ccw_device *)&privptr->channel[i].cdev,
+ parm);
+ spin_unlock_irqrestore(
+ get_ccwdev_lock(privptr->channel[i].cdev),
+ saveflags);
+ if (rc != 0) {
+ ccw_check_return_code(
+ privptr->channel[i].cdev, rc);
+ }
+ }
+ free_pages((unsigned long)privptr->p_buff_ccw,
+ (int)pages_to_order_of_mag(privptr->p_buff_ccw_num));
+ if (privptr->p_env->read_size < PAGE_SIZE) {
+ free_pages((unsigned long)privptr->p_buff_read,
+ (int)pages_to_order_of_mag(
+ privptr->p_buff_read_num));
+ }
+ else {
+ p_buf=privptr->p_read_active_first;
+ while (p_buf!=NULL) {
+ free_pages((unsigned long)p_buf->p_buffer,
+ (int)pages_to_order_of_mag(
+ privptr->p_buff_pages_perread ));
+ p_buf=p_buf->next;
+ }
+ }
+ if (privptr->p_env->write_size < PAGE_SIZE ) {
+ free_pages((unsigned long)privptr->p_buff_write,
+ (int)pages_to_order_of_mag(
+ privptr->p_buff_write_num));
+ }
+ else {
+ p_buf=privptr->p_write_active_first;
+ while (p_buf!=NULL) {
+ free_pages((unsigned long)p_buf->p_buffer,
+ (int)pages_to_order_of_mag(
+ privptr->p_buff_pages_perwrite ));
+ p_buf=p_buf->next;
+ }
+ }
+ privptr->buffs_alloc = 0;
+ privptr->channel[READ].flag= 0x00;
+ privptr->channel[WRITE].flag = 0x00;
+ privptr->p_buff_ccw=NULL;
+ privptr->p_buff_read=NULL;
+ privptr->p_buff_write=NULL;
+ claw_clear_busy(dev);
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d, rc=EIO\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(2,trace,"open EIO");
+ return -EIO;
+ }
+
+ /* Send SystemValidate command */
+
+ claw_clear_busy(dev);
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d, rc=0\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"openok");
+ return 0;
+} /* end of claw_open */
+
+/*-------------------------------------------------------------------*
+* *
+* claw_irq_handler *
+* *
+*--------------------------------------------------------------------*/
+static void
+claw_irq_handler(struct ccw_device *cdev,
+ unsigned long intparm, struct irb *irb)
+{
+ struct chbk *p_ch = NULL;
+ struct claw_privbk *privptr = NULL;
+ struct net_device *dev = NULL;
+ struct claw_env *p_env;
+ struct chbk *p_ch_r=NULL;
+
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s enter \n",__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"clawirq");
+ /* Bypass all 'unsolicited interrupts' */
+ if (!cdev->dev.driver_data) {
+ printk(KERN_WARNING "claw: unsolicited interrupt for device:"
+ "%s received c-%02x d-%02x\n",
+ cdev->dev.bus_id,irb->scsw.cstat, irb->scsw.dstat);
+#ifdef FUNCTRACE
+ printk(KERN_INFO "claw: %s() "
+ "exit on line %d\n",__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(2,trace,"badirq");
+ return;
+ }
+ privptr = (struct claw_privbk *)cdev->dev.driver_data;
+
+ /* Try to extract channel from driver data. */
+ if (privptr->channel[READ].cdev == cdev)
+ p_ch = &privptr->channel[READ];
+ else if (privptr->channel[WRITE].cdev == cdev)
+ p_ch = &privptr->channel[WRITE];
+ else {
+ printk(KERN_WARNING "claw: Can't determine channel for "
+ "interrupt, device %s\n", cdev->dev.bus_id);
+ CLAW_DBF_TEXT(2,trace,"badchan");
+ return;
+ }
+ CLAW_DBF_TEXT_(4,trace,"IRQCH=%d",p_ch->flag);
+
+ dev = (struct net_device *) (p_ch->ndev);
+ p_env=privptr->p_env;
+
+#ifdef IOTRACE
+ printk(KERN_INFO "%s: interrupt for device: %04x "
+ "received c-%02x d-%02x state-%02x\n",
+ dev->name, p_ch->devno, irb->scsw.cstat,
+ irb->scsw.dstat, p_ch->claw_state);
+#endif
+
+ /* Copy interruption response block. */
+ memcpy(p_ch->irb, irb, sizeof(struct irb));
+
+ /* Check for good subchannel return code, otherwise error message */
+ if (irb->scsw.cstat && !(irb->scsw.cstat & SCHN_STAT_PCI)) {
+ printk(KERN_INFO "%s: subchannel check for device: %04x -"
+ " Sch Stat %02x Dev Stat %02x CPA - %04x\n",
+ dev->name, p_ch->devno,
+ irb->scsw.cstat, irb->scsw.dstat,irb->scsw.cpa);
+#ifdef IOTRACE
+ dumpit((char *)irb,sizeof(struct irb));
+ dumpit((char *)(unsigned long)irb->scsw.cpa,
+ sizeof(struct ccw1));
+#endif
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(2,trace,"chanchk");
+ /* return; */
+ }
+
+ /* Check the reason-code of a unit check */
+ if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) {
+ ccw_check_unit_check(p_ch, irb->ecw[0]);
+ }
+
+ /* State machine to bring the connection up, down and to restart */
+ p_ch->last_dstat = irb->scsw.dstat;
+
+ switch (p_ch->claw_state) {
+ case CLAW_STOP:/* HALT_IO by claw_release (halt sequence) */
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: CLAW_STOP enter\n", dev->name);
+#endif
+ if (!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) ||
+ (p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) ||
+ (p_ch->irb->scsw.stctl ==
+ (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) {
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ return;
+ }
+ wake_up(&p_ch->wait); /* wake up claw_release */
+
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: CLAW_STOP exit\n", dev->name);
+#endif
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"stop");
+ return;
+
+ case CLAW_START_HALT_IO: /* HALT_IO issued by claw_open */
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: process CLAW_STAT_HALT_IO\n",
+ dev->name);
+#endif
+ if (!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) ||
+ (p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) ||
+ (p_ch->irb->scsw.stctl ==
+ (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) {
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"haltio");
+ return;
+ }
+ if (p_ch->flag == CLAW_READ) {
+ p_ch->claw_state = CLAW_START_READ;
+ wake_up(&p_ch->wait); /* wake claw_open (READ)*/
+ }
+ else
+ if (p_ch->flag == CLAW_WRITE) {
+ p_ch->claw_state = CLAW_START_WRITE;
+ /* send SYSTEM_VALIDATE */
+ claw_strt_read(dev, LOCK_NO);
+ claw_send_control(dev,
+ SYSTEM_VALIDATE_REQUEST,
+ 0, 0, 0,
+ p_env->host_name,
+ p_env->adapter_name );
+ } else {
+ printk(KERN_WARNING "claw: unsolicited "
+ "interrupt for device:"
+ "%s received c-%02x d-%02x\n",
+ cdev->dev.bus_id,
+ irb->scsw.cstat,
+ irb->scsw.dstat);
+ return;
+ }
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: process CLAW_STAT_HALT_IO exit\n",
+ dev->name);
+#endif
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"haltio");
+ return;
+ case CLAW_START_READ:
+ CLAW_DBF_TEXT(4,trace,"ReadIRQ");
+ if (p_ch->irb->scsw.dstat & DEV_STAT_UNIT_CHECK) {
+ clear_bit(0, (void *)&p_ch->IO_active);
+ if ((p_ch->irb->ecw[0] & 0x41) == 0x41 ||
+ (p_ch->irb->ecw[0] & 0x40) == 0x40 ||
+ (p_ch->irb->ecw[0]) == 0)
+ {
+ privptr->stats.rx_errors++;
+ printk(KERN_INFO "%s: Restart is "
+ "required after remote "
+ "side recovers \n",
+ dev->name);
+ }
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"notrdy");
+ return;
+ }
+ if ((p_ch->irb->scsw.cstat & SCHN_STAT_PCI) &&
+ (p_ch->irb->scsw.dstat==0)) {
+ if (test_and_set_bit(CLAW_BH_ACTIVE,
+ (void *)&p_ch->flag_a) == 0) {
+ tasklet_schedule(&p_ch->tasklet);
+ }
+ else {
+ CLAW_DBF_TEXT(4,trace,"PCINoBH");
+ }
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"PCI_read");
+ return;
+ }
+ if(!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) ||
+ (p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) ||
+ (p_ch->irb->scsw.stctl ==
+ (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) {
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"SPend_rd");
+ return;
+ }
+ clear_bit(0, (void *)&p_ch->IO_active);
+ claw_clearbit_busy(TB_RETRY,dev);
+ if (test_and_set_bit(CLAW_BH_ACTIVE,
+ (void *)&p_ch->flag_a) == 0) {
+ tasklet_schedule(&p_ch->tasklet);
+ }
+ else {
+ CLAW_DBF_TEXT(4,trace,"RdBHAct");
+ }
+
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: process CLAW_START_READ exit\n",
+ dev->name);
+#endif
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"RdIRQXit");
+ return;
+ case CLAW_START_WRITE:
+ if (p_ch->irb->scsw.dstat & DEV_STAT_UNIT_CHECK) {
+ printk(KERN_INFO "%s: Unit Check Occured in "
+ "write channel\n",dev->name);
+ clear_bit(0, (void *)&p_ch->IO_active);
+ if (p_ch->irb->ecw[0] & 0x80 ) {
+ printk(KERN_INFO "%s: Resetting Event "
+ "occurred:\n",dev->name);
+ init_timer(&p_ch->timer);
+ p_ch->timer.function =
+ (void *)claw_write_retry;
+ p_ch->timer.data = (unsigned long)p_ch;
+ p_ch->timer.expires = jiffies + 10*HZ;
+ add_timer(&p_ch->timer);
+ printk(KERN_INFO "%s: write connection "
+ "restarting\n",dev->name);
+ }
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"rstrtwrt");
+ return;
+ }
+ if (p_ch->irb->scsw.dstat & DEV_STAT_UNIT_EXCEP) {
+ clear_bit(0, (void *)&p_ch->IO_active);
+ printk(KERN_INFO "%s: Unit Exception "
+ "Occured in write channel\n",
+ dev->name);
+ }
+ if(!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) ||
+ (p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) ||
+ (p_ch->irb->scsw.stctl ==
+ (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) {
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"writeUE");
+ return;
+ }
+ clear_bit(0, (void *)&p_ch->IO_active);
+ if (claw_test_and_setbit_busy(TB_TX,dev)==0) {
+ claw_write_next(p_ch);
+ claw_clearbit_busy(TB_TX,dev);
+ claw_clear_busy(dev);
+ }
+ p_ch_r=(struct chbk *)&privptr->channel[READ];
+ if (test_and_set_bit(CLAW_BH_ACTIVE,
+ (void *)&p_ch_r->flag_a) == 0) {
+ tasklet_schedule(&p_ch_r->tasklet);
+ }
+
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: process CLAW_START_WRITE exit\n",
+ dev->name);
+#endif
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"StWtExit");
+ return;
+ default:
+ printk(KERN_WARNING "%s: wrong selection code - irq "
+ "state=%d\n",dev->name,p_ch->claw_state);
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(2,trace,"badIRQ");
+ return;
+ }
+
+} /* end of claw_irq_handler */
+
+
+/*-------------------------------------------------------------------*
+* claw_irq_tasklet *
+* *
+*--------------------------------------------------------------------*/
+static void
+claw_irq_tasklet ( unsigned long data )
+{
+ struct chbk * p_ch;
+ struct net_device *dev;
+ struct claw_privbk * privptr;
+
+ p_ch = (struct chbk *) data;
+ dev = (struct net_device *)p_ch->ndev;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__);
+#endif
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: variable p_ch =\n",dev->name);
+ dumpit((char *) p_ch, sizeof(struct chbk));
+#endif
+ CLAW_DBF_TEXT(4,trace,"IRQtask");
+
+ privptr = (struct claw_privbk *) dev->priv;
+
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: bh routine - state-%02x\n" ,
+ dev->name, p_ch->claw_state);
+#endif
+
+ unpack_read(dev);
+ clear_bit(CLAW_BH_ACTIVE, (void *)&p_ch->flag_a);
+ CLAW_DBF_TEXT(4,trace,"TskletXt");
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ return;
+} /* end of claw_irq_bh */
+
+/*-------------------------------------------------------------------*
+* claw_release *
+* *
+*--------------------------------------------------------------------*/
+static int
+claw_release(struct net_device *dev)
+{
+ int rc;
+ int i;
+ unsigned long saveflags;
+ unsigned long parm;
+ struct claw_privbk *privptr;
+ DECLARE_WAITQUEUE(wait, current);
+ struct ccwbk* p_this_ccw;
+ struct ccwbk* p_buf;
+
+ if (!dev)
+ return 0;
+ privptr = (struct claw_privbk *) dev->priv;
+ if (!privptr)
+ return 0;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"release");
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: variable dev =\n",dev->name);
+ dumpit((char *) dev, sizeof(struct net_device));
+ printk(KERN_INFO "Priv Buffalloc %d\n",privptr->buffs_alloc);
+ printk(KERN_INFO "Priv p_buff_ccw = %p\n",&privptr->p_buff_ccw);
+#endif
+ privptr->release_pend=1;
+ claw_setbit_busy(TB_STOP,dev);
+ for ( i = 1; i >=0 ; i--) {
+ spin_lock_irqsave(
+ get_ccwdev_lock(privptr->channel[i].cdev), saveflags);
+ /* del_timer(&privptr->channel[READ].timer); */
+ privptr->channel[i].claw_state = CLAW_STOP;
+ privptr->channel[i].IO_active = 0;
+ parm = (unsigned long) &privptr->channel[i];
+ if (i == WRITE)
+ claw_purge_skb_queue(
+ &privptr->channel[WRITE].collect_queue);
+ rc = ccw_device_halt (privptr->channel[i].cdev, parm);
+ if (privptr->system_validate_comp==0x00) /* never opened? */
+ init_waitqueue_head(&privptr->channel[i].wait);
+ add_wait_queue(&privptr->channel[i].wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_irqrestore(
+ get_ccwdev_lock(privptr->channel[i].cdev), saveflags);
+ schedule();
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&privptr->channel[i].wait, &wait);
+ if (rc != 0) {
+ ccw_check_return_code(privptr->channel[i].cdev, rc);
+ }
+ }
+ if (privptr->pk_skb != NULL) {
+ dev_kfree_skb(privptr->pk_skb);
+ privptr->pk_skb = NULL;
+ }
+ if(privptr->buffs_alloc != 1) {
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"none2fre");
+ return 0;
+ }
+ CLAW_DBF_TEXT(4,trace,"freebufs");
+ if (privptr->p_buff_ccw != NULL) {
+ free_pages((unsigned long)privptr->p_buff_ccw,
+ (int)pages_to_order_of_mag(privptr->p_buff_ccw_num));
+ }
+ CLAW_DBF_TEXT(4,trace,"freeread");
+ if (privptr->p_env->read_size < PAGE_SIZE) {
+ if (privptr->p_buff_read != NULL) {
+ free_pages((unsigned long)privptr->p_buff_read,
+ (int)pages_to_order_of_mag(privptr->p_buff_read_num));
+ }
+ }
+ else {
+ p_buf=privptr->p_read_active_first;
+ while (p_buf!=NULL) {
+ free_pages((unsigned long)p_buf->p_buffer,
+ (int)pages_to_order_of_mag(
+ privptr->p_buff_pages_perread ));
+ p_buf=p_buf->next;
+ }
+ }
+ CLAW_DBF_TEXT(4,trace,"freewrit");
+ if (privptr->p_env->write_size < PAGE_SIZE ) {
+ free_pages((unsigned long)privptr->p_buff_write,
+ (int)pages_to_order_of_mag(privptr->p_buff_write_num));
+ }
+ else {
+ p_buf=privptr->p_write_active_first;
+ while (p_buf!=NULL) {
+ free_pages((unsigned long)p_buf->p_buffer,
+ (int)pages_to_order_of_mag(
+ privptr->p_buff_pages_perwrite ));
+ p_buf=p_buf->next;
+ }
+ }
+ CLAW_DBF_TEXT(4,trace,"clearptr");
+ privptr->buffs_alloc = 0;
+ privptr->p_buff_ccw=NULL;
+ privptr->p_buff_read=NULL;
+ privptr->p_buff_write=NULL;
+ privptr->system_validate_comp=0;
+ privptr->release_pend=0;
+ /* Remove any writes that were pending and reset all reads */
+ p_this_ccw=privptr->p_read_active_first;
+ while (p_this_ccw!=NULL) {
+ p_this_ccw->header.length=0xffff;
+ p_this_ccw->header.opcode=0xff;
+ p_this_ccw->header.flag=0x00;
+ p_this_ccw=p_this_ccw->next;
+ }
+
+ while (privptr->p_write_active_first!=NULL) {
+ p_this_ccw=privptr->p_write_active_first;
+ p_this_ccw->header.flag=CLAW_PENDING;
+ privptr->p_write_active_first=p_this_ccw->next;
+ p_this_ccw->next=privptr->p_write_free_chain;
+ privptr->p_write_free_chain=p_this_ccw;
+ ++privptr->write_free_count;
+ }
+ privptr->p_write_active_last=NULL;
+ privptr->mtc_logical_link = -1;
+ privptr->mtc_skipping = 1;
+ privptr->mtc_offset=0;
+
+ if (((privptr->channel[READ].last_dstat |
+ privptr->channel[WRITE].last_dstat) &
+ ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
+ printk(KERN_WARNING "%s: channel problems during close - "
+ "read: %02x - write: %02x\n",
+ dev->name,
+ privptr->channel[READ].last_dstat,
+ privptr->channel[WRITE].last_dstat);
+ CLAW_DBF_TEXT(2,trace,"badclose");
+ }
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"rlsexit");
+ return 0;
+} /* end of claw_release */
+
+
+
+/*-------------------------------------------------------------------*
+* claw_write_retry *
+* *
+*--------------------------------------------------------------------*/
+
+static void
+claw_write_retry ( struct chbk *p_ch )
+{
+
+ struct net_device *dev=p_ch->ndev;
+
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__);
+ printk(KERN_INFO "claw: variable p_ch =\n");
+ dumpit((char *) p_ch, sizeof(struct chbk));
+#endif
+ CLAW_DBF_TEXT(4,trace,"w_retry");
+ if (p_ch->claw_state == CLAW_STOP) {
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ return;
+ }
+#ifdef DEBUGMSG
+ printk( KERN_INFO "%s:%s state-%02x\n" ,
+ dev->name,
+ __FUNCTION__,
+ p_ch->claw_state);
+#endif
+ claw_strt_out_IO( dev );
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"rtry_xit");
+ return;
+} /* end of claw_write_retry */
+
+
+/*-------------------------------------------------------------------*
+* claw_write_next *
+* *
+*--------------------------------------------------------------------*/
+
+static void
+claw_write_next ( struct chbk * p_ch )
+{
+
+ struct net_device *dev;
+ struct claw_privbk *privptr=NULL;
+ struct sk_buff *pk_skb;
+ int rc;
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter \n",p_ch->ndev->name,__FUNCTION__);
+ printk(KERN_INFO "%s: variable p_ch =\n",p_ch->ndev->name);
+ dumpit((char *) p_ch, sizeof(struct chbk));
+#endif
+ CLAW_DBF_TEXT(4,trace,"claw_wrt");
+ if (p_ch->claw_state == CLAW_STOP)
+ return;
+ dev = (struct net_device *) p_ch->ndev;
+ privptr = (struct claw_privbk *) dev->priv;
+ claw_free_wrt_buf( dev );
+ if ((privptr->write_free_count > 0) &&
+ (skb_queue_len(&p_ch->collect_queue) > 0)) {
+ pk_skb = claw_pack_skb(privptr);
+ while (pk_skb != NULL) {
+ rc = claw_hw_tx( pk_skb, dev,1);
+ if (privptr->write_free_count > 0) {
+ pk_skb = claw_pack_skb(privptr);
+ } else
+ pk_skb = NULL;
+ }
+ }
+ if (privptr->p_write_active_first!=NULL) {
+ claw_strt_out_IO(dev);
+ }
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ return;
+} /* end of claw_write_next */
+
+/*-------------------------------------------------------------------*
+* *
+* claw_timer *
+*--------------------------------------------------------------------*/
+
+static void
+claw_timer ( struct chbk * p_ch )
+{
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Entry\n",p_ch->ndev->name,__FUNCTION__);
+ printk(KERN_INFO "%s: variable p_ch =\n",p_ch->ndev->name);
+ dumpit((char *) p_ch, sizeof(struct chbk));
+#endif
+ CLAW_DBF_TEXT(4,trace,"timer");
+ p_ch->flag |= CLAW_TIMER;
+ wake_up(&p_ch->wait);
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ p_ch->ndev->name,__FUNCTION__,__LINE__);
+#endif
+ return;
+} /* end of claw_timer */
+
+
+/*
+*
+* functions
+*/
+
+
+/*-------------------------------------------------------------------*
+* *
+* pages_to_order_of_mag *
+* *
+* takes a number of pages from 1 to 512 and returns the *
+* log(num_pages)/log(2) get_free_pages() needs a base 2 order *
+* of magnitude get_free_pages() has an upper order of 9 *
+*--------------------------------------------------------------------*/
+
+static int inline
+pages_to_order_of_mag(int num_of_pages)
+{
+ int order_of_mag=1; /* assume 2 pages */
+ int nump=2;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s Enter pages = %d \n",__FUNCTION__,num_of_pages);
+#endif
+ CLAW_DBF_TEXT_(5,trace,"pages%d",num_of_pages);
+ if (num_of_pages == 1) {return 0; } /* magnitude of 0 = 1 page */
+ /* 512 pages = 2Meg on 4k page systems */
+ if (num_of_pages >= 512) {return 9; }
+ /* we have two or more pages order is at least 1 */
+ for (nump=2 ;nump <= 512;nump*=2) {
+ if (num_of_pages <= nump)
+ break;
+ order_of_mag +=1;
+ }
+ if (order_of_mag > 9) { order_of_mag = 9; } /* I know it's paranoid */
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s Exit on line %d, order = %d\n",
+ __FUNCTION__,__LINE__, order_of_mag);
+#endif
+ CLAW_DBF_TEXT_(5,trace,"mag%d",order_of_mag);
+ return order_of_mag;
+}
+
+/*-------------------------------------------------------------------*
+* *
+* add_claw_reads *
+* *
+*--------------------------------------------------------------------*/
+static int
+add_claw_reads(struct net_device *dev, struct ccwbk* p_first,
+ struct ccwbk* p_last)
+{
+ struct claw_privbk *privptr;
+ struct ccw1 temp_ccw;
+ struct endccw * p_end;
+#ifdef IOTRACE
+ struct ccwbk* p_buf;
+#endif
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__);
+#endif
+#ifdef DEBUGMSG
+ printk(KERN_INFO "dev\n");
+ dumpit((char *) dev, sizeof(struct net_device));
+ printk(KERN_INFO "p_first\n");
+ dumpit((char *) p_first, sizeof(struct ccwbk));
+ printk(KERN_INFO "p_last\n");
+ dumpit((char *) p_last, sizeof(struct ccwbk));
+#endif
+ CLAW_DBF_TEXT(4,trace,"addreads");
+ privptr = dev->priv;
+ p_end = privptr->p_end_ccw;
+
+ /* first CCW and last CCW contains a new set of read channel programs
+ * to apend the running channel programs
+ */
+ if ( p_first==NULL) {
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"addexit");
+ return 0;
+ }
+
+ /* set up ending CCW sequence for this segment */
+ if (p_end->read1) {
+ p_end->read1=0x00; /* second ending CCW is now active */
+ /* reset ending CCWs and setup TIC CCWs */
+ p_end->read2_nop2.cmd_code = CCW_CLAW_CMD_READFF;
+ p_end->read2_nop2.flags = CCW_FLAG_SLI | CCW_FLAG_SKIP;
+ p_last->r_TIC_1.cda =(__u32)__pa(&p_end->read2_nop1);
+ p_last->r_TIC_2.cda =(__u32)__pa(&p_end->read2_nop1);
+ p_end->read2_nop2.cda=0;
+ p_end->read2_nop2.count=1;
+ }
+ else {
+ p_end->read1=0x01; /* first ending CCW is now active */
+ /* reset ending CCWs and setup TIC CCWs */
+ p_end->read1_nop2.cmd_code = CCW_CLAW_CMD_READFF;
+ p_end->read1_nop2.flags = CCW_FLAG_SLI | CCW_FLAG_SKIP;
+ p_last->r_TIC_1.cda = (__u32)__pa(&p_end->read1_nop1);
+ p_last->r_TIC_2.cda = (__u32)__pa(&p_end->read1_nop1);
+ p_end->read1_nop2.cda=0;
+ p_end->read1_nop2.count=1;
+ }
+
+ if ( privptr-> p_read_active_first ==NULL ) {
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s:%s p_read_active_frist == NULL \n",
+ dev->name,__FUNCTION__);
+ printk(KERN_INFO "%s:%s Read active first/last changed \n",
+ dev->name,__FUNCTION__);
+#endif
+ privptr-> p_read_active_first= p_first; /* set new first */
+ privptr-> p_read_active_last = p_last; /* set new last */
+ }
+ else {
+
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s:%s Read in progress \n",
+ dev->name,__FUNCTION__);
+#endif
+ /* set up TIC ccw */
+ temp_ccw.cda= (__u32)__pa(&p_first->read);
+ temp_ccw.count=0;
+ temp_ccw.flags=0;
+ temp_ccw.cmd_code = CCW_CLAW_CMD_TIC;
+
+
+ if (p_end->read1) {
+
+ /* first set of CCW's is chained to the new read */
+ /* chain, so the second set is chained to the active chain. */
+ /* Therefore modify the second set to point to the new */
+ /* read chain set up TIC CCWs */
+ /* make sure we update the CCW so channel doesn't fetch it */
+ /* when it's only half done */
+ memcpy( &p_end->read2_nop2, &temp_ccw ,
+ sizeof(struct ccw1));
+ privptr->p_read_active_last->r_TIC_1.cda=
+ (__u32)__pa(&p_first->read);
+ privptr->p_read_active_last->r_TIC_2.cda=
+ (__u32)__pa(&p_first->read);
+ }
+ else {
+ /* make sure we update the CCW so channel doesn't */
+ /* fetch it when it is only half done */
+ memcpy( &p_end->read1_nop2, &temp_ccw ,
+ sizeof(struct ccw1));
+ privptr->p_read_active_last->r_TIC_1.cda=
+ (__u32)__pa(&p_first->read);
+ privptr->p_read_active_last->r_TIC_2.cda=
+ (__u32)__pa(&p_first->read);
+ }
+ /* chain in new set of blocks */
+ privptr->p_read_active_last->next = p_first;
+ privptr->p_read_active_last=p_last;
+ } /* end of if ( privptr-> p_read_active_first ==NULL) */
+#ifdef IOTRACE
+ printk(KERN_INFO "%s:%s dump p_last CCW BK \n",dev->name,__FUNCTION__);
+ dumpit((char *)p_last, sizeof(struct ccwbk));
+ printk(KERN_INFO "%s:%s dump p_end CCW BK \n",dev->name,__FUNCTION__);
+ dumpit((char *)p_end, sizeof(struct endccw));
+
+ printk(KERN_INFO "%s:%s dump p_first CCW BK \n",dev->name,__FUNCTION__);
+ dumpit((char *)p_first, sizeof(struct ccwbk));
+ printk(KERN_INFO "%s:%s Dump Active CCW chain \n",
+ dev->name,__FUNCTION__);
+ p_buf=privptr->p_read_active_first;
+ while (p_buf!=NULL) {
+ dumpit((char *)p_buf, sizeof(struct ccwbk));
+ p_buf=p_buf->next;
+ }
+#endif
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"addexit");
+ return 0;
+} /* end of add_claw_reads */
+
+/*-------------------------------------------------------------------*
+ * ccw_check_return_code *
+ * *
+ *-------------------------------------------------------------------*/
+
+static void inline
+ccw_check_return_code(struct ccw_device *cdev, int return_code)
+{
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s() > enter \n",
+ cdev->dev.bus_id,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"ccwret");
+#ifdef DEBUGMSG
+ printk(KERN_INFO "variable cdev =\n");
+ dumpit((char *) cdev, sizeof(struct ccw_device));
+ printk(KERN_INFO "variable return_code = %d\n",return_code);
+#endif
+ if (return_code != 0) {
+ switch (return_code) {
+ case -EBUSY:
+ printk(KERN_INFO "%s: Busy !\n",
+ cdev->dev.bus_id);
+ break;
+ case -ENODEV:
+ printk(KERN_EMERG "%s: Missing device called "
+ "for IO ENODEV\n", cdev->dev.bus_id);
+ break;
+ case -EIO:
+ printk(KERN_EMERG "%s: Status pending... EIO \n",
+ cdev->dev.bus_id);
+ break;
+ case -EINVAL:
+ printk(KERN_EMERG "%s: Invalid Dev State EINVAL \n",
+ cdev->dev.bus_id);
+ break;
+ default:
+ printk(KERN_EMERG "%s: Unknown error in "
+ "Do_IO %d\n",cdev->dev.bus_id, return_code);
+ }
+ }
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s() > exit on line %d\n",
+ cdev->dev.bus_id,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"ccwret");
+} /* end of ccw_check_return_code */
+
+/*-------------------------------------------------------------------*
+* ccw_check_unit_check *
+*--------------------------------------------------------------------*/
+
+static void inline
+ccw_check_unit_check(struct chbk * p_ch, unsigned char sense )
+{
+ struct net_device *dev = p_ch->ndev;
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s() > enter\n",dev->name,__FUNCTION__);
+#endif
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: variable dev =\n",dev->name);
+ dumpit((char *)dev, sizeof(struct net_device));
+ printk(KERN_INFO "%s: variable sense =\n",dev->name);
+ dumpit((char *)&sense, 2);
+#endif
+ CLAW_DBF_TEXT(4,trace,"unitchek");
+
+ printk(KERN_INFO "%s: Unit Check with sense byte:0x%04x\n",
+ dev->name, sense);
+
+ if (sense & 0x40) {
+ if (sense & 0x01) {
+ printk(KERN_WARNING "%s: Interface disconnect or "
+ "Selective reset "
+ "occurred (remote side)\n", dev->name);
+ }
+ else {
+ printk(KERN_WARNING "%s: System reset occured"
+ " (remote side)\n", dev->name);
+ }
+ }
+ else if (sense & 0x20) {
+ if (sense & 0x04) {
+ printk(KERN_WARNING "%s: Data-streaming "
+ "timeout)\n", dev->name);
+ }
+ else {
+ printk(KERN_WARNING "%s: Data-transfer parity"
+ " error\n", dev->name);
+ }
+ }
+ else if (sense & 0x10) {
+ if (sense & 0x20) {
+ printk(KERN_WARNING "%s: Hardware malfunction "
+ "(remote side)\n", dev->name);
+ }
+ else {
+ printk(KERN_WARNING "%s: read-data parity error "
+ "(remote side)\n", dev->name);
+ }
+ }
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s() exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+} /* end of ccw_check_unit_check */
+
+
+
+/*-------------------------------------------------------------------*
+* Dump buffer format *
+* *
+*--------------------------------------------------------------------*/
+#ifdef DEBUG
+static void
+dumpit(char* buf, int len)
+{
+
+ __u32 ct, sw, rm, dup;
+ char *ptr, *rptr;
+ char tbuf[82], tdup[82];
+#if (CONFIG_ARCH_S390X)
+ char addr[22];
+#else
+ char addr[12];
+#endif
+ char boff[12];
+ char bhex[82], duphex[82];
+ char basc[40];
+
+ sw = 0;
+ rptr =ptr=buf;
+ rm = 16;
+ duphex[0] = 0x00;
+ dup = 0;
+ for ( ct=0; ct < len; ct++, ptr++, rptr++ ) {
+ if (sw == 0) {
+#if (CONFIG_ARCH_S390X)
+ sprintf(addr, "%16.16lX",(unsigned long)rptr);
+#else
+ sprintf(addr, "%8.8X",(__u32)rptr);
+#endif
+ sprintf(boff, "%4.4X", (__u32)ct);
+ bhex[0] = '\0';
+ basc[0] = '\0';
+ }
+ if ((sw == 4) || (sw == 12)) {
+ strcat(bhex, " ");
+ }
+ if (sw == 8) {
+ strcat(bhex, " ");
+ }
+#if (CONFIG_ARCH_S390X)
+ sprintf(tbuf,"%2.2lX", (unsigned long)*ptr);
+#else
+ sprintf(tbuf,"%2.2X", (__u32)*ptr);
+#endif
+ tbuf[2] = '\0';
+ strcat(bhex, tbuf);
+ if ((0!=isprint(*ptr)) && (*ptr >= 0x20)) {
+ basc[sw] = *ptr;
+ }
+ else {
+ basc[sw] = '.';
+ }
+ basc[sw+1] = '\0';
+ sw++;
+ rm--;
+ if (sw==16) {
+ if ((strcmp(duphex, bhex)) !=0) {
+ if (dup !=0) {
+ sprintf(tdup,"Duplicate as above to"
+ " %s", addr);
+ printk( KERN_INFO " "
+ " --- %s ---\n",tdup);
+ }
+ printk( KERN_INFO " %s (+%s) : %s [%s]\n",
+ addr, boff, bhex, basc);
+ dup = 0;
+ strcpy(duphex, bhex);
+ }
+ else {
+ dup++;
+ }
+ sw = 0;
+ rm = 16;
+ }
+ } /* endfor */
+
+ if (sw != 0) {
+ for ( ; rm > 0; rm--, sw++ ) {
+ if ((sw==4) || (sw==12)) strcat(bhex, " ");
+ if (sw==8) strcat(bhex, " ");
+ strcat(bhex, " ");
+ strcat(basc, " ");
+ }
+ if (dup !=0) {
+ sprintf(tdup,"Duplicate as above to %s", addr);
+ printk( KERN_INFO " --- %s ---\n",
+ tdup);
+ }
+ printk( KERN_INFO " %s (+%s) : %s [%s]\n",
+ addr, boff, bhex, basc);
+ }
+ else {
+ if (dup >=1) {
+ sprintf(tdup,"Duplicate as above to %s", addr);
+ printk( KERN_INFO " --- %s ---\n",
+ tdup);
+ }
+ if (dup !=0) {
+ printk( KERN_INFO " %s (+%s) : %s [%s]\n",
+ addr, boff, bhex, basc);
+ }
+ }
+ return;
+
+} /* end of dumpit */
+#endif
+
+/*-------------------------------------------------------------------*
+* find_link *
+*--------------------------------------------------------------------*/
+static int
+find_link(struct net_device *dev, char *host_name, char *ws_name )
+{
+ struct claw_privbk *privptr;
+ struct claw_env *p_env;
+ int rc=0;
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s > enter \n",dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(2,setup,"findlink");
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: variable dev = \n",dev->name);
+ dumpit((char *) dev, sizeof(struct net_device));
+ printk(KERN_INFO "%s: variable host_name = %s\n",dev->name, host_name);
+ printk(KERN_INFO "%s: variable ws_name = %s\n",dev->name, ws_name);
+#endif
+ privptr=dev->priv;
+ p_env=privptr->p_env;
+ switch (p_env->packing)
+ {
+ case PACKING_ASK:
+ if ((memcmp(WS_APPL_NAME_PACKED, host_name, 8)!=0) ||
+ (memcmp(WS_APPL_NAME_PACKED, ws_name, 8)!=0 ))
+ rc = EINVAL;
+ break;
+ case DO_PACKED:
+ case PACK_SEND:
+ if ((memcmp(WS_APPL_NAME_IP_NAME, host_name, 8)!=0) ||
+ (memcmp(WS_APPL_NAME_IP_NAME, ws_name, 8)!=0 ))
+ rc = EINVAL;
+ break;
+ default:
+ if ((memcmp(HOST_APPL_NAME, host_name, 8)!=0) ||
+ (memcmp(p_env->api_type , ws_name, 8)!=0))
+ rc = EINVAL;
+ break;
+ }
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ return 0;
+} /* end of find_link */
+
+/*-------------------------------------------------------------------*
+ * claw_hw_tx *
+ * *
+ * *
+ *-------------------------------------------------------------------*/
+
+static int
+claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid)
+{
+ int rc=0;
+ struct claw_privbk *privptr;
+ struct ccwbk *p_this_ccw;
+ struct ccwbk *p_first_ccw;
+ struct ccwbk *p_last_ccw;
+ __u32 numBuffers;
+ signed long len_of_data;
+ unsigned long bytesInThisBuffer;
+ unsigned char *pDataAddress;
+ struct endccw *pEnd;
+ struct ccw1 tempCCW;
+ struct chbk *p_ch;
+ struct claw_env *p_env;
+ int lock;
+ struct clawph *pk_head;
+ struct chbk *ch;
+#ifdef IOTRACE
+ struct ccwbk *p_buf;
+#endif
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s() > enter\n",dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"hw_tx");
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: variable dev skb =\n",dev->name);
+ dumpit((char *) skb, sizeof(struct sk_buff));
+ printk(KERN_INFO "%s: variable dev =\n",dev->name);
+ dumpit((char *) dev, sizeof(struct net_device));
+ printk(KERN_INFO "%s: variable linkid = %ld\n",dev->name,linkid);
+#endif
+ privptr = (struct claw_privbk *) (dev->priv);
+ p_ch=(struct chbk *)&privptr->channel[WRITE];
+ p_env =privptr->p_env;
+#ifdef IOTRACE
+ printk(KERN_INFO "%s: %s() dump sk_buff \n",dev->name,__FUNCTION__);
+ dumpit((char *)skb ,sizeof(struct sk_buff));
+#endif
+ claw_free_wrt_buf(dev); /* Clean up free chain if posible */
+ /* scan the write queue to free any completed write packets */
+ p_first_ccw=NULL;
+ p_last_ccw=NULL;
+ if ((p_env->packing >= PACK_SEND) &&
+ (skb->cb[1] != 'P')) {
+ skb_push(skb,sizeof(struct clawph));
+ pk_head=(struct clawph *)skb->data;
+ pk_head->len=skb->len-sizeof(struct clawph);
+ if (pk_head->len%4) {
+ pk_head->len+= 4-(pk_head->len%4);
+ skb_pad(skb,4-(pk_head->len%4));
+ skb_put(skb,4-(pk_head->len%4));
+ }
+ if (p_env->packing == DO_PACKED)
+ pk_head->link_num = linkid;
+ else
+ pk_head->link_num = 0;
+ pk_head->flag = 0x00;
+ skb_pad(skb,4);
+ skb->cb[1] = 'P';
+ }
+ if (linkid == 0) {
+ if (claw_check_busy(dev)) {
+ if (privptr->write_free_count!=0) {
+ claw_clear_busy(dev);
+ }
+ else {
+ claw_strt_out_IO(dev );
+ claw_free_wrt_buf( dev );
+ if (privptr->write_free_count==0) {
+#ifdef IOTRACE
+ printk(KERN_INFO "%s: "
+ "(claw_check_busy) no free write "
+ "buffers\n", dev->name);
+#endif
+ ch = &privptr->channel[WRITE];
+ atomic_inc(&skb->users);
+ skb_queue_tail(&ch->collect_queue, skb);
+ goto Done;
+ }
+ else {
+ claw_clear_busy(dev);
+ }
+ }
+ }
+ /* tx lock */
+ if (claw_test_and_setbit_busy(TB_TX,dev)) { /* set to busy */
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: busy (claw_test_and_setbit_"
+ "busy)\n", dev->name);
+#endif
+ ch = &privptr->channel[WRITE];
+ atomic_inc(&skb->users);
+ skb_queue_tail(&ch->collect_queue, skb);
+ claw_strt_out_IO(dev );
+ rc=-EBUSY;
+ goto Done2;
+ }
+ }
+ /* See how many write buffers are required to hold this data */
+ numBuffers= ( skb->len + privptr->p_env->write_size - 1) /
+ ( privptr->p_env->write_size);
+
+ /* If that number of buffers isn't available, give up for now */
+ if (privptr->write_free_count < numBuffers ||
+ privptr->p_write_free_chain == NULL ) {
+
+ claw_setbit_busy(TB_NOBUFFER,dev);
+
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: busy (claw_setbit_busy"
+ "(TB_NOBUFFER))\n", dev->name);
+ printk(KERN_INFO " free_count: %d, numBuffers : %d\n",
+ (int)privptr->write_free_count,(int) numBuffers );
+#endif
+ ch = &privptr->channel[WRITE];
+ atomic_inc(&skb->users);
+ skb_queue_tail(&ch->collect_queue, skb);
+ CLAW_DBF_TEXT(2,trace,"clawbusy");
+ goto Done2;
+ }
+ pDataAddress=skb->data;
+ len_of_data=skb->len;
+
+ while (len_of_data > 0) {
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s() length-of-data is %ld \n",
+ dev->name ,__FUNCTION__,len_of_data);
+ dumpit((char *)pDataAddress ,64);
+#endif
+ p_this_ccw=privptr->p_write_free_chain; /* get a block */
+ if (p_this_ccw == NULL) { /* lost the race */
+ ch = &privptr->channel[WRITE];
+ atomic_inc(&skb->users);
+ skb_queue_tail(&ch->collect_queue, skb);
+ goto Done2;
+ }
+ privptr->p_write_free_chain=p_this_ccw->next;
+ p_this_ccw->next=NULL;
+ --privptr->write_free_count; /* -1 */
+ bytesInThisBuffer=len_of_data;
+ memcpy( p_this_ccw->p_buffer,pDataAddress, bytesInThisBuffer);
+ len_of_data-=bytesInThisBuffer;
+ pDataAddress+=(unsigned long)bytesInThisBuffer;
+ /* setup write CCW */
+ p_this_ccw->write.cmd_code = (linkid * 8) +1;
+ if (len_of_data>0) {
+ p_this_ccw->write.cmd_code+=MORE_to_COME_FLAG;
+ }
+ p_this_ccw->write.count=bytesInThisBuffer;
+ /* now add to end of this chain */
+ if (p_first_ccw==NULL) {
+ p_first_ccw=p_this_ccw;
+ }
+ if (p_last_ccw!=NULL) {
+ p_last_ccw->next=p_this_ccw;
+ /* set up TIC ccws */
+ p_last_ccw->w_TIC_1.cda=
+ (__u32)__pa(&p_this_ccw->write);
+ }
+ p_last_ccw=p_this_ccw; /* save new last block */
+#ifdef IOTRACE
+ printk(KERN_INFO "%s: %s() > CCW and Buffer %ld bytes long \n",
+ dev->name,__FUNCTION__,bytesInThisBuffer);
+ dumpit((char *)p_this_ccw, sizeof(struct ccwbk));
+ dumpit((char *)p_this_ccw->p_buffer, 64);
+#endif
+ }
+
+ /* FirstCCW and LastCCW now contain a new set of write channel
+ * programs to append to the running channel program
+ */
+
+ if (p_first_ccw!=NULL) {
+ /* setup ending ccw sequence for this segment */
+ pEnd=privptr->p_end_ccw;
+ if (pEnd->write1) {
+ pEnd->write1=0x00; /* second end ccw is now active */
+ /* set up Tic CCWs */
+ p_last_ccw->w_TIC_1.cda=
+ (__u32)__pa(&pEnd->write2_nop1);
+ pEnd->write2_nop2.cmd_code = CCW_CLAW_CMD_READFF;
+ pEnd->write2_nop2.flags =
+ CCW_FLAG_SLI | CCW_FLAG_SKIP;
+ pEnd->write2_nop2.cda=0;
+ pEnd->write2_nop2.count=1;
+ }
+ else { /* end of if (pEnd->write1)*/
+ pEnd->write1=0x01; /* first end ccw is now active */
+ /* set up Tic CCWs */
+ p_last_ccw->w_TIC_1.cda=
+ (__u32)__pa(&pEnd->write1_nop1);
+ pEnd->write1_nop2.cmd_code = CCW_CLAW_CMD_READFF;
+ pEnd->write1_nop2.flags =
+ CCW_FLAG_SLI | CCW_FLAG_SKIP;
+ pEnd->write1_nop2.cda=0;
+ pEnd->write1_nop2.count=1;
+ } /* end if if (pEnd->write1) */
+
+
+ if (privptr->p_write_active_first==NULL ) {
+ privptr->p_write_active_first=p_first_ccw;
+ privptr->p_write_active_last=p_last_ccw;
+ }
+ else {
+
+ /* set up Tic CCWs */
+
+ tempCCW.cda=(__u32)__pa(&p_first_ccw->write);
+ tempCCW.count=0;
+ tempCCW.flags=0;
+ tempCCW.cmd_code=CCW_CLAW_CMD_TIC;
+
+ if (pEnd->write1) {
+
+ /*
+ * first set of ending CCW's is chained to the new write
+ * chain, so the second set is chained to the active chain
+ * Therefore modify the second set to point the new write chain.
+ * make sure we update the CCW atomically
+ * so channel does not fetch it when it's only half done
+ */
+ memcpy( &pEnd->write2_nop2, &tempCCW ,
+ sizeof(struct ccw1));
+ privptr->p_write_active_last->w_TIC_1.cda=
+ (__u32)__pa(&p_first_ccw->write);
+ }
+ else {
+
+ /*make sure we update the CCW atomically
+ *so channel does not fetch it when it's only half done
+ */
+ memcpy(&pEnd->write1_nop2, &tempCCW ,
+ sizeof(struct ccw1));
+ privptr->p_write_active_last->w_TIC_1.cda=
+ (__u32)__pa(&p_first_ccw->write);
+
+ } /* end if if (pEnd->write1) */
+
+ privptr->p_write_active_last->next=p_first_ccw;
+ privptr->p_write_active_last=p_last_ccw;
+ }
+
+ } /* endif (p_first_ccw!=NULL) */
+
+
+#ifdef IOTRACE
+ printk(KERN_INFO "%s: %s() > Dump Active CCW chain \n",
+ dev->name,__FUNCTION__);
+ p_buf=privptr->p_write_active_first;
+ while (p_buf!=NULL) {
+ dumpit((char *)p_buf, sizeof(struct ccwbk));
+ p_buf=p_buf->next;
+ }
+ p_buf=(struct ccwbk*)privptr->p_end_ccw;
+ dumpit((char *)p_buf, sizeof(struct endccw));
+#endif
+ dev_kfree_skb(skb);
+ if (linkid==0) {
+ lock=LOCK_NO;
+ }
+ else {
+ lock=LOCK_YES;
+ }
+ claw_strt_out_IO(dev );
+ /* if write free count is zero , set NOBUFFER */
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s() > free_count is %d\n",
+ dev->name,__FUNCTION__,
+ (int) privptr->write_free_count );
+#endif
+ if (privptr->write_free_count==0) {
+ claw_setbit_busy(TB_NOBUFFER,dev);
+ }
+Done2:
+ claw_clearbit_busy(TB_TX,dev);
+Done:
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s() > exit on line %d, rc = %d \n",
+ dev->name,__FUNCTION__,__LINE__, rc);
+#endif
+ return(rc);
+} /* end of claw_hw_tx */
+
+/*-------------------------------------------------------------------*
+* *
+* init_ccw_bk *
+* *
+*--------------------------------------------------------------------*/
+
+static int
+init_ccw_bk(struct net_device *dev)
+{
+
+ __u32 ccw_blocks_required;
+ __u32 ccw_blocks_perpage;
+ __u32 ccw_pages_required;
+ __u32 claw_reads_perpage=1;
+ __u32 claw_read_pages;
+ __u32 claw_writes_perpage=1;
+ __u32 claw_write_pages;
+ void *p_buff=NULL;
+ struct ccwbk*p_free_chain;
+ struct ccwbk*p_buf;
+ struct ccwbk*p_last_CCWB;
+ struct ccwbk*p_first_CCWB;
+ struct endccw *p_endccw=NULL;
+ addr_t real_address;
+ struct claw_privbk *privptr=dev->priv;
+ struct clawh *pClawH=NULL;
+ addr_t real_TIC_address;
+ int i,j;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s() enter \n",dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"init_ccw");
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: variable dev =\n",dev->name);
+ dumpit((char *) dev, sizeof(struct net_device));
+#endif
+
+ /* initialize statistics field */
+ privptr->active_link_ID=0;
+ /* initialize ccwbk pointers */
+ privptr->p_write_free_chain=NULL; /* pointer to free ccw chain*/
+ privptr->p_write_active_first=NULL; /* pointer to the first write ccw*/
+ privptr->p_write_active_last=NULL; /* pointer to the last write ccw*/
+ privptr->p_read_active_first=NULL; /* pointer to the first read ccw*/
+ privptr->p_read_active_last=NULL; /* pointer to the last read ccw */
+ privptr->p_end_ccw=NULL; /* pointer to ending ccw */
+ privptr->p_claw_signal_blk=NULL; /* pointer to signal block */
+ privptr->buffs_alloc = 0;
+ memset(&privptr->end_ccw, 0x00, sizeof(struct endccw));
+ memset(&privptr->ctl_bk, 0x00, sizeof(struct clawctl));
+ /* initialize free write ccwbk counter */
+ privptr->write_free_count=0; /* number of free bufs on write chain */
+ p_last_CCWB = NULL;
+ p_first_CCWB= NULL;
+ /*
+ * We need 1 CCW block for each read buffer, 1 for each
+ * write buffer, plus 1 for ClawSignalBlock
+ */
+ ccw_blocks_required =
+ privptr->p_env->read_buffers+privptr->p_env->write_buffers+1;
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s() "
+ "ccw_blocks_required=%d\n",
+ dev->name,__FUNCTION__,
+ ccw_blocks_required);
+ printk(KERN_INFO "%s: %s() "
+ "PAGE_SIZE=0x%x\n",
+ dev->name,__FUNCTION__,
+ (unsigned int)PAGE_SIZE);
+ printk(KERN_INFO "%s: %s() > "
+ "PAGE_MASK=0x%x\n",
+ dev->name,__FUNCTION__,
+ (unsigned int)PAGE_MASK);
+#endif
+ /*
+ * compute number of CCW blocks that will fit in a page
+ */
+ ccw_blocks_perpage= PAGE_SIZE / CCWBK_SIZE;
+ ccw_pages_required=
+ (ccw_blocks_required+ccw_blocks_perpage -1) /
+ ccw_blocks_perpage;
+
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s() > ccw_blocks_perpage=%d\n",
+ dev->name,__FUNCTION__,
+ ccw_blocks_perpage);
+ printk(KERN_INFO "%s: %s() > ccw_pages_required=%d\n",
+ dev->name,__FUNCTION__,
+ ccw_pages_required);
+#endif
+ /*
+ * read and write sizes are set by 2 constants in claw.h
+ * 4k and 32k. Unpacked values other than 4k are not going to
+ * provide good performance. With packing buffers support 32k
+ * buffers are used.
+ */
+ if (privptr->p_env->read_size < PAGE_SIZE) {
+ claw_reads_perpage= PAGE_SIZE / privptr->p_env->read_size;
+ claw_read_pages= (privptr->p_env->read_buffers +
+ claw_reads_perpage -1) / claw_reads_perpage;
+ }
+ else { /* > or equal */
+ privptr->p_buff_pages_perread=
+ (privptr->p_env->read_size + PAGE_SIZE - 1) / PAGE_SIZE;
+ claw_read_pages=
+ privptr->p_env->read_buffers * privptr->p_buff_pages_perread;
+ }
+ if (privptr->p_env->write_size < PAGE_SIZE) {
+ claw_writes_perpage=
+ PAGE_SIZE / privptr->p_env->write_size;
+ claw_write_pages=
+ (privptr->p_env->write_buffers + claw_writes_perpage -1) /
+ claw_writes_perpage;
+
+ }
+ else { /* > or equal */
+ privptr->p_buff_pages_perwrite=
+ (privptr->p_env->read_size + PAGE_SIZE - 1) / PAGE_SIZE;
+ claw_write_pages=
+ privptr->p_env->write_buffers * privptr->p_buff_pages_perwrite;
+ }
+#ifdef DEBUGMSG
+ if (privptr->p_env->read_size < PAGE_SIZE) {
+ printk(KERN_INFO "%s: %s() reads_perpage=%d\n",
+ dev->name,__FUNCTION__,
+ claw_reads_perpage);
+ }
+ else {
+ printk(KERN_INFO "%s: %s() pages_perread=%d\n",
+ dev->name,__FUNCTION__,
+ privptr->p_buff_pages_perread);
+ }
+ printk(KERN_INFO "%s: %s() read_pages=%d\n",
+ dev->name,__FUNCTION__,
+ claw_read_pages);
+ if (privptr->p_env->write_size < PAGE_SIZE) {
+ printk(KERN_INFO "%s: %s() writes_perpage=%d\n",
+ dev->name,__FUNCTION__,
+ claw_writes_perpage);
+ }
+ else {
+ printk(KERN_INFO "%s: %s() pages_perwrite=%d\n",
+ dev->name,__FUNCTION__,
+ privptr->p_buff_pages_perwrite);
+ }
+ printk(KERN_INFO "%s: %s() write_pages=%d\n",
+ dev->name,__FUNCTION__,
+ claw_write_pages);
+#endif
+
+
+ /*
+ * allocate ccw_pages_required
+ */
+ if (privptr->p_buff_ccw==NULL) {
+ privptr->p_buff_ccw=
+ (void *)__get_free_pages(__GFP_DMA,
+ (int)pages_to_order_of_mag(ccw_pages_required ));
+ if (privptr->p_buff_ccw==NULL) {
+ printk(KERN_INFO "%s: %s() "
+ "__get_free_pages for CCWs failed : "
+ "pages is %d\n",
+ dev->name,__FUNCTION__,
+ ccw_pages_required );
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s() > "
+ "exit on line %d, rc = ENOMEM\n",
+ dev->name,__FUNCTION__,
+ __LINE__);
+#endif
+ return -ENOMEM;
+ }
+ privptr->p_buff_ccw_num=ccw_pages_required;
+ }
+ memset(privptr->p_buff_ccw, 0x00,
+ privptr->p_buff_ccw_num * PAGE_SIZE);
+
+ /*
+ * obtain ending ccw block address
+ *
+ */
+ privptr->p_end_ccw = (struct endccw *)&privptr->end_ccw;
+ real_address = (__u32)__pa(privptr->p_end_ccw);
+ /* Initialize ending CCW block */
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s() begin initialize ending CCW blocks\n",
+ dev->name,__FUNCTION__);
+#endif
+
+ p_endccw=privptr->p_end_ccw;
+ p_endccw->real=real_address;
+ p_endccw->write1=0x00;
+ p_endccw->read1=0x00;
+
+ /* write1_nop1 */
+ p_endccw->write1_nop1.cmd_code = CCW_CLAW_CMD_NOP;
+ p_endccw->write1_nop1.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ p_endccw->write1_nop1.count = 1;
+ p_endccw->write1_nop1.cda = 0;
+
+ /* write1_nop2 */
+ p_endccw->write1_nop2.cmd_code = CCW_CLAW_CMD_READFF;
+ p_endccw->write1_nop2.flags = CCW_FLAG_SLI | CCW_FLAG_SKIP;
+ p_endccw->write1_nop2.count = 1;
+ p_endccw->write1_nop2.cda = 0;
+
+ /* write2_nop1 */
+ p_endccw->write2_nop1.cmd_code = CCW_CLAW_CMD_NOP;
+ p_endccw->write2_nop1.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ p_endccw->write2_nop1.count = 1;
+ p_endccw->write2_nop1.cda = 0;
+
+ /* write2_nop2 */
+ p_endccw->write2_nop2.cmd_code = CCW_CLAW_CMD_READFF;
+ p_endccw->write2_nop2.flags = CCW_FLAG_SLI | CCW_FLAG_SKIP;
+ p_endccw->write2_nop2.count = 1;
+ p_endccw->write2_nop2.cda = 0;
+
+ /* read1_nop1 */
+ p_endccw->read1_nop1.cmd_code = CCW_CLAW_CMD_NOP;
+ p_endccw->read1_nop1.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ p_endccw->read1_nop1.count = 1;
+ p_endccw->read1_nop1.cda = 0;
+
+ /* read1_nop2 */
+ p_endccw->read1_nop2.cmd_code = CCW_CLAW_CMD_READFF;
+ p_endccw->read1_nop2.flags = CCW_FLAG_SLI | CCW_FLAG_SKIP;
+ p_endccw->read1_nop2.count = 1;
+ p_endccw->read1_nop2.cda = 0;
+
+ /* read2_nop1 */
+ p_endccw->read2_nop1.cmd_code = CCW_CLAW_CMD_NOP;
+ p_endccw->read2_nop1.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ p_endccw->read2_nop1.count = 1;
+ p_endccw->read2_nop1.cda = 0;
+
+ /* read2_nop2 */
+ p_endccw->read2_nop2.cmd_code = CCW_CLAW_CMD_READFF;
+ p_endccw->read2_nop2.flags = CCW_FLAG_SLI | CCW_FLAG_SKIP;
+ p_endccw->read2_nop2.count = 1;
+ p_endccw->read2_nop2.cda = 0;
+
+#ifdef IOTRACE
+ printk(KERN_INFO "%s: %s() dump claw ending CCW BK \n",
+ dev->name,__FUNCTION__);
+ dumpit((char *)p_endccw, sizeof(struct endccw));
+#endif
+
+ /*
+ * Build a chain of CCWs
+ *
+ */
+
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s() Begin build a chain of CCW buffer \n",
+ dev->name,__FUNCTION__);
+#endif
+ p_buff=privptr->p_buff_ccw;
+
+ p_free_chain=NULL;
+ for (i=0 ; i < ccw_pages_required; i++ ) {
+ real_address = (__u32)__pa(p_buff);
+ p_buf=p_buff;
+ for (j=0 ; j < ccw_blocks_perpage ; j++) {
+ p_buf->next = p_free_chain;
+ p_free_chain = p_buf;
+ p_buf->real=(__u32)__pa(p_buf);
+ ++p_buf;
+ }
+ p_buff+=PAGE_SIZE;
+ }
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s() "
+ "End build a chain of CCW buffer \n",
+ dev->name,__FUNCTION__);
+ p_buf=p_free_chain;
+ while (p_buf!=NULL) {
+ dumpit((char *)p_buf, sizeof(struct ccwbk));
+ p_buf=p_buf->next;
+ }
+#endif
+
+ /*
+ * Initialize ClawSignalBlock
+ *
+ */
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s() "
+ "Begin initialize ClawSignalBlock \n",
+ dev->name,__FUNCTION__);
+#endif
+ if (privptr->p_claw_signal_blk==NULL) {
+ privptr->p_claw_signal_blk=p_free_chain;
+ p_free_chain=p_free_chain->next;
+ pClawH=(struct clawh *)privptr->p_claw_signal_blk;
+ pClawH->length=0xffff;
+ pClawH->opcode=0xff;
+ pClawH->flag=CLAW_BUSY;
+ }
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s() > End initialize "
+ "ClawSignalBlock\n",
+ dev->name,__FUNCTION__);
+ dumpit((char *)privptr->p_claw_signal_blk, sizeof(struct ccwbk));
+#endif
+
+ /*
+ * allocate write_pages_required and add to free chain
+ */
+ if (privptr->p_buff_write==NULL) {
+ if (privptr->p_env->write_size < PAGE_SIZE) {
+ privptr->p_buff_write=
+ (void *)__get_free_pages(__GFP_DMA,
+ (int)pages_to_order_of_mag(claw_write_pages ));
+ if (privptr->p_buff_write==NULL) {
+ printk(KERN_INFO "%s: %s() __get_free_pages for write"
+ " bufs failed : get is for %d pages\n",
+ dev->name,__FUNCTION__,claw_write_pages );
+ free_pages((unsigned long)privptr->p_buff_ccw,
+ (int)pages_to_order_of_mag(privptr->p_buff_ccw_num));
+ privptr->p_buff_ccw=NULL;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s() > exit on line %d,"
+ "rc = ENOMEM\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ return -ENOMEM;
+ }
+ /*
+ * Build CLAW write free chain
+ *
+ */
+
+ memset(privptr->p_buff_write, 0x00,
+ ccw_pages_required * PAGE_SIZE);
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s() Begin build claw write free "
+ "chain \n",dev->name,__FUNCTION__);
+#endif
+ privptr->p_write_free_chain=NULL;
+
+ p_buff=privptr->p_buff_write;
+
+ for (i=0 ; i< privptr->p_env->write_buffers ; i++) {
+ p_buf = p_free_chain; /* get a CCW */
+ p_free_chain = p_buf->next;
+ p_buf->next =privptr->p_write_free_chain;
+ privptr->p_write_free_chain = p_buf;
+ p_buf-> p_buffer = (struct clawbuf *)p_buff;
+ p_buf-> write.cda = (__u32)__pa(p_buff);
+ p_buf-> write.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ p_buf-> w_read_FF.cmd_code = CCW_CLAW_CMD_READFF;
+ p_buf-> w_read_FF.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ p_buf-> w_read_FF.count = 1;
+ p_buf-> w_read_FF.cda =
+ (__u32)__pa(&p_buf-> header.flag);
+ p_buf-> w_TIC_1.cmd_code = CCW_CLAW_CMD_TIC;
+ p_buf-> w_TIC_1.flags = 0;
+ p_buf-> w_TIC_1.count = 0;
+
+ if (((unsigned long)p_buff+privptr->p_env->write_size) >=
+ ((unsigned long)(p_buff+2*
+ (privptr->p_env->write_size) -1) & PAGE_MASK)) {
+ p_buff= p_buff+privptr->p_env->write_size;
+ }
+ }
+ }
+ else /* Buffers are => PAGE_SIZE. 1 buff per get_free_pages */
+ {
+ privptr->p_write_free_chain=NULL;
+ for (i = 0; i< privptr->p_env->write_buffers ; i++) {
+ p_buff=(void *)__get_free_pages(__GFP_DMA,
+ (int)pages_to_order_of_mag(
+ privptr->p_buff_pages_perwrite) );
+#ifdef IOTRACE
+ printk(KERN_INFO "%s:%s __get_free_pages "
+ "for writes buf: get for %d pages\n",
+ dev->name,__FUNCTION__,
+ privptr->p_buff_pages_perwrite);
+#endif
+ if (p_buff==NULL) {
+ printk(KERN_INFO "%s:%s __get_free_pages"
+ "for writes buf failed : get is for %d pages\n",
+ dev->name,
+ __FUNCTION__,
+ privptr->p_buff_pages_perwrite );
+ free_pages((unsigned long)privptr->p_buff_ccw,
+ (int)pages_to_order_of_mag(
+ privptr->p_buff_ccw_num));
+ privptr->p_buff_ccw=NULL;
+ p_buf=privptr->p_buff_write;
+ while (p_buf!=NULL) {
+ free_pages((unsigned long)
+ p_buf->p_buffer,
+ (int)pages_to_order_of_mag(
+ privptr->p_buff_pages_perwrite));
+ p_buf=p_buf->next;
+ }
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s exit on line %d, rc = ENOMEM\n",
+ dev->name,
+ __FUNCTION__,
+ __LINE__);
+#endif
+ return -ENOMEM;
+ } /* Error on get_pages */
+ memset(p_buff, 0x00, privptr->p_env->write_size );
+ p_buf = p_free_chain;
+ p_free_chain = p_buf->next;
+ p_buf->next = privptr->p_write_free_chain;
+ privptr->p_write_free_chain = p_buf;
+ privptr->p_buff_write = p_buf;
+ p_buf->p_buffer=(struct clawbuf *)p_buff;
+ p_buf-> write.cda = (__u32)__pa(p_buff);
+ p_buf-> write.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ p_buf-> w_read_FF.cmd_code = CCW_CLAW_CMD_READFF;
+ p_buf-> w_read_FF.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ p_buf-> w_read_FF.count = 1;
+ p_buf-> w_read_FF.cda =
+ (__u32)__pa(&p_buf-> header.flag);
+ p_buf-> w_TIC_1.cmd_code = CCW_CLAW_CMD_TIC;
+ p_buf-> w_TIC_1.flags = 0;
+ p_buf-> w_TIC_1.count = 0;
+ } /* for all write_buffers */
+
+ } /* else buffers are PAGE_SIZE or bigger */
+
+ }
+ privptr->p_buff_write_num=claw_write_pages;
+ privptr->write_free_count=privptr->p_env->write_buffers;
+
+
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s:%s End build claw write free chain \n",
+ dev->name,__FUNCTION__);
+ p_buf=privptr->p_write_free_chain;
+ while (p_buf!=NULL) {
+ dumpit((char *)p_buf, sizeof(struct ccwbk));
+ p_buf=p_buf->next;
+ }
+#endif
+ /*
+ * allocate read_pages_required and chain to free chain
+ */
+ if (privptr->p_buff_read==NULL) {
+ if (privptr->p_env->read_size < PAGE_SIZE) {
+ privptr->p_buff_read=
+ (void *)__get_free_pages(__GFP_DMA,
+ (int)pages_to_order_of_mag(claw_read_pages) );
+ if (privptr->p_buff_read==NULL) {
+ printk(KERN_INFO "%s: %s() "
+ "__get_free_pages for read buf failed : "
+ "get is for %d pages\n",
+ dev->name,__FUNCTION__,claw_read_pages );
+ free_pages((unsigned long)privptr->p_buff_ccw,
+ (int)pages_to_order_of_mag(
+ privptr->p_buff_ccw_num));
+ /* free the write pages size is < page size */
+ free_pages((unsigned long)privptr->p_buff_write,
+ (int)pages_to_order_of_mag(
+ privptr->p_buff_write_num));
+ privptr->p_buff_ccw=NULL;
+ privptr->p_buff_write=NULL;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s() > exit on line %d, rc ="
+ " ENOMEM\n",dev->name,__FUNCTION__,__LINE__);
+#endif
+ return -ENOMEM;
+ }
+ memset(privptr->p_buff_read, 0x00, claw_read_pages * PAGE_SIZE);
+ privptr->p_buff_read_num=claw_read_pages;
+ /*
+ * Build CLAW read free chain
+ *
+ */
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s() Begin build claw read free chain \n",
+ dev->name,__FUNCTION__);
+#endif
+ p_buff=privptr->p_buff_read;
+ for (i=0 ; i< privptr->p_env->read_buffers ; i++) {
+ p_buf = p_free_chain;
+ p_free_chain = p_buf->next;
+
+ if (p_last_CCWB==NULL) {
+ p_buf->next=NULL;
+ real_TIC_address=0;
+ p_last_CCWB=p_buf;
+ }
+ else {
+ p_buf->next=p_first_CCWB;
+ real_TIC_address=
+ (__u32)__pa(&p_first_CCWB -> read );
+ }
+
+ p_first_CCWB=p_buf;
+
+ p_buf->p_buffer=(struct clawbuf *)p_buff;
+ /* initialize read command */
+ p_buf-> read.cmd_code = CCW_CLAW_CMD_READ;
+ p_buf-> read.cda = (__u32)__pa(p_buff);
+ p_buf-> read.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ p_buf-> read.count = privptr->p_env->read_size;
+
+ /* initialize read_h command */
+ p_buf-> read_h.cmd_code = CCW_CLAW_CMD_READHEADER;
+ p_buf-> read_h.cda =
+ (__u32)__pa(&(p_buf->header));
+ p_buf-> read_h.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ p_buf-> read_h.count = sizeof(struct clawh);
+
+ /* initialize Signal command */
+ p_buf-> signal.cmd_code = CCW_CLAW_CMD_SIGNAL_SMOD;
+ p_buf-> signal.cda =
+ (__u32)__pa(&(pClawH->flag));
+ p_buf-> signal.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ p_buf-> signal.count = 1;
+
+ /* initialize r_TIC_1 command */
+ p_buf-> r_TIC_1.cmd_code = CCW_CLAW_CMD_TIC;
+ p_buf-> r_TIC_1.cda = (__u32)real_TIC_address;
+ p_buf-> r_TIC_1.flags = 0;
+ p_buf-> r_TIC_1.count = 0;
+
+ /* initialize r_read_FF command */
+ p_buf-> r_read_FF.cmd_code = CCW_CLAW_CMD_READFF;
+ p_buf-> r_read_FF.cda =
+ (__u32)__pa(&(pClawH->flag));
+ p_buf-> r_read_FF.flags =
+ CCW_FLAG_SLI | CCW_FLAG_CC | CCW_FLAG_PCI;
+ p_buf-> r_read_FF.count = 1;
+
+ /* initialize r_TIC_2 */
+ memcpy(&p_buf->r_TIC_2,
+ &p_buf->r_TIC_1, sizeof(struct ccw1));
+
+ /* initialize Header */
+ p_buf->header.length=0xffff;
+ p_buf->header.opcode=0xff;
+ p_buf->header.flag=CLAW_PENDING;
+
+ if (((unsigned long)p_buff+privptr->p_env->read_size) >=
+ ((unsigned long)(p_buff+2*(privptr->p_env->read_size) -1)
+ & PAGE_MASK) ) {
+ p_buff= p_buff+privptr->p_env->read_size;
+ }
+ else {
+ p_buff=
+ (void *)((unsigned long)
+ (p_buff+2*(privptr->p_env->read_size) -1)
+ & PAGE_MASK) ;
+ }
+ } /* for read_buffers */
+ } /* read_size < PAGE_SIZE */
+ else { /* read Size >= PAGE_SIZE */
+
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s() Begin build claw read free chain \n",
+ dev->name,__FUNCTION__);
+#endif
+ for (i=0 ; i< privptr->p_env->read_buffers ; i++) {
+ p_buff = (void *)__get_free_pages(__GFP_DMA,
+ (int)pages_to_order_of_mag(privptr->p_buff_pages_perread) );
+ if (p_buff==NULL) {
+ printk(KERN_INFO "%s: %s() __get_free_pages for read "
+ "buf failed : get is for %d pages\n",
+ dev->name,__FUNCTION__,
+ privptr->p_buff_pages_perread );
+ free_pages((unsigned long)privptr->p_buff_ccw,
+ (int)pages_to_order_of_mag(privptr->p_buff_ccw_num));
+ /* free the write pages */
+ p_buf=privptr->p_buff_write;
+ while (p_buf!=NULL) {
+ free_pages((unsigned long)p_buf->p_buffer,
+ (int)pages_to_order_of_mag(
+ privptr->p_buff_pages_perwrite ));
+ p_buf=p_buf->next;
+ }
+ /* free any read pages already alloc */
+ p_buf=privptr->p_buff_read;
+ while (p_buf!=NULL) {
+ free_pages((unsigned long)p_buf->p_buffer,
+ (int)pages_to_order_of_mag(
+ privptr->p_buff_pages_perread ));
+ p_buf=p_buf->next;
+ }
+ privptr->p_buff_ccw=NULL;
+ privptr->p_buff_write=NULL;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s() exit on line %d, rc = ENOMEM\n",
+ dev->name,__FUNCTION__,
+ __LINE__);
+#endif
+ return -ENOMEM;
+ }
+ memset(p_buff, 0x00, privptr->p_env->read_size);
+ p_buf = p_free_chain;
+ privptr->p_buff_read = p_buf;
+ p_free_chain = p_buf->next;
+
+ if (p_last_CCWB==NULL) {
+ p_buf->next=NULL;
+ real_TIC_address=0;
+ p_last_CCWB=p_buf;
+ }
+ else {
+ p_buf->next=p_first_CCWB;
+ real_TIC_address=
+ (addr_t)__pa(
+ &p_first_CCWB -> read );
+ }
+
+ p_first_CCWB=p_buf;
+ /* save buff address */
+ p_buf->p_buffer=(struct clawbuf *)p_buff;
+ /* initialize read command */
+ p_buf-> read.cmd_code = CCW_CLAW_CMD_READ;
+ p_buf-> read.cda = (__u32)__pa(p_buff);
+ p_buf-> read.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ p_buf-> read.count = privptr->p_env->read_size;
+
+ /* initialize read_h command */
+ p_buf-> read_h.cmd_code = CCW_CLAW_CMD_READHEADER;
+ p_buf-> read_h.cda =
+ (__u32)__pa(&(p_buf->header));
+ p_buf-> read_h.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ p_buf-> read_h.count = sizeof(struct clawh);
+
+ /* initialize Signal command */
+ p_buf-> signal.cmd_code = CCW_CLAW_CMD_SIGNAL_SMOD;
+ p_buf-> signal.cda =
+ (__u32)__pa(&(pClawH->flag));
+ p_buf-> signal.flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ p_buf-> signal.count = 1;
+
+ /* initialize r_TIC_1 command */
+ p_buf-> r_TIC_1.cmd_code = CCW_CLAW_CMD_TIC;
+ p_buf-> r_TIC_1.cda = (__u32)real_TIC_address;
+ p_buf-> r_TIC_1.flags = 0;
+ p_buf-> r_TIC_1.count = 0;
+
+ /* initialize r_read_FF command */
+ p_buf-> r_read_FF.cmd_code = CCW_CLAW_CMD_READFF;
+ p_buf-> r_read_FF.cda =
+ (__u32)__pa(&(pClawH->flag));
+ p_buf-> r_read_FF.flags =
+ CCW_FLAG_SLI | CCW_FLAG_CC | CCW_FLAG_PCI;
+ p_buf-> r_read_FF.count = 1;
+
+ /* initialize r_TIC_2 */
+ memcpy(&p_buf->r_TIC_2, &p_buf->r_TIC_1,
+ sizeof(struct ccw1));
+
+ /* initialize Header */
+ p_buf->header.length=0xffff;
+ p_buf->header.opcode=0xff;
+ p_buf->header.flag=CLAW_PENDING;
+
+ } /* For read_buffers */
+ } /* read_size >= PAGE_SIZE */
+ } /* pBuffread = NULL */
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s() > End build claw read free chain \n",
+ dev->name,__FUNCTION__);
+ p_buf=p_first_CCWB;
+ while (p_buf!=NULL) {
+ dumpit((char *)p_buf, sizeof(struct ccwbk));
+ p_buf=p_buf->next;
+ }
+
+#endif
+ add_claw_reads( dev ,p_first_CCWB , p_last_CCWB);
+ privptr->buffs_alloc = 1;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s() exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ return 0;
+} /* end of init_ccw_bk */
+
+/*-------------------------------------------------------------------*
+* *
+* probe_error *
+* *
+*--------------------------------------------------------------------*/
+
+static void
+probe_error( struct ccwgroup_device *cgdev)
+{
+ struct claw_privbk *privptr;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s enter \n",__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"proberr");
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s variable cgdev =\n",__FUNCTION__);
+ dumpit((char *) cgdev, sizeof(struct ccwgroup_device));
+#endif
+ privptr=(struct claw_privbk *)cgdev->dev.driver_data;
+ if (privptr!=NULL) {
+ if (privptr->p_env != NULL) {
+ kfree(privptr->p_env);
+ privptr->p_env=NULL;
+ }
+ if (privptr->p_mtc_envelope!=NULL) {
+ kfree(privptr->p_mtc_envelope);
+ privptr->p_mtc_envelope=NULL;
+ }
+ kfree(privptr);
+ privptr=NULL;
+ }
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s > exit on line %d\n",
+ __FUNCTION__,__LINE__);
+#endif
+
+ return;
+} /* probe_error */
+
+
+
+/*-------------------------------------------------------------------*
+* claw_process_control *
+* *
+* *
+*--------------------------------------------------------------------*/
+
+static int
+claw_process_control( struct net_device *dev, struct ccwbk * p_ccw)
+{
+
+ struct clawbuf *p_buf;
+ struct clawctl ctlbk;
+ struct clawctl *p_ctlbk;
+ char temp_host_name[8];
+ char temp_ws_name[8];
+ struct claw_privbk *privptr;
+ struct claw_env *p_env;
+ struct sysval *p_sysval;
+ struct conncmd *p_connect=NULL;
+ int rc;
+ struct chbk *p_ch = NULL;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s() > enter \n",
+ dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(2,setup,"clw_cntl");
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: variable dev =\n",dev->name);
+ dumpit((char *) dev, sizeof(struct net_device));
+ printk(KERN_INFO "%s: variable p_ccw =\n",dev->name);
+ dumpit((char *) p_ccw, sizeof(struct ccwbk *));
+#endif
+ udelay(1000); /* Wait a ms for the control packets to
+ *catch up to each other */
+ privptr=dev->priv;
+ p_env=privptr->p_env;
+ memcpy( &temp_host_name, p_env->host_name, 8);
+ memcpy( &temp_ws_name, p_env->adapter_name , 8);
+ printk(KERN_INFO "%s: CLAW device %.8s: "
+ "Received Control Packet\n",
+ dev->name, temp_ws_name);
+ if (privptr->release_pend==1) {
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s() > "
+ "exit on line %d, rc=0\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ return 0;
+ }
+ p_buf=p_ccw->p_buffer;
+ p_ctlbk=&ctlbk;
+ if (p_env->packing == DO_PACKED) { /* packing in progress?*/
+ memcpy(p_ctlbk, &p_buf->buffer[4], sizeof(struct clawctl));
+ } else {
+ memcpy(p_ctlbk, p_buf, sizeof(struct clawctl));
+ }
+#ifdef IOTRACE
+ printk(KERN_INFO "%s: dump claw control data inbound\n",dev->name);
+ dumpit((char *)p_ctlbk, sizeof(struct clawctl));
+#endif
+ switch (p_ctlbk->command)
+ {
+ case SYSTEM_VALIDATE_REQUEST:
+ if (p_ctlbk->version!=CLAW_VERSION_ID) {
+ claw_snd_sys_validate_rsp(dev, p_ctlbk,
+ CLAW_RC_WRONG_VERSION );
+ printk("%s: %d is wrong version id. "
+ "Expected %d\n",
+ dev->name, p_ctlbk->version,
+ CLAW_VERSION_ID);
+ }
+ p_sysval=(struct sysval *)&(p_ctlbk->data);
+ printk( "%s: Recv Sys Validate Request: "
+ "Vers=%d,link_id=%d,Corr=%d,WS name=%."
+ "8s,Host name=%.8s\n",
+ dev->name, p_ctlbk->version,
+ p_ctlbk->linkid,
+ p_ctlbk->correlator,
+ p_sysval->WS_name,
+ p_sysval->host_name);
+ if (0!=memcmp(temp_host_name,p_sysval->host_name,8)) {
+ claw_snd_sys_validate_rsp(dev, p_ctlbk,
+ CLAW_RC_NAME_MISMATCH );
+ CLAW_DBF_TEXT(2,setup,"HSTBAD");
+ CLAW_DBF_TEXT_(2,setup,"%s",p_sysval->host_name);
+ CLAW_DBF_TEXT_(2,setup,"%s",temp_host_name);
+ printk(KERN_INFO "%s: Host name mismatch\n",
+ dev->name);
+ printk(KERN_INFO "%s: Received :%s: "
+ "expected :%s: \n",
+ dev->name,
+ p_sysval->host_name,
+ temp_host_name);
+ }
+ if (0!=memcmp(temp_ws_name,p_sysval->WS_name,8)) {
+ claw_snd_sys_validate_rsp(dev, p_ctlbk,
+ CLAW_RC_NAME_MISMATCH );
+ CLAW_DBF_TEXT(2,setup,"WSNBAD");
+ CLAW_DBF_TEXT_(2,setup,"%s",p_sysval->WS_name);
+ CLAW_DBF_TEXT_(2,setup,"%s",temp_ws_name);
+ printk(KERN_INFO "%s: WS name mismatch\n",
+ dev->name);
+ printk(KERN_INFO "%s: Received :%s: "
+ "expected :%s: \n",
+ dev->name,
+ p_sysval->WS_name,
+ temp_ws_name);
+ }
+ if (( p_sysval->write_frame_size < p_env->write_size) &&
+ ( p_env->packing == 0)) {
+ claw_snd_sys_validate_rsp(dev, p_ctlbk,
+ CLAW_RC_HOST_RCV_TOO_SMALL );
+ printk(KERN_INFO "%s: host write size is too "
+ "small\n", dev->name);
+ CLAW_DBF_TEXT(2,setup,"wrtszbad");
+ }
+ if (( p_sysval->read_frame_size < p_env->read_size) &&
+ ( p_env->packing == 0)) {
+ claw_snd_sys_validate_rsp(dev, p_ctlbk,
+ CLAW_RC_HOST_RCV_TOO_SMALL );
+ printk(KERN_INFO "%s: host read size is too "
+ "small\n", dev->name);
+ CLAW_DBF_TEXT(2,setup,"rdsizbad");
+ }
+ claw_snd_sys_validate_rsp(dev, p_ctlbk, 0 );
+ printk("%s: CLAW device %.8s: System validate"
+ " completed.\n",dev->name, temp_ws_name);
+ printk("%s: sys Validate Rsize:%d Wsize:%d\n",dev->name,
+ p_sysval->read_frame_size,p_sysval->write_frame_size);
+ privptr->system_validate_comp=1;
+ if(strncmp(p_env->api_type,WS_APPL_NAME_PACKED,6) == 0) {
+ p_env->packing = PACKING_ASK;
+ }
+ claw_strt_conn_req(dev);
+ break;
+
+ case SYSTEM_VALIDATE_RESPONSE:
+ p_sysval=(struct sysval *)&(p_ctlbk->data);
+ printk("%s: Recv Sys Validate Resp: Vers=%d,Corr=%d,RC=%d,"
+ "WS name=%.8s,Host name=%.8s\n",
+ dev->name,
+ p_ctlbk->version,
+ p_ctlbk->correlator,
+ p_ctlbk->rc,
+ p_sysval->WS_name,
+ p_sysval->host_name);
+ switch (p_ctlbk->rc)
+ {
+ case 0:
+ printk(KERN_INFO "%s: CLAW device "
+ "%.8s: System validate "
+ "completed.\n",
+ dev->name, temp_ws_name);
+ if (privptr->system_validate_comp == 0)
+ claw_strt_conn_req(dev);
+ privptr->system_validate_comp=1;
+ break;
+ case CLAW_RC_NAME_MISMATCH:
+ printk(KERN_INFO "%s: Sys Validate "
+ "Resp : Host, WS name is "
+ "mismatch\n",
+ dev->name);
+ break;
+ case CLAW_RC_WRONG_VERSION:
+ printk(KERN_INFO "%s: Sys Validate "
+ "Resp : Wrong version\n",
+ dev->name);
+ break;
+ case CLAW_RC_HOST_RCV_TOO_SMALL:
+ printk(KERN_INFO "%s: Sys Validate "
+ "Resp : bad frame size\n",
+ dev->name);
+ break;
+ default:
+ printk(KERN_INFO "%s: Sys Validate "
+ "error code=%d \n",
+ dev->name, p_ctlbk->rc );
+ break;
+ }
+ break;
+
+ case CONNECTION_REQUEST:
+ p_connect=(struct conncmd *)&(p_ctlbk->data);
+ printk(KERN_INFO "%s: Recv Conn Req: Vers=%d,link_id=%d,"
+ "Corr=%d,HOST appl=%.8s,WS appl=%.8s\n",
+ dev->name,
+ p_ctlbk->version,
+ p_ctlbk->linkid,
+ p_ctlbk->correlator,
+ p_connect->host_name,
+ p_connect->WS_name);
+ if (privptr->active_link_ID!=0 ) {
+ claw_snd_disc(dev, p_ctlbk);
+ printk(KERN_INFO "%s: Conn Req error : "
+ "already logical link is active \n",
+ dev->name);
+ }
+ if (p_ctlbk->linkid!=1 ) {
+ claw_snd_disc(dev, p_ctlbk);
+ printk(KERN_INFO "%s: Conn Req error : "
+ "req logical link id is not 1\n",
+ dev->name);
+ }
+ rc=find_link(dev,
+ p_connect->host_name, p_connect->WS_name);
+ if (rc!=0) {
+ claw_snd_disc(dev, p_ctlbk);
+ printk(KERN_INFO "%s: Conn Req error : "
+ "req appl name does not match\n",
+ dev->name);
+ }
+ claw_send_control(dev,
+ CONNECTION_CONFIRM, p_ctlbk->linkid,
+ p_ctlbk->correlator,
+ 0, p_connect->host_name,
+ p_connect->WS_name);
+ if (p_env->packing == PACKING_ASK) {
+ printk("%s: Now Pack ask\n",dev->name);
+ p_env->packing = PACK_SEND;
+ claw_snd_conn_req(dev,0);
+ }
+ printk(KERN_INFO "%s: CLAW device %.8s: Connection "
+ "completed link_id=%d.\n",
+ dev->name, temp_ws_name,
+ p_ctlbk->linkid);
+ privptr->active_link_ID=p_ctlbk->linkid;
+ p_ch=&privptr->channel[WRITE];
+ wake_up(&p_ch->wait); /* wake up claw_open ( WRITE) */
+ break;
+ case CONNECTION_RESPONSE:
+ p_connect=(struct conncmd *)&(p_ctlbk->data);
+ printk(KERN_INFO "%s: Revc Conn Resp: Vers=%d,link_id=%d,"
+ "Corr=%d,RC=%d,Host appl=%.8s, WS appl=%.8s\n",
+ dev->name,
+ p_ctlbk->version,
+ p_ctlbk->linkid,
+ p_ctlbk->correlator,
+ p_ctlbk->rc,
+ p_connect->host_name,
+ p_connect->WS_name);
+
+ if (p_ctlbk->rc !=0 ) {
+ printk(KERN_INFO "%s: Conn Resp error: rc=%d \n",
+ dev->name, p_ctlbk->rc);
+ return 1;
+ }
+ rc=find_link(dev,
+ p_connect->host_name, p_connect->WS_name);
+ if (rc!=0) {
+ claw_snd_disc(dev, p_ctlbk);
+ printk(KERN_INFO "%s: Conn Resp error: "
+ "req appl name does not match\n",
+ dev->name);
+ }
+ /* should be until CONNECTION_CONFIRM */
+ privptr->active_link_ID = - (p_ctlbk->linkid);
+ break;
+ case CONNECTION_CONFIRM:
+ p_connect=(struct conncmd *)&(p_ctlbk->data);
+ printk(KERN_INFO "%s: Recv Conn Confirm:Vers=%d,link_id=%d,"
+ "Corr=%d,Host appl=%.8s,WS appl=%.8s\n",
+ dev->name,
+ p_ctlbk->version,
+ p_ctlbk->linkid,
+ p_ctlbk->correlator,
+ p_connect->host_name,
+ p_connect->WS_name);
+ if (p_ctlbk->linkid== -(privptr->active_link_ID)) {
+ privptr->active_link_ID=p_ctlbk->linkid;
+ if (p_env->packing > PACKING_ASK) {
+ printk(KERN_INFO "%s: Confirmed Now packing\n",dev->name);
+ p_env->packing = DO_PACKED;
+ }
+ p_ch=&privptr->channel[WRITE];
+ wake_up(&p_ch->wait);
+ }
+ else {
+ printk(KERN_INFO "%s: Conn confirm: "
+ "unexpected linkid=%d \n",
+ dev->name, p_ctlbk->linkid);
+ claw_snd_disc(dev, p_ctlbk);
+ }
+ break;
+ case DISCONNECT:
+ printk(KERN_INFO "%s: Disconnect: "
+ "Vers=%d,link_id=%d,Corr=%d\n",
+ dev->name, p_ctlbk->version,
+ p_ctlbk->linkid, p_ctlbk->correlator);
+ if ((p_ctlbk->linkid == 2) &&
+ (p_env->packing == PACK_SEND)) {
+ privptr->active_link_ID = 1;
+ p_env->packing = DO_PACKED;
+ }
+ else
+ privptr->active_link_ID=0;
+ break;
+ case CLAW_ERROR:
+ printk(KERN_INFO "%s: CLAW ERROR detected\n",
+ dev->name);
+ break;
+ default:
+ printk(KERN_INFO "%s: Unexpected command code=%d \n",
+ dev->name, p_ctlbk->command);
+ break;
+ }
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s() exit on line %d, rc = 0\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+
+ return 0;
+} /* end of claw_process_control */
+
+
+/*-------------------------------------------------------------------*
+* claw_send_control *
+* *
+*--------------------------------------------------------------------*/
+
+static int
+claw_send_control(struct net_device *dev, __u8 type, __u8 link,
+ __u8 correlator, __u8 rc, char *local_name, char *remote_name)
+{
+ struct claw_privbk *privptr;
+ struct clawctl *p_ctl;
+ struct sysval *p_sysval;
+ struct conncmd *p_connect;
+ struct sk_buff *skb;
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s > enter \n",dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(2,setup,"sndcntl");
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: Sending Control Packet \n",dev->name);
+ printk(KERN_INFO "%s: variable type = 0x%X, link = "
+ "%d, correlator = %d, rc = %d\n",
+ dev->name,type, link, correlator, rc);
+ printk(KERN_INFO "%s: variable local_name = %s, "
+ "remote_name = %s\n",dev->name, local_name, remote_name);
+#endif
+ privptr=dev->priv;
+ p_ctl=(struct clawctl *)&privptr->ctl_bk;
+
+ p_ctl->command=type;
+ p_ctl->version=CLAW_VERSION_ID;
+ p_ctl->linkid=link;
+ p_ctl->correlator=correlator;
+ p_ctl->rc=rc;
+
+ p_sysval=(struct sysval *)&p_ctl->data;
+ p_connect=(struct conncmd *)&p_ctl->data;
+
+ switch (p_ctl->command) {
+ case SYSTEM_VALIDATE_REQUEST:
+ case SYSTEM_VALIDATE_RESPONSE:
+ memcpy(&p_sysval->host_name, local_name, 8);
+ memcpy(&p_sysval->WS_name, remote_name, 8);
+ if (privptr->p_env->packing > 0) {
+ p_sysval->read_frame_size=DEF_PACK_BUFSIZE;
+ p_sysval->write_frame_size=DEF_PACK_BUFSIZE;
+ } else {
+ /* how big is the piggest group of packets */
+ p_sysval->read_frame_size=privptr->p_env->read_size;
+ p_sysval->write_frame_size=privptr->p_env->write_size;
+ }
+ memset(&p_sysval->reserved, 0x00, 4);
+ break;
+ case CONNECTION_REQUEST:
+ case CONNECTION_RESPONSE:
+ case CONNECTION_CONFIRM:
+ case DISCONNECT:
+ memcpy(&p_sysval->host_name, local_name, 8);
+ memcpy(&p_sysval->WS_name, remote_name, 8);
+ if (privptr->p_env->packing > 0) {
+ /* How big is the biggest packet */
+ p_connect->reserved1[0]=CLAW_FRAME_SIZE;
+ p_connect->reserved1[1]=CLAW_FRAME_SIZE;
+ } else {
+ memset(&p_connect->reserved1, 0x00, 4);
+ memset(&p_connect->reserved2, 0x00, 4);
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* write Control Record to the device */
+
+
+ skb = dev_alloc_skb(sizeof(struct clawctl));
+ if (!skb) {
+ printk( "%s:%s low on mem, returning...\n",
+ dev->name,__FUNCTION__);
+#ifdef DEBUG
+ printk(KERN_INFO "%s:%s Exit, rc = ENOMEM\n",
+ dev->name,__FUNCTION__);
+#endif
+ return -ENOMEM;
+ }
+ memcpy(skb_put(skb, sizeof(struct clawctl)),
+ p_ctl, sizeof(struct clawctl));
+#ifdef IOTRACE
+ printk(KERN_INFO "%s: outbnd claw cntl data \n",dev->name);
+ dumpit((char *)p_ctl,sizeof(struct clawctl));
+#endif
+ if (privptr->p_env->packing >= PACK_SEND)
+ claw_hw_tx(skb, dev, 1);
+ else
+ claw_hw_tx(skb, dev, 0);
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+
+ return 0;
+} /* end of claw_send_control */
+
+/*-------------------------------------------------------------------*
+* claw_snd_conn_req *
+* *
+*--------------------------------------------------------------------*/
+static int
+claw_snd_conn_req(struct net_device *dev, __u8 link)
+{
+ int rc;
+ struct claw_privbk *privptr=dev->priv;
+ struct clawctl *p_ctl;
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(2,setup,"snd_conn");
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: variable link = %X, dev =\n",dev->name, link);
+ dumpit((char *) dev, sizeof(struct net_device));
+#endif
+ rc = 1;
+ p_ctl=(struct clawctl *)&privptr->ctl_bk;
+ p_ctl->linkid = link;
+ if ( privptr->system_validate_comp==0x00 ) {
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d, rc = 1\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ return rc;
+ }
+ if (privptr->p_env->packing == PACKING_ASK )
+ rc=claw_send_control(dev, CONNECTION_REQUEST,0,0,0,
+ WS_APPL_NAME_PACKED, WS_APPL_NAME_PACKED);
+ if (privptr->p_env->packing == PACK_SEND) {
+ rc=claw_send_control(dev, CONNECTION_REQUEST,0,0,0,
+ WS_APPL_NAME_IP_NAME, WS_APPL_NAME_IP_NAME);
+ }
+ if (privptr->p_env->packing == 0)
+ rc=claw_send_control(dev, CONNECTION_REQUEST,0,0,0,
+ HOST_APPL_NAME, privptr->p_env->api_type);
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d, rc = %d\n",
+ dev->name,__FUNCTION__,__LINE__, rc);
+#endif
+ return rc;
+
+} /* end of claw_snd_conn_req */
+
+
+/*-------------------------------------------------------------------*
+* claw_snd_disc *
+* *
+*--------------------------------------------------------------------*/
+
+static int
+claw_snd_disc(struct net_device *dev, struct clawctl * p_ctl)
+{
+ int rc;
+ struct conncmd * p_connect;
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(2,setup,"snd_dsc");
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: variable dev =\n",dev->name);
+ dumpit((char *) dev, sizeof(struct net_device));
+ printk(KERN_INFO "%s: variable p_ctl",dev->name);
+ dumpit((char *) p_ctl, sizeof(struct clawctl));
+#endif
+ p_connect=(struct conncmd *)&p_ctl->data;
+
+ rc=claw_send_control(dev, DISCONNECT, p_ctl->linkid,
+ p_ctl->correlator, 0,
+ p_connect->host_name, p_connect->WS_name);
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d, rc = %d\n",
+ dev->name,__FUNCTION__, __LINE__, rc);
+#endif
+ return rc;
+} /* end of claw_snd_disc */
+
+
+/*-------------------------------------------------------------------*
+* claw_snd_sys_validate_rsp *
+* *
+*--------------------------------------------------------------------*/
+
+static int
+claw_snd_sys_validate_rsp(struct net_device *dev,
+ struct clawctl *p_ctl, __u32 return_code)
+{
+ struct claw_env * p_env;
+ struct claw_privbk *privptr;
+ int rc;
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter\n",
+ dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(2,setup,"chkresp");
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: variable return_code = %d, dev =\n",
+ dev->name, return_code);
+ dumpit((char *) dev, sizeof(struct net_device));
+ printk(KERN_INFO "%s: variable p_ctl =\n",dev->name);
+ dumpit((char *) p_ctl, sizeof(struct clawctl));
+#endif
+ privptr = dev->priv;
+ p_env=privptr->p_env;
+ rc=claw_send_control(dev, SYSTEM_VALIDATE_RESPONSE,
+ p_ctl->linkid,
+ p_ctl->correlator,
+ return_code,
+ p_env->host_name,
+ p_env->adapter_name );
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d, rc = %d\n",
+ dev->name,__FUNCTION__,__LINE__, rc);
+#endif
+ return rc;
+} /* end of claw_snd_sys_validate_rsp */
+
+/*-------------------------------------------------------------------*
+* claw_strt_conn_req *
+* *
+*--------------------------------------------------------------------*/
+
+static int
+claw_strt_conn_req(struct net_device *dev )
+{
+ int rc;
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(2,setup,"conn_req");
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: variable dev =\n",dev->name);
+ dumpit((char *) dev, sizeof(struct net_device));
+#endif
+ rc=claw_snd_conn_req(dev, 1);
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d, rc = %d\n",
+ dev->name,__FUNCTION__,__LINE__, rc);
+#endif
+ return rc;
+} /* end of claw_strt_conn_req */
+
+
+
+/*-------------------------------------------------------------------*
+ * claw_stats *
+ *-------------------------------------------------------------------*/
+
+static struct
+net_device_stats *claw_stats(struct net_device *dev)
+{
+ struct claw_privbk *privptr;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"stats");
+ privptr = dev->priv;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ return &privptr->stats;
+} /* end of claw_stats */
+
+
+/*-------------------------------------------------------------------*
+* unpack_read *
+* *
+*--------------------------------------------------------------------*/
+static void
+unpack_read(struct net_device *dev )
+{
+ struct sk_buff *skb;
+ struct claw_privbk *privptr;
+ struct claw_env *p_env;
+ struct ccwbk *p_this_ccw;
+ struct ccwbk *p_first_ccw;
+ struct ccwbk *p_last_ccw;
+ struct clawph *p_packh;
+ void *p_packd;
+ struct clawctl *p_ctlrec=NULL;
+
+ __u32 len_of_data;
+ __u32 pack_off;
+ __u8 link_num;
+ __u8 mtc_this_frm=0;
+ __u32 bytes_to_mov;
+ struct chbk *p_ch = NULL;
+ int i=0;
+ int p=0;
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s enter \n",dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"unpkread");
+ p_first_ccw=NULL;
+ p_last_ccw=NULL;
+ p_packh=NULL;
+ p_packd=NULL;
+ privptr=dev->priv;
+ p_env = privptr->p_env;
+ p_this_ccw=privptr->p_read_active_first;
+ i=0;
+ while (p_this_ccw!=NULL && p_this_ccw->header.flag!=CLAW_PENDING) {
+#ifdef IOTRACE
+ printk(KERN_INFO "%s p_this_ccw \n",dev->name);
+ dumpit((char*)p_this_ccw, sizeof(struct ccwbk));
+ printk(KERN_INFO "%s Inbound p_this_ccw->p_buffer(64)"
+ " pk=%d \n",dev->name,p_env->packing);
+ dumpit((char *)p_this_ccw->p_buffer, 64 );
+#endif
+ pack_off = 0;
+ p = 0;
+ p_this_ccw->header.flag=CLAW_PENDING;
+ privptr->p_read_active_first=p_this_ccw->next;
+ p_this_ccw->next=NULL;
+ p_packh = (struct clawph *)p_this_ccw->p_buffer;
+ if ((p_env->packing == PACK_SEND) &&
+ (p_packh->len == 32) &&
+ (p_packh->link_num == 0)) { /* is it a packed ctl rec? */
+ p_packh++; /* peek past pack header */
+ p_ctlrec = (struct clawctl *)p_packh;
+ p_packh--; /* un peek */
+ if ((p_ctlrec->command == CONNECTION_RESPONSE) ||
+ (p_ctlrec->command == CONNECTION_CONFIRM))
+ p_env->packing = DO_PACKED;
+ }
+ if (p_env->packing == DO_PACKED)
+ link_num=p_packh->link_num;
+ else
+ link_num=p_this_ccw->header.opcode / 8;
+ if ((p_this_ccw->header.opcode & MORE_to_COME_FLAG)!=0) {
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s > More_to_come is ON\n",
+ dev->name,__FUNCTION__);
+#endif
+ mtc_this_frm=1;
+ if (p_this_ccw->header.length!=
+ privptr->p_env->read_size ) {
+ printk(KERN_INFO " %s: Invalid frame detected "
+ "length is %02x\n" ,
+ dev->name, p_this_ccw->header.length);
+ }
+ }
+
+ if (privptr->mtc_skipping) {
+ /*
+ * We're in the mode of skipping past a
+ * multi-frame message
+ * that we can't process for some reason or other.
+ * The first frame without the More-To-Come flag is
+ * the last frame of the skipped message.
+ */
+ /* in case of More-To-Come not set in this frame */
+ if (mtc_this_frm==0) {
+ privptr->mtc_skipping=0; /* Ok, the end */
+ privptr->mtc_logical_link=-1;
+ }
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s:%s goto next "
+ "frame from MoretoComeSkip \n",
+ dev->name,__FUNCTION__);
+#endif
+ goto NextFrame;
+ }
+
+ if (link_num==0) {
+ claw_process_control(dev, p_this_ccw);
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s:%s goto next "
+ "frame from claw_process_control \n",
+ dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"UnpkCntl");
+ goto NextFrame;
+ }
+unpack_next:
+ if (p_env->packing == DO_PACKED) {
+ if (pack_off > p_env->read_size)
+ goto NextFrame;
+ p_packd = p_this_ccw->p_buffer+pack_off;
+ p_packh = (struct clawph *) p_packd;
+ if ((p_packh->len == 0) || /* all done with this frame? */
+ (p_packh->flag != 0))
+ goto NextFrame;
+ bytes_to_mov = p_packh->len;
+ pack_off += bytes_to_mov+sizeof(struct clawph);
+ p++;
+ } else {
+ bytes_to_mov=p_this_ccw->header.length;
+ }
+ if (privptr->mtc_logical_link<0) {
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s mtc_logical_link < 0 \n",
+ dev->name,__FUNCTION__);
+#endif
+
+ /*
+ * if More-To-Come is set in this frame then we don't know
+ * length of entire message, and hence have to allocate
+ * large buffer */
+
+ /* We are starting a new envelope */
+ privptr->mtc_offset=0;
+ privptr->mtc_logical_link=link_num;
+ }
+
+ if (bytes_to_mov > (MAX_ENVELOPE_SIZE- privptr->mtc_offset) ) {
+ /* error */
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s > goto next "
+ "frame from MoretoComeSkip \n",
+ dev->name,
+ __FUNCTION__);
+ printk(KERN_INFO " bytes_to_mov %d > (MAX_ENVELOPE_"
+ "SIZE-privptr->mtc_offset %d)\n",
+ bytes_to_mov,(MAX_ENVELOPE_SIZE- privptr->mtc_offset));
+#endif
+ privptr->stats.rx_frame_errors++;
+ goto NextFrame;
+ }
+ if (p_env->packing == DO_PACKED) {
+ memcpy( privptr->p_mtc_envelope+ privptr->mtc_offset,
+ p_packd+sizeof(struct clawph), bytes_to_mov);
+
+ } else {
+ memcpy( privptr->p_mtc_envelope+ privptr->mtc_offset,
+ p_this_ccw->p_buffer, bytes_to_mov);
+ }
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s() received data \n",
+ dev->name,__FUNCTION__);
+ if (p_env->packing == DO_PACKED)
+ dumpit((char *)p_packd+sizeof(struct clawph),32);
+ else
+ dumpit((char *)p_this_ccw->p_buffer, 32);
+ printk(KERN_INFO "%s: %s() bytelength %d \n",
+ dev->name,__FUNCTION__,bytes_to_mov);
+#endif
+ if (mtc_this_frm==0) {
+ len_of_data=privptr->mtc_offset+bytes_to_mov;
+ skb=dev_alloc_skb(len_of_data);
+ if (skb) {
+ memcpy(skb_put(skb,len_of_data),
+ privptr->p_mtc_envelope,
+ len_of_data);
+ skb->mac.raw=skb->data;
+ skb->dev=dev;
+ skb->protocol=htons(ETH_P_IP);
+ skb->ip_summed=CHECKSUM_UNNECESSARY;
+ privptr->stats.rx_packets++;
+ privptr->stats.rx_bytes+=len_of_data;
+ netif_rx(skb);
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: %s() netif_"
+ "rx(skb) completed \n",
+ dev->name,__FUNCTION__);
+#endif
+ }
+ else {
+ privptr->stats.rx_dropped++;
+ printk(KERN_WARNING "%s: %s() low on memory\n",
+ dev->name,__FUNCTION__);
+ }
+ privptr->mtc_offset=0;
+ privptr->mtc_logical_link=-1;
+ }
+ else {
+ privptr->mtc_offset+=bytes_to_mov;
+ }
+ if (p_env->packing == DO_PACKED)
+ goto unpack_next;
+NextFrame:
+ /*
+ * Remove ThisCCWblock from active read queue, and add it
+ * to queue of free blocks to be reused.
+ */
+ i++;
+ p_this_ccw->header.length=0xffff;
+ p_this_ccw->header.opcode=0xff;
+ /*
+ * add this one to the free queue for later reuse
+ */
+ if (p_first_ccw==NULL) {
+ p_first_ccw = p_this_ccw;
+ }
+ else {
+ p_last_ccw->next = p_this_ccw;
+ }
+ p_last_ccw = p_this_ccw;
+ /*
+ * chain to next block on active read queue
+ */
+ p_this_ccw = privptr->p_read_active_first;
+ CLAW_DBF_TEXT_(4,trace,"rxpkt %d",p);
+ } /* end of while */
+
+ /* check validity */
+
+#ifdef IOTRACE
+ printk(KERN_INFO "%s:%s processed frame is %d \n",
+ dev->name,__FUNCTION__,i);
+ printk(KERN_INFO "%s:%s F:%lx L:%lx\n",
+ dev->name,
+ __FUNCTION__,
+ (unsigned long)p_first_ccw,
+ (unsigned long)p_last_ccw);
+#endif
+ CLAW_DBF_TEXT_(4,trace,"rxfrm %d",i);
+ add_claw_reads(dev, p_first_ccw, p_last_ccw);
+ p_ch=&privptr->channel[READ];
+ claw_strt_read(dev, LOCK_YES);
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s exit on line %d\n",
+ dev->name, __FUNCTION__, __LINE__);
+#endif
+ return;
+} /* end of unpack_read */
+
+/*-------------------------------------------------------------------*
+* claw_strt_read *
+* *
+*--------------------------------------------------------------------*/
+static void
+claw_strt_read (struct net_device *dev, int lock )
+{
+ int rc = 0;
+ __u32 parm;
+ unsigned long saveflags = 0;
+ struct claw_privbk *privptr=dev->priv;
+ struct ccwbk*p_ccwbk;
+ struct chbk *p_ch;
+ struct clawh *p_clawh;
+ p_ch=&privptr->channel[READ];
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__);
+ printk(KERN_INFO "%s: variable lock = %d, dev =\n",dev->name, lock);
+ dumpit((char *) dev, sizeof(struct net_device));
+#endif
+ CLAW_DBF_TEXT(4,trace,"StRdNter");
+ p_clawh=(struct clawh *)privptr->p_claw_signal_blk;
+ p_clawh->flag=CLAW_IDLE; /* 0x00 */
+
+ if ((privptr->p_write_active_first!=NULL &&
+ privptr->p_write_active_first->header.flag!=CLAW_PENDING) ||
+ (privptr->p_read_active_first!=NULL &&
+ privptr->p_read_active_first->header.flag!=CLAW_PENDING )) {
+ p_clawh->flag=CLAW_BUSY; /* 0xff */
+ }
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s:%s state-%02x\n" ,
+ dev->name,__FUNCTION__, p_ch->claw_state);
+#endif
+ if (lock==LOCK_YES) {
+ spin_lock_irqsave(get_ccwdev_lock(p_ch->cdev), saveflags);
+ }
+ if (test_and_set_bit(0, (void *)&p_ch->IO_active) == 0) {
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: HOT READ started in %s\n" ,
+ dev->name,__FUNCTION__);
+ p_clawh=(struct clawh *)privptr->p_claw_signal_blk;
+ dumpit((char *)&p_clawh->flag , 1);
+#endif
+ CLAW_DBF_TEXT(4,trace,"HotRead");
+ p_ccwbk=privptr->p_read_active_first;
+ parm = (unsigned long) p_ch;
+ rc = ccw_device_start (p_ch->cdev, &p_ccwbk->read, parm,
+ 0xff, 0);
+ if (rc != 0) {
+ ccw_check_return_code(p_ch->cdev, rc);
+ }
+ }
+ else {
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: No READ started by %s() In progress\n" ,
+ dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(2,trace,"ReadAct");
+ }
+
+ if (lock==LOCK_YES) {
+ spin_unlock_irqrestore(get_ccwdev_lock(p_ch->cdev), saveflags);
+ }
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"StRdExit");
+ return;
+} /* end of claw_strt_read */
+
+/*-------------------------------------------------------------------*
+* claw_strt_out_IO *
+* *
+*--------------------------------------------------------------------*/
+
+static void
+claw_strt_out_IO( struct net_device *dev )
+{
+ int rc = 0;
+ unsigned long parm;
+ struct claw_privbk *privptr;
+ struct chbk *p_ch;
+ struct ccwbk *p_first_ccw;
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__);
+#endif
+ if (!dev) {
+ return;
+ }
+ privptr=(struct claw_privbk *)dev->priv;
+ p_ch=&privptr->channel[WRITE];
+
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s:%s state-%02x\n" ,
+ dev->name,__FUNCTION__,p_ch->claw_state);
+#endif
+ CLAW_DBF_TEXT(4,trace,"strt_io");
+ p_first_ccw=privptr->p_write_active_first;
+
+ if (p_ch->claw_state == CLAW_STOP)
+ return;
+ if (p_first_ccw == NULL) {
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+ return;
+ }
+ if (test_and_set_bit(0, (void *)&p_ch->IO_active) == 0) {
+ parm = (unsigned long) p_ch;
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s:%s do_io \n" ,dev->name,__FUNCTION__);
+ dumpit((char *)p_first_ccw, sizeof(struct ccwbk));
+#endif
+ CLAW_DBF_TEXT(2,trace,"StWrtIO");
+ rc = ccw_device_start (p_ch->cdev,&p_first_ccw->write, parm,
+ 0xff, 0);
+ if (rc != 0) {
+ ccw_check_return_code(p_ch->cdev, rc);
+ }
+ }
+ dev->trans_start = jiffies;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ dev->name,__FUNCTION__,__LINE__);
+#endif
+
+ return;
+} /* end of claw_strt_out_IO */
+
+/*-------------------------------------------------------------------*
+* Free write buffers *
+* *
+*--------------------------------------------------------------------*/
+
+static void
+claw_free_wrt_buf( struct net_device *dev )
+{
+
+ struct claw_privbk *privptr=(struct claw_privbk *)dev->priv;
+ struct ccwbk*p_first_ccw;
+ struct ccwbk*p_last_ccw;
+ struct ccwbk*p_this_ccw;
+ struct ccwbk*p_next_ccw;
+#ifdef IOTRACE
+ struct ccwbk*p_buf;
+#endif
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__);
+ printk(KERN_INFO "%s: free count = %d variable dev =\n",
+ dev->name,privptr->write_free_count);
+#endif
+ CLAW_DBF_TEXT(4,trace,"freewrtb");
+ /* scan the write queue to free any completed write packets */
+ p_first_ccw=NULL;
+ p_last_ccw=NULL;
+#ifdef IOTRACE
+ printk(KERN_INFO "%s: Dump current CCW chain \n",dev->name );
+ p_buf=privptr->p_write_active_first;
+ while (p_buf!=NULL) {
+ dumpit((char *)p_buf, sizeof(struct ccwbk));
+ p_buf=p_buf->next;
+ }
+ if (p_buf==NULL) {
+ printk(KERN_INFO "%s: privptr->p_write_"
+ "active_first==NULL\n",dev->name );
+ }
+ p_buf=(struct ccwbk*)privptr->p_end_ccw;
+ dumpit((char *)p_buf, sizeof(struct endccw));
+#endif
+ p_this_ccw=privptr->p_write_active_first;
+ while ( (p_this_ccw!=NULL) && (p_this_ccw->header.flag!=CLAW_PENDING))
+ {
+ p_next_ccw = p_this_ccw->next;
+ if (((p_next_ccw!=NULL) &&
+ (p_next_ccw->header.flag!=CLAW_PENDING)) ||
+ ((p_this_ccw == privptr->p_write_active_last) &&
+ (p_this_ccw->header.flag!=CLAW_PENDING))) {
+ /* The next CCW is OK or this is */
+ /* the last CCW...free it @A1A */
+ privptr->p_write_active_first=p_this_ccw->next;
+ p_this_ccw->header.flag=CLAW_PENDING;
+ p_this_ccw->next=privptr->p_write_free_chain;
+ privptr->p_write_free_chain=p_this_ccw;
+ ++privptr->write_free_count;
+ privptr->stats.tx_bytes+= p_this_ccw->write.count;
+ p_this_ccw=privptr->p_write_active_first;
+ privptr->stats.tx_packets++;
+ }
+ else {
+ break;
+ }
+ }
+ if (privptr->write_free_count!=0) {
+ claw_clearbit_busy(TB_NOBUFFER,dev);
+ }
+ /* whole chain removed? */
+ if (privptr->p_write_active_first==NULL) {
+ privptr->p_write_active_last=NULL;
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s:%s p_write_"
+ "active_first==NULL\n",dev->name,__FUNCTION__);
+#endif
+ }
+#ifdef IOTRACE
+ printk(KERN_INFO "%s: Dump arranged CCW chain \n",dev->name );
+ p_buf=privptr->p_write_active_first;
+ while (p_buf!=NULL) {
+ dumpit((char *)p_buf, sizeof(struct ccwbk));
+ p_buf=p_buf->next;
+ }
+ if (p_buf==NULL) {
+ printk(KERN_INFO "%s: privptr->p_write_active_"
+ "first==NULL\n",dev->name );
+ }
+ p_buf=(struct ccwbk*)privptr->p_end_ccw;
+ dumpit((char *)p_buf, sizeof(struct endccw));
+#endif
+
+ CLAW_DBF_TEXT_(4,trace,"FWC=%d",privptr->write_free_count);
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d free_count =%d\n",
+ dev->name,__FUNCTION__, __LINE__,privptr->write_free_count);
+#endif
+ return;
+}
+
+/*-------------------------------------------------------------------*
+* claw free netdevice *
+* *
+*--------------------------------------------------------------------*/
+static void
+claw_free_netdevice(struct net_device * dev, int free_dev)
+{
+ struct claw_privbk *privptr;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(2,setup,"free_dev");
+
+ if (!dev)
+ return;
+ CLAW_DBF_TEXT_(2,setup,"%s",dev->name);
+ privptr = dev->priv;
+ if (dev->flags & IFF_RUNNING)
+ claw_release(dev);
+ if (privptr) {
+ privptr->channel[READ].ndev = NULL; /* say it's free */
+ }
+ dev->priv=NULL;
+#ifdef MODULE
+ if (free_dev) {
+ free_netdev(dev);
+ }
+#endif
+ CLAW_DBF_TEXT(2,setup,"feee_ok");
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit\n",dev->name,__FUNCTION__);
+#endif
+}
+
+/**
+ * Claw init netdevice
+ * Initialize everything of the net device except the name and the
+ * channel structs.
+ */
+static void
+claw_init_netdevice(struct net_device * dev)
+{
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(2,setup,"init_dev");
+ CLAW_DBF_TEXT_(2,setup,"%s",dev->name);
+ if (!dev) {
+ printk(KERN_WARNING "claw:%s BAD Device exit line %d\n",
+ __FUNCTION__,__LINE__);
+ CLAW_DBF_TEXT(2,setup,"baddev");
+ return;
+ }
+ dev->mtu = CLAW_DEFAULT_MTU_SIZE;
+ dev->hard_start_xmit = claw_tx;
+ dev->open = claw_open;
+ dev->stop = claw_release;
+ dev->get_stats = claw_stats;
+ dev->change_mtu = claw_change_mtu;
+ dev->hard_header_len = 0;
+ dev->addr_len = 0;
+ dev->type = ARPHRD_SLIP;
+ dev->tx_queue_len = 1300;
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+ SET_MODULE_OWNER(dev);
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit\n",dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(2,setup,"initok");
+ return;
+}
+
+/**
+ * Init a new channel in the privptr->channel[i].
+ *
+ * @param cdev The ccw_device to be added.
+ *
+ * @return 0 on success, !0 on error.
+ */
+static int
+add_channel(struct ccw_device *cdev,int i,struct claw_privbk *privptr)
+{
+ struct chbk *p_ch;
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter\n",cdev->dev.bus_id,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT_(2,setup,"%s",cdev->dev.bus_id);
+ privptr->channel[i].flag = i+1; /* Read is 1 Write is 2 */
+ p_ch = &privptr->channel[i];
+ p_ch->cdev = cdev;
+ snprintf(p_ch->id, CLAW_ID_SIZE, "cl-%s", cdev->dev.bus_id);
+ sscanf(cdev->dev.bus_id+4,"%x",&p_ch->devno);
+ if ((p_ch->irb = kmalloc(sizeof (struct irb),GFP_KERNEL)) == NULL) {
+ printk(KERN_WARNING "%s Out of memory in %s for irb\n",
+ p_ch->id,__FUNCTION__);
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ p_ch->id,__FUNCTION__,__LINE__);
+#endif
+ return -ENOMEM;
+ }
+ memset(p_ch->irb, 0, sizeof (struct irb));
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",
+ cdev->dev.bus_id,__FUNCTION__,__LINE__);
+#endif
+ return 0;
+}
+
+
+/**
+ *
+ * Setup an interface.
+ *
+ * @param cgdev Device to be setup.
+ *
+ * @returns 0 on success, !0 on failure.
+ */
+static int
+claw_new_device(struct ccwgroup_device *cgdev)
+{
+ struct claw_privbk *privptr;
+ struct claw_env *p_env;
+ struct net_device *dev;
+ int ret;
+
+ pr_debug("%s() called\n", __FUNCTION__);
+ printk(KERN_INFO "claw: add for %s\n",cgdev->cdev[READ]->dev.bus_id);
+ CLAW_DBF_TEXT(2,setup,"new_dev");
+ privptr = cgdev->dev.driver_data;
+ cgdev->cdev[READ]->dev.driver_data = privptr;
+ cgdev->cdev[WRITE]->dev.driver_data = privptr;
+ if (!privptr)
+ return -ENODEV;
+ p_env = privptr->p_env;
+ sscanf(cgdev->cdev[READ]->dev.bus_id+4,"%x",
+ &p_env->devno[READ]);
+ sscanf(cgdev->cdev[WRITE]->dev.bus_id+4,"%x",
+ &p_env->devno[WRITE]);
+ ret = add_channel(cgdev->cdev[0],0,privptr);
+ if (ret == 0)
+ ret = add_channel(cgdev->cdev[1],1,privptr);
+ if (ret != 0) {
+ printk(KERN_WARNING
+ "add channel failed "
+ "with ret = %d\n", ret);
+ goto out;
+ }
+ ret = ccw_device_set_online(cgdev->cdev[READ]);
+ if (ret != 0) {
+ printk(KERN_WARNING
+ "claw: ccw_device_set_online %s READ failed "
+ "with ret = %d\n",cgdev->cdev[READ]->dev.bus_id,ret);
+ goto out;
+ }
+ ret = ccw_device_set_online(cgdev->cdev[WRITE]);
+ if (ret != 0) {
+ printk(KERN_WARNING
+ "claw: ccw_device_set_online %s WRITE failed "
+ "with ret = %d\n",cgdev->cdev[WRITE]->dev.bus_id, ret);
+ goto out;
+ }
+ dev = alloc_netdev(0,"claw%d",claw_init_netdevice);
+ if (!dev) {
+ printk(KERN_WARNING "%s:alloc_netdev failed\n",__FUNCTION__);
+ goto out;
+ }
+ dev->priv = privptr;
+ cgdev->dev.driver_data = privptr;
+ cgdev->cdev[READ]->dev.driver_data = privptr;
+ cgdev->cdev[WRITE]->dev.driver_data = privptr;
+ /* sysfs magic */
+ SET_NETDEV_DEV(dev, &cgdev->dev);
+ if (register_netdev(dev) != 0) {
+ claw_free_netdevice(dev, 1);
+ CLAW_DBF_TEXT(2,trace,"regfail");
+ goto out;
+ }
+ dev->flags &=~IFF_RUNNING;
+ if (privptr->buffs_alloc == 0) {
+ ret=init_ccw_bk(dev);
+ if (ret !=0) {
+ printk(KERN_WARNING
+ "claw: init_ccw_bk failed with ret=%d\n", ret);
+ unregister_netdev(dev);
+ claw_free_netdevice(dev,1);
+ CLAW_DBF_TEXT(2,trace,"ccwmem");
+ goto out;
+ }
+ }
+ privptr->channel[READ].ndev = dev;
+ privptr->channel[WRITE].ndev = dev;
+ privptr->p_env->ndev = dev;
+
+ printk(KERN_INFO "%s:readsize=%d writesize=%d "
+ "readbuffer=%d writebuffer=%d read=0x%04x write=0x%04x\n",
+ dev->name, p_env->read_size,
+ p_env->write_size, p_env->read_buffers,
+ p_env->write_buffers, p_env->devno[READ],
+ p_env->devno[WRITE]);
+ printk(KERN_INFO "%s:host_name:%.8s, adapter_name "
+ ":%.8s api_type: %.8s\n",
+ dev->name, p_env->host_name,
+ p_env->adapter_name , p_env->api_type);
+ return 0;
+out:
+ ccw_device_set_offline(cgdev->cdev[1]);
+ ccw_device_set_offline(cgdev->cdev[0]);
+
+ return -ENODEV;
+}
+
+static void
+claw_purge_skb_queue(struct sk_buff_head *q)
+{
+ struct sk_buff *skb;
+
+ CLAW_DBF_TEXT(4,trace,"purgque");
+
+ while ((skb = skb_dequeue(q))) {
+ atomic_dec(&skb->users);
+ dev_kfree_skb_irq(skb);
+ }
+}
+
+/**
+ * Shutdown an interface.
+ *
+ * @param cgdev Device to be shut down.
+ *
+ * @returns 0 on success, !0 on failure.
+ */
+static int
+claw_shutdown_device(struct ccwgroup_device *cgdev)
+{
+ struct claw_privbk *priv;
+ struct net_device *ndev;
+ int ret;
+
+ pr_debug("%s() called\n", __FUNCTION__);
+ CLAW_DBF_TEXT_(2,setup,"%s",cgdev->dev.bus_id);
+ priv = cgdev->dev.driver_data;
+ if (!priv)
+ return -ENODEV;
+ ndev = priv->channel[READ].ndev;
+ if (ndev) {
+ /* Close the device */
+ printk(KERN_INFO
+ "%s: shuting down \n",ndev->name);
+ if (ndev->flags & IFF_RUNNING)
+ ret = claw_release(ndev);
+ ndev->flags &=~IFF_RUNNING;
+ unregister_netdev(ndev);
+ ndev->priv = NULL; /* cgdev data, not ndev's to free */
+ claw_free_netdevice(ndev, 1);
+ priv->channel[READ].ndev = NULL;
+ priv->channel[WRITE].ndev = NULL;
+ priv->p_env->ndev = NULL;
+ }
+ ccw_device_set_offline(cgdev->cdev[1]);
+ ccw_device_set_offline(cgdev->cdev[0]);
+ return 0;
+}
+
+static void
+claw_remove_device(struct ccwgroup_device *cgdev)
+{
+ struct claw_privbk *priv;
+
+ pr_debug("%s() called\n", __FUNCTION__);
+ CLAW_DBF_TEXT_(2,setup,"%s",cgdev->dev.bus_id);
+ priv = cgdev->dev.driver_data;
+ if (!priv) {
+ printk(KERN_WARNING "claw: %s() no Priv exiting\n",__FUNCTION__);
+ return;
+ }
+ printk(KERN_INFO "claw: %s() called %s will be removed.\n",
+ __FUNCTION__,cgdev->cdev[0]->dev.bus_id);
+ if (cgdev->state == CCWGROUP_ONLINE)
+ claw_shutdown_device(cgdev);
+ claw_remove_files(&cgdev->dev);
+ if (priv->p_mtc_envelope!=NULL) {
+ kfree(priv->p_mtc_envelope);
+ priv->p_mtc_envelope=NULL;
+ }
+ if (priv->p_env != NULL) {
+ kfree(priv->p_env);
+ priv->p_env=NULL;
+ }
+ if (priv->channel[0].irb != NULL) {
+ kfree(priv->channel[0].irb);
+ priv->channel[0].irb=NULL;
+ }
+ if (priv->channel[1].irb != NULL) {
+ kfree(priv->channel[1].irb);
+ priv->channel[1].irb=NULL;
+ }
+ kfree(priv);
+ cgdev->dev.driver_data=NULL;
+ cgdev->cdev[READ]->dev.driver_data = NULL;
+ cgdev->cdev[WRITE]->dev.driver_data = NULL;
+ put_device(&cgdev->dev);
+}
+
+
+/*
+ * sysfs attributes
+ */
+static ssize_t
+claw_hname_show(struct device *dev, char *buf)
+{
+ struct claw_privbk *priv;
+ struct claw_env * p_env;
+
+ priv = dev->driver_data;
+ if (!priv)
+ return -ENODEV;
+ p_env = priv->p_env;
+ return sprintf(buf, "%s\n",p_env->host_name);
+}
+
+static ssize_t
+claw_hname_write(struct device *dev, const char *buf, size_t count)
+{
+ struct claw_privbk *priv;
+ struct claw_env * p_env;
+
+ priv = dev->driver_data;
+ if (!priv)
+ return -ENODEV;
+ p_env = priv->p_env;
+ if (count > MAX_NAME_LEN+1)
+ return -EINVAL;
+ memset(p_env->host_name, 0x20, MAX_NAME_LEN);
+ strncpy(p_env->host_name,buf, count);
+ p_env->host_name[count-1] = 0x20; /* clear extra 0x0a */
+ p_env->host_name[MAX_NAME_LEN] = 0x00;
+ CLAW_DBF_TEXT(2,setup,"HstnSet");
+ CLAW_DBF_TEXT_(2,setup,"%s",p_env->host_name);
+
+ return count;
+}
+
+static DEVICE_ATTR(host_name, 0644, claw_hname_show, claw_hname_write);
+
+static ssize_t
+claw_adname_show(struct device *dev, char *buf)
+{
+ struct claw_privbk *priv;
+ struct claw_env * p_env;
+
+ priv = dev->driver_data;
+ if (!priv)
+ return -ENODEV;
+ p_env = priv->p_env;
+ return sprintf(buf, "%s\n",p_env->adapter_name);
+}
+
+static ssize_t
+claw_adname_write(struct device *dev, const char *buf, size_t count)
+{
+ struct claw_privbk *priv;
+ struct claw_env * p_env;
+
+ priv = dev->driver_data;
+ if (!priv)
+ return -ENODEV;
+ p_env = priv->p_env;
+ if (count > MAX_NAME_LEN+1)
+ return -EINVAL;
+ memset(p_env->adapter_name, 0x20, MAX_NAME_LEN);
+ strncpy(p_env->adapter_name,buf, count);
+ p_env->adapter_name[count-1] = 0x20; /* clear extra 0x0a */
+ p_env->adapter_name[MAX_NAME_LEN] = 0x00;
+ CLAW_DBF_TEXT(2,setup,"AdnSet");
+ CLAW_DBF_TEXT_(2,setup,"%s",p_env->adapter_name);
+
+ return count;
+}
+
+static DEVICE_ATTR(adapter_name, 0644, claw_adname_show, claw_adname_write);
+
+static ssize_t
+claw_apname_show(struct device *dev, char *buf)
+{
+ struct claw_privbk *priv;
+ struct claw_env * p_env;
+
+ priv = dev->driver_data;
+ if (!priv)
+ return -ENODEV;
+ p_env = priv->p_env;
+ return sprintf(buf, "%s\n",
+ p_env->api_type);
+}
+
+static ssize_t
+claw_apname_write(struct device *dev, const char *buf, size_t count)
+{
+ struct claw_privbk *priv;
+ struct claw_env * p_env;
+
+ priv = dev->driver_data;
+ if (!priv)
+ return -ENODEV;
+ p_env = priv->p_env;
+ if (count > MAX_NAME_LEN+1)
+ return -EINVAL;
+ memset(p_env->api_type, 0x20, MAX_NAME_LEN);
+ strncpy(p_env->api_type,buf, count);
+ p_env->api_type[count-1] = 0x20; /* we get a loose 0x0a */
+ p_env->api_type[MAX_NAME_LEN] = 0x00;
+ if(strncmp(p_env->api_type,WS_APPL_NAME_PACKED,6) == 0) {
+ p_env->read_size=DEF_PACK_BUFSIZE;
+ p_env->write_size=DEF_PACK_BUFSIZE;
+ p_env->packing=PACKING_ASK;
+ CLAW_DBF_TEXT(2,setup,"PACKING");
+ }
+ else {
+ p_env->packing=0;
+ p_env->read_size=CLAW_FRAME_SIZE;
+ p_env->write_size=CLAW_FRAME_SIZE;
+ CLAW_DBF_TEXT(2,setup,"ApiSet");
+ }
+ CLAW_DBF_TEXT_(2,setup,"%s",p_env->api_type);
+ return count;
+}
+
+static DEVICE_ATTR(api_type, 0644, claw_apname_show, claw_apname_write);
+
+static ssize_t
+claw_wbuff_show(struct device *dev, char *buf)
+{
+ struct claw_privbk *priv;
+ struct claw_env * p_env;
+
+ priv = dev->driver_data;
+ if (!priv)
+ return -ENODEV;
+ p_env = priv->p_env;
+ return sprintf(buf, "%d\n", p_env->write_buffers);
+}
+
+static ssize_t
+claw_wbuff_write(struct device *dev, const char *buf, size_t count)
+{
+ struct claw_privbk *priv;
+ struct claw_env * p_env;
+ int nnn,max;
+
+ priv = dev->driver_data;
+ if (!priv)
+ return -ENODEV;
+ p_env = priv->p_env;
+ sscanf(buf, "%i", &nnn);
+ if (p_env->packing) {
+ max = 64;
+ }
+ else {
+ max = 512;
+ }
+ if ((nnn > max ) || (nnn < 2))
+ return -EINVAL;
+ p_env->write_buffers = nnn;
+ CLAW_DBF_TEXT(2,setup,"Wbufset");
+ CLAW_DBF_TEXT_(2,setup,"WB=%d",p_env->write_buffers);
+ return count;
+}
+
+static DEVICE_ATTR(write_buffer, 0644, claw_wbuff_show, claw_wbuff_write);
+
+static ssize_t
+claw_rbuff_show(struct device *dev, char *buf)
+{
+ struct claw_privbk *priv;
+ struct claw_env * p_env;
+
+ priv = dev->driver_data;
+ if (!priv)
+ return -ENODEV;
+ p_env = priv->p_env;
+ return sprintf(buf, "%d\n", p_env->read_buffers);
+}
+
+static ssize_t
+claw_rbuff_write(struct device *dev, const char *buf, size_t count)
+{
+ struct claw_privbk *priv;
+ struct claw_env *p_env;
+ int nnn,max;
+
+ priv = dev->driver_data;
+ if (!priv)
+ return -ENODEV;
+ p_env = priv->p_env;
+ sscanf(buf, "%i", &nnn);
+ if (p_env->packing) {
+ max = 64;
+ }
+ else {
+ max = 512;
+ }
+ if ((nnn > max ) || (nnn < 2))
+ return -EINVAL;
+ p_env->read_buffers = nnn;
+ CLAW_DBF_TEXT(2,setup,"Rbufset");
+ CLAW_DBF_TEXT_(2,setup,"RB=%d",p_env->read_buffers);
+ return count;
+}
+
+static DEVICE_ATTR(read_buffer, 0644, claw_rbuff_show, claw_rbuff_write);
+
+static struct attribute *claw_attr[] = {
+ &dev_attr_read_buffer.attr,
+ &dev_attr_write_buffer.attr,
+ &dev_attr_adapter_name.attr,
+ &dev_attr_api_type.attr,
+ &dev_attr_host_name.attr,
+ NULL,
+};
+
+static struct attribute_group claw_attr_group = {
+ .attrs = claw_attr,
+};
+
+static int
+claw_add_files(struct device *dev)
+{
+ pr_debug("%s() called\n", __FUNCTION__);
+ CLAW_DBF_TEXT(2,setup,"add_file");
+ return sysfs_create_group(&dev->kobj, &claw_attr_group);
+}
+
+static void
+claw_remove_files(struct device *dev)
+{
+ pr_debug("%s() called\n", __FUNCTION__);
+ CLAW_DBF_TEXT(2,setup,"rem_file");
+ sysfs_remove_group(&dev->kobj, &claw_attr_group);
+}
+
+/*--------------------------------------------------------------------*
+* claw_init and cleanup *
+*---------------------------------------------------------------------*/
+
+static void __exit
+claw_cleanup(void)
+{
+ unregister_cu3088_discipline(&claw_group_driver);
+ claw_unregister_debug_facility();
+ printk(KERN_INFO "claw: Driver unloaded\n");
+
+}
+
+/**
+ * Initialize module.
+ * This is called just after the module is loaded.
+ *
+ * @return 0 on success, !0 on error.
+ */
+static int __init
+claw_init(void)
+{
+ int ret = 0;
+ printk(KERN_INFO "claw: starting driver "
+#ifdef MODULE
+ "module "
+#else
+ "compiled into kernel "
+#endif
+ " $Revision: 1.35 $ $Date: 2005/03/24 12:25:38 $ \n");
+
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "claw: %s() enter \n",__FUNCTION__);
+#endif
+ ret = claw_register_debug_facility();
+ if (ret) {
+ printk(KERN_WARNING "claw: %s() debug_register failed %d\n",
+ __FUNCTION__,ret);
+ return ret;
+ }
+ CLAW_DBF_TEXT(2,setup,"init_mod");
+ ret = register_cu3088_discipline(&claw_group_driver);
+ if (ret) {
+ claw_unregister_debug_facility();
+ printk(KERN_WARNING "claw; %s() cu3088 register failed %d\n",
+ __FUNCTION__,ret);
+ }
+#ifdef FUNCTRACE
+ printk(KERN_INFO "claw: %s() exit \n",__FUNCTION__);
+#endif
+ return ret;
+}
+
+module_init(claw_init);
+module_exit(claw_cleanup);
+
+
+
+/*--------------------------------------------------------------------*
+* End of File *
+*---------------------------------------------------------------------*/
+
+
diff --git a/drivers/s390/net/claw.h b/drivers/s390/net/claw.h
new file mode 100644
index 0000000000000..3df71970f6010
--- /dev/null
+++ b/drivers/s390/net/claw.h
@@ -0,0 +1,335 @@
+/*******************************************************
+* Define constants *
+* *
+********************************************************/
+#define VERSION_CLAW_H "$Revision: 1.6 $"
+/*-----------------------------------------------------*
+* CCW command codes for CLAW protocol *
+*------------------------------------------------------*/
+
+#define CCW_CLAW_CMD_WRITE 0x01 /* write - not including link */
+#define CCW_CLAW_CMD_READ 0x02 /* read */
+#define CCW_CLAW_CMD_NOP 0x03 /* NOP */
+#define CCW_CLAW_CMD_SENSE 0x04 /* Sense */
+#define CCW_CLAW_CMD_SIGNAL_SMOD 0x05 /* Signal Status Modifier */
+#define CCW_CLAW_CMD_TIC 0x08 /* TIC */
+#define CCW_CLAW_CMD_READHEADER 0x12 /* read header data */
+#define CCW_CLAW_CMD_READFF 0x22 /* read an FF */
+#define CCW_CLAW_CMD_SENSEID 0xe4 /* Sense ID */
+
+
+/*-----------------------------------------------------*
+* CLAW Unique constants *
+*------------------------------------------------------*/
+
+#define MORE_to_COME_FLAG 0x04 /* OR with write CCW in case of m-t-c */
+#define CLAW_IDLE 0x00 /* flag to indicate CLAW is idle */
+#define CLAW_BUSY 0xff /* flag to indicate CLAW is busy */
+#define CLAW_PENDING 0x00 /* flag to indicate i/o is pending */
+#define CLAW_COMPLETE 0xff /* flag to indicate i/o completed */
+
+/*-----------------------------------------------------*
+* CLAW control comand code *
+*------------------------------------------------------*/
+
+#define SYSTEM_VALIDATE_REQUEST 0x01 /* System Validate request */
+#define SYSTEM_VALIDATE_RESPONSE 0x02 /* System Validate response */
+#define CONNECTION_REQUEST 0x21 /* Connection request */
+#define CONNECTION_RESPONSE 0x22 /* Connection response */
+#define CONNECTION_CONFIRM 0x23 /* Connection confirm */
+#define DISCONNECT 0x24 /* Disconnect */
+#define CLAW_ERROR 0x41 /* CLAW error message */
+#define CLAW_VERSION_ID 2 /* CLAW version ID */
+
+/*-----------------------------------------------------*
+* CLAW adater sense bytes *
+*------------------------------------------------------*/
+
+#define CLAW_ADAPTER_SENSE_BYTE 0x41 /* Stop command issued to adapter */
+
+/*-----------------------------------------------------*
+* CLAW control command return codes *
+*------------------------------------------------------*/
+
+#define CLAW_RC_NAME_MISMATCH 166 /* names do not match */
+#define CLAW_RC_WRONG_VERSION 167 /* wrong CLAW version number */
+#define CLAW_RC_HOST_RCV_TOO_SMALL 180 /* Host maximum receive is */
+ /* less than Linux on zSeries*/
+ /* transmit size */
+
+/*-----------------------------------------------------*
+* CLAW Constants application name *
+*------------------------------------------------------*/
+
+#define HOST_APPL_NAME "TCPIP "
+#define WS_APPL_NAME_IP_LINK "TCPIP "
+#define WS_APPL_NAME_IP_NAME "IP "
+#define WS_APPL_NAME_API_LINK "API "
+#define WS_APPL_NAME_PACKED "PACKED "
+#define WS_NAME_NOT_DEF "NOT_DEF "
+#define PACKING_ASK 1
+#define PACK_SEND 2
+#define DO_PACKED 3
+
+#define MAX_ENVELOPE_SIZE 65536
+#define CLAW_DEFAULT_MTU_SIZE 4096
+#define DEF_PACK_BUFSIZE 32768
+#define READ 0
+#define WRITE 1
+
+#define TB_TX 0 /* sk buffer handling in process */
+#define TB_STOP 1 /* network device stop in process */
+#define TB_RETRY 2 /* retry in process */
+#define TB_NOBUFFER 3 /* no buffer on free queue */
+#define CLAW_MAX_LINK_ID 1
+#define CLAW_MAX_DEV 256 /* max claw devices */
+#define MAX_NAME_LEN 8 /* host name, adapter name length */
+#define CLAW_FRAME_SIZE 4096
+#define CLAW_ID_SIZE BUS_ID_SIZE+3
+
+/* state machine codes used in claw_irq_handler */
+
+#define CLAW_STOP 0
+#define CLAW_START_HALT_IO 1
+#define CLAW_START_SENSEID 2
+#define CLAW_START_READ 3
+#define CLAW_START_WRITE 4
+
+/*-----------------------------------------------------*
+* Lock flag *
+*------------------------------------------------------*/
+#define LOCK_YES 0
+#define LOCK_NO 1
+
+/*-----------------------------------------------------*
+* DBF Debug macros *
+*------------------------------------------------------*/
+#define CLAW_DBF_TEXT(level, name, text) \
+ do { \
+ debug_text_event(claw_dbf_##name, level, text); \
+ } while (0)
+
+#define CLAW_DBF_HEX(level,name,addr,len) \
+do { \
+ debug_event(claw_dbf_##name,level,(void*)(addr),len); \
+} while (0)
+
+#define CLAW_DBF_TEXT_(level,name,text...) \
+do { \
+ sprintf(debug_buffer, text); \
+ debug_text_event(claw_dbf_##name,level, debug_buffer);\
+} while (0)
+
+/*******************************************************
+* Define Control Blocks *
+* *
+********************************************************/
+
+/*------------------------------------------------------*/
+/* CLAW header */
+/*------------------------------------------------------*/
+
+struct clawh {
+ __u16 length; /* length of data read by preceding read CCW */
+ __u8 opcode; /* equivalent read CCW */
+ __u8 flag; /* flag of FF to indicate read was completed */
+};
+
+/*------------------------------------------------------*/
+/* CLAW Packing header 4 bytes */
+/*------------------------------------------------------*/
+struct clawph {
+ __u16 len; /* Length of Packed Data Area */
+ __u8 flag; /* Reserved not used */
+ __u8 link_num; /* Link ID */
+};
+
+/*------------------------------------------------------*/
+/* CLAW Ending struct ccwbk */
+/*------------------------------------------------------*/
+struct endccw {
+ __u32 real; /* real address of this block */
+ __u8 write1; /* write 1 is active */
+ __u8 read1; /* read 1 is active */
+ __u16 reserved; /* reserved for future use */
+ struct ccw1 write1_nop1;
+ struct ccw1 write1_nop2;
+ struct ccw1 write2_nop1;
+ struct ccw1 write2_nop2;
+ struct ccw1 read1_nop1;
+ struct ccw1 read1_nop2;
+ struct ccw1 read2_nop1;
+ struct ccw1 read2_nop2;
+};
+
+/*------------------------------------------------------*/
+/* CLAW struct ccwbk */
+/*------------------------------------------------------*/
+struct ccwbk {
+ void *next; /* pointer to next ccw block */
+ __u32 real; /* real address of this ccw */
+ void *p_buffer; /* virtual address of data */
+ struct clawh header; /* claw header */
+ struct ccw1 write; /* write CCW */
+ struct ccw1 w_read_FF; /* read FF */
+ struct ccw1 w_TIC_1; /* TIC */
+ struct ccw1 read; /* read CCW */
+ struct ccw1 read_h; /* read header */
+ struct ccw1 signal; /* signal SMOD */
+ struct ccw1 r_TIC_1; /* TIC1 */
+ struct ccw1 r_read_FF; /* read FF */
+ struct ccw1 r_TIC_2; /* TIC2 */
+};
+
+/*------------------------------------------------------*/
+/* CLAW control block */
+/*------------------------------------------------------*/
+struct clawctl {
+ __u8 command; /* control command */
+ __u8 version; /* CLAW protocol version */
+ __u8 linkid; /* link ID */
+ __u8 correlator; /* correlator */
+ __u8 rc; /* return code */
+ __u8 reserved1; /* reserved */
+ __u8 reserved2; /* reserved */
+ __u8 reserved3; /* reserved */
+ __u8 data[24]; /* command specific fields */
+};
+
+/*------------------------------------------------------*/
+/* Data for SYSTEMVALIDATE command */
+/*------------------------------------------------------*/
+struct sysval {
+ char WS_name[8]; /* Workstation System name */
+ char host_name[8]; /* Host system name */
+ __u16 read_frame_size; /* read frame size */
+ __u16 write_frame_size; /* write frame size */
+ __u8 reserved[4]; /* reserved */
+};
+
+/*------------------------------------------------------*/
+/* Data for Connect command */
+/*------------------------------------------------------*/
+struct conncmd {
+ char WS_name[8]; /* Workstation application name */
+ char host_name[8]; /* Host application name */
+ __u16 reserved1[2]; /* read frame size */
+ __u8 reserved2[4]; /* reserved */
+};
+
+/*------------------------------------------------------*/
+/* Data for CLAW error */
+/*------------------------------------------------------*/
+struct clawwerror {
+ char reserved1[8]; /* reserved */
+ char reserved2[8]; /* reserved */
+ char reserved3[8]; /* reserved */
+};
+
+/*------------------------------------------------------*/
+/* Data buffer for CLAW */
+/*------------------------------------------------------*/
+struct clawbuf {
+ char buffer[MAX_ENVELOPE_SIZE]; /* data buffer */
+};
+
+/*------------------------------------------------------*/
+/* Channel control block for read and write channel */
+/*------------------------------------------------------*/
+
+struct chbk {
+ unsigned int devno;
+ int irq;
+ char id[CLAW_ID_SIZE];
+ __u32 IO_active;
+ __u8 claw_state;
+ struct irb *irb;
+ struct ccw_device *cdev; /* pointer to the channel device */
+ struct net_device *ndev;
+ wait_queue_head_t wait;
+ struct tasklet_struct tasklet;
+ struct timer_list timer;
+ unsigned long flag_a; /* atomic flags */
+#define CLAW_BH_ACTIVE 0
+ unsigned long flag_b; /* atomic flags */
+#define CLAW_WRITE_ACTIVE 0
+ __u8 last_dstat;
+ __u8 flag;
+ struct sk_buff_head collect_queue;
+ spinlock_t collect_lock;
+#define CLAW_WRITE 0x02 /* - Set if this is a write channel */
+#define CLAW_READ 0x01 /* - Set if this is a read channel */
+#define CLAW_TIMER 0x80 /* - Set if timer made the wake_up */
+};
+
+/*--------------------------------------------------------------*
+* CLAW environment block *
+*---------------------------------------------------------------*/
+
+struct claw_env {
+ unsigned int devno[2]; /* device number */
+ char host_name[9]; /* Host name */
+ char adapter_name [9]; /* adapter name */
+ char api_type[9]; /* TCPIP, API or PACKED */
+ void *p_priv; /* privptr */
+ __u16 read_buffers; /* read buffer number */
+ __u16 write_buffers; /* write buffer number */
+ __u16 read_size; /* read buffer size */
+ __u16 write_size; /* write buffer size */
+ __u16 dev_id; /* device ident */
+ __u8 packing; /* are we packing? */
+ volatile __u8 queme_switch; /* gate for imed packing */
+ volatile unsigned long pk_delay; /* Delay for adaptive packing */
+ __u8 in_use; /* device active flag */
+ struct net_device *ndev; /* backward ptr to the net dev*/
+};
+
+/*--------------------------------------------------------------*
+* CLAW main control block *
+*---------------------------------------------------------------*/
+
+struct claw_privbk {
+ void *p_buff_ccw;
+ __u32 p_buff_ccw_num;
+ void *p_buff_read;
+ __u32 p_buff_read_num;
+ __u32 p_buff_pages_perread;
+ void *p_buff_write;
+ __u32 p_buff_write_num;
+ __u32 p_buff_pages_perwrite;
+ long active_link_ID; /* Active logical link ID */
+ struct ccwbk *p_write_free_chain; /* pointer to free ccw chain */
+ struct ccwbk *p_write_active_first; /* ptr to the first write ccw */
+ struct ccwbk *p_write_active_last; /* ptr to the last write ccw */
+ struct ccwbk *p_read_active_first; /* ptr to the first read ccw */
+ struct ccwbk *p_read_active_last; /* ptr to the last read ccw */
+ struct endccw *p_end_ccw; /*ptr to ending ccw */
+ struct ccwbk *p_claw_signal_blk; /* ptr to signal block */
+ __u32 write_free_count; /* number of free bufs for write */
+ struct net_device_stats stats; /* device status */
+ struct chbk channel[2]; /* Channel control blocks */
+ __u8 mtc_skipping;
+ int mtc_offset;
+ int mtc_logical_link;
+ void *p_mtc_envelope;
+ struct sk_buff *pk_skb; /* packing buffer */
+ int pk_cnt;
+ struct clawctl ctl_bk;
+ struct claw_env *p_env;
+ __u8 system_validate_comp;
+ __u8 release_pend;
+ __u8 checksum_received_ip_pkts;
+ __u8 buffs_alloc;
+ struct endccw end_ccw;
+ unsigned long tbusy;
+
+};
+
+
+/************************************************************/
+/* define global constants */
+/************************************************************/
+
+#define CCWBK_SIZE sizeof(struct ccwbk)
+
+
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index 2ec865e8c07a6..a341041a6cf77 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -24,7 +24,7 @@
#include "qeth_mpc.h"
-#define VERSION_QETH_H "$Revision: 1.132 $"
+#define VERSION_QETH_H "$Revision: 1.135 $"
#ifdef CONFIG_QETH_IPV6
#define QETH_VERSION_IPV6 ":IPv6"
@@ -68,7 +68,8 @@
#define QETH_DBF_TRACE_LEN 8
#define QETH_DBF_TRACE_INDEX 2
#define QETH_DBF_TRACE_NR_AREAS 2
-#define QETH_DBF_TRACE_LEVEL 5
+#define QETH_DBF_TRACE_LEVEL 3
+extern debug_info_t *qeth_dbf_trace;
#define QETH_DBF_SENSE_NAME "qeth_sense"
#define QETH_DBF_SENSE_LEN 64
@@ -206,6 +207,11 @@ struct qeth_perf_stats {
__u64 outbound_do_qdio_start_time;
unsigned int outbound_do_qdio_cnt;
unsigned int outbound_do_qdio_time;
+ /* eddp data */
+ unsigned int large_send_bytes;
+ unsigned int large_send_cnt;
+ unsigned int sg_skbs_sent;
+ unsigned int sg_frags_sent;
};
#endif /* CONFIG_QETH_PERF_STATS */
@@ -334,8 +340,8 @@ qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func)
struct qeth_hdr_layer3 {
__u8 id;
__u8 flags;
- __u16 inbound_checksum;
- __u32 token;
+ __u16 inbound_checksum; /*TSO:__u16 seqno */
+ __u32 token; /*TSO: __u32 reserved */
__u16 length;
__u8 vlan_prio;
__u8 ext_flags;
@@ -386,6 +392,7 @@ enum qeth_layer2_frame_flags {
enum qeth_header_ids {
QETH_HEADER_TYPE_LAYER3 = 0x01,
QETH_HEADER_TYPE_LAYER2 = 0x02,
+ QETH_HEADER_TYPE_TSO = 0x03,
};
/* flags for qeth_hdr.ext_flags */
#define QETH_HDR_EXT_VLAN_FRAME 0x01
@@ -394,6 +401,7 @@ enum qeth_header_ids {
#define QETH_HDR_EXT_SRC_MAC_ADDR 0x08
#define QETH_HDR_EXT_CSUM_HDR_REQ 0x10
#define QETH_HDR_EXT_CSUM_TRANSP_REQ 0x20
+#define QETH_HDR_EXT_UDP_TSO 0x40 /*bit off for TCP*/
static inline int
qeth_is_last_sbale(struct qdio_buffer_element *sbale)
@@ -448,11 +456,19 @@ struct qeth_qdio_q {
volatile int next_buf_to_init;
} __attribute__ ((aligned(256)));
+/* possible types of qeth large_send support */
+enum qeth_large_send_types {
+ QETH_LARGE_SEND_NO,
+ QETH_LARGE_SEND_EDDP,
+ QETH_LARGE_SEND_TSO,
+};
+
struct qeth_qdio_out_buffer {
struct qdio_buffer *buffer;
atomic_t state;
volatile int next_element_to_fill;
struct sk_buff_head skb_list;
+ struct list_head ctx_list;
};
struct qeth_card;
@@ -668,6 +684,14 @@ struct qeth_reply {
#define QETH_BROADCAST_WITH_ECHO 1
#define QETH_BROADCAST_WITHOUT_ECHO 2
+struct qeth_card_blkt {
+ int time_total;
+ int inter_packet;
+ int inter_packet_jumbo;
+};
+
+
+
struct qeth_card_info {
unsigned short unit_addr2;
unsigned short cula;
@@ -686,6 +710,7 @@ struct qeth_card_info {
int max_mtu;
int broadcast_capable;
int unique_id;
+ struct qeth_card_blkt blkt;
__u32 csum_mask;
};
@@ -704,6 +729,7 @@ struct qeth_card_options {
int add_hhlen;
int fake_ll;
int layer2;
+ enum qeth_large_send_types large_send;
};
/*
@@ -790,6 +816,57 @@ qeth_get_ipa_adp_type(enum qeth_link_types link_type)
}
inline static int
+qeth_realloc_headroom(struct qeth_card *card, struct sk_buff **skb, int size)
+{
+ struct sk_buff *new_skb = NULL;
+
+ if (skb_headroom(*skb) < size){
+ new_skb = skb_realloc_headroom(*skb, size);
+ if (!new_skb) {
+ PRINT_ERR("qeth_prepare_skb: could "
+ "not realloc headroom for qeth_hdr "
+ "on interface %s", QETH_CARD_IFNAME(card));
+ return -ENOMEM;
+ }
+ *skb = new_skb;
+ }
+ return 0;
+}
+static inline struct sk_buff *
+qeth_pskb_unshare(struct sk_buff *skb, int pri)
+{
+ struct sk_buff *nskb;
+ if (!skb_cloned(skb))
+ return skb;
+ nskb = skb_copy(skb, pri);
+ kfree_skb(skb); /* free our shared copy */
+ return nskb;
+}
+
+
+inline static void *
+qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size)
+{
+ void *hdr;
+
+ hdr = (void *) skb_push(*skb, size);
+ /*
+ * sanity check, the Linux memory allocation scheme should
+ * never present us cases like this one (the qdio header size plus
+ * the first 40 bytes of the paket cross a 4k boundary)
+ */
+ if ((((unsigned long) hdr) & (~(PAGE_SIZE - 1))) !=
+ (((unsigned long) hdr + size +
+ QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) {
+ PRINT_ERR("qeth_prepare_skb: misaligned "
+ "packet on interface %s. Discarded.",
+ QETH_CARD_IFNAME(card));
+ return NULL;
+ }
+ return hdr;
+}
+
+inline static int
qeth_get_hlen(__u8 link_type)
{
#ifdef CONFIG_QETH_IPV6
@@ -830,17 +907,6 @@ qeth_get_netdev_flags(struct qeth_card *card)
#endif
}
}
-static inline struct sk_buff *
-qeth_pskb_unshare(struct sk_buff *skb, int pri)
-{
- struct sk_buff *nskb;
- if (!skb_cloned(skb))
- return skb;
- nskb = skb_copy(skb, pri);
- kfree_skb(skb); /* free our shared copy */
- return nskb;
-}
-
inline static int
qeth_get_initial_mtu_for_card(struct qeth_card * card)
@@ -1084,4 +1150,13 @@ qeth_schedule_recovery(struct qeth_card *);
extern int
qeth_realloc_buffer_pool(struct qeth_card *, int);
+extern int
+qeth_set_large_send(struct qeth_card *);
+
+extern void
+qeth_fill_header(struct qeth_card *, struct qeth_hdr *,
+ struct sk_buff *, int, int);
+extern void
+qeth_flush_buffers(struct qeth_qdio_out_q *, int, int, int);
+
#endif /* __QETH_H__ */
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
new file mode 100644
index 0000000000000..7ee1c06ed68a8
--- /dev/null
+++ b/drivers/s390/net/qeth_eddp.c
@@ -0,0 +1,643 @@
+/*
+ *
+ * linux/drivers/s390/net/qeth_eddp.c ($Revision: 1.11 $)
+ *
+ * Enhanced Device Driver Packing (EDDP) support for the qeth driver.
+ *
+ * Copyright 2004 IBM Corporation
+ *
+ * Author(s): Thomas Spatzier <tspat@de.ibm.com>
+ *
+ * $Revision: 1.11 $ $Date: 2005/03/24 09:04:18 $
+ *
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/ip.h>
+#include <linux/inetdevice.h>
+#include <linux/netdevice.h>
+#include <linux/kernel.h>
+#include <linux/tcp.h>
+#include <net/tcp.h>
+#include <linux/skbuff.h>
+
+#include <net/ip.h>
+
+#include "qeth.h"
+#include "qeth_mpc.h"
+#include "qeth_eddp.h"
+
+int
+qeth_eddp_check_buffers_for_context(struct qeth_qdio_out_q *queue,
+ struct qeth_eddp_context *ctx)
+{
+ int index = queue->next_buf_to_fill;
+ int elements_needed = ctx->num_elements;
+ int elements_in_buffer;
+ int skbs_in_buffer;
+ int buffers_needed = 0;
+
+ QETH_DBF_TEXT(trace, 5, "eddpcbfc");
+ while(elements_needed > 0) {
+ buffers_needed++;
+ if (atomic_read(&queue->bufs[index].state) !=
+ QETH_QDIO_BUF_EMPTY)
+ return -EBUSY;
+
+ elements_in_buffer = QETH_MAX_BUFFER_ELEMENTS(queue->card) -
+ queue->bufs[index].next_element_to_fill;
+ skbs_in_buffer = elements_in_buffer / ctx->elements_per_skb;
+ elements_needed -= skbs_in_buffer * ctx->elements_per_skb;
+ index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q;
+ }
+ return buffers_needed;
+}
+
+static inline void
+qeth_eddp_free_context(struct qeth_eddp_context *ctx)
+{
+ int i;
+
+ QETH_DBF_TEXT(trace, 5, "eddpfctx");
+ for (i = 0; i < ctx->num_pages; ++i)
+ free_page((unsigned long)ctx->pages[i]);
+ kfree(ctx->pages);
+ if (ctx->elements != NULL)
+ kfree(ctx->elements);
+ kfree(ctx);
+}
+
+
+static inline void
+qeth_eddp_get_context(struct qeth_eddp_context *ctx)
+{
+ atomic_inc(&ctx->refcnt);
+}
+
+void
+qeth_eddp_put_context(struct qeth_eddp_context *ctx)
+{
+ if (atomic_dec_return(&ctx->refcnt) == 0)
+ qeth_eddp_free_context(ctx);
+}
+
+void
+qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *buf)
+{
+ struct qeth_eddp_context_reference *ref;
+
+ QETH_DBF_TEXT(trace, 6, "eddprctx");
+ while (!list_empty(&buf->ctx_list)){
+ ref = list_entry(buf->ctx_list.next,
+ struct qeth_eddp_context_reference, list);
+ qeth_eddp_put_context(ref->ctx);
+ list_del(&ref->list);
+ kfree(ref);
+ }
+}
+
+static inline int
+qeth_eddp_buf_ref_context(struct qeth_qdio_out_buffer *buf,
+ struct qeth_eddp_context *ctx)
+{
+ struct qeth_eddp_context_reference *ref;
+
+ QETH_DBF_TEXT(trace, 6, "eddprfcx");
+ ref = kmalloc(sizeof(struct qeth_eddp_context_reference), GFP_ATOMIC);
+ if (ref == NULL)
+ return -ENOMEM;
+ qeth_eddp_get_context(ctx);
+ ref->ctx = ctx;
+ list_add_tail(&ref->list, &buf->ctx_list);
+ return 0;
+}
+
+int
+qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
+ struct qeth_eddp_context *ctx,
+ int index)
+{
+ struct qeth_qdio_out_buffer *buf = NULL;
+ struct qdio_buffer *buffer;
+ int elements = ctx->num_elements;
+ int element = 0;
+ int flush_cnt = 0;
+ int must_refcnt = 1;
+ int i;
+
+ QETH_DBF_TEXT(trace, 5, "eddpfibu");
+ while (elements > 0) {
+ buf = &queue->bufs[index];
+ if (atomic_read(&buf->state) != QETH_QDIO_BUF_EMPTY){
+ /* normally this should not happen since we checked for
+ * available elements in qeth_check_elements_for_context
+ */
+ if (element == 0)
+ return -EBUSY;
+ else {
+ PRINT_WARN("could only partially fill eddp "
+ "buffer!\n");
+ goto out;
+ }
+ }
+ /* check if the whole next skb fits into current buffer */
+ if ((QETH_MAX_BUFFER_ELEMENTS(queue->card) -
+ buf->next_element_to_fill)
+ < ctx->elements_per_skb){
+ /* no -> go to next buffer */
+ atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
+ index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q;
+ flush_cnt++;
+ /* new buffer, so we have to add ctx to buffer'ctx_list
+ * and increment ctx's refcnt */
+ must_refcnt = 1;
+ continue;
+ }
+ if (must_refcnt){
+ must_refcnt = 0;
+ if (qeth_eddp_buf_ref_context(buf, ctx)){
+ PRINT_WARN("no memory to create eddp context "
+ "reference\n");
+ goto out_check;
+ }
+ }
+ buffer = buf->buffer;
+ /* fill one skb into buffer */
+ for (i = 0; i < ctx->elements_per_skb; ++i){
+ buffer->element[buf->next_element_to_fill].addr =
+ ctx->elements[element].addr;
+ buffer->element[buf->next_element_to_fill].length =
+ ctx->elements[element].length;
+ buffer->element[buf->next_element_to_fill].flags =
+ ctx->elements[element].flags;
+ buf->next_element_to_fill++;
+ element++;
+ elements--;
+ }
+ }
+out_check:
+ if (!queue->do_pack) {
+ QETH_DBF_TEXT(trace, 6, "fillbfnp");
+ /* set state to PRIMED -> will be flushed */
+ if (buf->next_element_to_fill > 0){
+ atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
+ flush_cnt++;
+ }
+ } else {
+#ifdef CONFIG_QETH_PERF_STATS
+ queue->card->perf_stats.skbs_sent_pack++;
+#endif
+ QETH_DBF_TEXT(trace, 6, "fillbfpa");
+ if (buf->next_element_to_fill >=
+ QETH_MAX_BUFFER_ELEMENTS(queue->card)) {
+ /*
+ * packed buffer if full -> set state PRIMED
+ * -> will be flushed
+ */
+ atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
+ flush_cnt++;
+ }
+ }
+out:
+ return flush_cnt;
+}
+
+static inline int
+qeth_get_skb_data_len(struct sk_buff *skb)
+{
+ int len = skb->len;
+ int i;
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i)
+ len -= skb_shinfo(skb)->frags[i].size;
+ return len;
+}
+
+static inline void
+qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx,
+ struct qeth_eddp_data *eddp)
+{
+ u8 *page;
+ int page_remainder;
+ int page_offset;
+ int hdr_len;
+ struct qeth_eddp_element *element;
+
+ QETH_DBF_TEXT(trace, 5, "eddpcrsh");
+ page = ctx->pages[ctx->offset >> PAGE_SHIFT];
+ page_offset = ctx->offset % PAGE_SIZE;
+ element = &ctx->elements[ctx->num_elements];
+ hdr_len = eddp->nhl + eddp->thl;
+ /* FIXME: layer2 and VLAN !!! */
+ if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2)
+ hdr_len += ETH_HLEN;
+ if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q))
+ hdr_len += VLAN_HLEN;
+ /* does complete header fit in current page ? */
+ page_remainder = PAGE_SIZE - page_offset;
+ if (page_remainder < (sizeof(struct qeth_hdr) + hdr_len)){
+ /* no -> go to start of next page */
+ ctx->offset += page_remainder;
+ page = ctx->pages[ctx->offset >> PAGE_SHIFT];
+ page_offset = 0;
+ }
+ memcpy(page + page_offset, &eddp->qh, sizeof(struct qeth_hdr));
+ element->addr = page + page_offset;
+ element->length = sizeof(struct qeth_hdr);
+ ctx->offset += sizeof(struct qeth_hdr);
+ page_offset += sizeof(struct qeth_hdr);
+ /* add mac header (?) */
+ if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2){
+ memcpy(page + page_offset, &eddp->mac, ETH_HLEN);
+ element->length += ETH_HLEN;
+ ctx->offset += ETH_HLEN;
+ page_offset += ETH_HLEN;
+ }
+ /* add VLAN tag */
+ if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)){
+ memcpy(page + page_offset, &eddp->vlan, VLAN_HLEN);
+ element->length += VLAN_HLEN;
+ ctx->offset += VLAN_HLEN;
+ page_offset += VLAN_HLEN;
+ }
+ /* add network header */
+ memcpy(page + page_offset, (u8 *)&eddp->nh, eddp->nhl);
+ element->length += eddp->nhl;
+ eddp->nh_in_ctx = page + page_offset;
+ ctx->offset += eddp->nhl;
+ page_offset += eddp->nhl;
+ /* add transport header */
+ memcpy(page + page_offset, (u8 *)&eddp->th, eddp->thl);
+ element->length += eddp->thl;
+ eddp->th_in_ctx = page + page_offset;
+ ctx->offset += eddp->thl;
+}
+
+static inline void
+qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
+ u32 *hcsum)
+{
+ struct skb_frag_struct *frag;
+ int left_in_frag;
+ int copy_len;
+ u8 *src;
+
+ QETH_DBF_TEXT(trace, 5, "eddpcdtc");
+ if (skb_shinfo(eddp->skb)->nr_frags == 0) {
+ memcpy(dst, eddp->skb->data + eddp->skb_offset, len);
+ *hcsum = csum_partial(eddp->skb->data + eddp->skb_offset, len,
+ *hcsum);
+ eddp->skb_offset += len;
+ } else {
+ while (len > 0) {
+ if (eddp->frag < 0) {
+ /* we're in skb->data */
+ left_in_frag = qeth_get_skb_data_len(eddp->skb)
+ - eddp->skb_offset;
+ src = eddp->skb->data + eddp->skb_offset;
+ } else {
+ frag = &skb_shinfo(eddp->skb)->
+ frags[eddp->frag];
+ left_in_frag = frag->size - eddp->frag_offset;
+ src = (u8 *)(
+ (page_to_pfn(frag->page) << PAGE_SHIFT)+
+ frag->page_offset + eddp->frag_offset);
+ }
+ if (left_in_frag <= 0) {
+ eddp->frag++;
+ eddp->frag_offset = 0;
+ continue;
+ }
+ copy_len = min(left_in_frag, len);
+ memcpy(dst, src, copy_len);
+ *hcsum = csum_partial(src, copy_len, *hcsum);
+ dst += copy_len;
+ eddp->frag_offset += copy_len;
+ eddp->skb_offset += copy_len;
+ len -= copy_len;
+ }
+ }
+}
+
+static inline void
+qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx,
+ struct qeth_eddp_data *eddp, int data_len,
+ u32 hcsum)
+{
+ u8 *page;
+ int page_remainder;
+ int page_offset;
+ struct qeth_eddp_element *element;
+ int first_lap = 1;
+
+ QETH_DBF_TEXT(trace, 5, "eddpcsdt");
+ page = ctx->pages[ctx->offset >> PAGE_SHIFT];
+ page_offset = ctx->offset % PAGE_SIZE;
+ element = &ctx->elements[ctx->num_elements];
+ while (data_len){
+ page_remainder = PAGE_SIZE - page_offset;
+ if (page_remainder < data_len){
+ qeth_eddp_copy_data_tcp(page + page_offset, eddp,
+ page_remainder, &hcsum);
+ element->length += page_remainder;
+ if (first_lap)
+ element->flags = SBAL_FLAGS_FIRST_FRAG;
+ else
+ element->flags = SBAL_FLAGS_MIDDLE_FRAG;
+ ctx->num_elements++;
+ element++;
+ data_len -= page_remainder;
+ ctx->offset += page_remainder;
+ page = ctx->pages[ctx->offset >> PAGE_SHIFT];
+ page_offset = 0;
+ element->addr = page + page_offset;
+ } else {
+ qeth_eddp_copy_data_tcp(page + page_offset, eddp,
+ data_len, &hcsum);
+ element->length += data_len;
+ if (!first_lap)
+ element->flags = SBAL_FLAGS_LAST_FRAG;
+ ctx->num_elements++;
+ ctx->offset += data_len;
+ data_len = 0;
+ }
+ first_lap = 0;
+ }
+ ((struct tcphdr *)eddp->th_in_ctx)->check = csum_fold(hcsum);
+}
+
+static inline u32
+qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len)
+{
+ u32 phcsum; /* pseudo header checksum */
+
+ QETH_DBF_TEXT(trace, 5, "eddpckt4");
+ eddp->th.tcp.h.check = 0;
+ /* compute pseudo header checksum */
+ phcsum = csum_tcpudp_nofold(eddp->nh.ip4.h.saddr, eddp->nh.ip4.h.daddr,
+ eddp->thl + data_len, IPPROTO_TCP, 0);
+ /* compute checksum of tcp header */
+ return csum_partial((u8 *)&eddp->th, eddp->thl, phcsum);
+}
+
+static inline u32
+qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len)
+{
+ u32 proto;
+ u32 phcsum; /* pseudo header checksum */
+
+ QETH_DBF_TEXT(trace, 5, "eddpckt6");
+ eddp->th.tcp.h.check = 0;
+ /* compute pseudo header checksum */
+ phcsum = csum_partial((u8 *)&eddp->nh.ip6.h.saddr,
+ sizeof(struct in6_addr), 0);
+ phcsum = csum_partial((u8 *)&eddp->nh.ip6.h.daddr,
+ sizeof(struct in6_addr), phcsum);
+ proto = htonl(IPPROTO_TCP);
+ phcsum = csum_partial((u8 *)&proto, sizeof(u32), phcsum);
+ return phcsum;
+}
+
+static inline struct qeth_eddp_data *
+qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl)
+{
+ struct qeth_eddp_data *eddp;
+
+ QETH_DBF_TEXT(trace, 5, "eddpcrda");
+ eddp = kmalloc(sizeof(struct qeth_eddp_data), GFP_ATOMIC);
+ if (eddp){
+ memset(eddp, 0, sizeof(struct qeth_eddp_data));
+ eddp->nhl = nhl;
+ eddp->thl = thl;
+ memcpy(&eddp->qh, qh, sizeof(struct qeth_hdr));
+ memcpy(&eddp->nh, nh, nhl);
+ memcpy(&eddp->th, th, thl);
+ eddp->frag = -1; /* initially we're in skb->data */
+ }
+ return eddp;
+}
+
+static inline void
+__qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
+ struct qeth_eddp_data *eddp)
+{
+ struct tcphdr *tcph;
+ int data_len;
+ u32 hcsum;
+
+ QETH_DBF_TEXT(trace, 5, "eddpftcp");
+ eddp->skb_offset = sizeof(struct qeth_hdr) + eddp->nhl + eddp->thl;
+ tcph = eddp->skb->h.th;
+ while (eddp->skb_offset < eddp->skb->len) {
+ data_len = min((int)skb_shinfo(eddp->skb)->tso_size,
+ (int)(eddp->skb->len - eddp->skb_offset));
+ /* prepare qdio hdr */
+ if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2){
+ eddp->qh.hdr.l2.pkt_length = data_len + ETH_HLEN +
+ eddp->nhl + eddp->thl -
+ sizeof(struct qeth_hdr);
+#ifdef CONFIG_QETH_VLAN
+ if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q))
+ eddp->qh.hdr.l2.pkt_length += VLAN_HLEN;
+#endif /* CONFIG_QETH_VLAN */
+ } else
+ eddp->qh.hdr.l3.length = data_len + eddp->nhl +
+ eddp->thl;
+ /* prepare ip hdr */
+ if (eddp->skb->protocol == ETH_P_IP){
+ eddp->nh.ip4.h.tot_len = data_len + eddp->nhl +
+ eddp->thl;
+ eddp->nh.ip4.h.check = 0;
+ eddp->nh.ip4.h.check =
+ ip_fast_csum((u8 *)&eddp->nh.ip4.h,
+ eddp->nh.ip4.h.ihl);
+ } else
+ eddp->nh.ip6.h.payload_len = data_len + eddp->thl;
+ /* prepare tcp hdr */
+ if (data_len == (eddp->skb->len - eddp->skb_offset)){
+ /* last segment -> set FIN and PSH flags */
+ eddp->th.tcp.h.fin = tcph->fin;
+ eddp->th.tcp.h.psh = tcph->psh;
+ }
+ if (eddp->skb->protocol == ETH_P_IP)
+ hcsum = qeth_eddp_check_tcp4_hdr(eddp, data_len);
+ else
+ hcsum = qeth_eddp_check_tcp6_hdr(eddp, data_len);
+ /* fill the next segment into the context */
+ qeth_eddp_create_segment_hdrs(ctx, eddp);
+ qeth_eddp_create_segment_data_tcp(ctx, eddp, data_len, hcsum);
+ if (eddp->skb_offset >= eddp->skb->len)
+ break;
+ /* prepare headers for next round */
+ if (eddp->skb->protocol == ETH_P_IP)
+ eddp->nh.ip4.h.id++;
+ eddp->th.tcp.h.seq += data_len;
+ }
+}
+
+static inline int
+qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
+ struct sk_buff *skb, struct qeth_hdr *qhdr)
+{
+ struct qeth_eddp_data *eddp = NULL;
+
+ QETH_DBF_TEXT(trace, 5, "eddpficx");
+ /* create our segmentation headers and copy original headers */
+ if (skb->protocol == ETH_P_IP)
+ eddp = qeth_eddp_create_eddp_data(qhdr, (u8 *)skb->nh.iph,
+ skb->nh.iph->ihl*4,
+ (u8 *)skb->h.th, skb->h.th->doff*4);
+ else
+ eddp = qeth_eddp_create_eddp_data(qhdr, (u8 *)skb->nh.ipv6h,
+ sizeof(struct ipv6hdr),
+ (u8 *)skb->h.th, skb->h.th->doff*4);
+
+ if (eddp == NULL) {
+ QETH_DBF_TEXT(trace, 2, "eddpfcnm");
+ return -ENOMEM;
+ }
+ if (qhdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) {
+ memcpy(&eddp->mac, eth_hdr(skb), ETH_HLEN);
+#ifdef CONFIG_QETH_VLAN
+ if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) {
+ eddp->vlan[0] = __constant_htons(skb->protocol);
+ eddp->vlan[1] = htons(vlan_tx_tag_get(skb));
+ }
+#endif /* CONFIG_QETH_VLAN */
+ }
+ /* the next flags will only be set on the last segment */
+ eddp->th.tcp.h.fin = 0;
+ eddp->th.tcp.h.psh = 0;
+ eddp->skb = skb;
+ /* begin segmentation and fill context */
+ __qeth_eddp_fill_context_tcp(ctx, eddp);
+ kfree(eddp);
+ return 0;
+}
+
+static inline void
+qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
+ int hdr_len)
+{
+ int skbs_per_page;
+
+ QETH_DBF_TEXT(trace, 5, "eddpcanp");
+ /* can we put multiple skbs in one page? */
+ skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->tso_size + hdr_len);
+ if (skbs_per_page > 1){
+ ctx->num_pages = (skb_shinfo(skb)->tso_segs + 1) /
+ skbs_per_page + 1;
+ ctx->elements_per_skb = 1;
+ } else {
+ /* no -> how many elements per skb? */
+ ctx->elements_per_skb = (skb_shinfo(skb)->tso_size + hdr_len +
+ PAGE_SIZE) >> PAGE_SHIFT;
+ ctx->num_pages = ctx->elements_per_skb *
+ (skb_shinfo(skb)->tso_segs + 1);
+ }
+ ctx->num_elements = ctx->elements_per_skb *
+ (skb_shinfo(skb)->tso_segs + 1);
+}
+
+static inline struct qeth_eddp_context *
+qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb,
+ int hdr_len)
+{
+ struct qeth_eddp_context *ctx = NULL;
+ u8 *addr;
+ int i;
+
+ QETH_DBF_TEXT(trace, 5, "creddpcg");
+ /* create the context and allocate pages */
+ ctx = kmalloc(sizeof(struct qeth_eddp_context), GFP_ATOMIC);
+ if (ctx == NULL){
+ QETH_DBF_TEXT(trace, 2, "ceddpcn1");
+ return NULL;
+ }
+ memset(ctx, 0, sizeof(struct qeth_eddp_context));
+ ctx->type = QETH_LARGE_SEND_EDDP;
+ qeth_eddp_calc_num_pages(ctx, skb, hdr_len);
+ if (ctx->elements_per_skb > QETH_MAX_BUFFER_ELEMENTS(card)){
+ QETH_DBF_TEXT(trace, 2, "ceddpcis");
+ kfree(ctx);
+ return NULL;
+ }
+ ctx->pages = kmalloc(ctx->num_pages * sizeof(u8 *), GFP_ATOMIC);
+ if (ctx->pages == NULL){
+ QETH_DBF_TEXT(trace, 2, "ceddpcn2");
+ kfree(ctx);
+ return NULL;
+ }
+ memset(ctx->pages, 0, ctx->num_pages * sizeof(u8 *));
+ for (i = 0; i < ctx->num_pages; ++i){
+ addr = (u8 *)__get_free_page(GFP_ATOMIC);
+ if (addr == NULL){
+ QETH_DBF_TEXT(trace, 2, "ceddpcn3");
+ ctx->num_pages = i;
+ qeth_eddp_free_context(ctx);
+ return NULL;
+ }
+ memset(addr, 0, PAGE_SIZE);
+ ctx->pages[i] = addr;
+ }
+ ctx->elements = kmalloc(ctx->num_elements *
+ sizeof(struct qeth_eddp_element), GFP_ATOMIC);
+ if (ctx->elements == NULL){
+ QETH_DBF_TEXT(trace, 2, "ceddpcn4");
+ qeth_eddp_free_context(ctx);
+ return NULL;
+ }
+ memset(ctx->elements, 0,
+ ctx->num_elements * sizeof(struct qeth_eddp_element));
+ /* reset num_elements; will be incremented again in fill_buffer to
+ * reflect number of actually used elements */
+ ctx->num_elements = 0;
+ return ctx;
+}
+
+static inline struct qeth_eddp_context *
+qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb,
+ struct qeth_hdr *qhdr)
+{
+ struct qeth_eddp_context *ctx = NULL;
+
+ QETH_DBF_TEXT(trace, 5, "creddpct");
+ if (skb->protocol == ETH_P_IP)
+ ctx = qeth_eddp_create_context_generic(card, skb,
+ sizeof(struct qeth_hdr) + skb->nh.iph->ihl*4 +
+ skb->h.th->doff*4);
+ else if (skb->protocol == ETH_P_IPV6)
+ ctx = qeth_eddp_create_context_generic(card, skb,
+ sizeof(struct qeth_hdr) + sizeof(struct ipv6hdr) +
+ skb->h.th->doff*4);
+ else
+ QETH_DBF_TEXT(trace, 2, "cetcpinv");
+
+ if (ctx == NULL) {
+ QETH_DBF_TEXT(trace, 2, "creddpnl");
+ return NULL;
+ }
+ if (qeth_eddp_fill_context_tcp(ctx, skb, qhdr)){
+ QETH_DBF_TEXT(trace, 2, "ceddptfe");
+ qeth_eddp_free_context(ctx);
+ return NULL;
+ }
+ atomic_set(&ctx->refcnt, 1);
+ return ctx;
+}
+
+struct qeth_eddp_context *
+qeth_eddp_create_context(struct qeth_card *card, struct sk_buff *skb,
+ struct qeth_hdr *qhdr)
+{
+ QETH_DBF_TEXT(trace, 5, "creddpc");
+ switch (skb->sk->sk_protocol){
+ case IPPROTO_TCP:
+ return qeth_eddp_create_context_tcp(card, skb, qhdr);
+ default:
+ QETH_DBF_TEXT(trace, 2, "eddpinvp");
+ }
+ return NULL;
+}
+
+
diff --git a/drivers/s390/net/qeth_eddp.h b/drivers/s390/net/qeth_eddp.h
new file mode 100644
index 0000000000000..e1b51860bc57b
--- /dev/null
+++ b/drivers/s390/net/qeth_eddp.h
@@ -0,0 +1,85 @@
+/*
+ * linux/drivers/s390/net/qeth_eddp.c ($Revision: 1.5 $)
+ *
+ * Header file for qeth enhanced device driver pakcing.
+ *
+ * Copyright 2004 IBM Corporation
+ *
+ * Author(s): Thomas Spatzier <tspat@de.ibm.com>
+ *
+ * $Revision: 1.5 $ $Date: 2005/03/24 09:04:18 $
+ *
+ */
+#ifndef __QETH_EDDP_H__
+#define __QETH_EDDP_H__
+
+struct qeth_eddp_element {
+ u32 flags;
+ u32 length;
+ void *addr;
+};
+
+struct qeth_eddp_context {
+ atomic_t refcnt;
+ enum qeth_large_send_types type;
+ int num_pages; /* # of allocated pages */
+ u8 **pages; /* pointers to pages */
+ int offset; /* offset in ctx during creation */
+ int num_elements; /* # of required 'SBALEs' */
+ struct qeth_eddp_element *elements; /* array of 'SBALEs' */
+ int elements_per_skb; /* # of 'SBALEs' per skb **/
+};
+
+struct qeth_eddp_context_reference {
+ struct list_head list;
+ struct qeth_eddp_context *ctx;
+};
+
+extern struct qeth_eddp_context *
+qeth_eddp_create_context(struct qeth_card *,struct sk_buff *,struct qeth_hdr *);
+
+extern void
+qeth_eddp_put_context(struct qeth_eddp_context *);
+
+extern int
+qeth_eddp_fill_buffer(struct qeth_qdio_out_q *,struct qeth_eddp_context *,int);
+
+extern void
+qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *);
+
+extern int
+qeth_eddp_check_buffers_for_context(struct qeth_qdio_out_q *,
+ struct qeth_eddp_context *);
+/*
+ * Data used for fragmenting a IP packet.
+ */
+struct qeth_eddp_data {
+ struct qeth_hdr qh;
+ struct ethhdr mac;
+ u16 vlan[2];
+ union {
+ struct {
+ struct iphdr h;
+ u8 options[40];
+ } ip4;
+ struct {
+ struct ipv6hdr h;
+ } ip6;
+ } nh;
+ u8 nhl;
+ void *nh_in_ctx; /* address of nh within the ctx */
+ union {
+ struct {
+ struct tcphdr h;
+ u8 options[40];
+ } tcp;
+ } th;
+ u8 thl;
+ void *th_in_ctx; /* address of th within the ctx */
+ struct sk_buff *skb;
+ int skb_offset;
+ int frag;
+ int frag_offset;
+} __attribute__ ((packed));
+
+#endif /* __QETH_EDDP_H__ */
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index b6c576b5c6030..607b92542df6c 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -1,6 +1,6 @@
/*
*
- * linux/drivers/s390/net/qeth_main.c ($Revision: 1.203 $)
+ * linux/drivers/s390/net/qeth_main.c ($Revision: 1.206 $)
*
* Linux on zSeries OSA Express and HiperSockets support
*
@@ -12,7 +12,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and
* Thomas Spatzier <tspat@de.ibm.com>
*
- * $Revision: 1.203 $ $Date: 2005/03/02 15:53:57 $
+ * $Revision: 1.206 $ $Date: 2005/03/24 09:04:18 $
*
* 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
@@ -61,6 +61,7 @@ qeth_eyecatcher(void)
#include <linux/reboot.h>
#include <linux/mii.h>
#include <linux/rcupdate.h>
+#include <linux/ethtool.h>
#include <net/arp.h>
#include <net/ip.h>
@@ -76,8 +77,10 @@ qeth_eyecatcher(void)
#include "qeth.h"
#include "qeth_mpc.h"
#include "qeth_fs.h"
+#include "qeth_eddp.h"
+#include "qeth_tso.h"
-#define VERSION_QETH_C "$Revision: 1.203 $"
+#define VERSION_QETH_C "$Revision: 1.206 $"
static const char *version = "qeth S/390 OSA-Express driver";
/**
@@ -87,7 +90,7 @@ static debug_info_t *qeth_dbf_setup = NULL;
static debug_info_t *qeth_dbf_data = NULL;
static debug_info_t *qeth_dbf_misc = NULL;
static debug_info_t *qeth_dbf_control = NULL;
-static debug_info_t *qeth_dbf_trace = NULL;
+debug_info_t *qeth_dbf_trace = NULL;
static debug_info_t *qeth_dbf_sense = NULL;
static debug_info_t *qeth_dbf_qerr = NULL;
@@ -1071,6 +1074,35 @@ qeth_setup_card(struct qeth_card *card)
}
static int
+is_1920_device (struct qeth_card *card)
+{
+ int single_queue = 0;
+ struct ccw_device *ccwdev;
+ struct channelPath_dsc {
+ u8 flags;
+ u8 lsn;
+ u8 desc;
+ u8 chpid;
+ u8 swla;
+ u8 zeroes;
+ u8 chla;
+ u8 chpp;
+ } *chp_dsc;
+
+ QETH_DBF_TEXT(setup, 2, "chk_1920");
+
+ ccwdev = card->data.ccwdev;
+ chp_dsc = (struct channelPath_dsc *)ccw_device_get_chp_desc(ccwdev, 0);
+ if (chp_dsc != NULL) {
+ /* CHPP field bit 6 == 1 -> single queue */
+ single_queue = ((chp_dsc->chpp & 0x02) == 0x02);
+ kfree(chp_dsc);
+ }
+ QETH_DBF_TEXT_(setup, 2, "rc:%x", single_queue);
+ return single_queue;
+}
+
+static int
qeth_determine_card_type(struct qeth_card *card)
{
int i = 0;
@@ -1081,7 +1113,14 @@ qeth_determine_card_type(struct qeth_card *card)
if ((CARD_RDEV(card)->id.dev_type == known_devices[i][2]) &&
(CARD_RDEV(card)->id.dev_model == known_devices[i][3])) {
card->info.type = known_devices[i][4];
- card->qdio.no_out_queues = known_devices[i][8];
+ if (is_1920_device(card)) {
+ PRINT_INFO("Priority Queueing not able "
+ "due to hardware limitations!\n");
+ card->qdio.no_out_queues = 1;
+ card->qdio.default_out_queue = 0;
+ } else {
+ card->qdio.no_out_queues = known_devices[i][8];
+ }
card->info.is_multicast_different = known_devices[i][9];
return 0;
}
@@ -1112,6 +1151,10 @@ qeth_probe_device(struct ccwgroup_device *gdev)
QETH_DBF_TEXT_(setup, 2, "1err%d", -ENOMEM);
return -ENOMEM;
}
+ card->read.ccwdev = gdev->cdev[0];
+ card->write.ccwdev = gdev->cdev[1];
+ card->data.ccwdev = gdev->cdev[2];
+
if ((rc = qeth_setup_card(card))){
QETH_DBF_TEXT_(setup, 2, "2err%d", rc);
put_device(dev);
@@ -1130,9 +1173,6 @@ qeth_probe_device(struct ccwgroup_device *gdev)
qeth_free_card(card);
return rc;
}
- card->read.ccwdev = gdev->cdev[0];
- card->write.ccwdev = gdev->cdev[1];
- card->data.ccwdev = gdev->cdev[2];
if ((rc = qeth_determine_card_type(card))){
PRINT_WARN("%s: not a valid card type\n", __func__);
QETH_DBF_TEXT_(setup, 2, "3err%d", rc);
@@ -1711,7 +1751,7 @@ qeth_send_control_data_cb(struct qeth_channel *channel,
(unsigned long)iob);
}
if (cmd)
- reply->rc = (s16) cmd->hdr.return_code;
+ reply->rc = (u16) cmd->hdr.return_code;
else if (iob->rc)
reply->rc = iob->rc;
if (keep_reply) {
@@ -2424,14 +2464,15 @@ qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
if (buf->buffer->element[0].flags & 0x40)
atomic_dec(&queue->set_pci_flags_count);
+ while ((skb = skb_dequeue(&buf->skb_list))){
+ atomic_dec(&skb->users);
+ dev_kfree_skb_any(skb);
+ }
+ qeth_eddp_buf_release_contexts(buf);
for(i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i){
buf->buffer->element[i].length = 0;
buf->buffer->element[i].addr = NULL;
buf->buffer->element[i].flags = 0;
- while ((skb = skb_dequeue(&buf->skb_list))){
- atomic_dec(&skb->users);
- dev_kfree_skb_any(skb);
- }
}
buf->next_element_to_fill = 0;
atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY);
@@ -2581,7 +2622,7 @@ qeth_handle_send_error(struct qeth_card *card,
return QETH_SEND_ERROR_LINK_FAILURE;
}
-static inline void
+void
qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
int index, int count)
{
@@ -2622,9 +2663,6 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
atomic_inc(&queue->set_pci_flags_count);
buf->buffer->element[0].flags |= 0x40;
}
-#ifdef CONFIG_QETH_PERF_STATS
- queue->card->perf_stats.bufs_sent_pack++;
-#endif
}
}
@@ -2746,6 +2784,7 @@ qeth_check_outbound_queue(struct qeth_qdio_out_q *queue)
{
int index;
int flush_cnt = 0;
+ int q_was_packing = 0;
/*
* check if weed have to switch to non-packing mode or if
@@ -2760,20 +2799,22 @@ qeth_check_outbound_queue(struct qeth_qdio_out_q *queue)
* do_send_packet. So, we check if there is a
* packing buffer to be flushed here.
*/
- /* TODO: try if we get a performance improvement
- * by calling netif_stop_queue here */
- /* save start index for flushing */
+ netif_stop_queue(queue->card->dev);
index = queue->next_buf_to_fill;
+ q_was_packing = queue->do_pack;
flush_cnt += qeth_switch_to_nonpacking_if_needed(queue);
if (!flush_cnt &&
!atomic_read(&queue->set_pci_flags_count))
flush_cnt +=
qeth_flush_buffers_on_no_pci(queue);
- /* were done with updating critical queue members */
- atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
- /* flushing can be done outside the lock */
+#ifdef CONFIG_QETH_PERF_STATS
+ if (q_was_packing)
+ queue->card->perf_stats.bufs_sent_pack +=
+ flush_cnt;
+#endif
if (flush_cnt)
qeth_flush_buffers(queue, 1, index, flush_cnt);
+ atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
}
}
}
@@ -2803,7 +2844,6 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status,
return;
}
}
-
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.outbound_handler_cnt++;
card->perf_stats.outbound_handler_start_time = qeth_get_micros();
@@ -2824,24 +2864,16 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status,
if (card->info.type != QETH_CARD_TYPE_IQD)
qeth_check_outbound_queue(queue);
- netif_wake_queue(card->dev);
+ netif_wake_queue(queue->card->dev);
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.outbound_handler_time += qeth_get_micros() -
card->perf_stats.outbound_handler_start_time;
#endif
}
-static char*
-qeth_create_qib_param_field(struct qeth_card *card)
+static void
+qeth_create_qib_param_field(struct qeth_card *card, char *param_field)
{
- char *param_field;
-
- param_field = kmalloc(QDIO_MAX_BUFFERS_PER_Q * sizeof(char),
- GFP_KERNEL);
- if (!param_field)
- return NULL;
-
- memset(param_field, 0, QDIO_MAX_BUFFERS_PER_Q * sizeof(char));
param_field[0] = _ascebc['P'];
param_field[1] = _ascebc['C'];
@@ -2850,8 +2882,18 @@ qeth_create_qib_param_field(struct qeth_card *card)
*((unsigned int *) (&param_field[4])) = QETH_PCI_THRESHOLD_A(card);
*((unsigned int *) (&param_field[8])) = QETH_PCI_THRESHOLD_B(card);
*((unsigned int *) (&param_field[12])) = QETH_PCI_TIMER_VALUE(card);
+}
- return param_field;
+static void
+qeth_create_qib_param_field_blkt(struct qeth_card *card, char *param_field)
+{
+ param_field[16] = _ascebc['B'];
+ param_field[17] = _ascebc['L'];
+ param_field[18] = _ascebc['K'];
+ param_field[19] = _ascebc['T'];
+ *((unsigned int *) (&param_field[20])) = card->info.blkt.time_total;
+ *((unsigned int *) (&param_field[24])) = card->info.blkt.inter_packet;
+ *((unsigned int *) (&param_field[28])) = card->info.blkt.inter_packet_jumbo;
}
static void
@@ -2901,7 +2943,7 @@ qeth_alloc_buffer_pool(struct qeth_card *card)
void *ptr;
int i, j;
- QETH_DBF_TEXT(trace,5,"clwkpool");
+ QETH_DBF_TEXT(trace,5,"alocpool");
for (i = 0; i < card->qdio.init_pool.buf_count; ++i){
pool_entry = kmalloc(sizeof(*pool_entry), GFP_KERNEL);
if (!pool_entry){
@@ -2989,12 +3031,13 @@ qeth_alloc_qdio_buffers(struct qeth_card *card)
QETH_DBF_HEX(setup, 2, &card->qdio.out_qs[i], sizeof(void *));
memset(card->qdio.out_qs[i], 0, sizeof(struct qeth_qdio_out_q));
card->qdio.out_qs[i]->queue_no = i;
- /* give inbound qeth_qdio_buffers their qdio_buffers */
+ /* give outbound qeth_qdio_buffers their qdio_buffers */
for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j){
card->qdio.out_qs[i]->bufs[j].buffer =
&card->qdio.out_qs[i]->qdio_bufs[j];
skb_queue_head_init(&card->qdio.out_qs[i]->bufs[j].
skb_list);
+ INIT_LIST_HEAD(&card->qdio.out_qs[i]->bufs[j].ctx_list);
}
}
card->qdio.state = QETH_QDIO_ALLOCATED;
@@ -3111,10 +3154,17 @@ qeth_qdio_establish(struct qeth_card *card)
int rc;
QETH_DBF_TEXT(setup, 2, "qdioest");
- qib_param_field = qeth_create_qib_param_field(card);
- if (!qib_param_field)
+
+ qib_param_field = kmalloc(QDIO_MAX_BUFFERS_PER_Q * sizeof(char),
+ GFP_KERNEL);
+ if (!qib_param_field)
return -ENOMEM;
+ memset(qib_param_field, 0, QDIO_MAX_BUFFERS_PER_Q * sizeof(char));
+
+ qeth_create_qib_param_field(card, qib_param_field);
+ qeth_create_qib_param_field_blkt(card, qib_param_field);
+
in_sbal_ptrs = kmalloc(QDIO_MAX_BUFFERS_PER_Q * sizeof(void *),
GFP_KERNEL);
if (!in_sbal_ptrs) {
@@ -3431,24 +3481,19 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
card->perf_stats.outbound_cnt++;
card->perf_stats.outbound_start_time = qeth_get_micros();
#endif
- /*
- * We only call netif_stop_queue in case of errors. Since we've
- * got our own synchronization on queues we can keep the stack's
- * queue running.
- */
- if ((rc = qeth_send_packet(card, skb))){
+ netif_stop_queue(dev);
+ if ((rc = qeth_send_packet(card, skb))) {
if (rc == -EBUSY) {
- netif_stop_queue(dev);
- rc = NETDEV_TX_BUSY;
+ return NETDEV_TX_BUSY;
} else {
card->stats.tx_errors++;
card->stats.tx_dropped++;
dev_kfree_skb_any(skb);
- /* set to OK; otherwise ksoftirqd goes to 100% */
+ /*set to OK; otherwise ksoftirqd goes to 100% */
rc = NETDEV_TX_OK;
}
}
-
+ netif_wake_queue(dev);
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.outbound_time += qeth_get_micros() -
card->perf_stats.outbound_start_time;
@@ -3642,8 +3687,9 @@ qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
/* TODO: IPv6!!! */
}
return card->qdio.default_out_queue;
+ case 1: /* fallthrough for single-out-queue 1920-device */
default:
- return 0;
+ return card->qdio.default_out_queue;
}
}
@@ -3664,22 +3710,16 @@ static inline int
qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb,
struct qeth_hdr **hdr, int ipv)
{
- struct sk_buff *new_skb;
+ int rc = 0;
#ifdef CONFIG_QETH_VLAN
u16 *tag;
#endif
QETH_DBF_TEXT(trace, 6, "prepskb");
- if (skb_headroom(*skb) < sizeof(struct qeth_hdr)){
- new_skb = skb_realloc_headroom(*skb, sizeof(struct qeth_hdr));
- if (!new_skb) {
- PRINT_ERR("qeth_prepare_skb: could "
- "not realloc headroom for qeth_hdr "
- "on interface %s", QETH_CARD_IFNAME(card));
- return -ENOMEM;
- }
- *skb = new_skb;
- }
+
+ rc = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr));
+ if (rc)
+ return rc;
#ifdef CONFIG_QETH_VLAN
if (card->vlangrp && vlan_tx_tag_present(*skb) &&
((ipv == 6) || card->options.layer2) ) {
@@ -3701,20 +3741,10 @@ qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb,
*(tag + 1) = htons(vlan_tx_tag_get(*skb));
}
#endif
- *hdr = (struct qeth_hdr *) skb_push(*skb, sizeof(struct qeth_hdr));
- /*
- * sanity check, the Linux memory allocation scheme should
- * never present us cases like this one (the 32bytes header plus
- * the first 40 bytes of the paket cross a 4k boundary)
- */
- if ((((unsigned long) *hdr) & (~(PAGE_SIZE - 1))) !=
- (((unsigned long) *hdr + sizeof(struct qeth_hdr) +
- QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) {
- PRINT_ERR("qeth_prepare_skb: misaligned "
- "packet on interface %s. Discarded.",
- QETH_CARD_IFNAME(card));
+ *hdr = (struct qeth_hdr *)
+ qeth_push_skb(card, skb, sizeof(struct qeth_hdr));
+ if (hdr == NULL)
return -EINVAL;
- }
return 0;
}
@@ -3806,12 +3836,13 @@ qeth_layer2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
#endif
}
-static inline void
+void
qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb, int ipv, int cast_type)
{
QETH_DBF_TEXT(trace, 6, "fillhdr");
+ memset(hdr, 0, sizeof(struct qeth_hdr));
if (card->options.layer2) {
qeth_layer2_fill_header(card, hdr, skb, cast_type);
return;
@@ -3862,21 +3893,59 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
}
}
-static inline int
-qeth_fill_buffer(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf,
- char *data, struct sk_buff *skb)
+static inline void
+__qeth_fill_buffer_frag(struct sk_buff *skb, struct qdio_buffer *buffer,
+ int *next_element_to_fill)
+{
+ int length = skb->len;
+ struct skb_frag_struct *frag;
+ int fragno;
+ unsigned long addr;
+ int element;
+ int first_lap = 1;
+
+ fragno = skb_shinfo(skb)->nr_frags; /* start with last frag */
+ element = *next_element_to_fill + fragno;
+ while (length > 0) {
+ if (fragno > 0) {
+ frag = &skb_shinfo(skb)->frags[fragno - 1];
+ addr = (page_to_pfn(frag->page) << PAGE_SHIFT) +
+ frag->page_offset;
+ buffer->element[element].addr = (char *)addr;
+ buffer->element[element].length = frag->size;
+ length -= frag->size;
+ if (first_lap)
+ buffer->element[element].flags =
+ SBAL_FLAGS_LAST_FRAG;
+ else
+ buffer->element[element].flags =
+ SBAL_FLAGS_MIDDLE_FRAG;
+ } else {
+ buffer->element[element].addr = skb->data;
+ buffer->element[element].length = length;
+ length = 0;
+ buffer->element[element].flags =
+ SBAL_FLAGS_FIRST_FRAG;
+ }
+ element--;
+ fragno--;
+ first_lap = 0;
+ }
+ *next_element_to_fill += skb_shinfo(skb)->nr_frags + 1;
+}
+
+static inline void
+__qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
+ int *next_element_to_fill)
{
- struct qdio_buffer *buffer;
int length = skb->len;
int length_here;
int element;
+ char *data;
int first_lap = 1;
- QETH_DBF_TEXT(trace, 6, "qdfillbf");
- buffer = buf->buffer;
- atomic_inc(&skb->users);
- skb_queue_tail(&buf->skb_list, skb);
- element = buf->next_element_to_fill;
+ element = *next_element_to_fill;
+ data = skb->data;
while (length > 0) {
/* length_here is the remaining amount of data in this page */
length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE);
@@ -3903,11 +3972,33 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf
element++;
first_lap = 0;
}
- buf->next_element_to_fill = element;
+ *next_element_to_fill = element;
+}
+
+static inline int
+qeth_fill_buffer(struct qeth_qdio_out_q *queue,
+ struct qeth_qdio_out_buffer *buf,
+ struct sk_buff *skb)
+{
+ struct qdio_buffer *buffer;
+ int flush_cnt = 0;
+
+ QETH_DBF_TEXT(trace, 6, "qdfillbf");
+ buffer = buf->buffer;
+ atomic_inc(&skb->users);
+ skb_queue_tail(&buf->skb_list, skb);
+ if (skb_shinfo(skb)->nr_frags == 0)
+ __qeth_fill_buffer(skb, buffer,
+ (int *)&buf->next_element_to_fill);
+ else
+ __qeth_fill_buffer_frag(skb, buffer,
+ (int *)&buf->next_element_to_fill);
+
if (!queue->do_pack) {
QETH_DBF_TEXT(trace, 6, "fillbfnp");
/* set state to PRIMED -> will be flushed */
atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
+ flush_cnt = 1;
} else {
QETH_DBF_TEXT(trace, 6, "fillbfpa");
#ifdef CONFIG_QETH_PERF_STATS
@@ -3920,17 +4011,21 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf
* -> will be flushed
*/
atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
+ flush_cnt = 1;
}
}
- return 0;
+ return flush_cnt;
}
static inline int
qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue,
struct sk_buff *skb, struct qeth_hdr *hdr,
- int elements_needed)
+ int elements_needed,
+ struct qeth_eddp_context *ctx)
{
struct qeth_qdio_out_buffer *buffer;
+ int buffers_needed = 0;
+ int flush_cnt = 0;
int index;
QETH_DBF_TEXT(trace, 6, "dosndpfa");
@@ -3951,22 +4046,42 @@ qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue,
atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
return -EBUSY;
}
- queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
- QDIO_MAX_BUFFERS_PER_Q;
+ if (ctx == NULL)
+ queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
+ QDIO_MAX_BUFFERS_PER_Q;
+ else {
+ buffers_needed = qeth_eddp_check_buffers_for_context(queue,ctx);
+ if (buffers_needed < 0) {
+ card->stats.tx_dropped++;
+ atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
+ return -EBUSY;
+ }
+ queue->next_buf_to_fill =
+ (queue->next_buf_to_fill + buffers_needed) %
+ QDIO_MAX_BUFFERS_PER_Q;
+ }
atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
- qeth_fill_buffer(queue, buffer, (char *)hdr, skb);
- qeth_flush_buffers(queue, 0, index, 1);
+ if (ctx == NULL) {
+ qeth_fill_buffer(queue, buffer, skb);
+ qeth_flush_buffers(queue, 0, index, 1);
+ } else {
+ flush_cnt = qeth_eddp_fill_buffer(queue, ctx, index);
+ WARN_ON(buffers_needed != flush_cnt);
+ qeth_flush_buffers(queue, 0, index, flush_cnt);
+ }
return 0;
}
static inline int
qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
struct sk_buff *skb, struct qeth_hdr *hdr,
- int elements_needed)
+ int elements_needed, struct qeth_eddp_context *ctx)
{
struct qeth_qdio_out_buffer *buffer;
int start_index;
int flush_count = 0;
+ int do_pack = 0;
+ int tmp;
int rc = 0;
QETH_DBF_TEXT(trace, 6, "dosndpkt");
@@ -3989,34 +4104,56 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
/* check if we need to switch packing state of this queue */
qeth_switch_to_packing_if_needed(queue);
if (queue->do_pack){
- /* does packet fit in current buffer? */
- if((QETH_MAX_BUFFER_ELEMENTS(card) -
- buffer->next_element_to_fill) < elements_needed){
- /* ... no -> set state PRIMED */
- atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED);
- flush_count++;
- queue->next_buf_to_fill =
- (queue->next_buf_to_fill + 1) %
- QDIO_MAX_BUFFERS_PER_Q;
- buffer = &queue->bufs[queue->next_buf_to_fill];
- /* we did a step forward, so check buffer state again */
- if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){
+ do_pack = 1;
+ if (ctx == NULL) {
+ /* does packet fit in current buffer? */
+ if((QETH_MAX_BUFFER_ELEMENTS(card) -
+ buffer->next_element_to_fill) < elements_needed){
+ /* ... no -> set state PRIMED */
+ atomic_set(&buffer->state,QETH_QDIO_BUF_PRIMED);
+ flush_count++;
+ queue->next_buf_to_fill =
+ (queue->next_buf_to_fill + 1) %
+ QDIO_MAX_BUFFERS_PER_Q;
+ buffer = &queue->bufs[queue->next_buf_to_fill];
+ /* we did a step forward, so check buffer state
+ * again */
+ if (atomic_read(&buffer->state) !=
+ QETH_QDIO_BUF_EMPTY){
+ card->stats.tx_dropped++;
+ qeth_flush_buffers(queue, 0, start_index, flush_count);
+ atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
+ return -EBUSY;
+ }
+ }
+ } else {
+ /* check if we have enough elements (including following
+ * free buffers) to handle eddp context */
+ if (qeth_eddp_check_buffers_for_context(queue,ctx) < 0){
+ printk("eddp tx_dropped 1\n");
card->stats.tx_dropped++;
- /* return EBUSY because we sent old packet, not
- * the current one */
rc = -EBUSY;
- atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
goto out;
}
}
}
- qeth_fill_buffer(queue, buffer, (char *)hdr, skb);
- if (atomic_read(&buffer->state) == QETH_QDIO_BUF_PRIMED){
- /* next time fill the next buffer */
- flush_count++;
- queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
- QDIO_MAX_BUFFERS_PER_Q;
+ if (ctx == NULL)
+ tmp = qeth_fill_buffer(queue, buffer, skb);
+ else {
+ tmp = qeth_eddp_fill_buffer(queue,ctx,queue->next_buf_to_fill);
+ if (tmp < 0) {
+ printk("eddp tx_dropped 2\n");
+ card->stats.tx_dropped++;
+ rc = - EBUSY;
+ goto out;
+ }
}
+ queue->next_buf_to_fill = (queue->next_buf_to_fill + tmp) %
+ QDIO_MAX_BUFFERS_PER_Q;
+ flush_count += tmp;
+out:
+ if (flush_count)
+ qeth_flush_buffers(queue, 0, start_index, flush_count);
/*
* queue->state will go from LOCKED -> UNLOCKED or from
* LOCKED_FLUSH -> LOCKED if output_handler wanted to 'notify' us
@@ -4024,6 +4161,8 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
* In that case we will enter this loop
*/
while (atomic_dec_return(&queue->state)){
+ flush_count = 0;
+ start_index = queue->next_buf_to_fill;
/* check if we can go back to non-packing state */
flush_count += qeth_switch_to_nonpacking_if_needed(queue);
/*
@@ -4032,11 +4171,14 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
*/
if (!flush_count && !atomic_read(&queue->set_pci_flags_count))
flush_count += qeth_flush_buffers_on_no_pci(queue);
+ if (flush_count)
+ qeth_flush_buffers(queue, 0, start_index, flush_count);
}
/* at this point the queue is UNLOCKED again */
-out:
- if (flush_count)
- qeth_flush_buffers(queue, 0, start_index, flush_count);
+#ifdef CONFIG_QETH_PERF_STATS
+ if (do_pack)
+ queue->card->perf_stats.bufs_sent_pack += flush_count;
+#endif /* CONFIG_QETH_PERF_STATS */
return rc;
}
@@ -4048,7 +4190,9 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
int cast_type;
struct qeth_qdio_out_q *queue;
struct qeth_hdr *hdr;
- int elements_needed;
+ int elements_needed = 0;
+ enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
+ struct qeth_eddp_context *ctx = NULL;
int rc;
QETH_DBF_TEXT(trace, 6, "sendpkt");
@@ -4065,32 +4209,73 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
}
}
cast_type = qeth_get_cast_type(card, skb);
+ if ((cast_type == RTN_BROADCAST) && (card->info.broadcast_capable == 0)){
+ card->stats.tx_dropped++;
+ card->stats.tx_errors++;
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
queue = card->qdio.out_qs
[qeth_get_priority_queue(card, skb, ipv, cast_type)];
+ if (skb_shinfo(skb)->tso_size)
+ large_send = card->options.large_send;
+
if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))){
- QETH_DBF_TEXT_(trace, 4, "1err%d", rc);
+ QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc);
return rc;
}
+ /*are we able to do TSO ? If so ,prepare and send it from here */
+ if ((large_send == QETH_LARGE_SEND_TSO) &&
+ (cast_type == RTN_UNSPEC)) {
+ rc = qeth_tso_send_packet(card, skb, queue,
+ ipv, cast_type);
+ goto do_statistics;
+ }
+
qeth_fill_header(card, hdr, skb, ipv, cast_type);
- elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) + skb->len)
- >> PAGE_SHIFT);
- if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){
- PRINT_ERR("qeth_do_send_packet: invalid size of "
- "IP packet. Discarded.");
- return -EINVAL;
+ if (large_send == QETH_LARGE_SEND_EDDP) {
+ ctx = qeth_eddp_create_context(card, skb, hdr);
+ if (ctx == NULL) {
+ PRINT_WARN("could not create eddp context\n");
+ return -EINVAL;
+ }
+ } else {
+ elements_needed = qeth_get_elements_no(card,(void*) hdr, skb);
+ if (!elements_needed)
+ return -EINVAL;
}
if (card->info.type != QETH_CARD_TYPE_IQD)
rc = qeth_do_send_packet(card, queue, skb, hdr,
- elements_needed);
+ elements_needed, ctx);
else
rc = qeth_do_send_packet_fast(card, queue, skb, hdr,
- elements_needed);
-
+ elements_needed, ctx);
+do_statistics:
if (!rc){
card->stats.tx_packets++;
card->stats.tx_bytes += skb->len;
+#ifdef CONFIG_QETH_PERF_STATS
+ if (skb_shinfo(skb)->tso_size) {
+ card->perf_stats.large_send_bytes += skb->len;
+ card->perf_stats.large_send_cnt++;
+ }
+ if (skb_shinfo(skb)->nr_frags > 0){
+ card->perf_stats.sg_skbs_sent++;
+ /* nr_frags + skb->data */
+ card->perf_stats.sg_frags_sent +=
+ skb_shinfo(skb)->nr_frags + 1;
+ }
+#endif /* CONFIG_QETH_PERF_STATS */
+ }
+ if (ctx != NULL) {
+ /* drop creator's reference */
+ qeth_eddp_put_context(ctx);
+ /* free skb; it's not referenced by a buffer */
+ if (rc == 0)
+ dev_kfree_skb_any(skb);
+
}
return rc;
}
@@ -4945,6 +5130,7 @@ out:
static void
qeth_free_vlan_addresses6(struct qeth_card *card, unsigned short vid)
{
+#ifdef CONFIG_QETH_IPV6
struct inet6_dev *in6_dev;
struct inet6_ifaddr *ifa;
struct qeth_ipaddr *addr;
@@ -4967,6 +5153,7 @@ qeth_free_vlan_addresses6(struct qeth_card *card, unsigned short vid)
}
}
in6_dev_put(in6_dev);
+#endif /* CONFIG_QETH_IPV6 */
}
static void
@@ -5566,7 +5753,7 @@ static int
qeth_layer3_register_addr_entry(struct qeth_card *card,
struct qeth_ipaddr *addr)
{
- //char buf[50];
+ char buf[50];
int rc;
int cnt = 3;
@@ -5592,12 +5779,9 @@ qeth_layer3_register_addr_entry(struct qeth_card *card,
} while ((--cnt > 0) && rc);
if (rc){
QETH_DBF_TEXT(trace, 2, "FAILED");
- /* TODO: re-activate this warning as soon as we have a
- * clean mirco code
qeth_ipaddr_to_string(addr->proto, (u8 *)&addr->u, buf);
- PRINT_WARN("Could not register IP address %s (rc=%x)\n",
- buf, rc);
- */
+ PRINT_WARN("Could not register IP address %s (rc=0x%x/%d)\n",
+ buf, rc, rc);
}
return rc;
}
@@ -5655,6 +5839,111 @@ qeth_deregister_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr)
return qeth_layer3_deregister_addr_entry(card, addr);
}
+static u32
+qeth_ethtool_get_tx_csum(struct net_device *dev)
+{
+ /* We may need to say that we support tx csum offload if
+ * we do EDDP or TSO. There are discussions going on to
+ * enforce rules in the stack and in ethtool that make
+ * SG and TSO depend on HW_CSUM. At the moment there are
+ * no such rules....
+ * If we say yes here, we have to checksum outbound packets
+ * any time. */
+ return 0;
+}
+
+static int
+qeth_ethtool_set_tx_csum(struct net_device *dev, u32 data)
+{
+ return -EINVAL;
+}
+
+static u32
+qeth_ethtool_get_rx_csum(struct net_device *dev)
+{
+ struct qeth_card *card = (struct qeth_card *)dev->priv;
+
+ return (card->options.checksum_type == HW_CHECKSUMMING);
+}
+
+static int
+qeth_ethtool_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct qeth_card *card = (struct qeth_card *)dev->priv;
+
+ if ((card->state != CARD_STATE_DOWN) &&
+ (card->state != CARD_STATE_RECOVER))
+ return -EPERM;
+ if (data)
+ card->options.checksum_type = HW_CHECKSUMMING;
+ else
+ card->options.checksum_type = SW_CHECKSUMMING;
+ return 0;
+}
+
+static u32
+qeth_ethtool_get_sg(struct net_device *dev)
+{
+ struct qeth_card *card = (struct qeth_card *)dev->priv;
+
+ return ((card->options.large_send != QETH_LARGE_SEND_NO) &&
+ (dev->features & NETIF_F_SG));
+}
+
+static int
+qeth_ethtool_set_sg(struct net_device *dev, u32 data)
+{
+ struct qeth_card *card = (struct qeth_card *)dev->priv;
+
+ if (data) {
+ if (card->options.large_send != QETH_LARGE_SEND_NO)
+ dev->features |= NETIF_F_SG;
+ else {
+ dev->features &= ~NETIF_F_SG;
+ return -EINVAL;
+ }
+ } else
+ dev->features &= ~NETIF_F_SG;
+ return 0;
+}
+
+static u32
+qeth_ethtool_get_tso(struct net_device *dev)
+{
+ struct qeth_card *card = (struct qeth_card *)dev->priv;
+
+ return ((card->options.large_send != QETH_LARGE_SEND_NO) &&
+ (dev->features & NETIF_F_TSO));
+}
+
+static int
+qeth_ethtool_set_tso(struct net_device *dev, u32 data)
+{
+ struct qeth_card *card = (struct qeth_card *)dev->priv;
+
+ if (data) {
+ if (card->options.large_send != QETH_LARGE_SEND_NO)
+ dev->features |= NETIF_F_TSO;
+ else {
+ dev->features &= ~NETIF_F_TSO;
+ return -EINVAL;
+ }
+ } else
+ dev->features &= ~NETIF_F_TSO;
+ return 0;
+}
+
+static struct ethtool_ops qeth_ethtool_ops = {
+ .get_tx_csum = qeth_ethtool_get_tx_csum,
+ .set_tx_csum = qeth_ethtool_set_tx_csum,
+ .get_rx_csum = qeth_ethtool_get_rx_csum,
+ .set_rx_csum = qeth_ethtool_set_rx_csum,
+ .get_sg = qeth_ethtool_get_sg,
+ .set_sg = qeth_ethtool_set_sg,
+ .get_tso = qeth_ethtool_get_tso,
+ .set_tso = qeth_ethtool_set_tso,
+};
+
static int
qeth_netdev_init(struct net_device *dev)
{
@@ -5704,6 +5993,8 @@ qeth_netdev_init(struct net_device *dev)
dev->addr_len = OSA_ADDR_LEN;
dev->mtu = card->info.initial_mtu;
+ SET_ETHTOOL_OPS(dev, &qeth_ethtool_ops);
+
SET_MODULE_OWNER(dev);
return 0;
}
@@ -6095,6 +6386,9 @@ qeth_query_ipassists_cb(struct qeth_card *card, struct qeth_reply *reply,
card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled;
#endif
}
+ QETH_DBF_TEXT(setup, 2, "suppenbl");
+ QETH_DBF_TEXT_(setup, 2, "%x",cmd->hdr.ipa_supported);
+ QETH_DBF_TEXT_(setup, 2, "%x",cmd->hdr.ipa_enabled);
return 0;
}
@@ -6495,26 +6789,33 @@ qeth_start_ipa_checksum(struct qeth_card *card)
return rc;
}
-/*
-static inline void
-qeth_print_ipassist_status(struct qeth_card *card)
+static int
+qeth_start_ipa_tso(struct qeth_card *card)
{
- char buf[255];
- int offset = 0;
+ int rc;
+
+ QETH_DBF_TEXT(trace,3,"sttso");
- offset += sprintf(buf, "IPAssist options of %s: ", card->info.if_name);
- if (qeth_is_enabled(card, IPA_ARP_PROCESSING))
- offset += sprintf(buf+offset, "ARP ");
- if (qeth_is_enabled(card, IPA_IP_FRAGMENTATION))
- offset += sprintf(buf+offset, "IP_FRAG");
- if (qeth_is_enabled(card, IPA_SOURCE_MAC))
- offset += sprintf(buf+offset, "SRC_MAC");
- if (qeth_is_enabled(card, IPA_FULL_VLAN))
- offset += sprintf(buf+offset, "VLAN");
- if (qeth_is_enabled(card, IPA_VLAN_PRIO))
- offset += sprintf(buf+offset, "VLAN_PRIO");
+ if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
+ PRINT_WARN("Outbound TSO not supported on %s\n",
+ QETH_CARD_IFNAME(card));
+ rc = -EOPNOTSUPP;
+ } else {
+ rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_TSO,
+ IPA_CMD_ASS_START,0);
+ if (rc)
+ PRINT_WARN("Could not start outbound TSO "
+ "assist on %s: rc=%i\n",
+ QETH_CARD_IFNAME(card), rc);
+ else
+ PRINT_INFO("Outbound TSO enabled\n");
+ }
+ if (rc && (card->options.large_send == QETH_LARGE_SEND_TSO)){
+ card->options.large_send = QETH_LARGE_SEND_NO;
+ card->dev->features &= ~ (NETIF_F_TSO | NETIF_F_SG);
+ }
+ return rc;
}
-*/
static int
qeth_start_ipassists(struct qeth_card *card)
@@ -6528,6 +6829,7 @@ qeth_start_ipassists(struct qeth_card *card)
qeth_start_ipa_ipv6(card); /* go on*/
qeth_start_ipa_broadcast(card); /* go on*/
qeth_start_ipa_checksum(card); /* go on*/
+ qeth_start_ipa_tso(card); /* go on*/
return 0;
}
@@ -6639,6 +6941,40 @@ qeth_setrouting_v6(struct qeth_card *card)
return rc;
}
+int
+qeth_set_large_send(struct qeth_card *card)
+{
+ int rc = 0;
+
+ if (card->dev == NULL)
+ return 0;
+
+ netif_stop_queue(card->dev);
+ switch (card->options.large_send) {
+ case QETH_LARGE_SEND_EDDP:
+ card->dev->features |= NETIF_F_TSO | NETIF_F_SG;
+ break;
+ case QETH_LARGE_SEND_TSO:
+ if (qeth_is_supported(card, IPA_OUTBOUND_TSO)){
+ card->dev->features |= NETIF_F_TSO | NETIF_F_SG;
+ } else {
+ PRINT_WARN("TSO not supported on %s. "
+ "large_send set to 'no'.\n",
+ card->dev->name);
+ card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG);
+ card->options.large_send = QETH_LARGE_SEND_NO;
+ rc = -EOPNOTSUPP;
+ }
+ break;
+ default: /* includes QETH_LARGE_SEND_NO */
+ card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG);
+ break;
+ }
+
+ netif_wake_queue(card->dev);
+ return rc;
+}
+
/*
* softsetup card: init IPA stuff
*/
@@ -6676,6 +7012,12 @@ qeth_softsetup_card(struct qeth_card *card)
#endif
goto out;
}
+ if ((card->options.large_send == QETH_LARGE_SEND_EDDP) ||
+ (card->options.large_send == QETH_LARGE_SEND_TSO))
+ card->dev->features |= NETIF_F_TSO | NETIF_F_SG;
+ else
+ card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG);
+
if ((rc = qeth_setadapter_parms(card)))
QETH_DBF_TEXT_(setup, 2, "2err%d", rc);
if ((rc = qeth_start_ipassists(card)))
diff --git a/drivers/s390/net/qeth_mpc.h b/drivers/s390/net/qeth_mpc.h
index 052c8406a3fb0..3d916b5c5d09c 100644
--- a/drivers/s390/net/qeth_mpc.h
+++ b/drivers/s390/net/qeth_mpc.h
@@ -14,7 +14,7 @@
#include <asm/qeth.h>
-#define VERSION_QETH_MPC_H "$Revision: 1.38 $"
+#define VERSION_QETH_MPC_H "$Revision: 1.43 $"
extern const char *VERSION_QETH_MPC_C;
@@ -182,6 +182,9 @@ enum qeth_ipa_funcs {
IPA_FULL_VLAN = 0x00004000L,
IPA_SOURCE_MAC = 0x00010000L,
IPA_OSA_MC_ROUTER = 0x00020000L,
+ IPA_QUERY_ARP_ASSIST = 0x00040000L,
+ IPA_INBOUND_TSO = 0x00080000L,
+ IPA_OUTBOUND_TSO = 0x00100000L,
};
/* SETIP/DELIP IPA Command: ***************************************************/
diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c
index 0cd33887bedc7..04719196fd201 100644
--- a/drivers/s390/net/qeth_proc.c
+++ b/drivers/s390/net/qeth_proc.c
@@ -236,6 +236,14 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
card->perf_stats.skbs_sent_pack,
card->perf_stats.bufs_sent_pack
);
+ seq_printf(s, " Skbs sent in SG mode : %i\n"
+ " Skb fragments sent in SG mode : %i\n\n",
+ card->perf_stats.sg_skbs_sent,
+ card->perf_stats.sg_frags_sent);
+ seq_printf(s, " large_send tx (in Kbytes) : %i\n"
+ " large_send count : %i\n\n",
+ card->perf_stats.large_send_bytes >> 10,
+ card->perf_stats.large_send_cnt);
seq_printf(s, " Packing state changes no pkg.->packing : %i/%i\n"
" Watermarks L/H : %i/%i\n"
" Current buffer usage (outbound q's) : "
@@ -262,7 +270,7 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
" Outbound time (in us, incl QDIO) : %i\n"
" Outbound count : %i\n"
" Outbound do_QDIO time (in us) : %i\n"
- " Outbound do_QDIO count : %i\n",
+ " Outbound do_QDIO count : %i\n\n",
card->perf_stats.inbound_time,
card->perf_stats.inbound_cnt,
card->perf_stats.inbound_do_qdio_time,
@@ -274,7 +282,6 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
card->perf_stats.outbound_do_qdio_time,
card->perf_stats.outbound_do_qdio_cnt
);
-
return 0;
}
diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c
index fe8b0e24e4465..2403483982111 100644
--- a/drivers/s390/net/qeth_sys.c
+++ b/drivers/s390/net/qeth_sys.c
@@ -1,6 +1,6 @@
/*
*
- * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.49 $)
+ * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.51 $)
*
* Linux on zSeries OSA Express and HiperSockets support
* This file contains code related to sysfs.
@@ -20,7 +20,7 @@
#include "qeth_mpc.h"
#include "qeth_fs.h"
-const char *VERSION_QETH_SYS_C = "$Revision: 1.49 $";
+const char *VERSION_QETH_SYS_C = "$Revision: 1.51 $";
/*****************************************************************************/
/* */
@@ -249,6 +249,16 @@ qeth_dev_prioqing_store(struct device *dev, const char *buf, size_t count)
(card->state != CARD_STATE_RECOVER))
return -EPERM;
+ /* check if 1920 devices are supported ,
+ * if though we have to permit priority queueing
+ */
+ if (card->qdio.no_out_queues == 1) {
+ PRINT_WARN("Priority queueing disabled due "
+ "to hardware limitations!\n");
+ card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT;
+ return -EPERM;
+ }
+
tmp = strsep((char **) &buf, "\n");
if (!strcmp(tmp, "prio_queueing_prec"))
card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_PREC;
@@ -731,6 +741,174 @@ qeth_dev_layer2_store(struct device *dev, const char *buf, size_t count)
static DEVICE_ATTR(layer2, 0644, qeth_dev_layer2_show,
qeth_dev_layer2_store);
+static ssize_t
+qeth_dev_large_send_show(struct device *dev, char *buf)
+{
+ struct qeth_card *card = dev->driver_data;
+
+ if (!card)
+ return -EINVAL;
+
+ switch (card->options.large_send) {
+ case QETH_LARGE_SEND_NO:
+ return sprintf(buf, "%s\n", "no");
+ case QETH_LARGE_SEND_EDDP:
+ return sprintf(buf, "%s\n", "EDDP");
+ case QETH_LARGE_SEND_TSO:
+ return sprintf(buf, "%s\n", "TSO");
+ default:
+ return sprintf(buf, "%s\n", "N/A");
+ }
+}
+
+static ssize_t
+qeth_dev_large_send_store(struct device *dev, const char *buf, size_t count)
+{
+ struct qeth_card *card = dev->driver_data;
+ enum qeth_large_send_types type;
+ int rc = 0;
+ char *tmp;
+
+ if (!card)
+ return -EINVAL;
+
+ tmp = strsep((char **) &buf, "\n");
+
+ if (!strcmp(tmp, "no")){
+ type = QETH_LARGE_SEND_NO;
+ } else if (!strcmp(tmp, "EDDP")) {
+ type = QETH_LARGE_SEND_EDDP;
+ } else if (!strcmp(tmp, "TSO")) {
+ type = QETH_LARGE_SEND_TSO;
+ } else {
+ PRINT_WARN("large_send: invalid mode %s!\n", tmp);
+ return -EINVAL;
+ }
+ if (card->options.large_send == type)
+ return count;
+ card->options.large_send = type;
+ if ((rc = qeth_set_large_send(card)))
+ return rc;
+
+ return count;
+}
+
+static DEVICE_ATTR(large_send, 0644, qeth_dev_large_send_show,
+ qeth_dev_large_send_store);
+
+static ssize_t
+qeth_dev_blkt_show(char *buf, struct qeth_card *card, int value )
+{
+
+ if (!card)
+ return -EINVAL;
+
+ return sprintf(buf, "%i\n", value);
+}
+
+static ssize_t
+qeth_dev_blkt_store(struct qeth_card *card, const char *buf, size_t count,
+ int *value, int max_value)
+{
+ char *tmp;
+ int i;
+
+ if (!card)
+ return -EINVAL;
+
+ if ((card->state != CARD_STATE_DOWN) &&
+ (card->state != CARD_STATE_RECOVER))
+ return -EPERM;
+
+ i = simple_strtoul(buf, &tmp, 10);
+ if (i <= max_value) {
+ *value = i;
+ } else {
+ PRINT_WARN("blkt total time: write values between"
+ " 0 and %d to this file!\n", max_value);
+ return -EINVAL;
+ }
+ return count;
+}
+
+static ssize_t
+qeth_dev_blkt_total_show(struct device *dev, char *buf)
+{
+ struct qeth_card *card = dev->driver_data;
+
+ return qeth_dev_blkt_show(buf, card, card->info.blkt.time_total);
+}
+
+
+static ssize_t
+qeth_dev_blkt_total_store(struct device *dev, const char *buf, size_t count)
+{
+ struct qeth_card *card = dev->driver_data;
+
+ return qeth_dev_blkt_store(card, buf, count,
+ &card->info.blkt.time_total,1000);
+}
+
+
+
+static DEVICE_ATTR(total, 0644, qeth_dev_blkt_total_show,
+ qeth_dev_blkt_total_store);
+
+static ssize_t
+qeth_dev_blkt_inter_show(struct device *dev, char *buf)
+{
+ struct qeth_card *card = dev->driver_data;
+
+ return qeth_dev_blkt_show(buf, card, card->info.blkt.inter_packet);
+}
+
+
+static ssize_t
+qeth_dev_blkt_inter_store(struct device *dev, const char *buf, size_t count)
+{
+ struct qeth_card *card = dev->driver_data;
+
+ return qeth_dev_blkt_store(card, buf, count,
+ &card->info.blkt.inter_packet,100);
+}
+
+static DEVICE_ATTR(inter, 0644, qeth_dev_blkt_inter_show,
+ qeth_dev_blkt_inter_store);
+
+static ssize_t
+qeth_dev_blkt_inter_jumbo_show(struct device *dev, char *buf)
+{
+ struct qeth_card *card = dev->driver_data;
+
+ return qeth_dev_blkt_show(buf, card,
+ card->info.blkt.inter_packet_jumbo);
+}
+
+
+static ssize_t
+qeth_dev_blkt_inter_jumbo_store(struct device *dev, const char *buf, size_t count)
+{
+ struct qeth_card *card = dev->driver_data;
+
+ return qeth_dev_blkt_store(card, buf, count,
+ &card->info.blkt.inter_packet_jumbo,100);
+}
+
+static DEVICE_ATTR(inter_jumbo, 0644, qeth_dev_blkt_inter_jumbo_show,
+ qeth_dev_blkt_inter_jumbo_store);
+
+static struct device_attribute * qeth_blkt_device_attrs[] = {
+ &dev_attr_total,
+ &dev_attr_inter,
+ &dev_attr_inter_jumbo,
+ NULL,
+};
+
+static struct attribute_group qeth_device_blkt_group = {
+ .name = "blkt",
+ .attrs = (struct attribute **)qeth_blkt_device_attrs,
+};
+
static struct device_attribute * qeth_device_attrs[] = {
&dev_attr_state,
&dev_attr_chpid,
@@ -752,6 +930,7 @@ static struct device_attribute * qeth_device_attrs[] = {
&dev_attr_broadcast_mode,
&dev_attr_canonical_macaddr,
&dev_attr_layer2,
+ &dev_attr_large_send,
NULL,
};
@@ -1506,6 +1685,8 @@ qeth_create_device_attributes(struct device *dev)
sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
}
+ if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_blkt_group)))
+ return ret;
return ret;
}
@@ -1517,6 +1698,7 @@ qeth_remove_device_attributes(struct device *dev)
sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
sysfs_remove_group(&dev->kobj, &qeth_device_rxip_group);
+ sysfs_remove_group(&dev->kobj, &qeth_device_blkt_group);
}
/**********************/
diff --git a/drivers/s390/net/qeth_tso.c b/drivers/s390/net/qeth_tso.c
new file mode 100644
index 0000000000000..c91976274e7b0
--- /dev/null
+++ b/drivers/s390/net/qeth_tso.c
@@ -0,0 +1,285 @@
+/*
+ * linux/drivers/s390/net/qeth_tso.c ($Revision: 1.6 $)
+ *
+ * Header file for qeth TCP Segmentation Offload support.
+ *
+ * Copyright 2004 IBM Corporation
+ *
+ * Author(s): Frank Pavlic <pavlic@de.ibm.com>
+ *
+ * $Revision: 1.6 $ $Date: 2005/03/24 09:04:18 $
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/tcp.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/ip6_checksum.h>
+#include "qeth.h"
+#include "qeth_mpc.h"
+#include "qeth_tso.h"
+
+/**
+ * skb already partially prepared
+ * classic qdio header in skb->data
+ * */
+static inline struct qeth_hdr_tso *
+qeth_tso_prepare_skb(struct qeth_card *card, struct sk_buff **skb)
+{
+ int rc = 0;
+
+ QETH_DBF_TEXT(trace, 5, "tsoprsk");
+ rc = qeth_realloc_headroom(card, skb,sizeof(struct qeth_hdr_ext_tso));
+ if (rc)
+ return NULL;
+
+ return qeth_push_skb(card, skb, sizeof(struct qeth_hdr_ext_tso));
+}
+
+/**
+ * fill header for a TSO packet
+ */
+static inline void
+qeth_tso_fill_header(struct qeth_card *card, struct sk_buff *skb)
+{
+ struct qeth_hdr_tso *hdr;
+ struct tcphdr *tcph;
+ struct iphdr *iph;
+
+ QETH_DBF_TEXT(trace, 5, "tsofhdr");
+
+ hdr = (struct qeth_hdr_tso *) skb->data;
+ iph = skb->nh.iph;
+ tcph = skb->h.th;
+ /*fix header to TSO values ...*/
+ hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO;
+ /*set values which are fix for the first approach ...*/
+ hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso);
+ hdr->ext.imb_hdr_no = 1;
+ hdr->ext.hdr_type = 1;
+ hdr->ext.hdr_version = 1;
+ hdr->ext.hdr_len = 28;
+ /*insert non-fix values */
+ hdr->ext.mss = skb_shinfo(skb)->tso_size;
+ hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4);
+ hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len -
+ sizeof(struct qeth_hdr_tso));
+}
+
+/**
+ * change some header values as requested by hardware
+ */
+static inline void
+qeth_tso_set_tcpip_header(struct qeth_card *card, struct sk_buff *skb)
+{
+ struct iphdr *iph;
+ struct ipv6hdr *ip6h;
+ struct tcphdr *tcph;
+
+ iph = skb->nh.iph;
+ ip6h = skb->nh.ipv6h;
+ tcph = skb->h.th;
+
+ tcph->check = 0;
+ if (skb->protocol == ETH_P_IPV6) {
+ ip6h->payload_len = 0;
+ tcph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
+ 0, IPPROTO_TCP, 0);
+ return;
+ }
+ /*OSA want us to set these values ...*/
+ tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+ 0, IPPROTO_TCP, 0);
+ iph->tot_len = 0;
+ iph->check = 0;
+}
+
+static inline struct qeth_hdr_tso *
+qeth_tso_prepare_packet(struct qeth_card *card, struct sk_buff *skb,
+ int ipv, int cast_type)
+{
+ struct qeth_hdr_tso *hdr;
+ int rc = 0;
+
+ QETH_DBF_TEXT(trace, 5, "tsoprep");
+
+ /*get headroom for tso qdio header */
+ hdr = (struct qeth_hdr_tso *) qeth_tso_prepare_skb(card, &skb);
+ if (hdr == NULL) {
+ QETH_DBF_TEXT_(trace, 4, "2err%d", rc);
+ return NULL;
+ }
+ memset(hdr, 0, sizeof(struct qeth_hdr_tso));
+ /*fill first 32 bytes of qdio header as used
+ *FIXME: TSO has two struct members
+ * with different names but same size
+ * */
+ qeth_fill_header(card, &hdr->hdr, skb, ipv, cast_type);
+ qeth_tso_fill_header(card, skb);
+ qeth_tso_set_tcpip_header(card, skb);
+ return hdr;
+}
+
+static inline int
+qeth_tso_get_queue_buffer(struct qeth_qdio_out_q *queue)
+{
+ struct qeth_qdio_out_buffer *buffer;
+ int flush_cnt = 0;
+
+ QETH_DBF_TEXT(trace, 5, "tsobuf");
+
+ /* force to non-packing*/
+ if (queue->do_pack)
+ queue->do_pack = 0;
+ buffer = &queue->bufs[queue->next_buf_to_fill];
+ /* get a new buffer if current is already in use*/
+ if ((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) &&
+ (buffer->next_element_to_fill > 0)) {
+ atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED);
+ queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
+ QDIO_MAX_BUFFERS_PER_Q;
+ flush_cnt++;
+ }
+ return flush_cnt;
+}
+
+static inline void
+__qeth_tso_fill_buffer_frag(struct qeth_qdio_out_buffer *buf,
+ struct sk_buff *skb)
+{
+ struct skb_frag_struct *frag;
+ struct qdio_buffer *buffer;
+ int fragno, cnt, element;
+ unsigned long addr;
+
+ QETH_DBF_TEXT(trace, 6, "tsfilfrg");
+
+ /*initialize variables ...*/
+ fragno = skb_shinfo(skb)->nr_frags;
+ buffer = buf->buffer;
+ element = buf->next_element_to_fill;
+ /*fill buffer elements .....*/
+ for (cnt = 0; cnt < fragno; cnt++) {
+ frag = &skb_shinfo(skb)->frags[cnt];
+ addr = (page_to_pfn(frag->page) << PAGE_SHIFT) +
+ frag->page_offset;
+ buffer->element[element].addr = (char *)addr;
+ buffer->element[element].length = frag->size;
+ if (cnt < (fragno - 1))
+ buffer->element[element].flags =
+ SBAL_FLAGS_MIDDLE_FRAG;
+ else
+ buffer->element[element].flags =
+ SBAL_FLAGS_LAST_FRAG;
+ element++;
+ }
+ buf->next_element_to_fill = element;
+}
+
+static inline int
+qeth_tso_fill_buffer(struct qeth_qdio_out_buffer *buf,
+ struct sk_buff *skb)
+{
+ int length, length_here, element;
+ int hdr_len;
+ struct qdio_buffer *buffer;
+ struct qeth_hdr_tso *hdr;
+ char *data;
+
+ QETH_DBF_TEXT(trace, 3, "tsfilbuf");
+
+ /*increment user count and queue skb ...*/
+ atomic_inc(&skb->users);
+ skb_queue_tail(&buf->skb_list, skb);
+
+ /*initialize all variables...*/
+ buffer = buf->buffer;
+ hdr = (struct qeth_hdr_tso *)skb->data;
+ hdr_len = sizeof(struct qeth_hdr_tso) + hdr->ext.dg_hdr_len;
+ data = skb->data + hdr_len;
+ length = skb->len - hdr_len;
+ element = buf->next_element_to_fill;
+ /*fill first buffer entry only with header information */
+ buffer->element[element].addr = skb->data;
+ buffer->element[element].length = hdr_len;
+ buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG;
+ buf->next_element_to_fill++;
+
+ if (skb_shinfo(skb)->nr_frags > 0) {
+ __qeth_tso_fill_buffer_frag(buf, skb);
+ goto out;
+ }
+
+ /*start filling buffer entries ...*/
+ element++;
+ while (length > 0) {
+ /* length_here is the remaining amount of data in this page */
+ length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE);
+ if (length < length_here)
+ length_here = length;
+ buffer->element[element].addr = data;
+ buffer->element[element].length = length_here;
+ length -= length_here;
+ if (!length)
+ buffer->element[element].flags =
+ SBAL_FLAGS_LAST_FRAG;
+ else
+ buffer->element[element].flags =
+ SBAL_FLAGS_MIDDLE_FRAG;
+ data += length_here;
+ element++;
+ }
+ /*set the buffer to primed ...*/
+ buf->next_element_to_fill = element;
+out:
+ atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
+ return 1;
+}
+
+int
+qeth_tso_send_packet(struct qeth_card *card, struct sk_buff *skb,
+ struct qeth_qdio_out_q *queue, int ipv, int cast_type)
+{
+ int flush_cnt = 0;
+ struct qeth_hdr_tso *hdr;
+ struct qeth_qdio_out_buffer *buffer;
+ int start_index;
+
+ QETH_DBF_TEXT(trace, 3, "tsosend");
+
+ if (!(hdr = qeth_tso_prepare_packet(card, skb, ipv, cast_type)))
+ return -ENOMEM;
+ /*check if skb fits in one SBAL ...*/
+ if (!(qeth_get_elements_no(card, (void*)hdr, skb)))
+ return -EINVAL;
+ /*lock queue, force switching to non-packing and send it ...*/
+ while (atomic_compare_and_swap(QETH_OUT_Q_UNLOCKED,
+ QETH_OUT_Q_LOCKED,
+ &queue->state));
+ start_index = queue->next_buf_to_fill;
+ buffer = &queue->bufs[queue->next_buf_to_fill];
+ /*check if card is too busy ...*/
+ if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){
+ card->stats.tx_dropped++;
+ goto out;
+ }
+ /*let's force to non-packing and get a new SBAL*/
+ flush_cnt += qeth_tso_get_queue_buffer(queue);
+ buffer = &queue->bufs[queue->next_buf_to_fill];
+ if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) {
+ card->stats.tx_dropped++;
+ goto out;
+ }
+ flush_cnt += qeth_tso_fill_buffer(buffer, skb);
+ queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
+ QDIO_MAX_BUFFERS_PER_Q;
+out:
+ atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
+ if (flush_cnt)
+ qeth_flush_buffers(queue, 0, start_index, flush_cnt);
+ /*do some statistics */
+ card->stats.tx_packets++;
+ card->stats.tx_bytes += skb->len;
+ return 0;
+}
diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h
new file mode 100644
index 0000000000000..83504dee3f57d
--- /dev/null
+++ b/drivers/s390/net/qeth_tso.h
@@ -0,0 +1,58 @@
+/*
+ * linux/drivers/s390/net/qeth_tso.h ($Revision: 1.4 $)
+ *
+ * Header file for qeth TCP Segmentation Offload support.
+ *
+ * Copyright 2004 IBM Corporation
+ *
+ * Author(s): Frank Pavlic <pavlic@de.ibm.com>
+ *
+ * $Revision: 1.4 $ $Date: 2005/03/24 09:04:18 $
+ *
+ */
+#ifndef __QETH_TSO_H__
+#define __QETH_TSO_H__
+
+
+extern int
+qeth_tso_send_packet(struct qeth_card *, struct sk_buff *,
+ struct qeth_qdio_out_q *, int , int);
+
+struct qeth_hdr_ext_tso {
+ __u16 hdr_tot_len;
+ __u8 imb_hdr_no;
+ __u8 reserved;
+ __u8 hdr_type;
+ __u8 hdr_version;
+ __u16 hdr_len;
+ __u32 payload_len;
+ __u16 mss;
+ __u16 dg_hdr_len;
+ __u8 padding[16];
+} __attribute__ ((packed));
+
+struct qeth_hdr_tso {
+ struct qeth_hdr hdr; /*hdr->hdr.l3.xxx*/
+ struct qeth_hdr_ext_tso ext;
+} __attribute__ ((packed));
+
+/*some helper functions*/
+
+static inline int
+qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb)
+{
+ int elements_needed = 0;
+
+ if (skb_shinfo(skb)->nr_frags > 0)
+ elements_needed = (skb_shinfo(skb)->nr_frags + 1);
+ if (elements_needed == 0 )
+ elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE)
+ + skb->len) >> PAGE_SHIFT);
+ if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){
+ PRINT_ERR("qeth_do_send_packet: invalid size of "
+ "IP packet. Discarded.");
+ return 0;
+ }
+ return elements_needed;
+}
+#endif /* __QETH_TSO_H__ */
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 0e2944424c2b1..6a43322ccb0a5 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -583,7 +583,7 @@ zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
retval = -ENOMEM;
goto out;
}
- memset(sg_list->sg, sg_list->count * sizeof(struct scatterlist), 0);
+ memset(sg_list->sg, 0, sg_list->count * sizeof(struct scatterlist));
for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) {
sg->length = min(size, PAGE_SIZE);
diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
index cf2457b667a40..6bdd768b731db 100644
--- a/drivers/sbus/char/flash.c
+++ b/drivers/sbus/char/flash.c
@@ -75,7 +75,7 @@ flash_mmap(struct file *file, struct vm_area_struct *vma)
pgprot_val(vma->vm_page_prot) |= _PAGE_E;
vma->vm_flags |= (VM_SHM | VM_LOCKED);
- if (remap_pfn_range(vma, vma->vm_start, addr, size, vma->vm_page_prot))
+ if (io_remap_pfn_range(vma, vma->vm_start, addr, size, vma->vm_page_prot))
return -EAGAIN;
return 0;
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index 057a24bba81a7..86ce541309549 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -626,8 +626,10 @@ static int vfc_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_flags |=
(VM_SHM | VM_LOCKED | VM_IO | VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE);
map_offset = (unsigned int) (long)dev->phys_regs;
- ret = io_remap_page_range(vma, vma->vm_start, map_offset, map_size,
- vma->vm_page_prot, dev->which_io);
+ ret = io_remap_pfn_range(vma, vma->vm_start,
+ MK_IOSPACE_PFN(dev->which_io,
+ map_offset >> PAGE_SHIFT),
+ map_size, vma->vm_page_prot);
if(ret)
return -EAGAIN;
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 049cf90461e22..f8d90d0ecfeac 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -579,6 +579,16 @@ static int __devinit pci_xircom_init(struct pci_dev *dev)
return 0;
}
+static int __devinit pci_netmos_init(struct pci_dev *dev)
+{
+ /* subdevice 0x00PS means <P> parallel, <S> serial */
+ unsigned int num_serial = dev->subsystem_device & 0xf;
+
+ if (num_serial == 0)
+ return -ENODEV;
+ return num_serial;
+}
+
static int
pci_default_setup(struct pci_dev *dev, struct pci_board *board,
struct uart_port *port, int idx)
@@ -936,6 +946,17 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
.setup = pci_default_setup,
},
/*
+ * Netmos cards
+ */
+ {
+ .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,
+ },
+ /*
* Default "match everything" terminator entry
*/
{
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index d3a69f6a2906d..fbfe5d35de330 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -827,4 +827,19 @@ config SERIAL_VR41XX_CONSOLE
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"
+ 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 and read the file
+ <file:Documentation/jsm.txt>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called jsm.
+
endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index ed4425ce50a38..81b77d769b846 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_SERIAL_ICOM) += icom.o
obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
+obj-$(CONFIG_SERIAL_JSM) += jsm/
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
obj-$(CONFIG_BLK_DEV_SGIIOC4) += ioc4_serial.o
diff --git a/drivers/serial/au1x00_uart.c b/drivers/serial/au1x00_uart.c
index c70f7aad8ed62..b6d3d50349407 100644
--- a/drivers/serial/au1x00_uart.c
+++ b/drivers/serial/au1x00_uart.c
@@ -320,7 +320,9 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
ignore_char:
*status = serial_inp(up, UART_LSR);
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
+ spin_unlock(&up->port.lock);
tty_flip_buffer_push(tty);
+ spin_lock(&up->port.lock);
}
static _INLINE_ void transmit_chars(struct uart_8250_port *up)
diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c
index 6a42a84bd0b71..d054f1265701c 100644
--- a/drivers/serial/ioc4_serial.c
+++ b/drivers/serial/ioc4_serial.c
@@ -2665,7 +2665,7 @@ ioc4_serial_core_attach(struct pci_dev *pdev)
__FUNCTION__, (void *)the_port,
(void *)port));
- the_port->lock = SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&the_port->lock);
/* membase, iobase and mapbase just need to be non-0 */
the_port->membase = (unsigned char __iomem *)1;
the_port->line = the_port->iobase = ii;
diff --git a/drivers/serial/jsm/Makefile b/drivers/serial/jsm/Makefile
new file mode 100644
index 0000000000000..e46b6e0f8b185
--- /dev/null
+++ b/drivers/serial/jsm/Makefile
@@ -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/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h
new file mode 100644
index 0000000000000..6926b100e2b04
--- /dev/null
+++ b/drivers/serial/jsm/jsm.h
@@ -0,0 +1,437 @@
+/************************************************************************
+ * 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.ltcfwd.linux.ibm.com>
+ *
+ ***********************************************************************/
+
+#ifndef __JSM_DRIVER_H
+#define __JSM_DRIVER_H
+
+#include <linux/kernel.h>
+#include <linux/version.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 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.1-1-INKERNEL"
+#define JSM_PARTNUM "40002438_A-INKERNEL"
+
+/*
+ * All the possible states the driver can be while being loaded.
+ */
+enum {
+ DRIVER_INITIALIZED = 0,
+ DRIVER_READY
+};
+
+/*
+ * All the possible states the board can be while booting up.
+ */
+enum {
+ BOARD_FAILED = 0,
+ BOARD_FOUND,
+ BOARD_READY
+};
+
+struct board_id {
+ u8 *name;
+ u32 maxports;
+};
+
+struct jsm_board;
+struct jsm_channel;
+
+/************************************************************************
+ * Per board operations structure *
+ ************************************************************************/
+struct board_ops {
+ irqreturn_t (*intr) (int irq, void *voidbrd, struct pt_regs *regs);
+ 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 */
+ char *name; /* Product Name */
+ u8 rev; /* PCI revision ID */
+ struct pci_dev *pci_dev;
+ u32 maxports; /* MAX ports this board can handle */
+
+ spinlock_t bd_lock; /* Used to protect board */
+
+ spinlock_t bd_intr_lock; /* Used to protect the poller tasklet and
+ * the interrupt routine from each other.
+ */
+
+ u32 state; /* State of card. */
+ wait_queue_head_t state_wait; /* Place to sleep on for state change */
+
+ u32 nasync; /* Number of ports on card */
+
+ u32 irq; /* Interrupt request number */
+ u64 intr_count; /* Count of interrupts */
+
+ u64 membase; /* Start of base memory of the card */
+ u64 membase_end; /* End of base memory of the card */
+
+ u8 *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 */
+
+ u16 dpatype; /* The board "type", as defined by DPA */
+ u16 dpastatus; /* The board "status", as defined by DPA */
+
+ 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 */
+
+ u64 ch_cpstime; /* Time for CPS calculations */
+
+ 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 */
+
+ u32 ch_old_baud; /* Cache of the current baud */
+ u32 ch_custom_speed;/* Custom baud, if set */
+
+ u32 ch_wopen; /* Waiting for open process cnt */
+
+ u8 ch_mostat; /* FEP output modem status */
+ u8 ch_mistat; /* FEP input modem status */
+
+ struct neo_uart_struct *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"
+
+/*
+ * Our Global Variables.
+ */
+extern struct uart_driver jsm_uart_driver;
+extern struct board_ops jsm_neo_ops;
+extern int jsm_debug;
+extern int jsm_rawreadok;
+
+extern int jsm_driver_state; /* The state of the driver */
+extern char *jsm_driver_state_text[];/* Array of driver state text */
+
+extern spinlock_t jsm_board_head_lock;
+extern struct list_head jsm_board_head;
+
+/*************************************************************************
+ *
+ * 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_carrier(struct jsm_channel *ch);
+void jsm_check_queue_flow_control(struct jsm_channel *ch);
+
+void jsm_create_driver_sysfiles(struct device_driver *);
+void jsm_remove_driver_sysfiles(struct device_driver *);
+
+#endif
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c
new file mode 100644
index 0000000000000..d4847d4f1473d
--- /dev/null
+++ b/drivers/serial/jsm/jsm_driver.c
@@ -0,0 +1,404 @@
+/************************************************************************
+ * 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.ltcfwd.linux.ibm.com>
+ *
+ ***********************************************************************/
+#include <linux/moduleparam.h>
+#include <linux/pci.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_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 = 253,
+ .minor = JSM_MINOR_START,
+ .nr = NR_PORTS,
+ .cons = NULL,
+};
+
+int jsm_debug;
+int jsm_rawreadok;
+module_param(jsm_debug, int, 0);
+module_param(jsm_rawreadok, int, 0);
+MODULE_PARM_DESC(jsm_debug, "Driver debugging level");
+MODULE_PARM_DESC(jsm_rawreadok, "Bypass flip buffers on input");
+
+/*
+ * Globals
+ */
+int jsm_driver_state = DRIVER_INITIALIZED;
+spinlock_t jsm_board_head_lock = SPIN_LOCK_UNLOCKED;
+LIST_HEAD(jsm_board_head);
+
+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 },
+ { 0,} /* 0 terminated list. */
+};
+MODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
+
+static struct board_id jsm_Ids[] = {
+ { PCI_DEVICE_NEO_2DB9_PCI_NAME, 2 },
+ { PCI_DEVICE_NEO_2DB9PRI_PCI_NAME, 2 },
+ { PCI_DEVICE_NEO_2RJ45_PCI_NAME, 2 },
+ { PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME, 2 },
+ { NULL, 0 }
+};
+
+char *jsm_driver_state_text[] = {
+ "Driver Initialized",
+ "Driver Ready."
+};
+
+static int jsm_finalize_board_init(struct jsm_board *brd)
+{
+ int rc = 0;
+
+ jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
+
+ if (brd->irq) {
+ rc = request_irq(brd->irq, brd->bd_ops->intr, SA_INTERRUPT|SA_SHIRQ, "JSM", brd);
+
+ if (rc) {
+ printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq);
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOFEP;
+ rc = -ENODEV;
+ } else
+ jsm_printk(INIT, INFO, &brd->pci_dev,
+ "Requested and received usage of IRQ %d\n", brd->irq);
+ }
+ return rc;
+}
+
+/*
+ * jsm_found_board()
+ *
+ * A board has been found, init it.
+ */
+static int jsm_found_board(struct pci_dev *pdev, int id)
+{
+ struct jsm_board *brd;
+ int i = 0;
+ int rc = 0;
+ struct list_head *tmp;
+ struct jsm_board *cur_board_entry;
+ unsigned long lock_flags;
+ int adapter_count = 0;
+ int retval;
+
+ brd = kmalloc(sizeof(struct jsm_board), GFP_KERNEL);
+ if (!brd) {
+ dev_err(&pdev->dev, "memory allocation for board structure failed\n");
+ return -ENOMEM;
+ }
+ memset(brd, 0, sizeof(struct jsm_board));
+
+ spin_lock_irqsave(&jsm_board_head_lock, lock_flags);
+ list_for_each(tmp, &jsm_board_head) {
+ cur_board_entry =
+ list_entry(tmp, struct jsm_board,
+ jsm_board_entry);
+ if (cur_board_entry->boardnum != adapter_count) {
+ break;
+ }
+ adapter_count++;
+ }
+
+ list_add_tail(&brd->jsm_board_entry, &jsm_board_head);
+ spin_unlock_irqrestore(&jsm_board_head_lock, lock_flags);
+
+ /* store the info for the board we've found */
+ brd->boardnum = adapter_count;
+ brd->pci_dev = pdev;
+ brd->name = jsm_Ids[id].name;
+ brd->maxports = jsm_Ids[id].maxports;
+ brd->dpastatus = BD_NOFEP;
+ init_waitqueue_head(&brd->state_wait);
+
+ spin_lock_init(&brd->bd_lock);
+ spin_lock_init(&brd->bd_intr_lock);
+
+ brd->state = BOARD_FOUND;
+
+ for (i = 0; i < brd->maxports; i++)
+ brd->channels[i] = NULL;
+
+ /* store which revision we have */
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &brd->rev);
+
+ brd->irq = pdev->irq;
+
+ switch(brd->pci_dev->device) {
+
+ case PCI_DEVICE_ID_NEO_2DB9:
+ case PCI_DEVICE_ID_NEO_2DB9PRI:
+ case PCI_DEVICE_ID_NEO_2RJ45:
+ case PCI_DEVICE_ID_NEO_2RJ45PRI:
+
+ /*
+ * This chip is set up 100% when we get to it.
+ * No need to enable global interrupts or anything.
+ */
+ brd->dpatype = T_NEO | T_PCIBUS;
+
+ 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);
+ jsm_printk(INIT, INFO, &brd->pci_dev,
+ "remapped mem: 0x%p\n", brd->re_map_membase);
+ if (!brd->re_map_membase) {
+ kfree(brd);
+ dev_err(&pdev->dev, "card has no PCI Memory resources, failing board.\n");
+ return -ENOMEM;
+ }
+ break;
+
+ default:
+ dev_err(&pdev->dev, "Did not find any compatible Neo or Classic PCI boards in system.\n");
+ kfree(brd);
+ return -ENXIO;
+ }
+
+ /*
+ * Do tty device initialization.
+ */
+ rc = jsm_finalize_board_init(brd);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Can't finalize board init (%d)\n", rc);
+ brd->state = BOARD_FAILED;
+ retval = -ENXIO;
+ goto failed0;
+ }
+
+ rc = jsm_tty_init(brd);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Can't init tty devices (%d)\n", rc);
+ brd->state = BOARD_FAILED;
+ retval = -ENXIO;
+ goto failed1;
+ }
+
+ rc = jsm_uart_port_init(brd);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Can't init uart port (%d)\n", rc);
+ brd->state = BOARD_FAILED;
+ retval = -ENXIO;
+ goto failed1;
+ }
+
+ brd->state = BOARD_READY;
+ brd->dpastatus = BD_RUNNING;
+
+ /* Log the information about the board */
+ dev_info(&pdev->dev, "board %d: %s (rev %d), irq %d\n",adapter_count, brd->name, 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 = kmalloc(MYFLIPLEN, GFP_KERNEL);
+ if (!brd->flipbuf) {
+ dev_err(&pdev->dev, "memory allocation for flipbuf failed\n");
+ brd->state = BOARD_FAILED;
+ retval = -ENOMEM;
+ goto failed1;
+ }
+ memset(brd->flipbuf, 0, MYFLIPLEN);
+
+ jsm_create_driver_sysfiles(pdev->dev.driver);
+
+ wake_up_interruptible(&brd->state_wait);
+ return 0;
+failed1:
+ free_irq(brd->irq, brd);
+failed0:
+ kfree(brd);
+ iounmap(brd->re_map_membase);
+ return retval;
+}
+
+/* returns count (>= 0), or negative on error */
+static int jsm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int rc;
+
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ dev_err(&pdev->dev, "Device enable FAILED\n");
+ return rc;
+ }
+
+ if ((rc = pci_request_regions(pdev, "jsm"))) {
+ dev_err(&pdev->dev, "pci_request_region FAILED\n");
+ pci_disable_device(pdev);
+ return rc;
+ }
+
+ if ((rc = jsm_found_board(pdev, ent->driver_data))) {
+ dev_err(&pdev->dev, "jsm_found_board FAILED\n");
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ return rc;
+ }
+ return rc;
+}
+
+
+/*
+ * jsm_cleanup_board()
+ *
+ * Free all the memory associated with a board
+ */
+static void jsm_cleanup_board(struct jsm_board *brd)
+{
+ int i = 0;
+
+ 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]) {
+ if (brd->channels[i]->ch_rqueue)
+ kfree(brd->channels[i]->ch_rqueue);
+ if (brd->channels[i]->ch_equeue)
+ kfree(brd->channels[i]->ch_equeue);
+ if (brd->channels[i]->ch_wqueue)
+ kfree(brd->channels[i]->ch_wqueue);
+ kfree(brd->channels[i]);
+ }
+ }
+
+ pci_release_regions(brd->pci_dev);
+ pci_disable_device(brd->pci_dev);
+ kfree(brd->flipbuf);
+ kfree(brd);
+}
+
+static void jsm_remove_one(struct pci_dev *dev)
+{
+ unsigned long lock_flags;
+ struct list_head *tmp;
+ struct jsm_board *brd;
+
+ spin_lock_irqsave(&jsm_board_head_lock, lock_flags);
+ list_for_each(tmp, &jsm_board_head) {
+ brd = list_entry(tmp, struct jsm_board,
+ jsm_board_entry);
+ if ( brd != NULL && brd->pci_dev == dev) {
+ jsm_remove_uart_port(brd);
+ jsm_cleanup_board(brd);
+ list_del(&brd->jsm_board_entry);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&jsm_board_head_lock, lock_flags);
+ return;
+}
+
+struct pci_driver jsm_driver = {
+ .name = "jsm",
+ .probe = jsm_init_one,
+ .id_table = jsm_pci_tbl,
+ .remove = __devexit_p(jsm_remove_one),
+};
+
+/*
+ * jsm_init_module()
+ *
+ * Module load. This is where it all starts.
+ */
+static int __init jsm_init_module(void)
+{
+ int rc = 0;
+
+ printk(KERN_INFO "%s, Digi International Part Number %s\n",
+ JSM_VERSION, JSM_VERSION);
+
+ /*
+ * Initialize global stuff
+ */
+
+ rc = uart_register_driver(&jsm_uart_driver);
+ if (rc < 0) {
+ return rc;
+ }
+
+ rc = pci_register_driver(&jsm_driver);
+ if (rc < 0) {
+ uart_unregister_driver(&jsm_uart_driver);
+ return rc;
+ }
+ jsm_driver_state = DRIVER_READY;
+
+ return rc;
+}
+
+module_init(jsm_init_module);
+
+/*
+ * jsm_exit_module()
+ *
+ * Module unload. This is where it all ends.
+ */
+static void __exit jsm_exit_module(void)
+{
+ jsm_remove_driver_sysfiles(&jsm_driver.driver);
+
+ pci_unregister_driver(&jsm_driver);
+
+ uart_unregister_driver(&jsm_uart_driver);
+}
+module_exit(jsm_exit_module);
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c
new file mode 100644
index 0000000000000..0511d6be7d173
--- /dev/null
+++ b/drivers/serial/jsm/jsm_neo.c
@@ -0,0 +1,1427 @@
+/************************************************************************
+ * 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.ltcfwd.linux.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 = readb(&ch->ch_neo_uart->ier);
+ u8 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 = readb(&ch->ch_neo_uart->ier);
+ u8 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 = readb(&ch->ch_neo_uart->ier);
+ u8 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 = readb(&ch->ch_neo_uart->ier);
+ u8 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 = readb(&ch->ch_neo_uart->ier);
+ u8 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 = readb(&ch->ch_neo_uart->ier);
+ u8 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;
+
+ len_written = 0;
+ 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);
+
+ if (!ch)
+ return;
+
+ /* Scrub off lower bits. They signify delta's, which I don't care about */
+ msignals &= 0xf0;
+
+ 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)
+{
+ u8 out;
+
+ if (!ch)
+ return;
+
+ out = ch->ch_mostat;
+
+ writeb(out, &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.
+ */
+void neo_clear_break(struct jsm_channel *ch, int force)
+{
+ u64 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;
+ u64 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;
+ u64 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 = 0;
+ u8 ier = 0;
+ u32 baud = 9600;
+ int quot = 0;
+ 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);
+ ch->ch_old_baud = 0;
+ return;
+
+ } else if (ch->ch_custom_speed) {
+ baud = ch->ch_custom_speed;
+ if (ch->ch_flags & CH_BAUD0)
+ ch->ch_flags &= ~(CH_BAUD0);
+ } else {
+ int iindex = 0;
+ int jindex = 0;
+
+ const u64 bauds[4][16] = {
+ {
+ 0, 50, 75, 110,
+ 134, 150, 200, 300,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 },
+ {
+ 0, 57600, 115200, 230400,
+ 460800, 150, 200, 921600,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 },
+ {
+ 0, 57600, 76800, 115200,
+ 131657, 153600, 230400, 460800,
+ 921600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 },
+ {
+ 0, 57600, 115200, 230400,
+ 460800, 150, 200, 921600,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 }
+ };
+
+ baud = C_BAUD(ch->uart_port.info->tty) & 0xff;
+
+ if (ch->ch_c_cflag & CBAUDEX)
+ iindex = 1;
+
+ jindex = baud;
+
+ if ((iindex >= 0) && (iindex < 4) && (jindex >= 0) && (jindex < 16))
+ baud = bauds[iindex][jindex];
+ else {
+ jsm_printk(IOCTL, DEBUG, &ch->ch_bd->pci_dev,
+ "baud indices were out of range (%d)(%d)",
+ iindex, jindex);
+ baud = 0;
+ }
+
+ if (baud == 0)
+ baud = 9600;
+
+ 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) {
+ ch->ch_old_baud = baud;
+ 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 pt_regs *regs)
+{
+ struct jsm_board *brd = (struct jsm_board *) 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;
+
+ brd->intr_count++;
+
+ /* 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
new file mode 100644
index 0000000000000..b6bc881166c0d
--- /dev/null
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -0,0 +1,1043 @@
+/************************************************************************
+ * 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.ltcfwd.linux.ibm.com>
+ *
+ ***********************************************************************/
+#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 "jsm.h"
+
+static inline int jsm_get_mstat(struct jsm_channel *ch)
+{
+ unsigned char mstat;
+ unsigned char 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, unsigned int tty_start)
+{
+ 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, unsigned int tty_stop)
+{
+ 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;
+
+ spin_lock_irqsave(&port->lock, lock_flags);
+ if (ch == port->info->tty->termios->c_cc[VSTART])
+ channel->ch_bd->bd_ops->send_start_character(channel);
+
+ if (ch == port->info->tty->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_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;
+ int rc = 0;
+ struct jsm_channel *channel = (struct jsm_channel *)port;
+
+ /* 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 = (u8 *) kmalloc(RQUEUESIZE, GFP_KERNEL);
+ if (!channel->ch_rqueue) {
+ jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
+ "unable to allocate read queue buf");
+ return -ENOMEM;
+ }
+ memset(channel->ch_rqueue, 0, RQUEUESIZE);
+ }
+ if (!channel->ch_equeue) {
+ channel->ch_equeue = (u8 *) kmalloc(EQUEUESIZE, GFP_KERNEL);
+ if (!channel->ch_equeue) {
+ jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
+ "unable to allocate error queue buf");
+ return -ENOMEM;
+ }
+ memset(channel->ch_equeue, 0, EQUEUESIZE);
+ }
+ if (!channel->ch_wqueue) {
+ channel->ch_wqueue = (u8 *) kmalloc(WQUEUESIZE, GFP_KERNEL);
+ if (!channel->ch_wqueue) {
+ jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
+ "unable to allocate write queue buf");
+ return -ENOMEM;
+ }
+ memset(channel->ch_wqueue, 0, WQUEUESIZE);
+ }
+
+ 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;
+
+ channel->ch_c_cflag = port->info->tty->termios->c_cflag;
+ channel->ch_c_iflag = port->info->tty->termios->c_iflag;
+ channel->ch_c_oflag = port->info->tty->termios->c_oflag;
+ channel->ch_c_lflag = port->info->tty->termios->c_lflag;
+ channel->ch_startc = port->info->tty->termios->c_cc[VSTART];
+ channel->ch_stopc = port->info->tty->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 rc;
+}
+
+static void jsm_tty_close(struct uart_port *port)
+{
+ struct jsm_board *bd;
+ struct termios *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 = channel->uart_port.info->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);
+ }
+
+ channel->ch_old_baud = 0;
+
+ /* 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 termios *termios,
+ struct termios *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,
+ .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 jsm_tty_init(struct jsm_board *brd)
+{
+ int i;
+ u8 *vaddr;
+ struct jsm_channel *ch;
+
+ if (!brd)
+ return -ENXIO;
+
+ jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
+
+ /*
+ * Initialize board structure elements.
+ */
+
+ vaddr = brd->re_map_membase;
+
+ 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] = kmalloc(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__);
+ }
+ memset(brd->channels[i], 0, sizeof(struct jsm_channel));
+ }
+ }
+
+ 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 = (struct neo_uart_struct *) ((u64) 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;
+ u8 *vaddr;
+ struct jsm_channel *ch;
+
+ if (!brd)
+ return -ENXIO;
+
+ jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
+
+ /*
+ * Initialize board structure elements.
+ */
+
+ vaddr = brd->re_map_membase;
+ 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.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;
+ brd->channels[i]->uart_port.line = brd->channels[i]->ch_portnum + brd->boardnum * 2;
+ if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port))
+ printk(KERN_INFO "Added device failed\n");
+ else
+ printk(KERN_INFO "Added device \n");
+ }
+
+ 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];
+
+ 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;
+ u64 lock_flags;
+ int flip_len;
+ int len = 0;
+ int n = 0;
+ char *buf = NULL;
+ char *buf2 = NULL;
+ int s = 0;
+ int i = 0;
+
+ jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n");
+
+ if (!ch)
+ return;
+
+ tp = ch->uart_port.info->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 the rxbuf is empty and we are not throttled, put as much
+ * as we can directly into the linux TTY flip buffer.
+ * The jsm_rawreadok case takes advantage of carnal knowledge that
+ * the char_buf and the flag_buf are next to each other and
+ * are each of (2 * TTY_FLIPBUF_SIZE) size.
+ *
+ * NOTE: if(!tty->real_raw), the call to ldisc.receive_buf
+ *actually still uses the flag buffer, so you can't
+ *use it for input data
+ */
+ if (jsm_rawreadok) {
+ if (tp->real_raw)
+ flip_len = MYFLIPLEN;
+ else
+ flip_len = 2 * TTY_FLIPBUF_SIZE;
+ } else
+ flip_len = TTY_FLIPBUF_SIZE - tp->flip.count;
+
+ len = min(data_len, flip_len);
+ len = min(len, (N_TTY_BUF_SIZE - 1) - tp->read_cnt);
+
+ if (len <= 0) {
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+ jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n");
+ return;
+ }
+
+ /*
+ * If we're bypassing flip buffers on rx, we can blast it
+ * right into the beginning of the buffer.
+ */
+ if (jsm_rawreadok) {
+ if (tp->real_raw) {
+ if (ch->ch_flags & CH_FLIPBUF_IN_USE) {
+ jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+ "JSM - FLIPBUF in use. delaying input\n");
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+ return;
+ }
+ ch->ch_flags |= CH_FLIPBUF_IN_USE;
+ buf = ch->ch_bd->flipbuf;
+ buf2 = NULL;
+ } else {
+ buf = tp->flip.char_buf;
+ buf2 = tp->flip.flag_buf;
+ }
+ } else {
+ buf = tp->flip.char_buf_ptr;
+ buf2 = tp->flip.flag_buf_ptr;
+ }
+
+ 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;
+
+ memcpy(buf, ch->ch_rqueue + tail, s);
+
+ /* buf2 is only set when port isn't raw */
+ if (buf2)
+ memcpy(buf2, ch->ch_equeue + tail, s);
+
+ tail += s;
+ buf += s;
+ if (buf2)
+ buf2 += s;
+ n -= s;
+ /* Flip queue if needed */
+ tail &= rmask;
+ }
+
+ /*
+ * In high performance mode, we don't have to update
+ * flag_buf or any of the counts or pointers into flip buf.
+ */
+ if (!jsm_rawreadok) {
+ if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
+ for (i = 0; i < len; i++) {
+ /*
+ * Give the Linux ld the flags in the
+ * format it likes.
+ */
+ if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI)
+ tp->flip.flag_buf_ptr[i] = TTY_BREAK;
+ else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE)
+ tp->flip.flag_buf_ptr[i] = TTY_PARITY;
+ else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE)
+ tp->flip.flag_buf_ptr[i] = TTY_FRAME;
+ else
+ tp->flip.flag_buf_ptr[i] = TTY_NORMAL;
+ }
+ } else {
+ memset(tp->flip.flag_buf_ptr, 0, len);
+ }
+
+ tp->flip.char_buf_ptr += len;
+ tp->flip.flag_buf_ptr += len;
+ tp->flip.count += len;
+ }
+ else if (!tp->real_raw) {
+ if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
+ for (i = 0; i < len; i++) {
+ /*
+ * Give the Linux ld the flags in the
+ * format it likes.
+ */
+ if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI)
+ tp->flip.flag_buf_ptr[i] = TTY_BREAK;
+ else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE)
+ tp->flip.flag_buf_ptr[i] = TTY_PARITY;
+ else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE)
+ tp->flip.flag_buf_ptr[i] = TTY_FRAME;
+ else
+ tp->flip.flag_buf_ptr[i] = TTY_NORMAL;
+ }
+ } else
+ memset(tp->flip.flag_buf, 0, len);
+ }
+
+ /*
+ * If we're doing raw reads, jam it right into the
+ * line disc bypassing the flip buffers.
+ */
+ if (jsm_rawreadok) {
+ if (tp->real_raw) {
+ ch->ch_r_tail = tail & rmask;
+ ch->ch_e_tail = tail & rmask;
+
+ jsm_check_queue_flow_control(ch);
+
+ /* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+ jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+ "jsm_input. %d real_raw len:%d calling receive_buf for board %d\n",
+ __LINE__, len, ch->ch_bd->boardnum);
+ tp->ldisc.receive_buf(tp, ch->ch_bd->flipbuf, NULL, len);
+
+ /* Allow use of channel flip buffer again */
+ spin_lock_irqsave(&ch->ch_lock, lock_flags);
+ ch->ch_flags &= ~CH_FLIPBUF_IN_USE;
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+ } else {
+ ch->ch_r_tail = tail & rmask;
+ ch->ch_e_tail = tail & rmask;
+
+ jsm_check_queue_flow_control(ch);
+
+ /* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+ jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+ "jsm_input. %d not real_raw len:%d calling receive_buf for board %d\n",
+ __LINE__, len, ch->ch_bd->boardnum);
+
+ tp->ldisc.receive_buf(tp, tp->flip.char_buf, tp->flip.flag_buf, len);
+ }
+ } else {
+ 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);
+
+ jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+ "jsm_input. %d not jsm_read raw okay scheduling flip\n", __LINE__);
+ tty_schedule_flip(tp);
+ }
+
+ jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");
+}
+
+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)
+{
+ int qleft = 0;
+
+ /* 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)) {
+ ch->ch_bd->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) {
+ ch->ch_bd->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) {
+ ch->ch_bd->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;
+ ch->ch_bd->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 = 0, n = 0;
+ int data_count = 0,data_count1 =0;
+ u16 head;
+ u16 tail;
+ u16 tmask;
+ u32 remain;
+ int temp_tail = port->info->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;
+
+ n = bufcount;
+
+ n = min(n, 56);
+ remain = WQUEUESIZE - head;
+
+ data_count = 0;
+ if (n >= remain) {
+ n -= remain;
+ while ((port->info->xmit.head != temp_tail) &&
+ (data_count < remain)) {
+ channel->ch_wqueue[head++] =
+ port->info->xmit.buf[temp_tail];
+
+ temp_tail++;
+ temp_tail &= (UART_XMIT_SIZE - 1);
+ data_count++;
+ }
+ if (data_count == remain) head = 0;
+ }
+
+ data_count1 = 0;
+ if (n > 0) {
+ remain = n;
+ while ((port->info->xmit.head != temp_tail) &&
+ (data_count1 < remain)) {
+ channel->ch_wqueue[head++] =
+ port->info->xmit.buf[temp_tail];
+
+ temp_tail++;
+ temp_tail &= (UART_XMIT_SIZE - 1);
+ data_count1++;
+
+ }
+ }
+
+ port->info->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;
+}
+
+static ssize_t jsm_driver_version_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", JSM_VERSION);
+}
+static DRIVER_ATTR(version, S_IRUSR, jsm_driver_version_show, NULL);
+
+static ssize_t jsm_driver_state_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", jsm_driver_state_text[jsm_driver_state]);
+}
+static DRIVER_ATTR(state, S_IRUSR, jsm_driver_state_show, NULL);
+
+void jsm_create_driver_sysfiles(struct device_driver *driverfs)
+{
+ driver_create_file(driverfs, &driver_attr_version);
+ driver_create_file(driverfs, &driver_attr_state);
+}
+
+void jsm_remove_driver_sysfiles(struct device_driver *driverfs)
+{
+ driver_remove_file(driverfs, &driver_attr_version);
+ driver_remove_file(driverfs, &driver_attr_state);
+}
diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
index 380c29539952b..bb6509f5fe8bb 100644
--- a/drivers/serial/m32r_sio.c
+++ b/drivers/serial/m32r_sio.c
@@ -26,6 +26,11 @@
* serial.c driver, and is currently the preferred form.
*/
#include <linux/config.h>
+
+#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>
@@ -40,12 +45,8 @@
#include <asm/io.h>
#include <asm/irq.h>
-#if defined(CONFIG_SERIAL_M32R_SIO_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#define PORT_SIO 1
-#define PORT_MAX_SIO 1
+#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>
@@ -83,44 +84,20 @@ unsigned int share_irqs_sio = M32R_SIO_SHARE_IRQS;
*/
#define is_real_interrupt(irq) ((irq) != 0)
-/*
- * This converts from our new CONFIG_ symbols to the symbols
- * that asm/serial.h expects. You _NEED_ to comment out the
- * linux/config.h include contained inside asm/serial.h for
- * this to work.
- */
-#undef CONFIG_SERIAL_MANY_PORTS
-#undef CONFIG_SERIAL_DETECT_IRQ
-#undef CONFIG_SERIAL_MULTIPORT
-#undef CONFIG_HUB6
-
-#ifdef CONFIG_SERIAL_M32R_SIO_DETECT_IRQ
-#define CONFIG_SERIAL_DETECT_IRQ 1
-#endif
-#ifdef CONFIG_SERIAL_M32R_SIO_MULTIPORT
-#define CONFIG_SERIAL_MULTIPORT 1
-#endif
-#ifdef CONFIG_SERIAL_M32R_SIO_MANY_PORTS
-#define CONFIG_SERIAL_MANY_PORTS 1
-#endif
+#include <asm/serial.h>
/*
- * HUB6 is always on. This will be removed once the header
- * files have been cleaned.
+ * 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.
*/
-#define CONFIG_HUB6 1
-
-#include <asm/serial.h>
+#ifndef SERIAL_PORT_DFNS
+#define SERIAL_PORT_DFNS
+#endif
-#ifdef CONFIG_SERIAL_M32R_PLDSIO
static struct old_serial_port old_serial_port[] = {
- { 0, BASE_BAUD, ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV, STD_COM_FLAGS },
+ SERIAL_PORT_DFNS /* defined in asm/serial.h */
};
-#else
-static struct old_serial_port old_serial_port[] = {
- { 0, BASE_BAUD, M32R_SIO_OFFSET, M32R_IRQ_SIO0_R, STD_COM_FLAGS },
-};
-#endif
#define UART_NR ARRAY_SIZE(old_serial_port)
@@ -153,9 +130,17 @@ 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_MAX_SIO+1] = {
- { "unknown", 1, 0 },
- { "M32RSIO", 1, 0 }
+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
@@ -460,7 +445,6 @@ static inline void m32r_sio_handle_port(struct uart_sio_port *up,
if (status & 0x04)
receive_chars(up, &status, regs);
- // check_modem_status(up);
if (status & 0x01)
transmit_chars(up);
}
@@ -842,13 +826,12 @@ m32r_sio_request_std_resource(struct uart_sio_port *up, struct resource **res)
int ret = 0;
switch (up->port.iotype) {
- case SERIAL_IO_MEM:
+ 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;
- start += UART_RSA_BASE << up->port.regshift;
*res = request_mem_region(start, size, "serial");
#endif
if (!*res)
@@ -856,8 +839,7 @@ m32r_sio_request_std_resource(struct uart_sio_port *up, struct resource **res)
}
break;
- case SERIAL_IO_HUB6:
- case SERIAL_IO_PORT:
+ case UPIO_PORT:
*res = request_region(up->port.iobase, size, "serial");
if (!*res)
ret = -EBUSY;
@@ -866,55 +848,15 @@ m32r_sio_request_std_resource(struct uart_sio_port *up, struct resource **res)
return ret;
}
-static int
-m32r_sio_request_rsa_resource(struct uart_sio_port *up, struct resource **res)
-{
- unsigned int size = 8 << up->port.regshift;
- unsigned long start;
- int ret = 0;
-
- switch (up->port.iotype) {
- case SERIAL_IO_MEM:
- if (up->port.mapbase) {
- start = up->port.mapbase;
- start += UART_RSA_BASE << up->port.regshift;
-#ifdef CONFIG_SERIAL_M32R_PLDSIO
- *res = request_mem_region(start, size, "serial-rsa");
-#else
- *res = request_mem_region(up->port.mapbase, size, "serial-rsa");
-#endif
- if (!*res)
- ret = -EBUSY;
- }
- break;
-
- case SERIAL_IO_HUB6:
- case SERIAL_IO_PORT:
- start = up->port.iobase;
- start += UART_RSA_BASE << up->port.regshift;
- *res = request_region(up->port.iobase, size, "serial-rsa");
- 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;
- if (up->port.type == PORT_RSA) {
- offset = UART_RSA_BASE << up->port.regshift;
- size = 8;
- }
-
size <<= up->port.regshift;
switch (up->port.iotype) {
- case SERIAL_IO_MEM:
+ case UPIO_MEM:
if (up->port.mapbase) {
/*
* Unmap the area.
@@ -930,8 +872,7 @@ static void m32r_sio_release_port(struct uart_port *port)
}
break;
- case SERIAL_IO_HUB6:
- case SERIAL_IO_PORT:
+ case UPIO_PORT:
start = up->port.iobase;
if (size)
@@ -947,14 +888,9 @@ static void m32r_sio_release_port(struct uart_port *port)
static int m32r_sio_request_port(struct uart_port *port)
{
struct uart_sio_port *up = (struct uart_sio_port *)port;
- struct resource *res = NULL, *res_rsa = NULL;
+ struct resource *res = NULL;
int ret = 0;
- if (up->port.type == PORT_RSA){
- ret = m32r_sio_request_rsa_resource(up, &res_rsa);
- if (ret < 0)
- return ret;
- }
ret = m32r_sio_request_std_resource(up, &res);
/*
@@ -969,11 +905,10 @@ static int m32r_sio_request_port(struct uart_port *port)
}
if (ret < 0) {
- if (res_rsa)
- release_resource(res_rsa);
if (res)
release_resource(res);
}
+
return ret;
}
@@ -983,7 +918,7 @@ static void m32r_sio_config_port(struct uart_port *port, int flags)
spin_lock_irqsave(&up->port.lock, flags);
- up->port.type = PORT_SIO;
+ 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);
@@ -994,8 +929,7 @@ 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 > PORT_MAX_SIO || ser->type == PORT_CIRRUS ||
- ser->type == PORT_STARTECH)
+ ser->type >= ARRAY_SIZE(uart_config))
return -EINVAL;
return 0;
}
@@ -1048,7 +982,6 @@ static void __init m32r_sio_isa_init_ports(void)
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.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;
@@ -1255,7 +1188,7 @@ static int __register_m32r_sio(struct serial_struct *req, int line)
}
/**
- * register_serial - configure a 16x50 serial port at runtime
+ * register_m32r_sio - configure a 16x50 serial port at runtime
* @req: request structure
*
* Configure the serial port specified by the request. If the
@@ -1272,7 +1205,7 @@ int register_m32r_sio(struct serial_struct *req)
return __register_m32r_sio(req, -1);
}
-int __init early_m32r_sio_setup(struct uart_port *port)
+int __init early_serial_setup(struct uart_port *port)
{
m32r_sio_isa_init_ports();
m32r_sio_ports[port->line].port = *port;
@@ -1282,7 +1215,7 @@ int __init early_m32r_sio_setup(struct uart_port *port)
}
/**
- * unregister_serial - remove a 16x50 serial port at runtime
+ * unregister_m32r_sio - remove a 16x50 serial port at runtime
* @line: serial line number
*
* Remove one serial port. This may be called from interrupt
@@ -1293,20 +1226,6 @@ void unregister_m32r_sio(int line)
uart_unregister_port(&m32r_sio_reg, line);
}
-/*
- * This is for ISAPNP only.
- */
-void m32r_sio_get_irq_map(unsigned int *map)
-{
- int i;
-
- for (i = 0; i < UART_NR; i++) {
- if (m32r_sio_ports[i].port.type != PORT_UNKNOWN &&
- m32r_sio_ports[i].port.irq < 16)
- *map |= 1 << m32r_sio_ports[i].port.irq;
- }
-}
-
/**
* m32r_sio_suspend_port - suspend one serial port
* @line: serial line number
@@ -1361,7 +1280,6 @@ module_exit(m32r_sio_exit);
EXPORT_SYMBOL(register_m32r_sio);
EXPORT_SYMBOL(unregister_m32r_sio);
-EXPORT_SYMBOL(m32r_sio_get_irq_map);
EXPORT_SYMBOL(m32r_sio_suspend_port);
EXPORT_SYMBOL(m32r_sio_resume_port);
diff --git a/drivers/serial/m32r_sio.h b/drivers/serial/m32r_sio.h
index f957c76f42321..07d0dd80aa3dd 100644
--- a/drivers/serial/m32r_sio.h
+++ b/drivers/serial/m32r_sio.h
@@ -36,7 +36,6 @@ struct old_serial_port {
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;
diff --git a/drivers/serial/m32r_sio_reg.h b/drivers/serial/m32r_sio_reg.h
index d94025568ebd5..9c864529451b1 100644
--- a/drivers/serial/m32r_sio_reg.h
+++ b/drivers/serial/m32r_sio_reg.h
@@ -104,31 +104,6 @@
#define UART_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
/*
- * These are the definitions for the FIFO Control Register
- * (16650 only)
- */
-#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */
-#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */
-#define UART_FCR_CLEAR_XMIT 0x04 /* Clear the XMIT FIFO */
-#define UART_FCR_DMA_SELECT 0x08 /* For DMA applications */
-#define UART_FCR_TRIGGER_MASK 0xC0 /* Mask for the FIFO trigger range */
-#define UART_FCR_TRIGGER_1 0x00 /* Mask for trigger set at 1 */
-#define UART_FCR_TRIGGER_4 0x40 /* Mask for trigger set at 4 */
-#define UART_FCR_TRIGGER_8 0x80 /* Mask for trigger set at 8 */
-#define UART_FCR_TRIGGER_14 0xC0 /* Mask for trigger set at 14 */
-/* 16650 redefinitions */
-#define UART_FCR6_R_TRIGGER_8 0x00 /* Mask for receive trigger set at 1 */
-#define UART_FCR6_R_TRIGGER_16 0x40 /* Mask for receive trigger set at 4 */
-#define UART_FCR6_R_TRIGGER_24 0x80 /* Mask for receive trigger set at 8 */
-#define UART_FCR6_R_TRIGGER_28 0xC0 /* Mask for receive trigger set at 14 */
-#define UART_FCR6_T_TRIGGER_16 0x00 /* Mask for transmit trigger set at 16 */
-#define UART_FCR6_T_TRIGGER_8 0x10 /* Mask for transmit trigger set at 8 */
-#define UART_FCR6_T_TRIGGER_24 0x20 /* Mask for transmit trigger set at 24 */
-#define UART_FCR6_T_TRIGGER_30 0x30 /* Mask for transmit trigger set at 30 */
-/* TI 16750 definitions */
-#define UART_FCR7_64BYTE 0x20 /* Go into 64 byte mode */
-
-/*
* These are the definitions for the Line Control Register
*
* Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting
@@ -174,170 +149,5 @@
#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 */
-/*
- * Sleep mode for ST16650 and TI16750.
- * Note that for 16650, EFR-bit 4 must be selected as well.
- */
-#define UART_IERX_SLEEP 0x10 /* Enable sleep mode */
-
-/*
- * These are the definitions for the Modem Control Register
- */
-#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
-#define UART_MCR_OUT2 0x08 /* Out2 complement */
-#define UART_MCR_OUT1 0x04 /* Out1 complement */
-#define UART_MCR_RTS 0x02 /* RTS complement */
-#define UART_MCR_DTR 0x01 /* DTR complement */
-
-/*
- * These are the definitions for the Modem Status Register
- */
-#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
-#define UART_MSR_RI 0x40 /* Ring Indicator */
-#define UART_MSR_DSR 0x20 /* Data Set Ready */
-#define UART_MSR_CTS 0x10 /* Clear to Send */
-#define UART_MSR_DDCD 0x08 /* Delta DCD */
-#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
-#define UART_MSR_DDSR 0x02 /* Delta DSR */
-#define UART_MSR_DCTS 0x01 /* Delta CTS */
-#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
-
-/*
- * These are the definitions for the Extended Features Register
- * (StarTech 16C660 only, when DLAB=1)
- */
-#define UART_EFR_CTS 0x80 /* CTS flow control */
-#define UART_EFR_RTS 0x40 /* RTS flow control */
-#define UART_EFR_SCD 0x20 /* Special character detect */
-#define UART_EFR_ECB 0x10 /* Enhanced control bit */
-/*
- * the low four bits control software flow control
- */
-
-/*
- * These register definitions are for the 16C950
- */
-#define UART_ASR 0x01 /* Additional Status Register */
-#define UART_RFL 0x03 /* Receiver FIFO level */
-#define UART_TFL 0x04 /* Transmitter FIFO level */
-#define UART_ICR 0x05 /* Index Control Register */
-
-/* The 16950 ICR registers */
-#define UART_ACR 0x00 /* Additional Control Register */
-#define UART_CPR 0x01 /* Clock Prescalar Register */
-#define UART_TCR 0x02 /* Times Clock Register */
-#define UART_CKS 0x03 /* Clock Select Register */
-#define UART_TTL 0x04 /* Transmitter Interrupt Trigger Level */
-#define UART_RTL 0x05 /* Receiver Interrupt Trigger Level */
-#define UART_FCL 0x06 /* Flow Control Level Lower */
-#define UART_FCH 0x07 /* Flow Control Level Higher */
-#define UART_ID1 0x08 /* ID #1 */
-#define UART_ID2 0x09 /* ID #2 */
-#define UART_ID3 0x0A /* ID #3 */
-#define UART_REV 0x0B /* Revision */
-#define UART_CSR 0x0C /* Channel Software Reset */
-#define UART_NMR 0x0D /* Nine-bit Mode Register */
-#define UART_CTR 0xFF
-
-/*
- * The 16C950 Additional Control Reigster
- */
-#define UART_ACR_RXDIS 0x01 /* Receiver disable */
-#define UART_ACR_TXDIS 0x02 /* Receiver disable */
-#define UART_ACR_DSRFC 0x04 /* DSR Flow Control */
-#define UART_ACR_TLENB 0x20 /* 950 trigger levels enable */
-#define UART_ACR_ICRRD 0x40 /* ICR Read enable */
-#define UART_ACR_ASREN 0x80 /* Additional status enable */
-
-/*
- * These are the definitions for the Feature Control Register
- * (XR16C85x only, when LCR=bf; doubles with the Interrupt Enable
- * Register, UART register #1)
- */
-#define UART_FCTR_RTS_NODELAY 0x00 /* RTS flow control delay */
-#define UART_FCTR_RTS_4DELAY 0x01
-#define UART_FCTR_RTS_6DELAY 0x02
-#define UART_FCTR_RTS_8DELAY 0x03
-#define UART_FCTR_IRDA 0x04 /* IrDa data encode select */
-#define UART_FCTR_TX_INT 0x08 /* Tx interrupt type select */
-#define UART_FCTR_TRGA 0x00 /* Tx/Rx 550 trigger table select */
-#define UART_FCTR_TRGB 0x10 /* Tx/Rx 650 trigger table select */
-#define UART_FCTR_TRGC 0x20 /* Tx/Rx 654 trigger table select */
-#define UART_FCTR_TRGD 0x30 /* Tx/Rx 850 programmable trigger select */
-#define UART_FCTR_SCR_SWAP 0x40 /* Scratch pad register swap */
-#define UART_FCTR_RX 0x00 /* Programmable trigger mode select */
-#define UART_FCTR_TX 0x80 /* Programmable trigger mode select */
-
-/*
- * These are the definitions for the Enhanced Mode Select Register
- * (XR16C85x only, when LCR=bf and FCTR bit 6=1; doubles with the
- * Scratch register, UART register #7)
- */
-#define UART_EMSR_FIFO_COUNT 0x01 /* Rx/Tx select */
-#define UART_EMSR_ALT_COUNT 0x02 /* Alternating count select */
-
-/*
- * These are the definitions for the Programmable Trigger
- * Register (XR16C85x only, when LCR=bf; doubles with the UART RX/TX
- * register, UART register #0)
- */
-#define UART_TRG_1 0x01
-#define UART_TRG_4 0x04
-#define UART_TRG_8 0x08
-#define UART_TRG_16 0x10
-#define UART_TRG_32 0x20
-#define UART_TRG_64 0x40
-#define UART_TRG_96 0x60
-#define UART_TRG_120 0x78
-#define UART_TRG_128 0x80
-
-/*
- * These definitions are for the RSA-DV II/S card, from
- *
- * Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
- */
-
-#define UART_RSA_BASE (-8)
-
-#define UART_RSA_MSR ((UART_RSA_BASE) + 0) /* I/O: Mode Select Register */
-
-#define UART_RSA_MSR_SWAP (1 << 0) /* Swap low/high 8 bytes in I/O port addr */
-#define UART_RSA_MSR_FIFO (1 << 2) /* Enable the external FIFO */
-#define UART_RSA_MSR_FLOW (1 << 3) /* Enable the auto RTS/CTS flow control */
-#define UART_RSA_MSR_ITYP (1 << 4) /* Level (1) / Edge triger (0) */
-
-#define UART_RSA_IER ((UART_RSA_BASE) + 1) /* I/O: Interrupt Enable Register */
-
-#define UART_RSA_IER_Rx_FIFO_H (1 << 0) /* Enable Rx FIFO half full int. */
-#define UART_RSA_IER_Tx_FIFO_H (1 << 1) /* Enable Tx FIFO half full int. */
-#define UART_RSA_IER_Tx_FIFO_E (1 << 2) /* Enable Tx FIFO empty int. */
-#define UART_RSA_IER_Rx_TOUT (1 << 3) /* Enable char receive timeout int */
-#define UART_RSA_IER_TIMER (1 << 4) /* Enable timer interrupt */
-
-#define UART_RSA_SRR ((UART_RSA_BASE) + 2) /* IN: Status Read Register */
-
-#define UART_RSA_SRR_Tx_FIFO_NEMP (1 << 0) /* Tx FIFO is not empty (1) */
-#define UART_RSA_SRR_Tx_FIFO_NHFL (1 << 1) /* Tx FIFO is not half full (1) */
-#define UART_RSA_SRR_Tx_FIFO_NFUL (1 << 2) /* Tx FIFO is not full (1) */
-#define UART_RSA_SRR_Rx_FIFO_NEMP (1 << 3) /* Rx FIFO is not empty (1) */
-#define UART_RSA_SRR_Rx_FIFO_NHFL (1 << 4) /* Rx FIFO is not half full (1) */
-#define UART_RSA_SRR_Rx_FIFO_NFUL (1 << 5) /* Rx FIFO is not full (1) */
-#define UART_RSA_SRR_Rx_TOUT (1 << 6) /* Character reception timeout occurred (1) */
-#define UART_RSA_SRR_TIMER (1 << 7) /* Timer interrupt occurred */
-
-#define UART_RSA_FRR ((UART_RSA_BASE) + 2) /* OUT: FIFO Reset Register */
-
-#define UART_RSA_TIVSR ((UART_RSA_BASE) + 3) /* I/O: Timer Interval Value Set Register */
-
-#define UART_RSA_TCR ((UART_RSA_BASE) + 4) /* OUT: Timer Control Register */
-
-#define UART_RSA_TCR_SWITCH (1 << 0) /* Timer on */
-
-/*
- * The RSA DSV/II board has two fixed clock frequencies. One is the
- * standard rate, and the other is 8 times faster.
- */
-#define SERIAL_RSA_BAUD_BASE (921600)
-#define SERIAL_RSA_BAUD_BASE_LO (SERIAL_RSA_BAUD_BASE / 8)
#endif /* _M32R_SIO_REG_H */
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index 210b0b16345ef..5538756f13ba8 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -5949,10 +5949,10 @@ static int ixj_build_filter_cadence(IXJ *j, IXJ_FILTER_CADENCE __user * cp)
j->cadence_f[lcp->filter].off3 = lcp->off3;
j->cadence_f[lcp->filter].off3min = 0;
j->cadence_f[lcp->filter].off3max = 0;
- kfree(lcp);
if(ixjdebug & 0x0002) {
printk(KERN_INFO "Cadence %d loaded\n", lcp->filter);
}
+ kfree(lcp);
return 0;
}
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 8f32b79e41de2..cb70fcd143297 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -199,7 +199,7 @@ MODULE_PARM_DESC(iProduct, "USB Product string");
/* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */
static char *__initdata dev_addr;
module_param(dev_addr, charp, S_IRUGO);
-MODULE_PARM_DESC(iProduct, "Device Ethernet Address");
+MODULE_PARM_DESC(dev_addr, "Device Ethernet Address");
/* this address is invisible to ifconfig */
static char *__initdata host_addr;
diff --git a/drivers/usb/media/pwc/pwc-if.c b/drivers/usb/media/pwc/pwc-if.c
index ded2d182a5c10..502e78c2fea30 100644
--- a/drivers/usb/media/pwc/pwc-if.c
+++ b/drivers/usb/media/pwc/pwc-if.c
@@ -1896,7 +1896,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
}
init_MUTEX(&pdev->modlock);
- pdev->ptrlock = SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&pdev->ptrlock);
pdev->udev = udev;
init_waitqueue_head(&pdev->frameq);
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index a4662d7b33785..e35b5adcd5fe7 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -3110,4 +3110,4 @@ module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
module_param(low_latency, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Low latency enabled or not");
+MODULE_PARM_DESC(low_latency, "Low latency enabled or not");
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c
index 9e1a835f7e5cd..f02965f395016 100644
--- a/drivers/video/acornfb.c
+++ b/drivers/video/acornfb.c
@@ -909,7 +909,7 @@ acornfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma
* some updates to the screen occasionally, but process switches
* should cause the caches and buffers to be flushed often enough.
*/
- if (io_remap_page_range(vma, vma->vm_start, off,
+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
return -EAGAIN;
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index 1aa9112627ea7..cacd88cc84ab6 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -408,7 +408,7 @@ au1100fb_mmap(struct fb_info *_fb,
/* This is an IO map - tell maydump to skip this VMA */
vma->vm_flags |= VM_IO;
- if (io_remap_page_range(vma, vma->vm_start, off,
+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot)) {
return -EAGAIN;
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index f0eb993dd6f7d..989e700159e01 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -315,7 +315,7 @@ static int controlfb_mmap(struct fb_info *info, struct file *file,
return -EINVAL;
off += start;
vma->vm_pgoff = off >> PAGE_SHIFT;
- if (io_remap_page_range(vma, vma->vm_start, off,
+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 305d46ad72f34..4a45e287ba459 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -940,8 +940,8 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
/* This is an IO map - tell maydump to skip this VMA */
vma->vm_flags |= VM_IO | VM_RESERVED;
#if defined(__sparc_v9__)
- if (io_remap_page_range(vma, vma->vm_start, off,
- vma->vm_end - vma->vm_start, vma->vm_page_prot, 0))
+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
#else
#if defined(__mc68000__)
@@ -957,7 +957,9 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
}
#endif
#elif defined(__powerpc__)
- pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
+ vma->vm_page_prot = phys_mem_access_prot(file, off,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
#elif defined(__alpha__)
/* Caching is off in the I/O space quadrant by design. */
#elif defined(__i386__) || defined(__x86_64__)
@@ -977,7 +979,7 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
#else
#warning What do we have to do here??
#endif
- if (io_remap_page_range(vma, vma->vm_start, off,
+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
#endif /* !__sparc_v9__ */
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index 6439fb0731586..33bedf94247ec 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -836,7 +836,7 @@ static int sa1100fb_mmap(struct fb_info *info, struct file *file,
vma->vm_pgoff = off >> PAGE_SHIFT;
vma->vm_flags |= VM_IO;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- return io_remap_page_range(vma, vma->vm_start, off,
+ return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
}
diff --git a/drivers/video/sbuslib.c b/drivers/video/sbuslib.c
index 70e875aaa2f56..34f72edba820e 100644
--- a/drivers/video/sbuslib.c
+++ b/drivers/video/sbuslib.c
@@ -74,10 +74,12 @@ int sbusfb_mmap_helper(struct sbus_mmap_map *map,
}
if (page + map_size > size)
map_size = size - page;
- r = io_remap_page_range(vma,
+ r = io_remap_pfn_range(vma,
vma->vm_start + page,
- map_offset, map_size,
- vma->vm_page_prot, iospace);
+ MK_IOSPACE_PFN(iospace,
+ map_offset >> PAGE_SHIFT),
+ map_size,
+ vma->vm_page_prot);
if (r)
return -EAGAIN;
page += map_size;
diff --git a/fs/Kconfig b/fs/Kconfig
index 4bb214ea133a6..6a4ad4bb7a54e 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -936,6 +936,7 @@ config HFS_FS
config HFSPLUS_FS
tristate "Apple Extended HFS file system support"
select NLS
+ select NLS_UTF8
help
If you say Y here, you will be able to mount extended format
Macintosh-formatted hard drive partitions with full read-write access.
diff --git a/fs/afs/kafsasyncd.c b/fs/afs/kafsasyncd.c
index e179e17acdc6f..6fc88ae8ad947 100644
--- a/fs/afs/kafsasyncd.c
+++ b/fs/afs/kafsasyncd.c
@@ -116,6 +116,8 @@ static int kafsasyncd(void *arg)
remove_wait_queue(&kafsasyncd_sleepq, &myself);
set_current_state(TASK_RUNNING);
+ try_to_freeze(PF_FREEZE);
+
/* discard pending signals */
afs_discard_my_signals();
diff --git a/fs/afs/kafstimod.c b/fs/afs/kafstimod.c
index e8bbffee58660..86e710dd057e7 100644
--- a/fs/afs/kafstimod.c
+++ b/fs/afs/kafstimod.c
@@ -91,6 +91,8 @@ static int kafstimod(void *arg)
complete_and_exit(&kafstimod_dead, 0);
}
+ try_to_freeze(PF_FREEZE);
+
/* discard pending signals */
afs_discard_my_signals();
diff --git a/fs/attr.c b/fs/attr.c
index d8524fc01e109..c3c76fe783464 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -135,14 +135,17 @@ int setattr_mask(unsigned int ia_valid)
int notify_change(struct dentry * dentry, struct iattr * attr)
{
struct inode *inode = dentry->d_inode;
- mode_t mode = inode->i_mode;
+ mode_t mode;
int error;
- struct timespec now = current_fs_time(inode->i_sb);
+ struct timespec now;
unsigned int ia_valid = attr->ia_valid;
if (!inode)
BUG();
+ mode = inode->i_mode;
+ now = current_fs_time(inode->i_sb);
+
attr->ia_ctime = now;
if (!(ia_valid & ATTR_ATIME_SET))
attr->ia_atime = now;
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index 90ce87a582319..672a31924f3cd 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -15,17 +15,6 @@
#include <linux/smp_lock.h>
#include <linux/namei.h>
-/*
- * The follow_link operation is special: it must behave as a no-op
- * so that a bad root inode can at least be unmounted. To do this
- * we must dput() the base and return the dentry with a dget().
- */
-static int bad_follow_link(struct dentry *dent, struct nameidata *nd)
-{
- nd_set_link(nd, ERR_PTR(-EIO));
- return 0;
-}
-
static int return_EIO(void)
{
return -EIO;
@@ -70,7 +59,8 @@ struct inode_operations bad_inode_ops =
.mknod = EIO_ERROR,
.rename = EIO_ERROR,
.readlink = EIO_ERROR,
- .follow_link = bad_follow_link,
+ /* follow_link must be no-op, otherwise unmounting this inode
+ won't work */
.truncate = EIO_ERROR,
.permission = EIO_ERROR,
.getattr = EIO_ERROR,
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index bb7d9032f64a1..009b8920c1fff 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -317,7 +317,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
(current->mm->start_brk = N_BSSADDR(ex));
current->mm->free_area_cache = current->mm->mmap_base;
- current->mm->rss = 0;
+ set_mm_counter(current->mm, rss, 0);
current->mm->mmap = NULL;
compute_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index a7ce4ea2dab1c..76ec9d8939ffe 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -773,7 +773,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
/* Do this so that we can load the interpreter, if need be. We will
change some of these later */
- current->mm->rss = 0;
+ set_mm_counter(current->mm, rss, 0);
current->mm->free_area_cache = current->mm->mmap_base;
retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP),
executable_stack);
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 745e9b8b3a5ea..134c9c0d1f54f 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -299,7 +299,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, struct pt_regs *regs
/* do this so that we can load the interpreter, if need be
* - we will change some of these later
*/
- current->mm->rss = 0;
+ set_mm_counter(current->mm, rss, 0);
#ifdef CONFIG_MMU
retval = setup_arg_pages(bprm, current->mm->start_stack, executable_stack);
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index fb440602cfc17..f0cd67d9d31b9 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -650,7 +650,7 @@ static int load_flat_file(struct linux_binprm * bprm,
current->mm->start_brk = datapos + data_len + bss_len;
current->mm->brk = (current->mm->start_brk + 3) & ~3;
current->mm->context.end_brk = memp + ksize((void *) memp) - stack_len;
- current->mm->rss = 0;
+ set_mm_counter(current->mm, rss, 0);
}
if (flags & FLAT_FLAG_KTRACE)
diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c
index f02ee506dd654..227a2682d2bfa 100644
--- a/fs/binfmt_som.c
+++ b/fs/binfmt_som.c
@@ -259,7 +259,7 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
create_som_tables(bprm);
current->mm->start_stack = bprm->p;
- current->mm->rss = 0;
+ set_mm_counter(current->mm, rss, 0);
#if 0
printk("(start_brk) %08lx\n" , (unsigned long) current->mm->start_brk);
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 9076a29748b38..44cc45607678a 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -66,7 +66,7 @@ module_param(cifs_min_rcv, int, 0);
MODULE_PARM_DESC(cifs_min_rcv,"Network buffers in pool. Default: 4 Range: 1 to 64");
unsigned int cifs_min_small = 30;
module_param(cifs_min_small, int, 0);
-MODULE_PARM_DESC(cifs_small_rcv,"Small network buffers in pool. Default: 30 Range: 2 to 256");
+MODULE_PARM_DESC(cifs_min_small,"Small network buffers in pool. Default: 30 Range: 2 to 256");
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");
diff --git a/fs/dcache.c b/fs/dcache.c
index 1cbc5d033f9d6..496a4e08369c4 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -36,6 +36,7 @@
/* #define DCACHE_DEBUG 1 */
int sysctl_vfs_cache_pressure = 100;
+EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);
__cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lock);
seqlock_t rename_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED;
diff --git a/fs/dquot.c b/fs/dquot.c
index ce245268668a8..11048e0b32c92 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -505,14 +505,12 @@ static void prune_dqcache(int count)
static int shrink_dqcache_memory(int nr, unsigned int gfp_mask)
{
- int ret;
-
- spin_lock(&dq_list_lock);
- if (nr)
+ if (nr) {
+ spin_lock(&dq_list_lock);
prune_dqcache(nr);
- ret = dqstats.allocated_dquots;
- spin_unlock(&dq_list_lock);
- return ret;
+ spin_unlock(&dq_list_lock);
+ }
+ return (dqstats.free_dquots / 100) * sysctl_vfs_cache_pressure;
}
/*
diff --git a/fs/exec.c b/fs/exec.c
index 98dcef04c830c..a8394499926cd 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -326,7 +326,7 @@ void install_arg_page(struct vm_area_struct *vma,
pte_unmap(pte);
goto out;
}
- mm->rss++;
+ inc_mm_counter(mm, rss);
lru_cache_add_active(page);
set_pte_at(mm, address, pte, pte_mkdirty(pte_mkwrite(mk_pte(
page, vma->vm_page_prot))));
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 1d0e117095110..37ca77a157ba5 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -518,12 +518,18 @@ static int ext2_check_descriptors (struct super_block * sb)
static loff_t ext2_max_size(int bits)
{
loff_t res = EXT2_NDIR_BLOCKS;
+ /* This constant is calculated to be the largest file size for a
+ * dense, 4k-blocksize file such that the total number of
+ * sectors in the file, including data and all indirect blocks,
+ * does not exceed 2^32. */
+ const loff_t upper_limit = 0x1ff7fffd000LL;
+
res += 1LL << (bits-2);
res += 1LL << (2*(bits-2));
res += 1LL << (3*(bits-2));
res <<= bits;
- if (res > (512LL << 32) - (1 << bits))
- res = (512LL << 32) - (1 << bits);
+ if (res > upper_limit)
+ res = upper_limit;
return res;
}
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 01fae128a1fe7..05be496c892f1 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -858,6 +858,12 @@ get_block:
return ret;
}
+static int ext3_writepages_get_block(struct inode *inode, sector_t iblock,
+ struct buffer_head *bh, int create)
+{
+ return ext3_direct_io_get_blocks(inode, iblock, 1, bh, create);
+}
+
/*
* `handle' can be NULL if create is zero
*/
@@ -1010,7 +1016,10 @@ retry:
ret = PTR_ERR(handle);
goto out;
}
- ret = block_prepare_write(page, from, to, ext3_get_block);
+ if (test_opt(inode->i_sb, NOBH))
+ ret = nobh_prepare_write(page, from, to, ext3_get_block);
+ else
+ ret = block_prepare_write(page, from, to, ext3_get_block);
if (ret)
goto prepare_write_failed;
@@ -1094,7 +1103,12 @@ static int ext3_writeback_commit_write(struct file *file, struct page *page,
new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
if (new_i_size > EXT3_I(inode)->i_disksize)
EXT3_I(inode)->i_disksize = new_i_size;
- ret = generic_commit_write(file, page, from, to);
+
+ if (test_opt(inode->i_sb, NOBH))
+ ret = nobh_commit_write(file, page, from, to);
+ else
+ ret = generic_commit_write(file, page, from, to);
+
ret2 = ext3_journal_stop(handle);
if (!ret)
ret = ret2;
@@ -1323,6 +1337,45 @@ out_fail:
return ret;
}
+static int
+ext3_writeback_writepage_helper(struct page *page,
+ struct writeback_control *wbc)
+{
+ return block_write_full_page(page, ext3_get_block, wbc);
+}
+
+static int
+ext3_writeback_writepages(struct address_space *mapping,
+ struct writeback_control *wbc)
+{
+ struct inode *inode = mapping->host;
+ handle_t *handle = NULL;
+ int err, ret = 0;
+
+ if (!mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
+ return ret;
+
+ handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode));
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ return ret;
+ }
+
+ ret = __mpage_writepages(mapping, wbc, ext3_writepages_get_block,
+ ext3_writeback_writepage_helper);
+
+ /*
+ * Need to reaquire the handle since ext3_writepages_get_block()
+ * can restart the handle
+ */
+ handle = journal_current_handle();
+
+ err = ext3_journal_stop(handle);
+ if (!ret)
+ ret = err;
+ return ret;
+}
+
static int ext3_writeback_writepage(struct page *page,
struct writeback_control *wbc)
{
@@ -1340,7 +1393,11 @@ static int ext3_writeback_writepage(struct page *page,
goto out_fail;
}
- ret = block_write_full_page(page, ext3_get_block, wbc);
+ if (test_opt(inode->i_sb, NOBH))
+ ret = nobh_writepage(page, ext3_get_block, wbc);
+ else
+ ret = block_write_full_page(page, ext3_get_block, wbc);
+
err = ext3_journal_stop(handle);
if (!ret)
ret = err;
@@ -1439,6 +1496,8 @@ static int ext3_releasepage(struct page *page, int wait)
journal_t *journal = EXT3_JOURNAL(page->mapping->host);
WARN_ON(PageChecked(page));
+ if (!page_has_buffers(page))
+ return 0;
return journal_try_to_free_buffers(journal, page, wait);
}
@@ -1554,6 +1613,7 @@ static struct address_space_operations ext3_writeback_aops = {
.readpage = ext3_readpage,
.readpages = ext3_readpages,
.writepage = ext3_writeback_writepage,
+ .writepages = ext3_writeback_writepages,
.sync_page = block_sync_page,
.prepare_write = ext3_prepare_write,
.commit_write = ext3_writeback_commit_write,
@@ -1600,13 +1660,28 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page,
unsigned blocksize, iblock, length, pos;
struct inode *inode = mapping->host;
struct buffer_head *bh;
- int err;
+ int err = 0;
void *kaddr;
blocksize = inode->i_sb->s_blocksize;
length = blocksize - (offset & (blocksize - 1));
iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
+ /*
+ * For "nobh" option, we can only work if we don't need to
+ * read-in the page - otherwise we create buffers to do the IO.
+ */
+ if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH)) {
+ if (PageUptodate(page)) {
+ kaddr = kmap_atomic(page, KM_USER0);
+ memset(kaddr + offset, 0, length);
+ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_USER0);
+ set_page_dirty(page);
+ goto unlock;
+ }
+ }
+
if (!page_has_buffers(page))
create_empty_buffers(page, blocksize, 0);
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index aa0f1b545bb6a..34288e100d957 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -576,7 +576,7 @@ enum {
Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
- Opt_reservation, Opt_noreservation, Opt_noload,
+ Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh,
Opt_commit, Opt_journal_update, Opt_journal_inum,
Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
@@ -611,6 +611,7 @@ static match_table_t tokens = {
{Opt_reservation, "reservation"},
{Opt_noreservation, "noreservation"},
{Opt_noload, "noload"},
+ {Opt_nobh, "nobh"},
{Opt_commit, "commit=%u"},
{Opt_journal_update, "journal=update"},
{Opt_journal_inum, "journal=%u"},
@@ -924,6 +925,9 @@ clear_qf_name:
match_int(&args[0], &option);
*n_blocks_count = option;
break;
+ case Opt_nobh:
+ set_opt(sbi->s_mount_opt, NOBH);
+ break;
default:
printk (KERN_ERR
"EXT3-fs: Unrecognized mount option \"%s\" "
@@ -1193,12 +1197,18 @@ static void ext3_orphan_cleanup (struct super_block * sb,
static loff_t ext3_max_size(int bits)
{
loff_t res = EXT3_NDIR_BLOCKS;
+ /* This constant is calculated to be the largest file size for a
+ * dense, 4k-blocksize file such that the total number of
+ * sectors in the file, including data and all indirect blocks,
+ * does not exceed 2^32. */
+ const loff_t upper_limit = 0x1ff7fffd000LL;
+
res += 1LL << (bits-2);
res += 1LL << (2*(bits-2));
res += 1LL << (3*(bits-2));
res <<= bits;
- if (res > (512LL << 32) - (1 << bits))
- res = (512LL << 32) - (1 << bits);
+ if (res > upper_limit)
+ res = upper_limit;
return res;
}
@@ -1563,6 +1573,19 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
break;
}
+ if (test_opt(sb, NOBH)) {
+ if (sb->s_blocksize_bits != PAGE_CACHE_SHIFT) {
+ printk(KERN_WARNING "EXT3-fs: Ignoring nobh option "
+ "since filesystem blocksize doesn't match "
+ "pagesize\n");
+ clear_opt(sbi->s_mount_opt, NOBH);
+ }
+ if (!(test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)) {
+ printk(KERN_WARNING "EXT3-fs: Ignoring nobh option - "
+ "its supported only with writeback mode\n");
+ clear_opt(sbi->s_mount_opt, NOBH);
+ }
+ }
/*
* The journal_load will have done any necessary log recovery,
* so we can safely mount the rest of the filesystem now.
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 03bbc72e01dca..8ccee8415488a 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -431,7 +431,8 @@ static void __exit fat_destroy_inodecache(void)
static int fat_remount(struct super_block *sb, int *flags, char *data)
{
- *flags |= MS_NODIRATIME;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ *flags |= MS_NODIRATIME | (sbi->options.isvfat ? 0 : MS_NOATIME);
return 0;
}
diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c
index b47ab4283cca6..6ad1211f84edb 100644
--- a/fs/hfs/bnode.c
+++ b/fs/hfs/bnode.c
@@ -285,6 +285,10 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
page = read_cache_page(mapping, block++, (filler_t *)mapping->a_ops->readpage, NULL);
if (IS_ERR(page))
goto fail;
+ if (PageError(page)) {
+ page_cache_release(page);
+ goto fail;
+ }
#if !REF_PAGES
page_cache_release(page);
#endif
@@ -326,12 +330,16 @@ struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num)
hfs_bnode_get(node);
spin_unlock(&tree->hash_lock);
wait_event(node->lock_wq, !test_bit(HFS_BNODE_NEW, &node->flags));
+ if (test_bit(HFS_BNODE_ERROR, &node->flags))
+ goto node_error;
return node;
}
spin_unlock(&tree->hash_lock);
node = __hfs_bnode_create(tree, num);
if (!node)
return ERR_PTR(-ENOMEM);
+ if (test_bit(HFS_BNODE_ERROR, &node->flags))
+ goto node_error;
if (!test_bit(HFS_BNODE_NEW, &node->flags))
return node;
@@ -416,6 +424,10 @@ struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num)
node = __hfs_bnode_create(tree, num);
if (!node)
return ERR_PTR(-ENOMEM);
+ if (test_bit(HFS_BNODE_ERROR, &node->flags)) {
+ hfs_bnode_put(node);
+ return ERR_PTR(-EIO);
+ }
pagep = node->page;
memset(kmap(*pagep) + node->page_offset, 0,
diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c
index 4f7289239d02e..cbc8510ad2221 100644
--- a/fs/hfs/extent.c
+++ b/fs/hfs/extent.c
@@ -49,22 +49,21 @@ static void hfs_ext_build_key(hfs_btree_key *key, u32 cnid, u16 block, u8 type)
* This function has no side-effects */
int hfs_ext_keycmp(const btree_key *key1, const btree_key *key2)
{
- unsigned int tmp;
- int retval;
-
- tmp = be32_to_cpu(key1->ext.FNum) - be32_to_cpu(key2->ext.FNum);
- if (tmp != 0) {
- retval = (int)tmp;
- } else {
- tmp = (unsigned char)key1->ext.FkType - (unsigned char)key2->ext.FkType;
- if (tmp != 0) {
- retval = (int)tmp;
- } else {
- retval = (int)(be16_to_cpu(key1->ext.FABN)
- - be16_to_cpu(key2->ext.FABN));
- }
- }
- return retval;
+ __be32 fnum1, fnum2;
+ __be16 block1, block2;
+
+ fnum1 = key1->ext.FNum;
+ fnum2 = key2->ext.FNum;
+ if (fnum1 != fnum2)
+ return be32_to_cpu(fnum1) < be32_to_cpu(fnum2) ? -1 : 1;
+ if (key1->ext.FkType != key2->ext.FkType)
+ return key1->ext.FkType < key2->ext.FkType ? -1 : 1;
+
+ block1 = key1->ext.FABN;
+ block2 = key2->ext.FABN;
+ if (block1 == block2)
+ return 0;
+ return be16_to_cpu(block1) < be16_to_cpu(block2) ? -1 : 1;
}
/*
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index f1757d1390ed2..7519123260945 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -74,12 +74,6 @@ static int hfs_releasepage(struct page *page, int mask)
;
else if (atomic_read(&node->refcnt))
res = 0;
- else for (i = 0; i < tree->pages_per_bnode; i++) {
- if (PageActive(node->page[i])) {
- res = 0;
- break;
- }
- }
if (res && node) {
hfs_bnode_unhash(node);
hfs_bnode_free(node);
@@ -103,7 +97,7 @@ static int hfs_releasepage(struct page *page, int mask)
spin_unlock(&tree->hash_lock);
}
//printk("releasepage: %lu,%x = %d\n", page->index, mask, res);
- return res;
+ return res ? try_to_free_buffers(page) : 0;
}
static int hfs_get_blocks(struct inode *inode, sector_t iblock, unsigned long max_blocks,
@@ -177,14 +171,16 @@ struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, int mode)
HFS_I(inode)->flags = 0;
HFS_I(inode)->rsrc_inode = NULL;
HFS_I(inode)->fs_blocks = 0;
- if (S_ISDIR(inode->i_mode)) {
+ if (S_ISDIR(mode)) {
inode->i_size = 2;
HFS_SB(sb)->folder_count++;
if (dir->i_ino == HFS_ROOT_CNID)
HFS_SB(sb)->root_dirs++;
inode->i_op = &hfs_dir_inode_operations;
inode->i_fop = &hfs_dir_operations;
- } else if (S_ISREG(inode->i_mode)) {
+ inode->i_mode |= S_IRWXUGO;
+ inode->i_mode &= ~HFS_SB(inode->i_sb)->s_dir_umask;
+ } else if (S_ISREG(mode)) {
HFS_I(inode)->clump_blocks = HFS_SB(sb)->clumpablks;
HFS_SB(sb)->file_count++;
if (dir->i_ino == HFS_ROOT_CNID)
@@ -192,6 +188,10 @@ struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, int mode)
inode->i_op = &hfs_file_inode_operations;
inode->i_fop = &hfs_file_operations;
inode->i_mapping->a_ops = &hfs_aops;
+ inode->i_mode |= S_IRUGO|S_IXUGO;
+ if (mode & S_IWUSR)
+ inode->i_mode |= S_IWUGO;
+ inode->i_mode &= ~HFS_SB(inode->i_sb)->s_file_umask;
HFS_I(inode)->phys_size = 0;
HFS_I(inode)->alloc_blocks = 0;
HFS_I(inode)->first_blocks = 0;
@@ -320,7 +320,7 @@ static int hfs_read_inode(struct inode *inode, void *data)
inode->i_mode = S_IRUGO | S_IXUGO;
if (!(rec->file.Flags & HFS_FIL_LOCK))
inode->i_mode |= S_IWUGO;
- inode->i_mode &= hsb->s_file_umask;
+ inode->i_mode &= ~hsb->s_file_umask;
inode->i_mode |= S_IFREG;
inode->i_ctime = inode->i_atime = inode->i_mtime =
hfs_m_to_utime(rec->file.MdDat);
@@ -332,7 +332,7 @@ static int hfs_read_inode(struct inode *inode, void *data)
inode->i_ino = be32_to_cpu(rec->dir.DirID);
inode->i_size = be16_to_cpu(rec->dir.Val) + 2;
HFS_I(inode)->fs_blocks = 0;
- inode->i_mode = S_IFDIR | (S_IRWXUGO & hsb->s_dir_umask);
+ inode->i_mode = S_IFDIR | (S_IRWXUGO & ~hsb->s_dir_umask);
inode->i_ctime = inode->i_atime = inode->i_mtime =
hfs_m_to_utime(rec->dir.MdDat);
inode->i_op = &hfs_dir_inode_operations;
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index f26142d833a9c..1e2c193134cc8 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/init.h>
+#include <linux/parser.h>
#include <linux/vfs.h>
#include "hfs_fs.h"
@@ -134,6 +135,34 @@ static struct super_operations hfs_super_operations = {
.remount_fs = hfs_remount,
};
+enum {
+ opt_uid, opt_gid, opt_umask, opt_file_umask, opt_dir_umask,
+ opt_part, opt_session, opt_type, opt_creator, opt_quiet,
+ opt_err
+};
+
+static match_table_t tokens = {
+ { opt_uid, "uid=%u" },
+ { opt_gid, "gid=%u" },
+ { opt_umask, "umask=%o" },
+ { opt_file_umask, "file_umask=%o" },
+ { opt_dir_umask, "dir_umask=%o" },
+ { opt_part, "part=%u" },
+ { opt_session, "session=%u" },
+ { opt_type, "type=%s" },
+ { opt_creator, "creator=%s" },
+ { opt_quiet, "quiet" },
+ { opt_err, NULL }
+};
+
+static inline int match_fourchar(substring_t *arg, u32 *result)
+{
+ if (arg->to - arg->from != 4)
+ return -EINVAL;
+ memcpy(result, arg->from, 4);
+ return 0;
+}
+
/*
* parse_options()
*
@@ -142,13 +171,15 @@ static struct super_operations hfs_super_operations = {
*/
static int parse_options(char *options, struct hfs_sb_info *hsb)
{
- char *this_char, *value;
+ char *p;
+ substring_t args[MAX_OPT_ARGS];
+ int tmp, token;
/* initialize the sb with defaults */
hsb->s_uid = current->uid;
hsb->s_gid = current->gid;
- hsb->s_file_umask = 0644;
- hsb->s_dir_umask = 0755;
+ hsb->s_file_umask = 0133;
+ hsb->s_dir_umask = 0022;
hsb->s_type = hsb->s_creator = cpu_to_be32(0x3f3f3f3f); /* == '????' */
hsb->s_quiet = 0;
hsb->part = -1;
@@ -157,77 +188,82 @@ static int parse_options(char *options, struct hfs_sb_info *hsb)
if (!options)
return 1;
- while ((this_char = strsep(&options, ",")) != 0) {
- if (!*this_char)
+ while ((p = strsep(&options, ",")) != NULL) {
+ if (!*p)
continue;
- value = strchr(this_char, '=');
- if (value)
- *value++ = 0;
- /* Numeric-valued options */
- if (!strcmp(this_char, "uid")) {
- if (!value || !*value)
- return 0;
- hsb->s_uid = simple_strtoul(value, &value, 0);
- if (*value)
+ token = match_token(p, tokens, args);
+ switch (token) {
+ case opt_uid:
+ if (match_int(&args[0], &tmp)) {
+ printk("HFS: uid requires an argument\n");
return 0;
- } else if (!strcmp(this_char, "gid")) {
- if (!value || !*value)
+ }
+ hsb->s_uid = (uid_t)tmp;
+ break;
+ case opt_gid:
+ if (match_int(&args[0], &tmp)) {
+ printk("HFS: gid requires an argument\n");
return 0;
- hsb->s_gid = simple_strtoul(value, &value, 0);
- if (*value)
+ }
+ hsb->s_gid = (gid_t)tmp;
+ break;
+ case opt_umask:
+ if (match_octal(&args[0], &tmp)) {
+ printk("HFS: umask requires a value\n");
return 0;
- } else if (!strcmp(this_char, "umask")) {
- if (!value || !*value)
+ }
+ hsb->s_file_umask = (umode_t)tmp;
+ hsb->s_dir_umask = (umode_t)tmp;
+ break;
+ case opt_file_umask:
+ if (match_octal(&args[0], &tmp)) {
+ printk("HFS: file_umask requires a value\n");
return 0;
- hsb->s_file_umask = simple_strtoul(value, &value, 8);
- hsb->s_dir_umask = hsb->s_file_umask;
- if (*value)
+ }
+ hsb->s_file_umask = (umode_t)tmp;
+ break;
+ case opt_dir_umask:
+ if (match_octal(&args[0], &tmp)) {
+ printk("HFS: dir_umask requires a value\n");
return 0;
- } else if (!strcmp(this_char, "file_umask")) {
- if (!value || !*value)
+ }
+ hsb->s_dir_umask = (umode_t)tmp;
+ break;
+ case opt_part:
+ if (match_int(&args[0], &hsb->part)) {
+ printk("HFS: part requires an argument\n");
return 0;
- hsb->s_file_umask = simple_strtoul(value, &value, 8);
- if (*value)
+ }
+ break;
+ case opt_session:
+ if (match_int(&args[0], &hsb->session)) {
+ printk("HFS: session requires an argument\n");
return 0;
- } else if (!strcmp(this_char, "dir_umask")) {
- if (!value || !*value)
+ }
+ break;
+ case opt_type:
+ if (match_fourchar(&args[0], &hsb->s_type)) {
+ printk("HFS+-fs: type requires a 4 character value\n");
return 0;
- hsb->s_dir_umask = simple_strtoul(value, &value, 8);
- if (*value)
- return 0;
- } else if (!strcmp(this_char, "part")) {
- if (!value || !*value)
- return 0;
- hsb->part = simple_strtoul(value, &value, 0);
- if (*value)
- return 0;
- } else if (!strcmp(this_char, "session")) {
- if (!value || !*value)
- return 0;
- hsb->session = simple_strtoul(value, &value, 0);
- if (*value)
- return 0;
- /* String-valued options */
- } else if (!strcmp(this_char, "type") && value) {
- if (strlen(value) != 4)
- return 0;
- memcpy(&hsb->s_type, value, 4);
- } else if (!strcmp(this_char, "creator") && value) {
- if (strlen(value) != 4)
- return 0;
- memcpy(&hsb->s_creator, value, 4);
- /* Boolean-valued options */
- } else if (!strcmp(this_char, "quiet")) {
- if (value)
+ }
+ break;
+ case opt_creator:
+ if (match_fourchar(&args[0], &hsb->s_creator)) {
+ printk("HFS+-fs: creator requires a 4 character value\n");
return 0;
+ }
+ break;
+ case opt_quiet:
hsb->s_quiet = 1;
- } else
+ break;
+ default:
return 0;
+ }
}
hsb->s_dir_umask &= 0777;
- hsb->s_file_umask &= 0777;
+ hsb->s_file_umask &= 0577;
return 1;
}
diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c
index f44e826e5e666..267872e84d714 100644
--- a/fs/hfsplus/bnode.c
+++ b/fs/hfsplus/bnode.c
@@ -446,6 +446,10 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
page = read_cache_page(mapping, block, (filler_t *)mapping->a_ops->readpage, NULL);
if (IS_ERR(page))
goto fail;
+ if (PageError(page)) {
+ page_cache_release(page);
+ goto fail;
+ }
#if !REF_PAGES
page_cache_release(page);
#endif
@@ -487,12 +491,16 @@ struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num)
hfs_bnode_get(node);
spin_unlock(&tree->hash_lock);
wait_event(node->lock_wq, !test_bit(HFS_BNODE_NEW, &node->flags));
+ if (test_bit(HFS_BNODE_ERROR, &node->flags))
+ goto node_error;
return node;
}
spin_unlock(&tree->hash_lock);
node = __hfs_bnode_create(tree, num);
if (!node)
return ERR_PTR(-ENOMEM);
+ if (test_bit(HFS_BNODE_ERROR, &node->flags))
+ goto node_error;
if (!test_bit(HFS_BNODE_NEW, &node->flags))
return node;
@@ -579,6 +587,10 @@ struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num)
node = __hfs_bnode_create(tree, num);
if (!node)
return ERR_PTR(-ENOMEM);
+ if (test_bit(HFS_BNODE_ERROR, &node->flags)) {
+ hfs_bnode_put(node);
+ return ERR_PTR(-EIO);
+ }
pagep = node->page;
memset(kmap(*pagep) + node->page_offset, 0,
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c
index 8f194a492a27c..94712790c8b3f 100644
--- a/fs/hfsplus/catalog.c
+++ b/fs/hfsplus/catalog.c
@@ -25,14 +25,14 @@ int hfsplus_cat_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2)
return hfsplus_unistrcmp(&k1->cat.name, &k2->cat.name);
}
-void hfsplus_cat_build_key(hfsplus_btree_key *key, u32 parent,
- struct qstr *str)
+void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key,
+ u32 parent, struct qstr *str)
{
int len;
key->cat.parent = cpu_to_be32(parent);
if (str) {
- hfsplus_asc2uni(&key->cat.name, str->name, str->len);
+ hfsplus_asc2uni(sb, &key->cat.name, str->name, str->len);
len = be16_to_cpu(key->cat.name.length);
} else {
key->cat.name.length = 0;
@@ -113,13 +113,14 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i
}
}
-static int hfsplus_fill_cat_thread(hfsplus_cat_entry *entry, int type,
+static int hfsplus_fill_cat_thread(struct super_block *sb,
+ hfsplus_cat_entry *entry, int type,
u32 parentid, struct qstr *str)
{
entry->type = cpu_to_be16(type);
entry->thread.reserved = 0;
entry->thread.parentID = cpu_to_be32(parentid);
- hfsplus_asc2uni(&entry->thread.nodeName, str->name, str->len);
+ hfsplus_asc2uni(sb, &entry->thread.nodeName, str->name, str->len);
return 10 + be16_to_cpu(entry->thread.nodeName.length) * 2;
}
@@ -131,7 +132,7 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
int err;
u16 type;
- hfsplus_cat_build_key(fd->search_key, cnid, NULL);
+ hfsplus_cat_build_key(sb, fd->search_key, cnid, NULL);
err = hfs_brec_read(fd, &tmp, sizeof(hfsplus_cat_entry));
if (err)
return err;
@@ -159,8 +160,8 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct ino
sb = dir->i_sb;
hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
- hfsplus_cat_build_key(fd.search_key, cnid, NULL);
- entry_size = hfsplus_fill_cat_thread(&entry, S_ISDIR(inode->i_mode) ?
+ hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
+ entry_size = hfsplus_fill_cat_thread(sb, &entry, S_ISDIR(inode->i_mode) ?
HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD,
dir->i_ino, str);
err = hfs_brec_find(&fd);
@@ -173,7 +174,7 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct ino
if (err)
goto err2;
- hfsplus_cat_build_key(fd.search_key, dir->i_ino, str);
+ hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str);
entry_size = hfsplus_cat_build_record(&entry, cnid, inode);
err = hfs_brec_find(&fd);
if (err != -ENOENT) {
@@ -193,7 +194,7 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct ino
return 0;
err1:
- hfsplus_cat_build_key(fd.search_key, cnid, NULL);
+ hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
if (!hfs_brec_find(&fd))
hfs_brec_remove(&fd);
err2:
@@ -217,7 +218,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
if (!str) {
int len;
- hfsplus_cat_build_key(fd.search_key, cnid, NULL);
+ hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
err = hfs_brec_find(&fd);
if (err)
goto out;
@@ -229,7 +230,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
hfs_bnode_read(fd.bnode, &fd.search_key->cat.name.unicode, off + 2, len);
fd.search_key->key_len = cpu_to_be16(6 + len);
} else
- hfsplus_cat_build_key(fd.search_key, dir->i_ino, str);
+ hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str);
err = hfs_brec_find(&fd);
if (err)
@@ -259,7 +260,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
if (err)
goto out;
- hfsplus_cat_build_key(fd.search_key, cnid, NULL);
+ hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
err = hfs_brec_find(&fd);
if (err)
goto out;
@@ -294,7 +295,7 @@ int hfsplus_rename_cat(u32 cnid,
dst_fd = src_fd;
/* find the old dir entry and read the data */
- hfsplus_cat_build_key(src_fd.search_key, src_dir->i_ino, src_name);
+ hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
err = hfs_brec_find(&src_fd);
if (err)
goto out;
@@ -303,7 +304,7 @@ int hfsplus_rename_cat(u32 cnid,
src_fd.entrylength);
/* create new dir entry with the data from the old entry */
- hfsplus_cat_build_key(dst_fd.search_key, dst_dir->i_ino, dst_name);
+ hfsplus_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name);
err = hfs_brec_find(&dst_fd);
if (err != -ENOENT) {
if (!err)
@@ -319,7 +320,7 @@ int hfsplus_rename_cat(u32 cnid,
mark_inode_dirty(dst_dir);
/* finally remove the old entry */
- hfsplus_cat_build_key(src_fd.search_key, src_dir->i_ino, src_name);
+ hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
err = hfs_brec_find(&src_fd);
if (err)
goto out;
@@ -331,7 +332,7 @@ int hfsplus_rename_cat(u32 cnid,
mark_inode_dirty(src_dir);
/* remove old thread entry */
- hfsplus_cat_build_key(src_fd.search_key, cnid, NULL);
+ hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL);
err = hfs_brec_find(&src_fd);
if (err)
goto out;
@@ -341,8 +342,8 @@ int hfsplus_rename_cat(u32 cnid,
goto out;
/* create new thread entry */
- hfsplus_cat_build_key(dst_fd.search_key, cnid, NULL);
- entry_size = hfsplus_fill_cat_thread(&entry, type, dst_dir->i_ino, dst_name);
+ hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL);
+ entry_size = hfsplus_fill_cat_thread(sb, &entry, type, dst_dir->i_ino, dst_name);
err = hfs_brec_find(&dst_fd);
if (err != -ENOENT) {
if (!err)
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 2793e3489b1e9..7bda76667a4af 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -40,7 +40,7 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
sb = dir->i_sb;
dentry->d_fsdata = NULL;
hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
- hfsplus_cat_build_key(fd.search_key, dir->i_ino, &dentry->d_name);
+ hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name);
again:
err = hfs_brec_read(&fd, &entry, sizeof(entry));
if (err) {
@@ -80,7 +80,7 @@ again:
linkid = be32_to_cpu(entry.file.permissions.dev);
str.len = sprintf(name, "iNode%d", linkid);
str.name = name;
- hfsplus_cat_build_key(fd.search_key, HFSPLUS_SB(sb).hidden_dir->i_ino, &str);
+ hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_SB(sb).hidden_dir->i_ino, &str);
goto again;
} else if (!dentry->d_fsdata)
dentry->d_fsdata = (void *)(unsigned long)cnid;
@@ -118,7 +118,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
return 0;
hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
- hfsplus_cat_build_key(fd.search_key, inode->i_ino, NULL);
+ hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL);
err = hfs_brec_find(&fd);
if (err)
goto out;
@@ -164,7 +164,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
type = be16_to_cpu(entry.type);
len = HFSPLUS_MAX_STRLEN;
- err = hfsplus_uni2asc(&fd.key->cat.name, strbuf, &len);
+ err = hfsplus_uni2asc(sb, &fd.key->cat.name, strbuf, &len);
if (err)
goto out;
if (type == HFSPLUS_FOLDER) {
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index 5078b43db9fd3..533094a570df3 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -114,6 +114,7 @@ struct hfsplus_sb_info {
struct hfs_btree *attr_tree;
struct inode *alloc_file;
struct inode *hidden_dir;
+ struct nls_table *nls;
/* Runtime variables */
u32 blockoffset;
@@ -150,6 +151,7 @@ struct hfsplus_sb_info {
};
#define HFSPLUS_SB_WRITEBACKUP 0x0001
+#define HFSPLUS_SB_NODECOMPOSE 0x0002
struct hfsplus_inode_info {
@@ -305,7 +307,7 @@ int hfs_brec_goto(struct hfs_find_data *, int);
/* catalog.c */
int hfsplus_cat_cmp_key(hfsplus_btree_key *, hfsplus_btree_key *);
-void hfsplus_cat_build_key(hfsplus_btree_key *, u32, struct qstr *);
+void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *, u32, struct qstr *);
int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *);
int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *);
int hfsplus_delete_cat(u32, struct inode *, struct qstr *);
@@ -345,12 +347,14 @@ int parse_options(char *, struct hfsplus_sb_info *);
void fill_defaults(struct hfsplus_sb_info *);
/* tables.c */
-extern u16 case_fold_table[];
+extern u16 hfsplus_case_fold_table[];
+extern u16 hfsplus_decompose_table[];
+extern u16 hfsplus_compose_table[];
/* unicode.c */
int hfsplus_unistrcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *);
-int hfsplus_uni2asc(const struct hfsplus_unistr *, char *, int *);
-int hfsplus_asc2uni(struct hfsplus_unistr *, const char *, int);
+int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *);
+int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int);
/* wrapper.c */
int hfsplus_read_wrapper(struct super_block *);
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index b2b56c3836a26..d5642705f6336 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -71,12 +71,6 @@ static int hfsplus_releasepage(struct page *page, int mask)
;
else if (atomic_read(&node->refcnt))
res = 0;
- else for (i = 0; i < tree->pages_per_bnode; i++) {
- if (PageActive(node->page[i])) {
- res = 0;
- break;
- }
- }
if (res && node) {
hfs_bnode_unhash(node);
hfs_bnode_free(node);
@@ -100,7 +94,7 @@ static int hfsplus_releasepage(struct page *page, int mask)
spin_unlock(&tree->hash_lock);
}
//printk("releasepage: %lu,%x = %d\n", page->index, mask, res);
- return res;
+ return res ? try_to_free_buffers(page) : 0;
}
static int hfsplus_get_blocks(struct inode *inode, sector_t iblock, unsigned long max_blocks,
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c
index 20c802ff5db04..1cca0102c98d3 100644
--- a/fs/hfsplus/options.c
+++ b/fs/hfsplus/options.c
@@ -11,8 +11,32 @@
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/parser.h>
+#include <linux/nls.h>
#include "hfsplus_fs.h"
+enum {
+ opt_creator, opt_type,
+ opt_umask, opt_uid, opt_gid,
+ opt_part, opt_session, opt_nls,
+ opt_nodecompose, opt_decompose,
+ opt_err
+};
+
+static match_table_t tokens = {
+ { opt_creator, "creator=%s" },
+ { opt_type, "type=%s" },
+ { opt_umask, "umask=%o" },
+ { opt_uid, "uid=%u" },
+ { opt_gid, "gid=%u" },
+ { opt_part, "part=%u" },
+ { opt_session, "session=%u" },
+ { opt_nls, "nls=%s" },
+ { opt_decompose, "decompose" },
+ { opt_nodecompose, "nodecompose" },
+ { opt_err, NULL }
+};
+
/* Initialize an options object to reasonable defaults */
void fill_defaults(struct hfsplus_sb_info *opts)
{
@@ -29,99 +53,110 @@ void fill_defaults(struct hfsplus_sb_info *opts)
}
/* convert a "four byte character" to a 32 bit int with error checks */
-static int fill_fourchar(u32 *result, char *input)
-{
- u32 out;
- int i;
-
- if (!result || !input || !*input || (strlen(input) != 4))
- return 0;
-
- for (out = 0, i = 0; i < 4; i++) {
- out <<= 8;
- out |= ((int)(input[i])) & 0xFF;
- }
- *result = out;
- return 1;
-}
-
-/* convert a string to int with error checks */
-static int fill_int(int *result, char *input, int base)
+static inline int match_fourchar(substring_t *arg, u32 *result)
{
- char *tmp = input;
- int intval;
-
- if (!result || !input || !*input)
- return 0;
-
- intval = simple_strtoul(tmp, &tmp, base);
- if (*tmp)
- return 0;
-
- *result = intval;
- return 1;
+ if (arg->to - arg->from != 4)
+ return -EINVAL;
+ memcpy(result, arg->from, 4);
+ return 0;
}
/* Parse options from mount. Returns 0 on failure */
/* input is the options passed to mount() as a string */
-int parse_options(char *input, struct hfsplus_sb_info *results)
+int parse_options(char *input, struct hfsplus_sb_info *sbi)
{
- char *curropt, *value;
- int tmp;
+ char *p;
+ substring_t args[MAX_OPT_ARGS];
+ int tmp, token;
if (!input)
- return 1;
+ goto done;
- while ((curropt = strsep(&input,",")) != NULL) {
- if (!*curropt)
+ while ((p = strsep(&input, ",")) != NULL) {
+ if (!*p)
continue;
- if ((value = strchr(curropt, '=')) != NULL)
- *value++ = '\0';
-
- if (!strcmp(curropt, "creator")) {
- if (!fill_fourchar(&(results->creator), value)) {
+ token = match_token(p, tokens, args);
+ switch (token) {
+ case opt_creator:
+ if (match_fourchar(&args[0], &sbi->creator)) {
printk("HFS+-fs: creator requires a 4 character value\n");
return 0;
}
- } else if (!strcmp(curropt, "type")) {
- if (!fill_fourchar(&(results->type), value)) {
+ break;
+ case opt_type:
+ if (match_fourchar(&args[0], &sbi->type)) {
printk("HFS+-fs: type requires a 4 character value\n");
return 0;
}
- } else if (!strcmp(curropt, "umask")) {
- if (!fill_int(&tmp, value, 8)) {
+ break;
+ case opt_umask:
+ if (match_octal(&args[0], &tmp)) {
printk("HFS+-fs: umask requires a value\n");
return 0;
}
- results->umask = (umode_t)tmp;
- } else if (!strcmp(curropt, "uid")) {
- if (!fill_int(&tmp, value, 0)) {
+ sbi->umask = (umode_t)tmp;
+ break;
+ case opt_uid:
+ if (match_int(&args[0], &tmp)) {
printk("HFS+-fs: uid requires an argument\n");
return 0;
}
- results->uid = (uid_t)tmp;
- } else if (!strcmp(curropt, "gid")) {
- if (!fill_int(&tmp, value, 0)) {
+ sbi->uid = (uid_t)tmp;
+ break;
+ case opt_gid:
+ if (match_int(&args[0], &tmp)) {
printk("HFS+-fs: gid requires an argument\n");
return 0;
}
- results->gid = (gid_t)tmp;
- } else if (!strcmp(curropt, "part")) {
- if (!fill_int(&results->part, value, 0)) {
+ sbi->gid = (gid_t)tmp;
+ break;
+ case opt_part:
+ if (match_int(&args[0], &sbi->part)) {
printk("HFS+-fs: part requires an argument\n");
return 0;
}
- } else if (!strcmp(curropt, "session")) {
- if (!fill_int(&results->session, value, 0)) {
+ break;
+ case opt_session:
+ if (match_int(&args[0], &sbi->session)) {
printk("HFS+-fs: session requires an argument\n");
return 0;
}
- } else {
- printk("HFS+-fs: unknown option %s\n", curropt);
+ break;
+ case opt_nls:
+ if (sbi->nls) {
+ printk("HFS+-fs: unable to change nls mapping\n");
+ return 0;
+ }
+ p = match_strdup(&args[0]);
+ sbi->nls = load_nls(p);
+ if (!sbi->nls) {
+ printk("HFS+-fs: unable to load nls mapping \"%s\"\n", p);
+ kfree(p);
+ return 0;
+ }
+ kfree(p);
+ break;
+ case opt_decompose:
+ sbi->flags &= ~HFSPLUS_SB_NODECOMPOSE;
+ break;
+ case opt_nodecompose:
+ sbi->flags |= HFSPLUS_SB_NODECOMPOSE;
+ break;
+ default:
return 0;
}
}
+done:
+ if (!sbi->nls) {
+ /* try utf8 first, as this is the old default behaviour */
+ sbi->nls = load_nls("utf8");
+ if (!sbi->nls)
+ sbi->nls = load_nls_default();
+ if (!sbi->nls)
+ return 0;
+ }
+
return 1;
}
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index d16322f930c29..5f8044664a3c4 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/vfs.h>
+#include <linux/nls.h>
static struct inode *hfsplus_alloc_inode(struct super_block *sb);
static void hfsplus_destroy_inode(struct inode *inode);
@@ -223,6 +224,8 @@ static void hfsplus_put_super(struct super_block *sb)
iput(HFSPLUS_SB(sb).alloc_file);
iput(HFSPLUS_SB(sb).hidden_dir);
brelse(HFSPLUS_SB(sb).s_vhbh);
+ if (HFSPLUS_SB(sb).nls)
+ unload_nls(HFSPLUS_SB(sb).nls);
}
static int hfsplus_statfs(struct super_block *sb, struct kstatfs *buf)
@@ -280,13 +283,13 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
struct hfs_find_data fd;
struct inode *root;
struct qstr str;
+ struct nls_table *nls = NULL;
int err = -EINVAL;
sbi = kmalloc(sizeof(struct hfsplus_sb_info), GFP_KERNEL);
- if (!sbi) {
- err = -ENOMEM;
- goto out2;
- }
+ if (!sbi)
+ return -ENOMEM;
+
memset(sbi, 0, sizeof(HFSPLUS_SB(sb)));
sb->s_fs_info = sbi;
INIT_HLIST_HEAD(&sbi->rsrc_inodes);
@@ -295,7 +298,16 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
if (!silent)
printk("HFS+-fs: unable to parse mount options\n");
err = -EINVAL;
- goto out2;
+ goto cleanup;
+ }
+
+ /* temporarily use utf8 to correctly find the hidden dir below */
+ nls = sbi->nls;
+ sbi->nls = load_nls("utf8");
+ if (!nls) {
+ printk("HFS+: unable to load nls for utf8\n");
+ err = -EINVAL;
+ goto cleanup;
}
/* Grab the volume header */
@@ -303,7 +315,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
if (!silent)
printk("HFS+-fs: unable to find HFS+ superblock\n");
err = -EINVAL;
- goto out2;
+ goto cleanup;
}
vhdr = HFSPLUS_SB(sb).s_vhdr;
@@ -376,7 +388,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1;
str.name = HFSP_HIDDENDIR_NAME;
hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
- hfsplus_cat_build_key(fd.search_key, HFSPLUS_ROOT_CNID, &str);
+ hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str);
if (!hfs_brec_read(&fd, &entry, sizeof(entry))) {
hfs_find_exit(&fd);
if (entry.type != cpu_to_be16(HFSPLUS_FOLDER))
@@ -410,11 +422,14 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
mark_inode_dirty(HFSPLUS_SB(sb).hidden_dir);
}
out:
+ unload_nls(sbi->nls);
+ sbi->nls = nls;
return 0;
cleanup:
hfsplus_put_super(sb);
-out2:
+ if (nls)
+ unload_nls(nls);
return err;
}
diff --git a/fs/hfsplus/tables.c b/fs/hfsplus/tables.c
index ce2ed6657715a..1b911730a0c10 100644
--- a/fs/hfsplus/tables.c
+++ b/fs/hfsplus/tables.c
@@ -11,7 +11,7 @@
* (HFS Plus Volume Format)
*/
-u16 case_fold_table[] = {
+u16 hfsplus_case_fold_table[] = {
/*
* The lower case table consists of a 256-entry high-byte table followed by
* some number of 256-entry subtables. The high-byte table contains either an
@@ -406,3 +406,2840 @@ u16 case_fold_table[] = {
/* F */ 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7,
0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF,
};
+
+u16 hfsplus_decompose_table[] = {
+ /* base table */
+ 0x0010, 0x04c0, 0x0000, 0x06f0, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x07b0,
+ /* char table 0x0___ */
+ 0x0020, 0x0070, 0x0160, 0x0190, 0x0230, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x02d0, 0x0340, 0x0360, 0x03b0, 0x03e0, 0x0400, 0x0430,
+ /* char table 0x00__ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0030, 0x0040, 0x0050, 0x0060,
+ /* char values 0x00c_ */
+ 0x2042, 0x204a, 0x2052, 0x205a, 0x2062, 0x206a, 0x0000, 0x2072,
+ 0x207a, 0x2082, 0x208a, 0x2092, 0x209a, 0x20a2, 0x20aa, 0x20b2,
+ /* char values 0x00d_ */
+ 0x0000, 0x20ba, 0x20c2, 0x20ca, 0x20d2, 0x20da, 0x20e2, 0x0000,
+ 0x0000, 0x20ea, 0x20f2, 0x20fa, 0x2102, 0x210a, 0x0000, 0x0000,
+ /* char values 0x00e_ */
+ 0x2112, 0x211a, 0x2122, 0x212a, 0x2132, 0x213a, 0x0000, 0x2142,
+ 0x214a, 0x2152, 0x215a, 0x2162, 0x216a, 0x2172, 0x217a, 0x2182,
+ /* char values 0x00f_ */
+ 0x0000, 0x218a, 0x2192, 0x219a, 0x21a2, 0x21aa, 0x21b2, 0x0000,
+ 0x0000, 0x21ba, 0x21c2, 0x21ca, 0x21d2, 0x21da, 0x0000, 0x21e2,
+ /* char table 0x01__ */
+ 0x0080, 0x0090, 0x00a0, 0x00b0, 0x00c0, 0x00d0, 0x00e0, 0x00f0,
+ 0x0000, 0x0000, 0x0100, 0x0110, 0x0120, 0x0130, 0x0140, 0x0150,
+ /* char values 0x010_ */
+ 0x21ea, 0x21f2, 0x21fa, 0x2202, 0x220a, 0x2212, 0x221a, 0x2222,
+ 0x222a, 0x2232, 0x223a, 0x2242, 0x224a, 0x2252, 0x225a, 0x2262,
+ /* char values 0x011_ */
+ 0x0000, 0x0000, 0x226a, 0x2272, 0x227a, 0x2282, 0x228a, 0x2292,
+ 0x229a, 0x22a2, 0x22aa, 0x22b2, 0x22ba, 0x22c2, 0x22ca, 0x22d2,
+ /* char values 0x012_ */
+ 0x22da, 0x22e2, 0x22ea, 0x22f2, 0x22fa, 0x2302, 0x0000, 0x0000,
+ 0x230a, 0x2312, 0x231a, 0x2322, 0x232a, 0x2332, 0x233a, 0x2342,
+ /* char values 0x013_ */
+ 0x234a, 0x0000, 0x0000, 0x0000, 0x2352, 0x235a, 0x2362, 0x236a,
+ 0x0000, 0x2372, 0x237a, 0x2382, 0x238a, 0x2392, 0x239a, 0x0000,
+ /* char values 0x014_ */
+ 0x0000, 0x0000, 0x0000, 0x23a2, 0x23aa, 0x23b2, 0x23ba, 0x23c2,
+ 0x23ca, 0x0000, 0x0000, 0x0000, 0x23d2, 0x23da, 0x23e2, 0x23ea,
+ /* char values 0x015_ */
+ 0x23f2, 0x23fa, 0x0000, 0x0000, 0x2402, 0x240a, 0x2412, 0x241a,
+ 0x2422, 0x242a, 0x2432, 0x243a, 0x2442, 0x244a, 0x2452, 0x245a,
+ /* char values 0x016_ */
+ 0x2462, 0x246a, 0x2472, 0x247a, 0x2482, 0x248a, 0x0000, 0x0000,
+ 0x2492, 0x249a, 0x24a2, 0x24aa, 0x24b2, 0x24ba, 0x24c2, 0x24ca,
+ /* char values 0x017_ */
+ 0x24d2, 0x24da, 0x24e2, 0x24ea, 0x24f2, 0x24fa, 0x2502, 0x250a,
+ 0x2512, 0x251a, 0x2522, 0x252a, 0x2532, 0x253a, 0x2542, 0x0000,
+ /* char values 0x01a_ */
+ 0x254a, 0x2552, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x255a,
+ /* char values 0x01b_ */
+ 0x2562, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x01c_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x256a, 0x2572, 0x257a,
+ /* char values 0x01d_ */
+ 0x2582, 0x258a, 0x2592, 0x259a, 0x25a2, 0x25ab, 0x25b7, 0x25c3,
+ 0x25cf, 0x25db, 0x25e7, 0x25f3, 0x25ff, 0x0000, 0x260b, 0x2617,
+ /* char values 0x01e_ */
+ 0x2623, 0x262f, 0x263a, 0x2642, 0x0000, 0x0000, 0x264a, 0x2652,
+ 0x265a, 0x2662, 0x266a, 0x2672, 0x267b, 0x2687, 0x2692, 0x269a,
+ /* char values 0x01f_ */
+ 0x26a2, 0x0000, 0x0000, 0x0000, 0x26aa, 0x26b2, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x26bb, 0x26c7, 0x26d2, 0x26da, 0x26e2, 0x26ea,
+ /* char table 0x02__ */
+ 0x0170, 0x0180, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x020_ */
+ 0x26f2, 0x26fa, 0x2702, 0x270a, 0x2712, 0x271a, 0x2722, 0x272a,
+ 0x2732, 0x273a, 0x2742, 0x274a, 0x2752, 0x275a, 0x2762, 0x276a,
+ /* char values 0x021_ */
+ 0x2772, 0x277a, 0x2782, 0x278a, 0x2792, 0x279a, 0x27a2, 0x27aa,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char table 0x03__ */
+ 0x0000, 0x01a0, 0x0000, 0x0000, 0x01b0, 0x0000, 0x0000, 0x01c0,
+ 0x01d0, 0x01e0, 0x01f0, 0x0200, 0x0210, 0x0220, 0x0000, 0x0000,
+ /* char values 0x031_ */
+ 0x27b2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x034_ */
+ 0x27b9, 0x27bd, 0x0000, 0x27c1, 0x27c6, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x037_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x27cd, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x27d1, 0x0000,
+ /* char values 0x038_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x27d6, 0x27de, 0x27e5,
+ 0x27ea, 0x27f2, 0x27fa, 0x0000, 0x2802, 0x0000, 0x280a, 0x2812,
+ /* char values 0x039_ */
+ 0x281b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x03a_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x2826, 0x282e, 0x2836, 0x283e, 0x2846, 0x284e,
+ /* char values 0x03b_ */
+ 0x2857, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x03c_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x2862, 0x286a, 0x2872, 0x287a, 0x2882, 0x0000,
+ /* char values 0x03d_ */
+ 0x0000, 0x0000, 0x0000, 0x288a, 0x2892, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char table 0x04__ */
+ 0x0240, 0x0250, 0x0000, 0x0260, 0x0000, 0x0270, 0x0000, 0x0280,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0290, 0x02a0, 0x02b0, 0x02c0,
+ /* char values 0x040_ */
+ 0x0000, 0x289a, 0x0000, 0x28a2, 0x0000, 0x0000, 0x0000, 0x28aa,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x28b2, 0x0000, 0x28ba, 0x0000,
+ /* char values 0x041_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x28c2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x043_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x28ca, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x045_ */
+ 0x0000, 0x28d2, 0x0000, 0x28da, 0x0000, 0x0000, 0x0000, 0x28e2,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x28ea, 0x0000, 0x28f2, 0x0000,
+ /* char values 0x047_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x28fa, 0x2902,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x04c_ */
+ 0x0000, 0x290a, 0x2912, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x04d_ */
+ 0x291a, 0x2922, 0x292a, 0x2932, 0x2939, 0x293d, 0x2942, 0x294a,
+ 0x2951, 0x2955, 0x295a, 0x2962, 0x296a, 0x2972, 0x297a, 0x2982,
+ /* char values 0x04e_ */
+ 0x2989, 0x298d, 0x2992, 0x299a, 0x29a2, 0x29aa, 0x29b2, 0x29ba,
+ 0x29c1, 0x29c5, 0x29ca, 0x29d2, 0x0000, 0x0000, 0x29da, 0x29e2,
+ /* char values 0x04f_ */
+ 0x29ea, 0x29f2, 0x29fa, 0x2a02, 0x2a0a, 0x2a12, 0x0000, 0x0000,
+ 0x2a1a, 0x2a22, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char table 0x09__ */
+ 0x0000, 0x0000, 0x02e0, 0x02f0, 0x0000, 0x0300, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0310, 0x0320, 0x0330, 0x0000, 0x0000,
+ /* char values 0x092_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2a2a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x093_ */
+ 0x0000, 0x2a32, 0x0000, 0x0000, 0x2a3a, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x095_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2a42, 0x2a4a, 0x2a52, 0x2a5a, 0x2a62, 0x2a6a, 0x2a72, 0x2a7a,
+ /* char values 0x09b_ */
+ 0x2a82, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x09c_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x2a8a, 0x2a92, 0x0000, 0x0000, 0x0000,
+ /* char values 0x09d_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x2a9a, 0x2aa2, 0x0000, 0x2aaa,
+ /* char table 0x0a__ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0350, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x0a5_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2ab2, 0x2aba, 0x2ac2, 0x2aca, 0x0000, 0x2ad2, 0x0000,
+ /* char table 0x0b__ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0370, 0x0380, 0x0000, 0x0000,
+ 0x0000, 0x0390, 0x0000, 0x0000, 0x03a0, 0x0000, 0x0000, 0x0000,
+ /* char values 0x0b4_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2ada, 0x0000, 0x0000, 0x2ae2, 0x2aea, 0x0000, 0x0000, 0x0000,
+ /* char values 0x0b5_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x2af2, 0x2afa, 0x0000, 0x2b02,
+ /* char values 0x0b9_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x2b0a, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x0bc_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x2b12, 0x2b1a, 0x2b22, 0x0000, 0x0000, 0x0000,
+ /* char table 0x0c__ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x03c0, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x03d0, 0x0000, 0x0000, 0x0000,
+ /* char values 0x0c4_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2b2a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x0cc_ */
+ 0x2b32, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2b3a,
+ 0x2b42, 0x0000, 0x2b4a, 0x2b53, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char table 0x0d__ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x03f0, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x0d4_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x2b5e, 0x2b66, 0x2b6e, 0x0000, 0x0000, 0x0000,
+ /* char table 0x0e__ */
+ 0x0000, 0x0000, 0x0000, 0x0410, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0420, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x0e3_ */
+ 0x0000, 0x0000, 0x0000, 0x2b76, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x0eb_ */
+ 0x0000, 0x0000, 0x0000, 0x2b7e, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char table 0x0f__ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0440, 0x0450, 0x0460, 0x0470,
+ 0x0480, 0x0490, 0x04a0, 0x04b0, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x0f4_ */
+ 0x0000, 0x0000, 0x0000, 0x2b86, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2b8e, 0x0000, 0x0000,
+ /* char values 0x0f5_ */
+ 0x0000, 0x0000, 0x2b96, 0x0000, 0x0000, 0x0000, 0x0000, 0x2b9e,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x2ba6, 0x0000, 0x0000, 0x0000,
+ /* char values 0x0f6_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2bae, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x0f7_ */
+ 0x0000, 0x0000, 0x0000, 0x2bb6, 0x0000, 0x2bbe, 0x2bc6, 0x2bcf,
+ 0x2bda, 0x2be3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x0f8_ */
+ 0x0000, 0x2bee, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x0f9_ */
+ 0x0000, 0x0000, 0x0000, 0x2bf6, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2bfe, 0x0000, 0x0000,
+ /* char values 0x0fa_ */
+ 0x0000, 0x0000, 0x2c06, 0x0000, 0x0000, 0x0000, 0x0000, 0x2c0e,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x2c16, 0x0000, 0x0000, 0x0000,
+ /* char values 0x0fb_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2c1e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char table 0x1___ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x04d0, 0x05e0,
+ /* char table 0x1e__ */
+ 0x04e0, 0x04f0, 0x0500, 0x0510, 0x0520, 0x0530, 0x0540, 0x0550,
+ 0x0560, 0x0570, 0x0580, 0x0590, 0x05a0, 0x05b0, 0x05c0, 0x05d0,
+ /* char values 0x1e0_ */
+ 0x2c26, 0x2c2e, 0x2c36, 0x2c3e, 0x2c46, 0x2c4e, 0x2c56, 0x2c5e,
+ 0x2c67, 0x2c73, 0x2c7e, 0x2c86, 0x2c8e, 0x2c96, 0x2c9e, 0x2ca6,
+ /* char values 0x1e1_ */
+ 0x2cae, 0x2cb6, 0x2cbe, 0x2cc6, 0x2ccf, 0x2cdb, 0x2ce7, 0x2cf3,
+ 0x2cfe, 0x2d06, 0x2d0e, 0x2d16, 0x2d1f, 0x2d2b, 0x2d36, 0x2d3e,
+ /* char values 0x1e2_ */
+ 0x2d46, 0x2d4e, 0x2d56, 0x2d5e, 0x2d66, 0x2d6e, 0x2d76, 0x2d7e,
+ 0x2d86, 0x2d8e, 0x2d96, 0x2d9e, 0x2da6, 0x2dae, 0x2db7, 0x2dc3,
+ /* char values 0x1e3_ */
+ 0x2dce, 0x2dd6, 0x2dde, 0x2de6, 0x2dee, 0x2df6, 0x2dfe, 0x2e06,
+ 0x2e0f, 0x2e1b, 0x2e26, 0x2e2e, 0x2e36, 0x2e3e, 0x2e46, 0x2e4e,
+ /* char values 0x1e4_ */
+ 0x2e56, 0x2e5e, 0x2e66, 0x2e6e, 0x2e76, 0x2e7e, 0x2e86, 0x2e8e,
+ 0x2e96, 0x2e9e, 0x2ea6, 0x2eae, 0x2eb7, 0x2ec3, 0x2ecf, 0x2edb,
+ /* char values 0x1e5_ */
+ 0x2ee7, 0x2ef3, 0x2eff, 0x2f0b, 0x2f16, 0x2f1e, 0x2f26, 0x2f2e,
+ 0x2f36, 0x2f3e, 0x2f46, 0x2f4e, 0x2f57, 0x2f63, 0x2f6e, 0x2f76,
+ /* char values 0x1e6_ */
+ 0x2f7e, 0x2f86, 0x2f8e, 0x2f96, 0x2f9f, 0x2fab, 0x2fb7, 0x2fc3,
+ 0x2fcf, 0x2fdb, 0x2fe6, 0x2fee, 0x2ff6, 0x2ffe, 0x3006, 0x300e,
+ /* char values 0x1e7_ */
+ 0x3016, 0x301e, 0x3026, 0x302e, 0x3036, 0x303e, 0x3046, 0x304e,
+ 0x3057, 0x3063, 0x306f, 0x307b, 0x3086, 0x308e, 0x3096, 0x309e,
+ /* char values 0x1e8_ */
+ 0x30a6, 0x30ae, 0x30b6, 0x30be, 0x30c6, 0x30ce, 0x30d6, 0x30de,
+ 0x30e6, 0x30ee, 0x30f6, 0x30fe, 0x3106, 0x310e, 0x3116, 0x311e,
+ /* char values 0x1e9_ */
+ 0x3126, 0x312e, 0x3136, 0x313e, 0x3146, 0x314e, 0x3156, 0x315e,
+ 0x3166, 0x316e, 0x0000, 0x3176, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x1ea_ */
+ 0x317e, 0x3186, 0x318e, 0x3196, 0x319f, 0x31ab, 0x31b7, 0x31c3,
+ 0x31cf, 0x31db, 0x31e7, 0x31f3, 0x31ff, 0x320b, 0x3217, 0x3223,
+ /* char values 0x1eb_ */
+ 0x322f, 0x323b, 0x3247, 0x3253, 0x325f, 0x326b, 0x3277, 0x3283,
+ 0x328e, 0x3296, 0x329e, 0x32a6, 0x32ae, 0x32b6, 0x32bf, 0x32cb,
+ /* char values 0x1ec_ */
+ 0x32d7, 0x32e3, 0x32ef, 0x32fb, 0x3307, 0x3313, 0x331f, 0x332b,
+ 0x3336, 0x333e, 0x3346, 0x334e, 0x3356, 0x335e, 0x3366, 0x336e,
+ /* char values 0x1ed_ */
+ 0x3377, 0x3383, 0x338f, 0x339b, 0x33a7, 0x33b3, 0x33bf, 0x33cb,
+ 0x33d7, 0x33e3, 0x33ef, 0x33fb, 0x3407, 0x3413, 0x341f, 0x342b,
+ /* char values 0x1ee_ */
+ 0x3437, 0x3443, 0x344f, 0x345b, 0x3466, 0x346e, 0x3476, 0x347e,
+ 0x3487, 0x3493, 0x349f, 0x34ab, 0x34b7, 0x34c3, 0x34cf, 0x34db,
+ /* char values 0x1ef_ */
+ 0x34e7, 0x34f3, 0x34fe, 0x3506, 0x350e, 0x3516, 0x351e, 0x3526,
+ 0x352e, 0x3536, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char table 0x1f__ */
+ 0x05f0, 0x0600, 0x0610, 0x0620, 0x0630, 0x0640, 0x0650, 0x0660,
+ 0x0670, 0x0680, 0x0690, 0x06a0, 0x06b0, 0x06c0, 0x06d0, 0x06e0,
+ /* char values 0x1f0_ */
+ 0x353e, 0x3546, 0x354f, 0x355b, 0x3567, 0x3573, 0x357f, 0x358b,
+ 0x3596, 0x359e, 0x35a7, 0x35b3, 0x35bf, 0x35cb, 0x35d7, 0x35e3,
+ /* char values 0x1f1_ */
+ 0x35ee, 0x35f6, 0x35ff, 0x360b, 0x3617, 0x3623, 0x0000, 0x0000,
+ 0x362e, 0x3636, 0x363f, 0x364b, 0x3657, 0x3663, 0x0000, 0x0000,
+ /* char values 0x1f2_ */
+ 0x366e, 0x3676, 0x367f, 0x368b, 0x3697, 0x36a3, 0x36af, 0x36bb,
+ 0x36c6, 0x36ce, 0x36d7, 0x36e3, 0x36ef, 0x36fb, 0x3707, 0x3713,
+ /* char values 0x1f3_ */
+ 0x371e, 0x3726, 0x372f, 0x373b, 0x3747, 0x3753, 0x375f, 0x376b,
+ 0x3776, 0x377e, 0x3787, 0x3793, 0x379f, 0x37ab, 0x37b7, 0x37c3,
+ /* char values 0x1f4_ */
+ 0x37ce, 0x37d6, 0x37df, 0x37eb, 0x37f7, 0x3803, 0x0000, 0x0000,
+ 0x380e, 0x3816, 0x381f, 0x382b, 0x3837, 0x3843, 0x0000, 0x0000,
+ /* char values 0x1f5_ */
+ 0x384e, 0x3856, 0x385f, 0x386b, 0x3877, 0x3883, 0x388f, 0x389b,
+ 0x0000, 0x38a6, 0x0000, 0x38af, 0x0000, 0x38bb, 0x0000, 0x38c7,
+ /* char values 0x1f6_ */
+ 0x38d2, 0x38da, 0x38e3, 0x38ef, 0x38fb, 0x3907, 0x3913, 0x391f,
+ 0x392a, 0x3932, 0x393b, 0x3947, 0x3953, 0x395f, 0x396b, 0x3977,
+ /* char values 0x1f7_ */
+ 0x3982, 0x398a, 0x3992, 0x399a, 0x39a2, 0x39aa, 0x39b2, 0x39ba,
+ 0x39c2, 0x39ca, 0x39d2, 0x39da, 0x39e2, 0x39ea, 0x0000, 0x0000,
+ /* char values 0x1f8_ */
+ 0x39f3, 0x39ff, 0x3a0c, 0x3a1c, 0x3a2c, 0x3a3c, 0x3a4c, 0x3a5c,
+ 0x3a6b, 0x3a77, 0x3a84, 0x3a94, 0x3aa4, 0x3ab4, 0x3ac4, 0x3ad4,
+ /* char values 0x1f9_ */
+ 0x3ae3, 0x3aef, 0x3afc, 0x3b0c, 0x3b1c, 0x3b2c, 0x3b3c, 0x3b4c,
+ 0x3b5b, 0x3b67, 0x3b74, 0x3b84, 0x3b94, 0x3ba4, 0x3bb4, 0x3bc4,
+ /* char values 0x1fa_ */
+ 0x3bd3, 0x3bdf, 0x3bec, 0x3bfc, 0x3c0c, 0x3c1c, 0x3c2c, 0x3c3c,
+ 0x3c4b, 0x3c57, 0x3c64, 0x3c74, 0x3c84, 0x3c94, 0x3ca4, 0x3cb4,
+ /* char values 0x1fb_ */
+ 0x3cc2, 0x3cca, 0x3cd3, 0x3cde, 0x3ce7, 0x0000, 0x3cf2, 0x3cfb,
+ 0x3d06, 0x3d0e, 0x3d16, 0x3d1e, 0x3d26, 0x0000, 0x3d2d, 0x0000,
+ /* char values 0x1fc_ */
+ 0x0000, 0x3d32, 0x3d3b, 0x3d46, 0x3d4f, 0x0000, 0x3d5a, 0x3d63,
+ 0x3d6e, 0x3d76, 0x3d7e, 0x3d86, 0x3d8e, 0x3d96, 0x3d9e, 0x3da6,
+ /* char values 0x1fd_ */
+ 0x3dae, 0x3db6, 0x3dbf, 0x3dcb, 0x0000, 0x0000, 0x3dd6, 0x3ddf,
+ 0x3dea, 0x3df2, 0x3dfa, 0x3e02, 0x0000, 0x3e0a, 0x3e12, 0x3e1a,
+ /* char values 0x1fe_ */
+ 0x3e22, 0x3e2a, 0x3e33, 0x3e3f, 0x3e4a, 0x3e52, 0x3e5a, 0x3e63,
+ 0x3e6e, 0x3e76, 0x3e7e, 0x3e86, 0x3e8e, 0x3e96, 0x3e9e, 0x3ea5,
+ /* char values 0x1ff_ */
+ 0x0000, 0x0000, 0x3eab, 0x3eb6, 0x3ebf, 0x0000, 0x3eca, 0x3ed3,
+ 0x3ede, 0x3ee6, 0x3eee, 0x3ef6, 0x3efe, 0x3f05, 0x0000, 0x0000,
+ /* char table 0x3___ */
+ 0x0700, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char table 0x30__ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0710, 0x0720, 0x0730, 0x0740,
+ 0x0000, 0x0750, 0x0760, 0x0770, 0x0780, 0x0790, 0x0000, 0x07a0,
+ /* char values 0x304_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x3f0a, 0x0000, 0x3f12, 0x0000,
+ /* char values 0x305_ */
+ 0x3f1a, 0x0000, 0x3f22, 0x0000, 0x3f2a, 0x0000, 0x3f32, 0x0000,
+ 0x3f3a, 0x0000, 0x3f42, 0x0000, 0x3f4a, 0x0000, 0x3f52, 0x0000,
+ /* char values 0x306_ */
+ 0x3f5a, 0x0000, 0x3f62, 0x0000, 0x0000, 0x3f6a, 0x0000, 0x3f72,
+ 0x0000, 0x3f7a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x307_ */
+ 0x3f82, 0x3f8a, 0x0000, 0x3f92, 0x3f9a, 0x0000, 0x3fa2, 0x3faa,
+ 0x0000, 0x3fb2, 0x3fba, 0x0000, 0x3fc2, 0x3fca, 0x0000, 0x0000,
+ /* char values 0x309_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x3fd2, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3fda, 0x0000,
+ /* char values 0x30a_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x3fe2, 0x0000, 0x3fea, 0x0000,
+ /* char values 0x30b_ */
+ 0x3ff2, 0x0000, 0x3ffa, 0x0000, 0x4002, 0x0000, 0x400a, 0x0000,
+ 0x4012, 0x0000, 0x401a, 0x0000, 0x4022, 0x0000, 0x402a, 0x0000,
+ /* char values 0x30c_ */
+ 0x4032, 0x0000, 0x403a, 0x0000, 0x0000, 0x4042, 0x0000, 0x404a,
+ 0x0000, 0x4052, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0x30d_ */
+ 0x405a, 0x4062, 0x0000, 0x406a, 0x4072, 0x0000, 0x407a, 0x4082,
+ 0x0000, 0x408a, 0x4092, 0x0000, 0x409a, 0x40a2, 0x0000, 0x0000,
+ /* char values 0x30f_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x40aa, 0x0000, 0x0000, 0x40b2,
+ 0x40ba, 0x40c2, 0x40ca, 0x0000, 0x0000, 0x0000, 0x40d2, 0x0000,
+ /* char table 0xf___ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x07c0, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char table 0xfb__ */
+ 0x0000, 0x07d0, 0x07e0, 0x07f0, 0x0800, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* char values 0xfb1_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x40da,
+ /* char values 0xfb2_ */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x40e2, 0x40ea, 0x40f3, 0x40ff, 0x410a, 0x4112,
+ /* char values 0xfb3_ */
+ 0x411a, 0x4122, 0x412a, 0x4132, 0x413a, 0x4142, 0x414a, 0x0000,
+ 0x4152, 0x415a, 0x4162, 0x416a, 0x4172, 0x0000, 0x417a, 0x0000,
+ /* char values 0xfb4_ */
+ 0x4182, 0x418a, 0x0000, 0x4192, 0x419a, 0x0000, 0x41a2, 0x41aa,
+ 0x41b2, 0x41ba, 0x41c2, 0x41ca, 0x41d2, 0x41da, 0x41e2, 0x0000,
+ /* decomposed characters */
+ 0x0041, 0x0300, 0x0041, 0x0301, 0x0041, 0x0302, 0x0041, 0x0303,
+ 0x0041, 0x0308, 0x0041, 0x030a, 0x0043, 0x0327, 0x0045, 0x0300,
+ 0x0045, 0x0301, 0x0045, 0x0302, 0x0045, 0x0308, 0x0049, 0x0300,
+ 0x0049, 0x0301, 0x0049, 0x0302, 0x0049, 0x0308, 0x004e, 0x0303,
+ 0x004f, 0x0300, 0x004f, 0x0301, 0x004f, 0x0302, 0x004f, 0x0303,
+ 0x004f, 0x0308, 0x0055, 0x0300, 0x0055, 0x0301, 0x0055, 0x0302,
+ 0x0055, 0x0308, 0x0059, 0x0301, 0x0061, 0x0300, 0x0061, 0x0301,
+ 0x0061, 0x0302, 0x0061, 0x0303, 0x0061, 0x0308, 0x0061, 0x030a,
+ 0x0063, 0x0327, 0x0065, 0x0300, 0x0065, 0x0301, 0x0065, 0x0302,
+ 0x0065, 0x0308, 0x0069, 0x0300, 0x0069, 0x0301, 0x0069, 0x0302,
+ 0x0069, 0x0308, 0x006e, 0x0303, 0x006f, 0x0300, 0x006f, 0x0301,
+ 0x006f, 0x0302, 0x006f, 0x0303, 0x006f, 0x0308, 0x0075, 0x0300,
+ 0x0075, 0x0301, 0x0075, 0x0302, 0x0075, 0x0308, 0x0079, 0x0301,
+ 0x0079, 0x0308, 0x0041, 0x0304, 0x0061, 0x0304, 0x0041, 0x0306,
+ 0x0061, 0x0306, 0x0041, 0x0328, 0x0061, 0x0328, 0x0043, 0x0301,
+ 0x0063, 0x0301, 0x0043, 0x0302, 0x0063, 0x0302, 0x0043, 0x0307,
+ 0x0063, 0x0307, 0x0043, 0x030c, 0x0063, 0x030c, 0x0044, 0x030c,
+ 0x0064, 0x030c, 0x0045, 0x0304, 0x0065, 0x0304, 0x0045, 0x0306,
+ 0x0065, 0x0306, 0x0045, 0x0307, 0x0065, 0x0307, 0x0045, 0x0328,
+ 0x0065, 0x0328, 0x0045, 0x030c, 0x0065, 0x030c, 0x0047, 0x0302,
+ 0x0067, 0x0302, 0x0047, 0x0306, 0x0067, 0x0306, 0x0047, 0x0307,
+ 0x0067, 0x0307, 0x0047, 0x0327, 0x0067, 0x0327, 0x0048, 0x0302,
+ 0x0068, 0x0302, 0x0049, 0x0303, 0x0069, 0x0303, 0x0049, 0x0304,
+ 0x0069, 0x0304, 0x0049, 0x0306, 0x0069, 0x0306, 0x0049, 0x0328,
+ 0x0069, 0x0328, 0x0049, 0x0307, 0x004a, 0x0302, 0x006a, 0x0302,
+ 0x004b, 0x0327, 0x006b, 0x0327, 0x004c, 0x0301, 0x006c, 0x0301,
+ 0x004c, 0x0327, 0x006c, 0x0327, 0x004c, 0x030c, 0x006c, 0x030c,
+ 0x004e, 0x0301, 0x006e, 0x0301, 0x004e, 0x0327, 0x006e, 0x0327,
+ 0x004e, 0x030c, 0x006e, 0x030c, 0x004f, 0x0304, 0x006f, 0x0304,
+ 0x004f, 0x0306, 0x006f, 0x0306, 0x004f, 0x030b, 0x006f, 0x030b,
+ 0x0052, 0x0301, 0x0072, 0x0301, 0x0052, 0x0327, 0x0072, 0x0327,
+ 0x0052, 0x030c, 0x0072, 0x030c, 0x0053, 0x0301, 0x0073, 0x0301,
+ 0x0053, 0x0302, 0x0073, 0x0302, 0x0053, 0x0327, 0x0073, 0x0327,
+ 0x0053, 0x030c, 0x0073, 0x030c, 0x0054, 0x0327, 0x0074, 0x0327,
+ 0x0054, 0x030c, 0x0074, 0x030c, 0x0055, 0x0303, 0x0075, 0x0303,
+ 0x0055, 0x0304, 0x0075, 0x0304, 0x0055, 0x0306, 0x0075, 0x0306,
+ 0x0055, 0x030a, 0x0075, 0x030a, 0x0055, 0x030b, 0x0075, 0x030b,
+ 0x0055, 0x0328, 0x0075, 0x0328, 0x0057, 0x0302, 0x0077, 0x0302,
+ 0x0059, 0x0302, 0x0079, 0x0302, 0x0059, 0x0308, 0x005a, 0x0301,
+ 0x007a, 0x0301, 0x005a, 0x0307, 0x007a, 0x0307, 0x005a, 0x030c,
+ 0x007a, 0x030c, 0x004f, 0x031b, 0x006f, 0x031b, 0x0055, 0x031b,
+ 0x0075, 0x031b, 0x0041, 0x030c, 0x0061, 0x030c, 0x0049, 0x030c,
+ 0x0069, 0x030c, 0x004f, 0x030c, 0x006f, 0x030c, 0x0055, 0x030c,
+ 0x0075, 0x030c, 0x0055, 0x0308, 0x0304, 0x0075, 0x0308, 0x0304,
+ 0x0055, 0x0308, 0x0301, 0x0075, 0x0308, 0x0301, 0x0055, 0x0308,
+ 0x030c, 0x0075, 0x0308, 0x030c, 0x0055, 0x0308, 0x0300, 0x0075,
+ 0x0308, 0x0300, 0x0041, 0x0308, 0x0304, 0x0061, 0x0308, 0x0304,
+ 0x0041, 0x0307, 0x0304, 0x0061, 0x0307, 0x0304, 0x00c6, 0x0304,
+ 0x00e6, 0x0304, 0x0047, 0x030c, 0x0067, 0x030c, 0x004b, 0x030c,
+ 0x006b, 0x030c, 0x004f, 0x0328, 0x006f, 0x0328, 0x004f, 0x0328,
+ 0x0304, 0x006f, 0x0328, 0x0304, 0x01b7, 0x030c, 0x0292, 0x030c,
+ 0x006a, 0x030c, 0x0047, 0x0301, 0x0067, 0x0301, 0x0041, 0x030a,
+ 0x0301, 0x0061, 0x030a, 0x0301, 0x00c6, 0x0301, 0x00e6, 0x0301,
+ 0x00d8, 0x0301, 0x00f8, 0x0301, 0x0041, 0x030f, 0x0061, 0x030f,
+ 0x0041, 0x0311, 0x0061, 0x0311, 0x0045, 0x030f, 0x0065, 0x030f,
+ 0x0045, 0x0311, 0x0065, 0x0311, 0x0049, 0x030f, 0x0069, 0x030f,
+ 0x0049, 0x0311, 0x0069, 0x0311, 0x004f, 0x030f, 0x006f, 0x030f,
+ 0x004f, 0x0311, 0x006f, 0x0311, 0x0052, 0x030f, 0x0072, 0x030f,
+ 0x0052, 0x0311, 0x0072, 0x0311, 0x0055, 0x030f, 0x0075, 0x030f,
+ 0x0055, 0x0311, 0x0075, 0x0311, 0x0306, 0x0307, 0x0300, 0x0301,
+ 0x0313, 0x0308, 0x030d, 0x02b9, 0x003b, 0x00a8, 0x030d, 0x0391,
+ 0x030d, 0x00b7, 0x0395, 0x030d, 0x0397, 0x030d, 0x0399, 0x030d,
+ 0x039f, 0x030d, 0x03a5, 0x030d, 0x03a9, 0x030d, 0x03b9, 0x0308,
+ 0x030d, 0x0399, 0x0308, 0x03a5, 0x0308, 0x03b1, 0x030d, 0x03b5,
+ 0x030d, 0x03b7, 0x030d, 0x03b9, 0x030d, 0x03c5, 0x0308, 0x030d,
+ 0x03b9, 0x0308, 0x03c5, 0x0308, 0x03bf, 0x030d, 0x03c5, 0x030d,
+ 0x03c9, 0x030d, 0x03d2, 0x030d, 0x03d2, 0x0308, 0x0415, 0x0308,
+ 0x0413, 0x0301, 0x0406, 0x0308, 0x041a, 0x0301, 0x0423, 0x0306,
+ 0x0418, 0x0306, 0x0438, 0x0306, 0x0435, 0x0308, 0x0433, 0x0301,
+ 0x0456, 0x0308, 0x043a, 0x0301, 0x0443, 0x0306, 0x0474, 0x030f,
+ 0x0475, 0x030f, 0x0416, 0x0306, 0x0436, 0x0306, 0x0410, 0x0306,
+ 0x0430, 0x0306, 0x0410, 0x0308, 0x0430, 0x0308, 0x00c6, 0x00e6,
+ 0x0415, 0x0306, 0x0435, 0x0306, 0x018f, 0x0259, 0x018f, 0x0308,
+ 0x0259, 0x0308, 0x0416, 0x0308, 0x0436, 0x0308, 0x0417, 0x0308,
+ 0x0437, 0x0308, 0x01b7, 0x0292, 0x0418, 0x0304, 0x0438, 0x0304,
+ 0x0418, 0x0308, 0x0438, 0x0308, 0x041e, 0x0308, 0x043e, 0x0308,
+ 0x019f, 0x0275, 0x019f, 0x0308, 0x0275, 0x0308, 0x0423, 0x0304,
+ 0x0443, 0x0304, 0x0423, 0x0308, 0x0443, 0x0308, 0x0423, 0x030b,
+ 0x0443, 0x030b, 0x0427, 0x0308, 0x0447, 0x0308, 0x042b, 0x0308,
+ 0x044b, 0x0308, 0x0928, 0x093c, 0x0930, 0x093c, 0x0933, 0x093c,
+ 0x0915, 0x093c, 0x0916, 0x093c, 0x0917, 0x093c, 0x091c, 0x093c,
+ 0x0921, 0x093c, 0x0922, 0x093c, 0x092b, 0x093c, 0x092f, 0x093c,
+ 0x09ac, 0x09bc, 0x09c7, 0x09be, 0x09c7, 0x09d7, 0x09a1, 0x09bc,
+ 0x09a2, 0x09bc, 0x09af, 0x09bc, 0x0a16, 0x0a3c, 0x0a17, 0x0a3c,
+ 0x0a1c, 0x0a3c, 0x0a21, 0x0a3c, 0x0a2b, 0x0a3c, 0x0b47, 0x0b56,
+ 0x0b47, 0x0b3e, 0x0b47, 0x0b57, 0x0b21, 0x0b3c, 0x0b22, 0x0b3c,
+ 0x0b2f, 0x0b3c, 0x0b92, 0x0bd7, 0x0bc6, 0x0bbe, 0x0bc7, 0x0bbe,
+ 0x0bc6, 0x0bd7, 0x0c46, 0x0c56, 0x0cbf, 0x0cd5, 0x0cc6, 0x0cd5,
+ 0x0cc6, 0x0cd6, 0x0cc6, 0x0cc2, 0x0cc6, 0x0cc2, 0x0cd5, 0x0d46,
+ 0x0d3e, 0x0d47, 0x0d3e, 0x0d46, 0x0d57, 0x0e4d, 0x0e32, 0x0ecd,
+ 0x0eb2, 0x0f42, 0x0fb7, 0x0f4c, 0x0fb7, 0x0f51, 0x0fb7, 0x0f56,
+ 0x0fb7, 0x0f5b, 0x0fb7, 0x0f40, 0x0fb5, 0x0f72, 0x0f71, 0x0f74,
+ 0x0f71, 0x0fb2, 0x0f80, 0x0fb2, 0x0f80, 0x0f71, 0x0fb3, 0x0f80,
+ 0x0fb3, 0x0f80, 0x0f71, 0x0f80, 0x0f71, 0x0f92, 0x0fb7, 0x0f9c,
+ 0x0fb7, 0x0fa1, 0x0fb7, 0x0fa6, 0x0fb7, 0x0fab, 0x0fb7, 0x0f90,
+ 0x0fb5, 0x0041, 0x0325, 0x0061, 0x0325, 0x0042, 0x0307, 0x0062,
+ 0x0307, 0x0042, 0x0323, 0x0062, 0x0323, 0x0042, 0x0331, 0x0062,
+ 0x0331, 0x0043, 0x0327, 0x0301, 0x0063, 0x0327, 0x0301, 0x0044,
+ 0x0307, 0x0064, 0x0307, 0x0044, 0x0323, 0x0064, 0x0323, 0x0044,
+ 0x0331, 0x0064, 0x0331, 0x0044, 0x0327, 0x0064, 0x0327, 0x0044,
+ 0x032d, 0x0064, 0x032d, 0x0045, 0x0304, 0x0300, 0x0065, 0x0304,
+ 0x0300, 0x0045, 0x0304, 0x0301, 0x0065, 0x0304, 0x0301, 0x0045,
+ 0x032d, 0x0065, 0x032d, 0x0045, 0x0330, 0x0065, 0x0330, 0x0045,
+ 0x0327, 0x0306, 0x0065, 0x0327, 0x0306, 0x0046, 0x0307, 0x0066,
+ 0x0307, 0x0047, 0x0304, 0x0067, 0x0304, 0x0048, 0x0307, 0x0068,
+ 0x0307, 0x0048, 0x0323, 0x0068, 0x0323, 0x0048, 0x0308, 0x0068,
+ 0x0308, 0x0048, 0x0327, 0x0068, 0x0327, 0x0048, 0x032e, 0x0068,
+ 0x032e, 0x0049, 0x0330, 0x0069, 0x0330, 0x0049, 0x0308, 0x0301,
+ 0x0069, 0x0308, 0x0301, 0x004b, 0x0301, 0x006b, 0x0301, 0x004b,
+ 0x0323, 0x006b, 0x0323, 0x004b, 0x0331, 0x006b, 0x0331, 0x004c,
+ 0x0323, 0x006c, 0x0323, 0x004c, 0x0323, 0x0304, 0x006c, 0x0323,
+ 0x0304, 0x004c, 0x0331, 0x006c, 0x0331, 0x004c, 0x032d, 0x006c,
+ 0x032d, 0x004d, 0x0301, 0x006d, 0x0301, 0x004d, 0x0307, 0x006d,
+ 0x0307, 0x004d, 0x0323, 0x006d, 0x0323, 0x004e, 0x0307, 0x006e,
+ 0x0307, 0x004e, 0x0323, 0x006e, 0x0323, 0x004e, 0x0331, 0x006e,
+ 0x0331, 0x004e, 0x032d, 0x006e, 0x032d, 0x004f, 0x0303, 0x0301,
+ 0x006f, 0x0303, 0x0301, 0x004f, 0x0303, 0x0308, 0x006f, 0x0303,
+ 0x0308, 0x004f, 0x0304, 0x0300, 0x006f, 0x0304, 0x0300, 0x004f,
+ 0x0304, 0x0301, 0x006f, 0x0304, 0x0301, 0x0050, 0x0301, 0x0070,
+ 0x0301, 0x0050, 0x0307, 0x0070, 0x0307, 0x0052, 0x0307, 0x0072,
+ 0x0307, 0x0052, 0x0323, 0x0072, 0x0323, 0x0052, 0x0323, 0x0304,
+ 0x0072, 0x0323, 0x0304, 0x0052, 0x0331, 0x0072, 0x0331, 0x0053,
+ 0x0307, 0x0073, 0x0307, 0x0053, 0x0323, 0x0073, 0x0323, 0x0053,
+ 0x0301, 0x0307, 0x0073, 0x0301, 0x0307, 0x0053, 0x030c, 0x0307,
+ 0x0073, 0x030c, 0x0307, 0x0053, 0x0323, 0x0307, 0x0073, 0x0323,
+ 0x0307, 0x0054, 0x0307, 0x0074, 0x0307, 0x0054, 0x0323, 0x0074,
+ 0x0323, 0x0054, 0x0331, 0x0074, 0x0331, 0x0054, 0x032d, 0x0074,
+ 0x032d, 0x0055, 0x0324, 0x0075, 0x0324, 0x0055, 0x0330, 0x0075,
+ 0x0330, 0x0055, 0x032d, 0x0075, 0x032d, 0x0055, 0x0303, 0x0301,
+ 0x0075, 0x0303, 0x0301, 0x0055, 0x0304, 0x0308, 0x0075, 0x0304,
+ 0x0308, 0x0056, 0x0303, 0x0076, 0x0303, 0x0056, 0x0323, 0x0076,
+ 0x0323, 0x0057, 0x0300, 0x0077, 0x0300, 0x0057, 0x0301, 0x0077,
+ 0x0301, 0x0057, 0x0308, 0x0077, 0x0308, 0x0057, 0x0307, 0x0077,
+ 0x0307, 0x0057, 0x0323, 0x0077, 0x0323, 0x0058, 0x0307, 0x0078,
+ 0x0307, 0x0058, 0x0308, 0x0078, 0x0308, 0x0059, 0x0307, 0x0079,
+ 0x0307, 0x005a, 0x0302, 0x007a, 0x0302, 0x005a, 0x0323, 0x007a,
+ 0x0323, 0x005a, 0x0331, 0x007a, 0x0331, 0x0068, 0x0331, 0x0074,
+ 0x0308, 0x0077, 0x030a, 0x0079, 0x030a, 0x017f, 0x0307, 0x0041,
+ 0x0323, 0x0061, 0x0323, 0x0041, 0x0309, 0x0061, 0x0309, 0x0041,
+ 0x0302, 0x0301, 0x0061, 0x0302, 0x0301, 0x0041, 0x0302, 0x0300,
+ 0x0061, 0x0302, 0x0300, 0x0041, 0x0302, 0x0309, 0x0061, 0x0302,
+ 0x0309, 0x0041, 0x0302, 0x0303, 0x0061, 0x0302, 0x0303, 0x0041,
+ 0x0323, 0x0302, 0x0061, 0x0323, 0x0302, 0x0041, 0x0306, 0x0301,
+ 0x0061, 0x0306, 0x0301, 0x0041, 0x0306, 0x0300, 0x0061, 0x0306,
+ 0x0300, 0x0041, 0x0306, 0x0309, 0x0061, 0x0306, 0x0309, 0x0041,
+ 0x0306, 0x0303, 0x0061, 0x0306, 0x0303, 0x0041, 0x0323, 0x0306,
+ 0x0061, 0x0323, 0x0306, 0x0045, 0x0323, 0x0065, 0x0323, 0x0045,
+ 0x0309, 0x0065, 0x0309, 0x0045, 0x0303, 0x0065, 0x0303, 0x0045,
+ 0x0302, 0x0301, 0x0065, 0x0302, 0x0301, 0x0045, 0x0302, 0x0300,
+ 0x0065, 0x0302, 0x0300, 0x0045, 0x0302, 0x0309, 0x0065, 0x0302,
+ 0x0309, 0x0045, 0x0302, 0x0303, 0x0065, 0x0302, 0x0303, 0x0045,
+ 0x0323, 0x0302, 0x0065, 0x0323, 0x0302, 0x0049, 0x0309, 0x0069,
+ 0x0309, 0x0049, 0x0323, 0x0069, 0x0323, 0x004f, 0x0323, 0x006f,
+ 0x0323, 0x004f, 0x0309, 0x006f, 0x0309, 0x004f, 0x0302, 0x0301,
+ 0x006f, 0x0302, 0x0301, 0x004f, 0x0302, 0x0300, 0x006f, 0x0302,
+ 0x0300, 0x004f, 0x0302, 0x0309, 0x006f, 0x0302, 0x0309, 0x004f,
+ 0x0302, 0x0303, 0x006f, 0x0302, 0x0303, 0x004f, 0x0323, 0x0302,
+ 0x006f, 0x0323, 0x0302, 0x004f, 0x031b, 0x0301, 0x006f, 0x031b,
+ 0x0301, 0x004f, 0x031b, 0x0300, 0x006f, 0x031b, 0x0300, 0x004f,
+ 0x031b, 0x0309, 0x006f, 0x031b, 0x0309, 0x004f, 0x031b, 0x0303,
+ 0x006f, 0x031b, 0x0303, 0x004f, 0x031b, 0x0323, 0x006f, 0x031b,
+ 0x0323, 0x0055, 0x0323, 0x0075, 0x0323, 0x0055, 0x0309, 0x0075,
+ 0x0309, 0x0055, 0x031b, 0x0301, 0x0075, 0x031b, 0x0301, 0x0055,
+ 0x031b, 0x0300, 0x0075, 0x031b, 0x0300, 0x0055, 0x031b, 0x0309,
+ 0x0075, 0x031b, 0x0309, 0x0055, 0x031b, 0x0303, 0x0075, 0x031b,
+ 0x0303, 0x0055, 0x031b, 0x0323, 0x0075, 0x031b, 0x0323, 0x0059,
+ 0x0300, 0x0079, 0x0300, 0x0059, 0x0323, 0x0079, 0x0323, 0x0059,
+ 0x0309, 0x0079, 0x0309, 0x0059, 0x0303, 0x0079, 0x0303, 0x03b1,
+ 0x0313, 0x03b1, 0x0314, 0x03b1, 0x0313, 0x0300, 0x03b1, 0x0314,
+ 0x0300, 0x03b1, 0x0313, 0x0301, 0x03b1, 0x0314, 0x0301, 0x03b1,
+ 0x0313, 0x0342, 0x03b1, 0x0314, 0x0342, 0x0391, 0x0313, 0x0391,
+ 0x0314, 0x0391, 0x0313, 0x0300, 0x0391, 0x0314, 0x0300, 0x0391,
+ 0x0313, 0x0301, 0x0391, 0x0314, 0x0301, 0x0391, 0x0313, 0x0342,
+ 0x0391, 0x0314, 0x0342, 0x03b5, 0x0313, 0x03b5, 0x0314, 0x03b5,
+ 0x0313, 0x0300, 0x03b5, 0x0314, 0x0300, 0x03b5, 0x0313, 0x0301,
+ 0x03b5, 0x0314, 0x0301, 0x0395, 0x0313, 0x0395, 0x0314, 0x0395,
+ 0x0313, 0x0300, 0x0395, 0x0314, 0x0300, 0x0395, 0x0313, 0x0301,
+ 0x0395, 0x0314, 0x0301, 0x03b7, 0x0313, 0x03b7, 0x0314, 0x03b7,
+ 0x0313, 0x0300, 0x03b7, 0x0314, 0x0300, 0x03b7, 0x0313, 0x0301,
+ 0x03b7, 0x0314, 0x0301, 0x03b7, 0x0313, 0x0342, 0x03b7, 0x0314,
+ 0x0342, 0x0397, 0x0313, 0x0397, 0x0314, 0x0397, 0x0313, 0x0300,
+ 0x0397, 0x0314, 0x0300, 0x0397, 0x0313, 0x0301, 0x0397, 0x0314,
+ 0x0301, 0x0397, 0x0313, 0x0342, 0x0397, 0x0314, 0x0342, 0x03b9,
+ 0x0313, 0x03b9, 0x0314, 0x03b9, 0x0313, 0x0300, 0x03b9, 0x0314,
+ 0x0300, 0x03b9, 0x0313, 0x0301, 0x03b9, 0x0314, 0x0301, 0x03b9,
+ 0x0313, 0x0342, 0x03b9, 0x0314, 0x0342, 0x0399, 0x0313, 0x0399,
+ 0x0314, 0x0399, 0x0313, 0x0300, 0x0399, 0x0314, 0x0300, 0x0399,
+ 0x0313, 0x0301, 0x0399, 0x0314, 0x0301, 0x0399, 0x0313, 0x0342,
+ 0x0399, 0x0314, 0x0342, 0x03bf, 0x0313, 0x03bf, 0x0314, 0x03bf,
+ 0x0313, 0x0300, 0x03bf, 0x0314, 0x0300, 0x03bf, 0x0313, 0x0301,
+ 0x03bf, 0x0314, 0x0301, 0x039f, 0x0313, 0x039f, 0x0314, 0x039f,
+ 0x0313, 0x0300, 0x039f, 0x0314, 0x0300, 0x039f, 0x0313, 0x0301,
+ 0x039f, 0x0314, 0x0301, 0x03c5, 0x0313, 0x03c5, 0x0314, 0x03c5,
+ 0x0313, 0x0300, 0x03c5, 0x0314, 0x0300, 0x03c5, 0x0313, 0x0301,
+ 0x03c5, 0x0314, 0x0301, 0x03c5, 0x0313, 0x0342, 0x03c5, 0x0314,
+ 0x0342, 0x03a5, 0x0314, 0x03a5, 0x0314, 0x0300, 0x03a5, 0x0314,
+ 0x0301, 0x03a5, 0x0314, 0x0342, 0x03c9, 0x0313, 0x03c9, 0x0314,
+ 0x03c9, 0x0313, 0x0300, 0x03c9, 0x0314, 0x0300, 0x03c9, 0x0313,
+ 0x0301, 0x03c9, 0x0314, 0x0301, 0x03c9, 0x0313, 0x0342, 0x03c9,
+ 0x0314, 0x0342, 0x03a9, 0x0313, 0x03a9, 0x0314, 0x03a9, 0x0313,
+ 0x0300, 0x03a9, 0x0314, 0x0300, 0x03a9, 0x0313, 0x0301, 0x03a9,
+ 0x0314, 0x0301, 0x03a9, 0x0313, 0x0342, 0x03a9, 0x0314, 0x0342,
+ 0x03b1, 0x0300, 0x03b1, 0x0301, 0x03b5, 0x0300, 0x03b5, 0x0301,
+ 0x03b7, 0x0300, 0x03b7, 0x0301, 0x03b9, 0x0300, 0x03b9, 0x0301,
+ 0x03bf, 0x0300, 0x03bf, 0x0301, 0x03c5, 0x0300, 0x03c5, 0x0301,
+ 0x03c9, 0x0300, 0x03c9, 0x0301, 0x03b1, 0x0345, 0x0313, 0x03b1,
+ 0x0345, 0x0314, 0x03b1, 0x0345, 0x0313, 0x0300, 0x03b1, 0x0345,
+ 0x0314, 0x0300, 0x03b1, 0x0345, 0x0313, 0x0301, 0x03b1, 0x0345,
+ 0x0314, 0x0301, 0x03b1, 0x0345, 0x0313, 0x0342, 0x03b1, 0x0345,
+ 0x0314, 0x0342, 0x0391, 0x0345, 0x0313, 0x0391, 0x0345, 0x0314,
+ 0x0391, 0x0345, 0x0313, 0x0300, 0x0391, 0x0345, 0x0314, 0x0300,
+ 0x0391, 0x0345, 0x0313, 0x0301, 0x0391, 0x0345, 0x0314, 0x0301,
+ 0x0391, 0x0345, 0x0313, 0x0342, 0x0391, 0x0345, 0x0314, 0x0342,
+ 0x03b7, 0x0345, 0x0313, 0x03b7, 0x0345, 0x0314, 0x03b7, 0x0345,
+ 0x0313, 0x0300, 0x03b7, 0x0345, 0x0314, 0x0300, 0x03b7, 0x0345,
+ 0x0313, 0x0301, 0x03b7, 0x0345, 0x0314, 0x0301, 0x03b7, 0x0345,
+ 0x0313, 0x0342, 0x03b7, 0x0345, 0x0314, 0x0342, 0x0397, 0x0345,
+ 0x0313, 0x0397, 0x0345, 0x0314, 0x0397, 0x0345, 0x0313, 0x0300,
+ 0x0397, 0x0345, 0x0314, 0x0300, 0x0397, 0x0345, 0x0313, 0x0301,
+ 0x0397, 0x0345, 0x0314, 0x0301, 0x0397, 0x0345, 0x0313, 0x0342,
+ 0x0397, 0x0345, 0x0314, 0x0342, 0x03c9, 0x0345, 0x0313, 0x03c9,
+ 0x0345, 0x0314, 0x03c9, 0x0345, 0x0313, 0x0300, 0x03c9, 0x0345,
+ 0x0314, 0x0300, 0x03c9, 0x0345, 0x0313, 0x0301, 0x03c9, 0x0345,
+ 0x0314, 0x0301, 0x03c9, 0x0345, 0x0313, 0x0342, 0x03c9, 0x0345,
+ 0x0314, 0x0342, 0x03a9, 0x0345, 0x0313, 0x03a9, 0x0345, 0x0314,
+ 0x03a9, 0x0345, 0x0313, 0x0300, 0x03a9, 0x0345, 0x0314, 0x0300,
+ 0x03a9, 0x0345, 0x0313, 0x0301, 0x03a9, 0x0345, 0x0314, 0x0301,
+ 0x03a9, 0x0345, 0x0313, 0x0342, 0x03a9, 0x0345, 0x0314, 0x0342,
+ 0x03b1, 0x0306, 0x03b1, 0x0304, 0x03b1, 0x0345, 0x0300, 0x03b1,
+ 0x0345, 0x03b1, 0x0345, 0x0301, 0x03b1, 0x0342, 0x03b1, 0x0345,
+ 0x0342, 0x0391, 0x0306, 0x0391, 0x0304, 0x0391, 0x0300, 0x0391,
+ 0x0301, 0x0391, 0x0345, 0x03b9, 0x00a8, 0x0342, 0x03b7, 0x0345,
+ 0x0300, 0x03b7, 0x0345, 0x03b7, 0x0345, 0x0301, 0x03b7, 0x0342,
+ 0x03b7, 0x0345, 0x0342, 0x0395, 0x0300, 0x0395, 0x0301, 0x0397,
+ 0x0300, 0x0397, 0x0301, 0x0397, 0x0345, 0x1fbf, 0x0300, 0x1fbf,
+ 0x0301, 0x1fbf, 0x0342, 0x03b9, 0x0306, 0x03b9, 0x0304, 0x03b9,
+ 0x0308, 0x0300, 0x03b9, 0x0308, 0x0301, 0x03b9, 0x0342, 0x03b9,
+ 0x0308, 0x0342, 0x0399, 0x0306, 0x0399, 0x0304, 0x0399, 0x0300,
+ 0x0399, 0x0301, 0x1ffe, 0x0300, 0x1ffe, 0x0301, 0x1ffe, 0x0342,
+ 0x03c5, 0x0306, 0x03c5, 0x0304, 0x03c5, 0x0308, 0x0300, 0x03c5,
+ 0x0308, 0x0301, 0x03c1, 0x0313, 0x03c1, 0x0314, 0x03c5, 0x0342,
+ 0x03c5, 0x0308, 0x0342, 0x03a5, 0x0306, 0x03a5, 0x0304, 0x03a5,
+ 0x0300, 0x03a5, 0x0301, 0x03a1, 0x0314, 0x00a8, 0x0300, 0x00a8,
+ 0x0301, 0x0060, 0x03c9, 0x0345, 0x0300, 0x03c9, 0x0345, 0x03bf,
+ 0x0345, 0x0301, 0x03c9, 0x0342, 0x03c9, 0x0345, 0x0342, 0x039f,
+ 0x0300, 0x039f, 0x0301, 0x03a9, 0x0300, 0x03a9, 0x0301, 0x03a9,
+ 0x0345, 0x00b4, 0x304b, 0x3099, 0x304d, 0x3099, 0x304f, 0x3099,
+ 0x3051, 0x3099, 0x3053, 0x3099, 0x3055, 0x3099, 0x3057, 0x3099,
+ 0x3059, 0x3099, 0x305b, 0x3099, 0x305d, 0x3099, 0x305f, 0x3099,
+ 0x3061, 0x3099, 0x3064, 0x3099, 0x3066, 0x3099, 0x3068, 0x3099,
+ 0x306f, 0x3099, 0x306f, 0x309a, 0x3072, 0x3099, 0x3072, 0x309a,
+ 0x3075, 0x3099, 0x3075, 0x309a, 0x3078, 0x3099, 0x3078, 0x309a,
+ 0x307b, 0x3099, 0x307b, 0x309a, 0x3046, 0x3099, 0x309d, 0x3099,
+ 0x30ab, 0x3099, 0x30ad, 0x3099, 0x30af, 0x3099, 0x30b1, 0x3099,
+ 0x30b3, 0x3099, 0x30b5, 0x3099, 0x30b7, 0x3099, 0x30b9, 0x3099,
+ 0x30bb, 0x3099, 0x30bd, 0x3099, 0x30bf, 0x3099, 0x30c1, 0x3099,
+ 0x30c4, 0x3099, 0x30c6, 0x3099, 0x30c8, 0x3099, 0x30cf, 0x3099,
+ 0x30cf, 0x309a, 0x30d2, 0x3099, 0x30d2, 0x309a, 0x30d5, 0x3099,
+ 0x30d5, 0x309a, 0x30d8, 0x3099, 0x30d8, 0x309a, 0x30db, 0x3099,
+ 0x30db, 0x309a, 0x30a6, 0x3099, 0x30ef, 0x3099, 0x30f0, 0x3099,
+ 0x30f1, 0x3099, 0x30f2, 0x3099, 0x30fd, 0x3099, 0x05f2, 0x05b7,
+ 0x05e9, 0x05c1, 0x05e9, 0x05c2, 0x05e9, 0x05bc, 0x05c1, 0x05e9,
+ 0x05bc, 0x05c2, 0x05d0, 0x05b7, 0x05d0, 0x05b8, 0x05d0, 0x05bc,
+ 0x05d1, 0x05bc, 0x05d2, 0x05bc, 0x05d3, 0x05bc, 0x05d4, 0x05bc,
+ 0x05d5, 0x05bc, 0x05d6, 0x05bc, 0x05d8, 0x05bc, 0x05d9, 0x05bc,
+ 0x05da, 0x05bc, 0x05db, 0x05bc, 0x05dc, 0x05bc, 0x05de, 0x05bc,
+ 0x05e0, 0x05bc, 0x05e1, 0x05bc, 0x05e3, 0x05bc, 0x05e4, 0x05bc,
+ 0x05e6, 0x05bc, 0x05e7, 0x05bc, 0x05e8, 0x05bc, 0x05e9, 0x05bc,
+ 0x05ea, 0x05bc, 0x05d5, 0x05b9, 0x05d1, 0x05bf, 0x05db, 0x05bf,
+ 0x05e4, 0x05bf
+};
+
+u16 hfsplus_compose_table[] = {
+ /* base */
+ 0x0000, 0x0050, 0x0300, 0x00a4, 0x0301, 0x00e4, 0x0302, 0x015c,
+ 0x0303, 0x0192, 0x0304, 0x01b4, 0x0306, 0x01e6, 0x0307, 0x0220,
+ 0x0308, 0x0270, 0x0309, 0x02d2, 0x030a, 0x02ec, 0x030b, 0x02fa,
+ 0x030c, 0x0308, 0x030d, 0x034c, 0x030f, 0x0370, 0x0311, 0x038e,
+ 0x0313, 0x03a8, 0x0314, 0x03c6, 0x031b, 0x03e8, 0x0323, 0x03f2,
+ 0x0324, 0x0440, 0x0325, 0x0446, 0x0327, 0x044c, 0x0328, 0x047a,
+ 0x032d, 0x0490, 0x032e, 0x04aa, 0x0330, 0x04b0, 0x0331, 0x04be,
+ 0x0342, 0x04e2, 0x0345, 0x04f4, 0x05b7, 0x0504, 0x05b8, 0x050a,
+ 0x05b9, 0x050e, 0x05bc, 0x0512, 0x05bf, 0x0540, 0x05c1, 0x0548,
+ 0x05c2, 0x054c, 0x093c, 0x0550, 0x09bc, 0x0568, 0x09be, 0x0572,
+ 0x09d7, 0x0576, 0x0a3c, 0x057a, 0x0b3c, 0x0586, 0x0b3e, 0x058e,
+ 0x0b56, 0x0592, 0x0b57, 0x0596, 0x0bbe, 0x059a, 0x0bd7, 0x05a0,
+ 0x0c56, 0x05a6, 0x0cc2, 0x05aa, 0x0cd5, 0x05ae, 0x0cd6, 0x05b4,
+ 0x0d3e, 0x05b8, 0x0d57, 0x05be, 0x0e32, 0x05c2, 0x0eb2, 0x05c6,
+ 0x0f71, 0x05ca, 0x0f80, 0x05d2, 0x0fb5, 0x05d8, 0x0fb7, 0x05de,
+ 0x1100, 0x00a2, 0x1101, 0x00a2, 0x1102, 0x00a2, 0x1103, 0x00a2,
+ 0x1104, 0x00a2, 0x1105, 0x00a2, 0x1106, 0x00a2, 0x1107, 0x00a2,
+ 0x1108, 0x00a2, 0x1109, 0x00a2, 0x110a, 0x00a2, 0x110b, 0x00a2,
+ 0x110c, 0x00a2, 0x110d, 0x00a2, 0x110e, 0x00a2, 0x110f, 0x00a2,
+ 0x1110, 0x00a2, 0x1111, 0x00a2, 0x1112, 0x00a2, 0x3099, 0x05f4,
+ 0x309a, 0x0656,
+ /* hangul marker */
+ 0xffff, 0x0000,
+ /* 0x0300 */
+ 0x0340, 0x001f, 0x0041, 0x066c, 0x0045, 0x066e, 0x0049, 0x0670,
+ 0x004f, 0x0672, 0x0055, 0x0674, 0x0057, 0x0676, 0x0059, 0x0678,
+ 0x0061, 0x067a, 0x0065, 0x067c, 0x0069, 0x067e, 0x006f, 0x0680,
+ 0x0075, 0x0682, 0x0077, 0x0684, 0x0079, 0x0686, 0x00a8, 0x0688,
+ 0x0391, 0x068a, 0x0395, 0x068c, 0x0397, 0x068e, 0x0399, 0x0690,
+ 0x039f, 0x0692, 0x03a5, 0x0694, 0x03a9, 0x0696, 0x03b1, 0x0698,
+ 0x03b5, 0x069a, 0x03b7, 0x069c, 0x03b9, 0x069e, 0x03bf, 0x06a0,
+ 0x03c5, 0x06a2, 0x03c9, 0x06a4, 0x1fbf, 0x06a6, 0x1ffe, 0x06a8,
+ /* 0x0301 */
+ 0x0341, 0x003b, 0x0041, 0x06aa, 0x0043, 0x06ac, 0x0045, 0x06ae,
+ 0x0047, 0x06b0, 0x0049, 0x06b2, 0x004b, 0x06b4, 0x004c, 0x06b6,
+ 0x004d, 0x06b8, 0x004e, 0x06ba, 0x004f, 0x06bc, 0x0050, 0x06be,
+ 0x0052, 0x06c0, 0x0053, 0x06c2, 0x0055, 0x06c6, 0x0057, 0x06c8,
+ 0x0059, 0x06ca, 0x005a, 0x06cc, 0x0061, 0x06ce, 0x0063, 0x06d0,
+ 0x0065, 0x06d2, 0x0067, 0x06d4, 0x0069, 0x06d6, 0x006b, 0x06d8,
+ 0x006c, 0x06da, 0x006d, 0x06dc, 0x006e, 0x06de, 0x006f, 0x06e0,
+ 0x0070, 0x06e2, 0x0072, 0x06e4, 0x0073, 0x06e6, 0x0075, 0x06ea,
+ 0x0077, 0x06ec, 0x0079, 0x06ee, 0x007a, 0x06f0, 0x00a8, 0x06f2,
+ 0x00c6, 0x06f4, 0x00d8, 0x06f6, 0x00e6, 0x06f8, 0x00f8, 0x06fa,
+ 0x0391, 0x06fc, 0x0395, 0x06fe, 0x0397, 0x0700, 0x0399, 0x0702,
+ 0x039f, 0x0704, 0x03a5, 0x0706, 0x03a9, 0x0708, 0x03b1, 0x070a,
+ 0x03b5, 0x070c, 0x03b7, 0x070e, 0x03b9, 0x0710, 0x03bf, 0x0712,
+ 0x03c5, 0x0714, 0x03c9, 0x0716, 0x0413, 0x0718, 0x041a, 0x071a,
+ 0x0433, 0x071c, 0x043a, 0x071e, 0x1fbf, 0x0720, 0x1ffe, 0x0722,
+ /* 0x0302 */
+ 0x0000, 0x001a, 0x0041, 0x0724, 0x0043, 0x072e, 0x0045, 0x0730,
+ 0x0047, 0x073a, 0x0048, 0x073c, 0x0049, 0x073e, 0x004a, 0x0740,
+ 0x004f, 0x0742, 0x0053, 0x074c, 0x0055, 0x074e, 0x0057, 0x0750,
+ 0x0059, 0x0752, 0x005a, 0x0754, 0x0061, 0x0756, 0x0063, 0x0760,
+ 0x0065, 0x0762, 0x0067, 0x076c, 0x0068, 0x076e, 0x0069, 0x0770,
+ 0x006a, 0x0772, 0x006f, 0x0774, 0x0073, 0x077e, 0x0075, 0x0780,
+ 0x0077, 0x0782, 0x0079, 0x0784, 0x007a, 0x0786,
+ /* 0x0303 */
+ 0x0000, 0x0010, 0x0041, 0x0788, 0x0045, 0x078a, 0x0049, 0x078c,
+ 0x004e, 0x078e, 0x004f, 0x0790, 0x0055, 0x0796, 0x0056, 0x079a,
+ 0x0059, 0x079c, 0x0061, 0x079e, 0x0065, 0x07a0, 0x0069, 0x07a2,
+ 0x006e, 0x07a4, 0x006f, 0x07a6, 0x0075, 0x07ac, 0x0076, 0x07b0,
+ 0x0079, 0x07b2,
+ /* 0x0304 */
+ 0x0000, 0x0018, 0x0041, 0x07b4, 0x0045, 0x07b6, 0x0047, 0x07bc,
+ 0x0049, 0x07be, 0x004f, 0x07c0, 0x0055, 0x07c6, 0x0061, 0x07ca,
+ 0x0065, 0x07cc, 0x0067, 0x07d2, 0x0069, 0x07d4, 0x006f, 0x07d6,
+ 0x0075, 0x07dc, 0x00c6, 0x07e0, 0x00e6, 0x07e2, 0x0391, 0x07e4,
+ 0x0399, 0x07e6, 0x03a5, 0x07e8, 0x03b1, 0x07ea, 0x03b9, 0x07ec,
+ 0x03c5, 0x07ee, 0x0418, 0x07f0, 0x0423, 0x07f2, 0x0438, 0x07f4,
+ 0x0443, 0x07f6,
+ /* 0x0306 */
+ 0x0000, 0x001c, 0x0041, 0x07f8, 0x0045, 0x0802, 0x0047, 0x0804,
+ 0x0049, 0x0806, 0x004f, 0x0808, 0x0055, 0x080a, 0x0061, 0x080c,
+ 0x0065, 0x0816, 0x0067, 0x0818, 0x0069, 0x081a, 0x006f, 0x081c,
+ 0x0075, 0x081e, 0x0391, 0x0820, 0x0399, 0x0822, 0x03a5, 0x0824,
+ 0x03b1, 0x0826, 0x03b9, 0x0828, 0x03c5, 0x082a, 0x0410, 0x082c,
+ 0x0415, 0x082e, 0x0416, 0x0830, 0x0418, 0x0832, 0x0423, 0x0834,
+ 0x0430, 0x0836, 0x0435, 0x0838, 0x0436, 0x083a, 0x0438, 0x083c,
+ 0x0443, 0x083e,
+ /* 0x0307 */
+ 0x0000, 0x0027, 0x0041, 0x0840, 0x0042, 0x0844, 0x0043, 0x0846,
+ 0x0044, 0x0848, 0x0045, 0x084a, 0x0046, 0x084c, 0x0047, 0x084e,
+ 0x0048, 0x0850, 0x0049, 0x0852, 0x004d, 0x0854, 0x004e, 0x0856,
+ 0x0050, 0x0858, 0x0052, 0x085a, 0x0053, 0x085c, 0x0054, 0x085e,
+ 0x0057, 0x0860, 0x0058, 0x0862, 0x0059, 0x0864, 0x005a, 0x0866,
+ 0x0061, 0x0868, 0x0062, 0x086c, 0x0063, 0x086e, 0x0064, 0x0870,
+ 0x0065, 0x0872, 0x0066, 0x0874, 0x0067, 0x0876, 0x0068, 0x0878,
+ 0x006d, 0x087a, 0x006e, 0x087c, 0x0070, 0x087e, 0x0072, 0x0880,
+ 0x0073, 0x0882, 0x0074, 0x0884, 0x0077, 0x0886, 0x0078, 0x0888,
+ 0x0079, 0x088a, 0x007a, 0x088c, 0x017f, 0x088e, 0x0306, 0x0890,
+ /* 0x0308 */
+ 0x0000, 0x0030, 0x0041, 0x0892, 0x0045, 0x0896, 0x0048, 0x0898,
+ 0x0049, 0x089a, 0x004f, 0x089e, 0x0055, 0x08a0, 0x0057, 0x08aa,
+ 0x0058, 0x08ac, 0x0059, 0x08ae, 0x0061, 0x08b0, 0x0065, 0x08b4,
+ 0x0068, 0x08b6, 0x0069, 0x08b8, 0x006f, 0x08bc, 0x0074, 0x08be,
+ 0x0075, 0x08c0, 0x0077, 0x08ca, 0x0078, 0x08cc, 0x0079, 0x08ce,
+ 0x018f, 0x08d0, 0x019f, 0x08d2, 0x0259, 0x08d4, 0x0275, 0x08d6,
+ 0x0399, 0x08d8, 0x03a5, 0x08da, 0x03b9, 0x08dc, 0x03c5, 0x08e6,
+ 0x03d2, 0x08f0, 0x0406, 0x08f2, 0x0410, 0x08f4, 0x0415, 0x08f6,
+ 0x0416, 0x08f8, 0x0417, 0x08fa, 0x0418, 0x08fc, 0x041e, 0x08fe,
+ 0x0423, 0x0900, 0x0427, 0x0902, 0x042b, 0x0904, 0x0430, 0x0906,
+ 0x0435, 0x0908, 0x0436, 0x090a, 0x0437, 0x090c, 0x0438, 0x090e,
+ 0x043e, 0x0910, 0x0443, 0x0912, 0x0447, 0x0914, 0x044b, 0x0916,
+ 0x0456, 0x0918,
+ /* 0x0309 */
+ 0x0000, 0x000c, 0x0041, 0x091a, 0x0045, 0x091c, 0x0049, 0x091e,
+ 0x004f, 0x0920, 0x0055, 0x0922, 0x0059, 0x0924, 0x0061, 0x0926,
+ 0x0065, 0x0928, 0x0069, 0x092a, 0x006f, 0x092c, 0x0075, 0x092e,
+ 0x0079, 0x0930,
+ /* 0x030a */
+ 0x0000, 0x0006, 0x0041, 0x0932, 0x0055, 0x0936, 0x0061, 0x0938,
+ 0x0075, 0x093c, 0x0077, 0x093e, 0x0079, 0x0940,
+ /* 0x030b */
+ 0x0000, 0x0006, 0x004f, 0x0942, 0x0055, 0x0944, 0x006f, 0x0946,
+ 0x0075, 0x0948, 0x0423, 0x094a, 0x0443, 0x094c,
+ /* 0x030c */
+ 0x0000, 0x0021, 0x0041, 0x094e, 0x0043, 0x0950, 0x0044, 0x0952,
+ 0x0045, 0x0954, 0x0047, 0x0956, 0x0049, 0x0958, 0x004b, 0x095a,
+ 0x004c, 0x095c, 0x004e, 0x095e, 0x004f, 0x0960, 0x0052, 0x0962,
+ 0x0053, 0x0964, 0x0054, 0x0968, 0x0055, 0x096a, 0x005a, 0x096c,
+ 0x0061, 0x096e, 0x0063, 0x0970, 0x0064, 0x0972, 0x0065, 0x0974,
+ 0x0067, 0x0976, 0x0069, 0x0978, 0x006a, 0x097a, 0x006b, 0x097c,
+ 0x006c, 0x097e, 0x006e, 0x0980, 0x006f, 0x0982, 0x0072, 0x0984,
+ 0x0073, 0x0986, 0x0074, 0x098a, 0x0075, 0x098c, 0x007a, 0x098e,
+ 0x01b7, 0x0990, 0x0292, 0x0992,
+ /* 0x030d */
+ 0x0000, 0x0011, 0x00a8, 0x0994, 0x0308, 0x0996, 0x0391, 0x0998,
+ 0x0395, 0x099a, 0x0397, 0x099c, 0x0399, 0x099e, 0x039f, 0x09a0,
+ 0x03a5, 0x09a2, 0x03a9, 0x09a4, 0x03b1, 0x09a6, 0x03b5, 0x09a8,
+ 0x03b7, 0x09aa, 0x03b9, 0x09ac, 0x03bf, 0x09ae, 0x03c5, 0x09b0,
+ 0x03c9, 0x09b2, 0x03d2, 0x09b4,
+ /* 0x030f */
+ 0x0000, 0x000e, 0x0041, 0x09b6, 0x0045, 0x09b8, 0x0049, 0x09ba,
+ 0x004f, 0x09bc, 0x0052, 0x09be, 0x0055, 0x09c0, 0x0061, 0x09c2,
+ 0x0065, 0x09c4, 0x0069, 0x09c6, 0x006f, 0x09c8, 0x0072, 0x09ca,
+ 0x0075, 0x09cc, 0x0474, 0x09ce, 0x0475, 0x09d0,
+ /* 0x0311 */
+ 0x0000, 0x000c, 0x0041, 0x09d2, 0x0045, 0x09d4, 0x0049, 0x09d6,
+ 0x004f, 0x09d8, 0x0052, 0x09da, 0x0055, 0x09dc, 0x0061, 0x09de,
+ 0x0065, 0x09e0, 0x0069, 0x09e2, 0x006f, 0x09e4, 0x0072, 0x09e6,
+ 0x0075, 0x09e8,
+ /* 0x0313 */
+ 0x0343, 0x000e, 0x0391, 0x09ea, 0x0395, 0x09f2, 0x0397, 0x09f8,
+ 0x0399, 0x0a00, 0x039f, 0x0a08, 0x03a9, 0x0a0e, 0x03b1, 0x0a16,
+ 0x03b5, 0x0a1e, 0x03b7, 0x0a24, 0x03b9, 0x0a2c, 0x03bf, 0x0a34,
+ 0x03c1, 0x0a3a, 0x03c5, 0x0a3c, 0x03c9, 0x0a44,
+ /* 0x0314 */
+ 0x0000, 0x0010, 0x0391, 0x0a4c, 0x0395, 0x0a54, 0x0397, 0x0a5a,
+ 0x0399, 0x0a62, 0x039f, 0x0a6a, 0x03a1, 0x0a70, 0x03a5, 0x0a72,
+ 0x03a9, 0x0a7a, 0x03b1, 0x0a82, 0x03b5, 0x0a8a, 0x03b7, 0x0a90,
+ 0x03b9, 0x0a98, 0x03bf, 0x0aa0, 0x03c1, 0x0aa6, 0x03c5, 0x0aa8,
+ 0x03c9, 0x0ab0,
+ /* 0x031b */
+ 0x0000, 0x0004, 0x004f, 0x0ab8, 0x0055, 0x0ac4, 0x006f, 0x0ad0,
+ 0x0075, 0x0adc,
+ /* 0x0323 */
+ 0x0000, 0x0026, 0x0041, 0x0ae8, 0x0042, 0x0aee, 0x0044, 0x0af0,
+ 0x0045, 0x0af2, 0x0048, 0x0af6, 0x0049, 0x0af8, 0x004b, 0x0afa,
+ 0x004c, 0x0afc, 0x004d, 0x0b00, 0x004e, 0x0b02, 0x004f, 0x0b04,
+ 0x0052, 0x0b08, 0x0053, 0x0b0c, 0x0054, 0x0b10, 0x0055, 0x0b12,
+ 0x0056, 0x0b14, 0x0057, 0x0b16, 0x0059, 0x0b18, 0x005a, 0x0b1a,
+ 0x0061, 0x0b1c, 0x0062, 0x0b22, 0x0064, 0x0b24, 0x0065, 0x0b26,
+ 0x0068, 0x0b2a, 0x0069, 0x0b2c, 0x006b, 0x0b2e, 0x006c, 0x0b30,
+ 0x006d, 0x0b34, 0x006e, 0x0b36, 0x006f, 0x0b38, 0x0072, 0x0b3c,
+ 0x0073, 0x0b40, 0x0074, 0x0b44, 0x0075, 0x0b46, 0x0076, 0x0b48,
+ 0x0077, 0x0b4a, 0x0079, 0x0b4c, 0x007a, 0x0b4e,
+ /* 0x0324 */
+ 0x0000, 0x0002, 0x0055, 0x0b50, 0x0075, 0x0b52,
+ /* 0x0325 */
+ 0x0000, 0x0002, 0x0041, 0x0b54, 0x0061, 0x0b56,
+ /* 0x0327 */
+ 0x0000, 0x0016, 0x0043, 0x0b58, 0x0044, 0x0b5c, 0x0045, 0x0b5e,
+ 0x0047, 0x0b62, 0x0048, 0x0b64, 0x004b, 0x0b66, 0x004c, 0x0b68,
+ 0x004e, 0x0b6a, 0x0052, 0x0b6c, 0x0053, 0x0b6e, 0x0054, 0x0b70,
+ 0x0063, 0x0b72, 0x0064, 0x0b76, 0x0065, 0x0b78, 0x0067, 0x0b7c,
+ 0x0068, 0x0b7e, 0x006b, 0x0b80, 0x006c, 0x0b82, 0x006e, 0x0b84,
+ 0x0072, 0x0b86, 0x0073, 0x0b88, 0x0074, 0x0b8a,
+ /* 0x0328 */
+ 0x0000, 0x000a, 0x0041, 0x0b8c, 0x0045, 0x0b8e, 0x0049, 0x0b90,
+ 0x004f, 0x0b92, 0x0055, 0x0b96, 0x0061, 0x0b98, 0x0065, 0x0b9a,
+ 0x0069, 0x0b9c, 0x006f, 0x0b9e, 0x0075, 0x0ba2,
+ /* 0x032d */
+ 0x0000, 0x000c, 0x0044, 0x0ba4, 0x0045, 0x0ba6, 0x004c, 0x0ba8,
+ 0x004e, 0x0baa, 0x0054, 0x0bac, 0x0055, 0x0bae, 0x0064, 0x0bb0,
+ 0x0065, 0x0bb2, 0x006c, 0x0bb4, 0x006e, 0x0bb6, 0x0074, 0x0bb8,
+ 0x0075, 0x0bba,
+ /* 0x032e */
+ 0x0000, 0x0002, 0x0048, 0x0bbc, 0x0068, 0x0bbe,
+ /* 0x0330 */
+ 0x0000, 0x0006, 0x0045, 0x0bc0, 0x0049, 0x0bc2, 0x0055, 0x0bc4,
+ 0x0065, 0x0bc6, 0x0069, 0x0bc8, 0x0075, 0x0bca,
+ /* 0x0331 */
+ 0x0000, 0x0011, 0x0042, 0x0bcc, 0x0044, 0x0bce, 0x004b, 0x0bd0,
+ 0x004c, 0x0bd2, 0x004e, 0x0bd4, 0x0052, 0x0bd6, 0x0054, 0x0bd8,
+ 0x005a, 0x0bda, 0x0062, 0x0bdc, 0x0064, 0x0bde, 0x0068, 0x0be0,
+ 0x006b, 0x0be2, 0x006c, 0x0be4, 0x006e, 0x0be6, 0x0072, 0x0be8,
+ 0x0074, 0x0bea, 0x007a, 0x0bec,
+ /* 0x0342 */
+ 0x0000, 0x0008, 0x00a8, 0x0bee, 0x03b1, 0x0bf0, 0x03b7, 0x0bf2,
+ 0x03b9, 0x0bf4, 0x03c5, 0x0bf6, 0x03c9, 0x0bf8, 0x1fbf, 0x0bfa,
+ 0x1ffe, 0x0bfc,
+ /* 0x0345 */
+ 0x0000, 0x0007, 0x0391, 0x0bfe, 0x0397, 0x0c04, 0x03a9, 0x0c0a,
+ 0x03b1, 0x0c10, 0x03b7, 0x0c1c, 0x03bf, 0x0c28, 0x03c9, 0x0c2c,
+ /* 0x05b7 */
+ 0x0000, 0x0002, 0x05d0, 0x0c36, 0x05f2, 0x0c38,
+ /* 0x05b8 */
+ 0x0000, 0x0001, 0x05d0, 0x0c3a,
+ /* 0x05b9 */
+ 0x0000, 0x0001, 0x05d5, 0x0c3c,
+ /* 0x05bc */
+ 0x0000, 0x0016, 0x05d0, 0x0c3e, 0x05d1, 0x0c40, 0x05d2, 0x0c42,
+ 0x05d3, 0x0c44, 0x05d4, 0x0c46, 0x05d5, 0x0c48, 0x05d6, 0x0c4a,
+ 0x05d8, 0x0c4c, 0x05d9, 0x0c4e, 0x05da, 0x0c50, 0x05db, 0x0c52,
+ 0x05dc, 0x0c54, 0x05de, 0x0c56, 0x05e0, 0x0c58, 0x05e1, 0x0c5a,
+ 0x05e3, 0x0c5c, 0x05e4, 0x0c5e, 0x05e6, 0x0c60, 0x05e7, 0x0c62,
+ 0x05e8, 0x0c64, 0x05e9, 0x0c66, 0x05ea, 0x0c6c,
+ /* 0x05bf */
+ 0x0000, 0x0003, 0x05d1, 0x0c6e, 0x05db, 0x0c70, 0x05e4, 0x0c72,
+ /* 0x05c1 */
+ 0x0000, 0x0001, 0x05e9, 0x0c74,
+ /* 0x05c2 */
+ 0x0000, 0x0001, 0x05e9, 0x0c76,
+ /* 0x093c */
+ 0x0000, 0x000b, 0x0915, 0x0c78, 0x0916, 0x0c7a, 0x0917, 0x0c7c,
+ 0x091c, 0x0c7e, 0x0921, 0x0c80, 0x0922, 0x0c82, 0x0928, 0x0c84,
+ 0x092b, 0x0c86, 0x092f, 0x0c88, 0x0930, 0x0c8a, 0x0933, 0x0c8c,
+ /* 0x09bc */
+ 0x0000, 0x0004, 0x09a1, 0x0c8e, 0x09a2, 0x0c90, 0x09ac, 0x0c92,
+ 0x09af, 0x0c94,
+ /* 0x09be */
+ 0x0000, 0x0001, 0x09c7, 0x0c96,
+ /* 0x09d7 */
+ 0x0000, 0x0001, 0x09c7, 0x0c98,
+ /* 0x0a3c */
+ 0x0000, 0x0005, 0x0a16, 0x0c9a, 0x0a17, 0x0c9c, 0x0a1c, 0x0c9e,
+ 0x0a21, 0x0ca0, 0x0a2b, 0x0ca2,
+ /* 0x0b3c */
+ 0x0000, 0x0003, 0x0b21, 0x0ca4, 0x0b22, 0x0ca6, 0x0b2f, 0x0ca8,
+ /* 0x0b3e */
+ 0x0000, 0x0001, 0x0b47, 0x0caa,
+ /* 0x0b56 */
+ 0x0000, 0x0001, 0x0b47, 0x0cac,
+ /* 0x0b57 */
+ 0x0000, 0x0001, 0x0b47, 0x0cae,
+ /* 0x0bbe */
+ 0x0000, 0x0002, 0x0bc6, 0x0cb0, 0x0bc7, 0x0cb2,
+ /* 0x0bd7 */
+ 0x0000, 0x0002, 0x0b92, 0x0cb4, 0x0bc6, 0x0cb6,
+ /* 0x0c56 */
+ 0x0000, 0x0001, 0x0c46, 0x0cb8,
+ /* 0x0cc2 */
+ 0x0000, 0x0001, 0x0cc6, 0x0cba,
+ /* 0x0cd5 */
+ 0x0000, 0x0002, 0x0cbf, 0x0cbe, 0x0cc6, 0x0cc0,
+ /* 0x0cd6 */
+ 0x0000, 0x0001, 0x0cc6, 0x0cc2,
+ /* 0x0d3e */
+ 0x0000, 0x0002, 0x0d46, 0x0cc4, 0x0d47, 0x0cc6,
+ /* 0x0d57 */
+ 0x0000, 0x0001, 0x0d46, 0x0cc8,
+ /* 0x0e32 */
+ 0x0000, 0x0001, 0x0e4d, 0x0cca,
+ /* 0x0eb2 */
+ 0x0000, 0x0001, 0x0ecd, 0x0ccc,
+ /* 0x0f71 */
+ 0x0000, 0x0003, 0x0f72, 0x0cce, 0x0f74, 0x0cd0, 0x0f80, 0x0cd2,
+ /* 0x0f80 */
+ 0x0000, 0x0002, 0x0fb2, 0x0cd4, 0x0fb3, 0x0cd8,
+ /* 0x0fb5 */
+ 0x0000, 0x0002, 0x0f40, 0x0cdc, 0x0f90, 0x0cde,
+ /* 0x0fb7 */
+ 0x0000, 0x000a, 0x0f42, 0x0ce0, 0x0f4c, 0x0ce2, 0x0f51, 0x0ce4,
+ 0x0f56, 0x0ce6, 0x0f5b, 0x0ce8, 0x0f92, 0x0cea, 0x0f9c, 0x0cec,
+ 0x0fa1, 0x0cee, 0x0fa6, 0x0cf0, 0x0fab, 0x0cf2,
+ /* 0x3099 */
+ 0x0000, 0x0030, 0x3046, 0x0cf4, 0x304b, 0x0cf6, 0x304d, 0x0cf8,
+ 0x304f, 0x0cfa, 0x3051, 0x0cfc, 0x3053, 0x0cfe, 0x3055, 0x0d00,
+ 0x3057, 0x0d02, 0x3059, 0x0d04, 0x305b, 0x0d06, 0x305d, 0x0d08,
+ 0x305f, 0x0d0a, 0x3061, 0x0d0c, 0x3064, 0x0d0e, 0x3066, 0x0d10,
+ 0x3068, 0x0d12, 0x306f, 0x0d14, 0x3072, 0x0d16, 0x3075, 0x0d18,
+ 0x3078, 0x0d1a, 0x307b, 0x0d1c, 0x309d, 0x0d1e, 0x30a6, 0x0d20,
+ 0x30ab, 0x0d22, 0x30ad, 0x0d24, 0x30af, 0x0d26, 0x30b1, 0x0d28,
+ 0x30b3, 0x0d2a, 0x30b5, 0x0d2c, 0x30b7, 0x0d2e, 0x30b9, 0x0d30,
+ 0x30bb, 0x0d32, 0x30bd, 0x0d34, 0x30bf, 0x0d36, 0x30c1, 0x0d38,
+ 0x30c4, 0x0d3a, 0x30c6, 0x0d3c, 0x30c8, 0x0d3e, 0x30cf, 0x0d40,
+ 0x30d2, 0x0d42, 0x30d5, 0x0d44, 0x30d8, 0x0d46, 0x30db, 0x0d48,
+ 0x30ef, 0x0d4a, 0x30f0, 0x0d4c, 0x30f1, 0x0d4e, 0x30f2, 0x0d50,
+ 0x30fd, 0x0d52,
+ /* 0x309a */
+ 0x0000, 0x000a, 0x306f, 0x0d54, 0x3072, 0x0d56, 0x3075, 0x0d58,
+ 0x3078, 0x0d5a, 0x307b, 0x0d5c, 0x30cf, 0x0d5e, 0x30d2, 0x0d60,
+ 0x30d5, 0x0d62, 0x30d8, 0x0d64, 0x30db, 0x0d66,
+ /* 0x0041 0x0300 */
+ 0x00c0, 0x0000,
+ /* 0x0045 0x0300 */
+ 0x00c8, 0x0000,
+ /* 0x0049 0x0300 */
+ 0x00cc, 0x0000,
+ /* 0x004f 0x0300 */
+ 0x00d2, 0x0000,
+ /* 0x0055 0x0300 */
+ 0x00d9, 0x0000,
+ /* 0x0057 0x0300 */
+ 0x1e80, 0x0000,
+ /* 0x0059 0x0300 */
+ 0x1ef2, 0x0000,
+ /* 0x0061 0x0300 */
+ 0x00e0, 0x0000,
+ /* 0x0065 0x0300 */
+ 0x00e8, 0x0000,
+ /* 0x0069 0x0300 */
+ 0x00ec, 0x0000,
+ /* 0x006f 0x0300 */
+ 0x00f2, 0x0000,
+ /* 0x0075 0x0300 */
+ 0x00f9, 0x0000,
+ /* 0x0077 0x0300 */
+ 0x1e81, 0x0000,
+ /* 0x0079 0x0300 */
+ 0x1ef3, 0x0000,
+ /* 0x00a8 0x0300 */
+ 0x1fed, 0x0000,
+ /* 0x0391 0x0300 */
+ 0x1fba, 0x0000,
+ /* 0x0395 0x0300 */
+ 0x1fc8, 0x0000,
+ /* 0x0397 0x0300 */
+ 0x1fca, 0x0000,
+ /* 0x0399 0x0300 */
+ 0x1fda, 0x0000,
+ /* 0x039f 0x0300 */
+ 0x1ff8, 0x0000,
+ /* 0x03a5 0x0300 */
+ 0x1fea, 0x0000,
+ /* 0x03a9 0x0300 */
+ 0x1ffa, 0x0000,
+ /* 0x03b1 0x0300 */
+ 0x1f70, 0x0000,
+ /* 0x03b5 0x0300 */
+ 0x1f72, 0x0000,
+ /* 0x03b7 0x0300 */
+ 0x1f74, 0x0000,
+ /* 0x03b9 0x0300 */
+ 0x1f76, 0x0000,
+ /* 0x03bf 0x0300 */
+ 0x1f78, 0x0000,
+ /* 0x03c5 0x0300 */
+ 0x1f7a, 0x0000,
+ /* 0x03c9 0x0300 */
+ 0x1f7c, 0x0000,
+ /* 0x1fbf 0x0300 */
+ 0x1fcd, 0x0000,
+ /* 0x1ffe 0x0300 */
+ 0x1fdd, 0x0000,
+ /* 0x0041 0x0301 */
+ 0x00c1, 0x0000,
+ /* 0x0043 0x0301 */
+ 0x0106, 0x0000,
+ /* 0x0045 0x0301 */
+ 0x00c9, 0x0000,
+ /* 0x0047 0x0301 */
+ 0x01f4, 0x0000,
+ /* 0x0049 0x0301 */
+ 0x00cd, 0x0000,
+ /* 0x004b 0x0301 */
+ 0x1e30, 0x0000,
+ /* 0x004c 0x0301 */
+ 0x0139, 0x0000,
+ /* 0x004d 0x0301 */
+ 0x1e3e, 0x0000,
+ /* 0x004e 0x0301 */
+ 0x0143, 0x0000,
+ /* 0x004f 0x0301 */
+ 0x00d3, 0x0000,
+ /* 0x0050 0x0301 */
+ 0x1e54, 0x0000,
+ /* 0x0052 0x0301 */
+ 0x0154, 0x0000,
+ /* 0x0053 0x0301 */
+ 0x015a, 0x0001, 0x0307, 0x0d68,
+ /* 0x0055 0x0301 */
+ 0x00da, 0x0000,
+ /* 0x0057 0x0301 */
+ 0x1e82, 0x0000,
+ /* 0x0059 0x0301 */
+ 0x00dd, 0x0000,
+ /* 0x005a 0x0301 */
+ 0x0179, 0x0000,
+ /* 0x0061 0x0301 */
+ 0x00e1, 0x0000,
+ /* 0x0063 0x0301 */
+ 0x0107, 0x0000,
+ /* 0x0065 0x0301 */
+ 0x00e9, 0x0000,
+ /* 0x0067 0x0301 */
+ 0x01f5, 0x0000,
+ /* 0x0069 0x0301 */
+ 0x00ed, 0x0000,
+ /* 0x006b 0x0301 */
+ 0x1e31, 0x0000,
+ /* 0x006c 0x0301 */
+ 0x013a, 0x0000,
+ /* 0x006d 0x0301 */
+ 0x1e3f, 0x0000,
+ /* 0x006e 0x0301 */
+ 0x0144, 0x0000,
+ /* 0x006f 0x0301 */
+ 0x00f3, 0x0000,
+ /* 0x0070 0x0301 */
+ 0x1e55, 0x0000,
+ /* 0x0072 0x0301 */
+ 0x0155, 0x0000,
+ /* 0x0073 0x0301 */
+ 0x015b, 0x0001, 0x0307, 0x0d6a,
+ /* 0x0075 0x0301 */
+ 0x00fa, 0x0000,
+ /* 0x0077 0x0301 */
+ 0x1e83, 0x0000,
+ /* 0x0079 0x0301 */
+ 0x00fd, 0x0000,
+ /* 0x007a 0x0301 */
+ 0x017a, 0x0000,
+ /* 0x00a8 0x0301 */
+ 0x1fee, 0x0000,
+ /* 0x00c6 0x0301 */
+ 0x01fc, 0x0000,
+ /* 0x00d8 0x0301 */
+ 0x01fe, 0x0000,
+ /* 0x00e6 0x0301 */
+ 0x01fd, 0x0000,
+ /* 0x00f8 0x0301 */
+ 0x01ff, 0x0000,
+ /* 0x0391 0x0301 */
+ 0x1fbb, 0x0000,
+ /* 0x0395 0x0301 */
+ 0x1fc9, 0x0000,
+ /* 0x0397 0x0301 */
+ 0x1fcb, 0x0000,
+ /* 0x0399 0x0301 */
+ 0x1fdb, 0x0000,
+ /* 0x039f 0x0301 */
+ 0x1ff9, 0x0000,
+ /* 0x03a5 0x0301 */
+ 0x1feb, 0x0000,
+ /* 0x03a9 0x0301 */
+ 0x1ffb, 0x0000,
+ /* 0x03b1 0x0301 */
+ 0x1f71, 0x0000,
+ /* 0x03b5 0x0301 */
+ 0x1f73, 0x0000,
+ /* 0x03b7 0x0301 */
+ 0x1f75, 0x0000,
+ /* 0x03b9 0x0301 */
+ 0x1f77, 0x0000,
+ /* 0x03bf 0x0301 */
+ 0x1f79, 0x0000,
+ /* 0x03c5 0x0301 */
+ 0x1f7b, 0x0000,
+ /* 0x03c9 0x0301 */
+ 0x1f7d, 0x0000,
+ /* 0x0413 0x0301 */
+ 0x0403, 0x0000,
+ /* 0x041a 0x0301 */
+ 0x040c, 0x0000,
+ /* 0x0433 0x0301 */
+ 0x0453, 0x0000,
+ /* 0x043a 0x0301 */
+ 0x045c, 0x0000,
+ /* 0x1fbf 0x0301 */
+ 0x1fce, 0x0000,
+ /* 0x1ffe 0x0301 */
+ 0x1fde, 0x0000,
+ /* 0x0041 0x0302 */
+ 0x00c2, 0x0004, 0x0300, 0x0d6c, 0x0301, 0x0d6e, 0x0303, 0x0d70,
+ 0x0309, 0x0d72,
+ /* 0x0043 0x0302 */
+ 0x0108, 0x0000,
+ /* 0x0045 0x0302 */
+ 0x00ca, 0x0004, 0x0300, 0x0d74, 0x0301, 0x0d76, 0x0303, 0x0d78,
+ 0x0309, 0x0d7a,
+ /* 0x0047 0x0302 */
+ 0x011c, 0x0000,
+ /* 0x0048 0x0302 */
+ 0x0124, 0x0000,
+ /* 0x0049 0x0302 */
+ 0x00ce, 0x0000,
+ /* 0x004a 0x0302 */
+ 0x0134, 0x0000,
+ /* 0x004f 0x0302 */
+ 0x00d4, 0x0004, 0x0300, 0x0d7c, 0x0301, 0x0d7e, 0x0303, 0x0d80,
+ 0x0309, 0x0d82,
+ /* 0x0053 0x0302 */
+ 0x015c, 0x0000,
+ /* 0x0055 0x0302 */
+ 0x00db, 0x0000,
+ /* 0x0057 0x0302 */
+ 0x0174, 0x0000,
+ /* 0x0059 0x0302 */
+ 0x0176, 0x0000,
+ /* 0x005a 0x0302 */
+ 0x1e90, 0x0000,
+ /* 0x0061 0x0302 */
+ 0x00e2, 0x0004, 0x0300, 0x0d84, 0x0301, 0x0d86, 0x0303, 0x0d88,
+ 0x0309, 0x0d8a,
+ /* 0x0063 0x0302 */
+ 0x0109, 0x0000,
+ /* 0x0065 0x0302 */
+ 0x00ea, 0x0004, 0x0300, 0x0d8c, 0x0301, 0x0d8e, 0x0303, 0x0d90,
+ 0x0309, 0x0d92,
+ /* 0x0067 0x0302 */
+ 0x011d, 0x0000,
+ /* 0x0068 0x0302 */
+ 0x0125, 0x0000,
+ /* 0x0069 0x0302 */
+ 0x00ee, 0x0000,
+ /* 0x006a 0x0302 */
+ 0x0135, 0x0000,
+ /* 0x006f 0x0302 */
+ 0x00f4, 0x0004, 0x0300, 0x0d94, 0x0301, 0x0d96, 0x0303, 0x0d98,
+ 0x0309, 0x0d9a,
+ /* 0x0073 0x0302 */
+ 0x015d, 0x0000,
+ /* 0x0075 0x0302 */
+ 0x00fb, 0x0000,
+ /* 0x0077 0x0302 */
+ 0x0175, 0x0000,
+ /* 0x0079 0x0302 */
+ 0x0177, 0x0000,
+ /* 0x007a 0x0302 */
+ 0x1e91, 0x0000,
+ /* 0x0041 0x0303 */
+ 0x00c3, 0x0000,
+ /* 0x0045 0x0303 */
+ 0x1ebc, 0x0000,
+ /* 0x0049 0x0303 */
+ 0x0128, 0x0000,
+ /* 0x004e 0x0303 */
+ 0x00d1, 0x0000,
+ /* 0x004f 0x0303 */
+ 0x00d5, 0x0002, 0x0301, 0x0d9c, 0x0308, 0x0d9e,
+ /* 0x0055 0x0303 */
+ 0x0168, 0x0001, 0x0301, 0x0da0,
+ /* 0x0056 0x0303 */
+ 0x1e7c, 0x0000,
+ /* 0x0059 0x0303 */
+ 0x1ef8, 0x0000,
+ /* 0x0061 0x0303 */
+ 0x00e3, 0x0000,
+ /* 0x0065 0x0303 */
+ 0x1ebd, 0x0000,
+ /* 0x0069 0x0303 */
+ 0x0129, 0x0000,
+ /* 0x006e 0x0303 */
+ 0x00f1, 0x0000,
+ /* 0x006f 0x0303 */
+ 0x00f5, 0x0002, 0x0301, 0x0da2, 0x0308, 0x0da4,
+ /* 0x0075 0x0303 */
+ 0x0169, 0x0001, 0x0301, 0x0da6,
+ /* 0x0076 0x0303 */
+ 0x1e7d, 0x0000,
+ /* 0x0079 0x0303 */
+ 0x1ef9, 0x0000,
+ /* 0x0041 0x0304 */
+ 0x0100, 0x0000,
+ /* 0x0045 0x0304 */
+ 0x0112, 0x0002, 0x0300, 0x0da8, 0x0301, 0x0daa,
+ /* 0x0047 0x0304 */
+ 0x1e20, 0x0000,
+ /* 0x0049 0x0304 */
+ 0x012a, 0x0000,
+ /* 0x004f 0x0304 */
+ 0x014c, 0x0002, 0x0300, 0x0dac, 0x0301, 0x0dae,
+ /* 0x0055 0x0304 */
+ 0x016a, 0x0001, 0x0308, 0x0db0,
+ /* 0x0061 0x0304 */
+ 0x0101, 0x0000,
+ /* 0x0065 0x0304 */
+ 0x0113, 0x0002, 0x0300, 0x0db2, 0x0301, 0x0db4,
+ /* 0x0067 0x0304 */
+ 0x1e21, 0x0000,
+ /* 0x0069 0x0304 */
+ 0x012b, 0x0000,
+ /* 0x006f 0x0304 */
+ 0x014d, 0x0002, 0x0300, 0x0db6, 0x0301, 0x0db8,
+ /* 0x0075 0x0304 */
+ 0x016b, 0x0001, 0x0308, 0x0dba,
+ /* 0x00c6 0x0304 */
+ 0x01e2, 0x0000,
+ /* 0x00e6 0x0304 */
+ 0x01e3, 0x0000,
+ /* 0x0391 0x0304 */
+ 0x1fb9, 0x0000,
+ /* 0x0399 0x0304 */
+ 0x1fd9, 0x0000,
+ /* 0x03a5 0x0304 */
+ 0x1fe9, 0x0000,
+ /* 0x03b1 0x0304 */
+ 0x1fb1, 0x0000,
+ /* 0x03b9 0x0304 */
+ 0x1fd1, 0x0000,
+ /* 0x03c5 0x0304 */
+ 0x1fe1, 0x0000,
+ /* 0x0418 0x0304 */
+ 0x04e2, 0x0000,
+ /* 0x0423 0x0304 */
+ 0x04ee, 0x0000,
+ /* 0x0438 0x0304 */
+ 0x04e3, 0x0000,
+ /* 0x0443 0x0304 */
+ 0x04ef, 0x0000,
+ /* 0x0041 0x0306 */
+ 0x0102, 0x0004, 0x0300, 0x0dbc, 0x0301, 0x0dbe, 0x0303, 0x0dc0,
+ 0x0309, 0x0dc2,
+ /* 0x0045 0x0306 */
+ 0x0114, 0x0000,
+ /* 0x0047 0x0306 */
+ 0x011e, 0x0000,
+ /* 0x0049 0x0306 */
+ 0x012c, 0x0000,
+ /* 0x004f 0x0306 */
+ 0x014e, 0x0000,
+ /* 0x0055 0x0306 */
+ 0x016c, 0x0000,
+ /* 0x0061 0x0306 */
+ 0x0103, 0x0004, 0x0300, 0x0dc4, 0x0301, 0x0dc6, 0x0303, 0x0dc8,
+ 0x0309, 0x0dca,
+ /* 0x0065 0x0306 */
+ 0x0115, 0x0000,
+ /* 0x0067 0x0306 */
+ 0x011f, 0x0000,
+ /* 0x0069 0x0306 */
+ 0x012d, 0x0000,
+ /* 0x006f 0x0306 */
+ 0x014f, 0x0000,
+ /* 0x0075 0x0306 */
+ 0x016d, 0x0000,
+ /* 0x0391 0x0306 */
+ 0x1fb8, 0x0000,
+ /* 0x0399 0x0306 */
+ 0x1fd8, 0x0000,
+ /* 0x03a5 0x0306 */
+ 0x1fe8, 0x0000,
+ /* 0x03b1 0x0306 */
+ 0x1fb0, 0x0000,
+ /* 0x03b9 0x0306 */
+ 0x1fd0, 0x0000,
+ /* 0x03c5 0x0306 */
+ 0x1fe0, 0x0000,
+ /* 0x0410 0x0306 */
+ 0x04d0, 0x0000,
+ /* 0x0415 0x0306 */
+ 0x04d6, 0x0000,
+ /* 0x0416 0x0306 */
+ 0x04c1, 0x0000,
+ /* 0x0418 0x0306 */
+ 0x0419, 0x0000,
+ /* 0x0423 0x0306 */
+ 0x040e, 0x0000,
+ /* 0x0430 0x0306 */
+ 0x04d1, 0x0000,
+ /* 0x0435 0x0306 */
+ 0x04d7, 0x0000,
+ /* 0x0436 0x0306 */
+ 0x04c2, 0x0000,
+ /* 0x0438 0x0306 */
+ 0x0439, 0x0000,
+ /* 0x0443 0x0306 */
+ 0x045e, 0x0000,
+ /* 0x0041 0x0307 */
+ 0x0000, 0x0001, 0x0304, 0x0dcc,
+ /* 0x0042 0x0307 */
+ 0x1e02, 0x0000,
+ /* 0x0043 0x0307 */
+ 0x010a, 0x0000,
+ /* 0x0044 0x0307 */
+ 0x1e0a, 0x0000,
+ /* 0x0045 0x0307 */
+ 0x0116, 0x0000,
+ /* 0x0046 0x0307 */
+ 0x1e1e, 0x0000,
+ /* 0x0047 0x0307 */
+ 0x0120, 0x0000,
+ /* 0x0048 0x0307 */
+ 0x1e22, 0x0000,
+ /* 0x0049 0x0307 */
+ 0x0130, 0x0000,
+ /* 0x004d 0x0307 */
+ 0x1e40, 0x0000,
+ /* 0x004e 0x0307 */
+ 0x1e44, 0x0000,
+ /* 0x0050 0x0307 */
+ 0x1e56, 0x0000,
+ /* 0x0052 0x0307 */
+ 0x1e58, 0x0000,
+ /* 0x0053 0x0307 */
+ 0x1e60, 0x0000,
+ /* 0x0054 0x0307 */
+ 0x1e6a, 0x0000,
+ /* 0x0057 0x0307 */
+ 0x1e86, 0x0000,
+ /* 0x0058 0x0307 */
+ 0x1e8a, 0x0000,
+ /* 0x0059 0x0307 */
+ 0x1e8e, 0x0000,
+ /* 0x005a 0x0307 */
+ 0x017b, 0x0000,
+ /* 0x0061 0x0307 */
+ 0x0000, 0x0001, 0x0304, 0x0dce,
+ /* 0x0062 0x0307 */
+ 0x1e03, 0x0000,
+ /* 0x0063 0x0307 */
+ 0x010b, 0x0000,
+ /* 0x0064 0x0307 */
+ 0x1e0b, 0x0000,
+ /* 0x0065 0x0307 */
+ 0x0117, 0x0000,
+ /* 0x0066 0x0307 */
+ 0x1e1f, 0x0000,
+ /* 0x0067 0x0307 */
+ 0x0121, 0x0000,
+ /* 0x0068 0x0307 */
+ 0x1e23, 0x0000,
+ /* 0x006d 0x0307 */
+ 0x1e41, 0x0000,
+ /* 0x006e 0x0307 */
+ 0x1e45, 0x0000,
+ /* 0x0070 0x0307 */
+ 0x1e57, 0x0000,
+ /* 0x0072 0x0307 */
+ 0x1e59, 0x0000,
+ /* 0x0073 0x0307 */
+ 0x1e61, 0x0000,
+ /* 0x0074 0x0307 */
+ 0x1e6b, 0x0000,
+ /* 0x0077 0x0307 */
+ 0x1e87, 0x0000,
+ /* 0x0078 0x0307 */
+ 0x1e8b, 0x0000,
+ /* 0x0079 0x0307 */
+ 0x1e8f, 0x0000,
+ /* 0x007a 0x0307 */
+ 0x017c, 0x0000,
+ /* 0x017f 0x0307 */
+ 0x1e9b, 0x0000,
+ /* 0x0306 0x0307 */
+ 0x0310, 0x0000,
+ /* 0x0041 0x0308 */
+ 0x00c4, 0x0001, 0x0304, 0x0dd0,
+ /* 0x0045 0x0308 */
+ 0x00cb, 0x0000,
+ /* 0x0048 0x0308 */
+ 0x1e26, 0x0000,
+ /* 0x0049 0x0308 */
+ 0x00cf, 0x0001, 0x0301, 0x0dd2,
+ /* 0x004f 0x0308 */
+ 0x00d6, 0x0000,
+ /* 0x0055 0x0308 */
+ 0x00dc, 0x0004, 0x0300, 0x0dd4, 0x0301, 0x0dd6, 0x0304, 0x0dd8,
+ 0x030c, 0x0dda,
+ /* 0x0057 0x0308 */
+ 0x1e84, 0x0000,
+ /* 0x0058 0x0308 */
+ 0x1e8c, 0x0000,
+ /* 0x0059 0x0308 */
+ 0x0178, 0x0000,
+ /* 0x0061 0x0308 */
+ 0x00e4, 0x0001, 0x0304, 0x0ddc,
+ /* 0x0065 0x0308 */
+ 0x00eb, 0x0000,
+ /* 0x0068 0x0308 */
+ 0x1e27, 0x0000,
+ /* 0x0069 0x0308 */
+ 0x00ef, 0x0001, 0x0301, 0x0dde,
+ /* 0x006f 0x0308 */
+ 0x00f6, 0x0000,
+ /* 0x0074 0x0308 */
+ 0x1e97, 0x0000,
+ /* 0x0075 0x0308 */
+ 0x00fc, 0x0004, 0x0300, 0x0de0, 0x0301, 0x0de2, 0x0304, 0x0de4,
+ 0x030c, 0x0de6,
+ /* 0x0077 0x0308 */
+ 0x1e85, 0x0000,
+ /* 0x0078 0x0308 */
+ 0x1e8d, 0x0000,
+ /* 0x0079 0x0308 */
+ 0x00ff, 0x0000,
+ /* 0x018f 0x0308 */
+ 0x04da, 0x0000,
+ /* 0x019f 0x0308 */
+ 0x04ea, 0x0000,
+ /* 0x0259 0x0308 */
+ 0x04db, 0x0000,
+ /* 0x0275 0x0308 */
+ 0x04eb, 0x0000,
+ /* 0x0399 0x0308 */
+ 0x03aa, 0x0000,
+ /* 0x03a5 0x0308 */
+ 0x03ab, 0x0000,
+ /* 0x03b9 0x0308 */
+ 0x03ca, 0x0004, 0x0300, 0x0de8, 0x0301, 0x0dea, 0x030d, 0x0dec,
+ 0x0342, 0x0dee,
+ /* 0x03c5 0x0308 */
+ 0x03cb, 0x0004, 0x0300, 0x0df0, 0x0301, 0x0df2, 0x030d, 0x0df4,
+ 0x0342, 0x0df6,
+ /* 0x03d2 0x0308 */
+ 0x03d4, 0x0000,
+ /* 0x0406 0x0308 */
+ 0x0407, 0x0000,
+ /* 0x0410 0x0308 */
+ 0x04d2, 0x0000,
+ /* 0x0415 0x0308 */
+ 0x0401, 0x0000,
+ /* 0x0416 0x0308 */
+ 0x04dc, 0x0000,
+ /* 0x0417 0x0308 */
+ 0x04de, 0x0000,
+ /* 0x0418 0x0308 */
+ 0x04e4, 0x0000,
+ /* 0x041e 0x0308 */
+ 0x04e6, 0x0000,
+ /* 0x0423 0x0308 */
+ 0x04f0, 0x0000,
+ /* 0x0427 0x0308 */
+ 0x04f4, 0x0000,
+ /* 0x042b 0x0308 */
+ 0x04f8, 0x0000,
+ /* 0x0430 0x0308 */
+ 0x04d3, 0x0000,
+ /* 0x0435 0x0308 */
+ 0x0451, 0x0000,
+ /* 0x0436 0x0308 */
+ 0x04dd, 0x0000,
+ /* 0x0437 0x0308 */
+ 0x04df, 0x0000,
+ /* 0x0438 0x0308 */
+ 0x04e5, 0x0000,
+ /* 0x043e 0x0308 */
+ 0x04e7, 0x0000,
+ /* 0x0443 0x0308 */
+ 0x04f1, 0x0000,
+ /* 0x0447 0x0308 */
+ 0x04f5, 0x0000,
+ /* 0x044b 0x0308 */
+ 0x04f9, 0x0000,
+ /* 0x0456 0x0308 */
+ 0x0457, 0x0000,
+ /* 0x0041 0x0309 */
+ 0x1ea2, 0x0000,
+ /* 0x0045 0x0309 */
+ 0x1eba, 0x0000,
+ /* 0x0049 0x0309 */
+ 0x1ec8, 0x0000,
+ /* 0x004f 0x0309 */
+ 0x1ece, 0x0000,
+ /* 0x0055 0x0309 */
+ 0x1ee6, 0x0000,
+ /* 0x0059 0x0309 */
+ 0x1ef6, 0x0000,
+ /* 0x0061 0x0309 */
+ 0x1ea3, 0x0000,
+ /* 0x0065 0x0309 */
+ 0x1ebb, 0x0000,
+ /* 0x0069 0x0309 */
+ 0x1ec9, 0x0000,
+ /* 0x006f 0x0309 */
+ 0x1ecf, 0x0000,
+ /* 0x0075 0x0309 */
+ 0x1ee7, 0x0000,
+ /* 0x0079 0x0309 */
+ 0x1ef7, 0x0000,
+ /* 0x0041 0x030a */
+ 0x00c5, 0x0001, 0x0301, 0x0df8,
+ /* 0x0055 0x030a */
+ 0x016e, 0x0000,
+ /* 0x0061 0x030a */
+ 0x00e5, 0x0001, 0x0301, 0x0dfa,
+ /* 0x0075 0x030a */
+ 0x016f, 0x0000,
+ /* 0x0077 0x030a */
+ 0x1e98, 0x0000,
+ /* 0x0079 0x030a */
+ 0x1e99, 0x0000,
+ /* 0x004f 0x030b */
+ 0x0150, 0x0000,
+ /* 0x0055 0x030b */
+ 0x0170, 0x0000,
+ /* 0x006f 0x030b */
+ 0x0151, 0x0000,
+ /* 0x0075 0x030b */
+ 0x0171, 0x0000,
+ /* 0x0423 0x030b */
+ 0x04f2, 0x0000,
+ /* 0x0443 0x030b */
+ 0x04f3, 0x0000,
+ /* 0x0041 0x030c */
+ 0x01cd, 0x0000,
+ /* 0x0043 0x030c */
+ 0x010c, 0x0000,
+ /* 0x0044 0x030c */
+ 0x010e, 0x0000,
+ /* 0x0045 0x030c */
+ 0x011a, 0x0000,
+ /* 0x0047 0x030c */
+ 0x01e6, 0x0000,
+ /* 0x0049 0x030c */
+ 0x01cf, 0x0000,
+ /* 0x004b 0x030c */
+ 0x01e8, 0x0000,
+ /* 0x004c 0x030c */
+ 0x013d, 0x0000,
+ /* 0x004e 0x030c */
+ 0x0147, 0x0000,
+ /* 0x004f 0x030c */
+ 0x01d1, 0x0000,
+ /* 0x0052 0x030c */
+ 0x0158, 0x0000,
+ /* 0x0053 0x030c */
+ 0x0160, 0x0001, 0x0307, 0x0dfc,
+ /* 0x0054 0x030c */
+ 0x0164, 0x0000,
+ /* 0x0055 0x030c */
+ 0x01d3, 0x0000,
+ /* 0x005a 0x030c */
+ 0x017d, 0x0000,
+ /* 0x0061 0x030c */
+ 0x01ce, 0x0000,
+ /* 0x0063 0x030c */
+ 0x010d, 0x0000,
+ /* 0x0064 0x030c */
+ 0x010f, 0x0000,
+ /* 0x0065 0x030c */
+ 0x011b, 0x0000,
+ /* 0x0067 0x030c */
+ 0x01e7, 0x0000,
+ /* 0x0069 0x030c */
+ 0x01d0, 0x0000,
+ /* 0x006a 0x030c */
+ 0x01f0, 0x0000,
+ /* 0x006b 0x030c */
+ 0x01e9, 0x0000,
+ /* 0x006c 0x030c */
+ 0x013e, 0x0000,
+ /* 0x006e 0x030c */
+ 0x0148, 0x0000,
+ /* 0x006f 0x030c */
+ 0x01d2, 0x0000,
+ /* 0x0072 0x030c */
+ 0x0159, 0x0000,
+ /* 0x0073 0x030c */
+ 0x0161, 0x0001, 0x0307, 0x0dfe,
+ /* 0x0074 0x030c */
+ 0x0165, 0x0000,
+ /* 0x0075 0x030c */
+ 0x01d4, 0x0000,
+ /* 0x007a 0x030c */
+ 0x017e, 0x0000,
+ /* 0x01b7 0x030c */
+ 0x01ee, 0x0000,
+ /* 0x0292 0x030c */
+ 0x01ef, 0x0000,
+ /* 0x00a8 0x030d */
+ 0x0385, 0x0000,
+ /* 0x0308 0x030d */
+ 0x0344, 0x0000,
+ /* 0x0391 0x030d */
+ 0x0386, 0x0000,
+ /* 0x0395 0x030d */
+ 0x0388, 0x0000,
+ /* 0x0397 0x030d */
+ 0x0389, 0x0000,
+ /* 0x0399 0x030d */
+ 0x038a, 0x0000,
+ /* 0x039f 0x030d */
+ 0x038c, 0x0000,
+ /* 0x03a5 0x030d */
+ 0x038e, 0x0000,
+ /* 0x03a9 0x030d */
+ 0x038f, 0x0000,
+ /* 0x03b1 0x030d */
+ 0x03ac, 0x0000,
+ /* 0x03b5 0x030d */
+ 0x03ad, 0x0000,
+ /* 0x03b7 0x030d */
+ 0x03ae, 0x0000,
+ /* 0x03b9 0x030d */
+ 0x03af, 0x0000,
+ /* 0x03bf 0x030d */
+ 0x03cc, 0x0000,
+ /* 0x03c5 0x030d */
+ 0x03cd, 0x0000,
+ /* 0x03c9 0x030d */
+ 0x03ce, 0x0000,
+ /* 0x03d2 0x030d */
+ 0x03d3, 0x0000,
+ /* 0x0041 0x030f */
+ 0x0200, 0x0000,
+ /* 0x0045 0x030f */
+ 0x0204, 0x0000,
+ /* 0x0049 0x030f */
+ 0x0208, 0x0000,
+ /* 0x004f 0x030f */
+ 0x020c, 0x0000,
+ /* 0x0052 0x030f */
+ 0x0210, 0x0000,
+ /* 0x0055 0x030f */
+ 0x0214, 0x0000,
+ /* 0x0061 0x030f */
+ 0x0201, 0x0000,
+ /* 0x0065 0x030f */
+ 0x0205, 0x0000,
+ /* 0x0069 0x030f */
+ 0x0209, 0x0000,
+ /* 0x006f 0x030f */
+ 0x020d, 0x0000,
+ /* 0x0072 0x030f */
+ 0x0211, 0x0000,
+ /* 0x0075 0x030f */
+ 0x0215, 0x0000,
+ /* 0x0474 0x030f */
+ 0x0476, 0x0000,
+ /* 0x0475 0x030f */
+ 0x0477, 0x0000,
+ /* 0x0041 0x0311 */
+ 0x0202, 0x0000,
+ /* 0x0045 0x0311 */
+ 0x0206, 0x0000,
+ /* 0x0049 0x0311 */
+ 0x020a, 0x0000,
+ /* 0x004f 0x0311 */
+ 0x020e, 0x0000,
+ /* 0x0052 0x0311 */
+ 0x0212, 0x0000,
+ /* 0x0055 0x0311 */
+ 0x0216, 0x0000,
+ /* 0x0061 0x0311 */
+ 0x0203, 0x0000,
+ /* 0x0065 0x0311 */
+ 0x0207, 0x0000,
+ /* 0x0069 0x0311 */
+ 0x020b, 0x0000,
+ /* 0x006f 0x0311 */
+ 0x020f, 0x0000,
+ /* 0x0072 0x0311 */
+ 0x0213, 0x0000,
+ /* 0x0075 0x0311 */
+ 0x0217, 0x0000,
+ /* 0x0391 0x0313 */
+ 0x1f08, 0x0003, 0x0300, 0x0e00, 0x0301, 0x0e02, 0x0342, 0x0e04,
+ /* 0x0395 0x0313 */
+ 0x1f18, 0x0002, 0x0300, 0x0e06, 0x0301, 0x0e08,
+ /* 0x0397 0x0313 */
+ 0x1f28, 0x0003, 0x0300, 0x0e0a, 0x0301, 0x0e0c, 0x0342, 0x0e0e,
+ /* 0x0399 0x0313 */
+ 0x1f38, 0x0003, 0x0300, 0x0e10, 0x0301, 0x0e12, 0x0342, 0x0e14,
+ /* 0x039f 0x0313 */
+ 0x1f48, 0x0002, 0x0300, 0x0e16, 0x0301, 0x0e18,
+ /* 0x03a9 0x0313 */
+ 0x1f68, 0x0003, 0x0300, 0x0e1a, 0x0301, 0x0e1c, 0x0342, 0x0e1e,
+ /* 0x03b1 0x0313 */
+ 0x1f00, 0x0003, 0x0300, 0x0e20, 0x0301, 0x0e22, 0x0342, 0x0e24,
+ /* 0x03b5 0x0313 */
+ 0x1f10, 0x0002, 0x0300, 0x0e26, 0x0301, 0x0e28,
+ /* 0x03b7 0x0313 */
+ 0x1f20, 0x0003, 0x0300, 0x0e2a, 0x0301, 0x0e2c, 0x0342, 0x0e2e,
+ /* 0x03b9 0x0313 */
+ 0x1f30, 0x0003, 0x0300, 0x0e30, 0x0301, 0x0e32, 0x0342, 0x0e34,
+ /* 0x03bf 0x0313 */
+ 0x1f40, 0x0002, 0x0300, 0x0e36, 0x0301, 0x0e38,
+ /* 0x03c1 0x0313 */
+ 0x1fe4, 0x0000,
+ /* 0x03c5 0x0313 */
+ 0x1f50, 0x0003, 0x0300, 0x0e3a, 0x0301, 0x0e3c, 0x0342, 0x0e3e,
+ /* 0x03c9 0x0313 */
+ 0x1f60, 0x0003, 0x0300, 0x0e40, 0x0301, 0x0e42, 0x0342, 0x0e44,
+ /* 0x0391 0x0314 */
+ 0x1f09, 0x0003, 0x0300, 0x0e46, 0x0301, 0x0e48, 0x0342, 0x0e4a,
+ /* 0x0395 0x0314 */
+ 0x1f19, 0x0002, 0x0300, 0x0e4c, 0x0301, 0x0e4e,
+ /* 0x0397 0x0314 */
+ 0x1f29, 0x0003, 0x0300, 0x0e50, 0x0301, 0x0e52, 0x0342, 0x0e54,
+ /* 0x0399 0x0314 */
+ 0x1f39, 0x0003, 0x0300, 0x0e56, 0x0301, 0x0e58, 0x0342, 0x0e5a,
+ /* 0x039f 0x0314 */
+ 0x1f49, 0x0002, 0x0300, 0x0e5c, 0x0301, 0x0e5e,
+ /* 0x03a1 0x0314 */
+ 0x1fec, 0x0000,
+ /* 0x03a5 0x0314 */
+ 0x1f59, 0x0003, 0x0300, 0x0e60, 0x0301, 0x0e62, 0x0342, 0x0e64,
+ /* 0x03a9 0x0314 */
+ 0x1f69, 0x0003, 0x0300, 0x0e66, 0x0301, 0x0e68, 0x0342, 0x0e6a,
+ /* 0x03b1 0x0314 */
+ 0x1f01, 0x0003, 0x0300, 0x0e6c, 0x0301, 0x0e6e, 0x0342, 0x0e70,
+ /* 0x03b5 0x0314 */
+ 0x1f11, 0x0002, 0x0300, 0x0e72, 0x0301, 0x0e74,
+ /* 0x03b7 0x0314 */
+ 0x1f21, 0x0003, 0x0300, 0x0e76, 0x0301, 0x0e78, 0x0342, 0x0e7a,
+ /* 0x03b9 0x0314 */
+ 0x1f31, 0x0003, 0x0300, 0x0e7c, 0x0301, 0x0e7e, 0x0342, 0x0e80,
+ /* 0x03bf 0x0314 */
+ 0x1f41, 0x0002, 0x0300, 0x0e82, 0x0301, 0x0e84,
+ /* 0x03c1 0x0314 */
+ 0x1fe5, 0x0000,
+ /* 0x03c5 0x0314 */
+ 0x1f51, 0x0003, 0x0300, 0x0e86, 0x0301, 0x0e88, 0x0342, 0x0e8a,
+ /* 0x03c9 0x0314 */
+ 0x1f61, 0x0003, 0x0300, 0x0e8c, 0x0301, 0x0e8e, 0x0342, 0x0e90,
+ /* 0x004f 0x031b */
+ 0x01a0, 0x0005, 0x0300, 0x0e92, 0x0301, 0x0e94, 0x0303, 0x0e96,
+ 0x0309, 0x0e98, 0x0323, 0x0e9a,
+ /* 0x0055 0x031b */
+ 0x01af, 0x0005, 0x0300, 0x0e9c, 0x0301, 0x0e9e, 0x0303, 0x0ea0,
+ 0x0309, 0x0ea2, 0x0323, 0x0ea4,
+ /* 0x006f 0x031b */
+ 0x01a1, 0x0005, 0x0300, 0x0ea6, 0x0301, 0x0ea8, 0x0303, 0x0eaa,
+ 0x0309, 0x0eac, 0x0323, 0x0eae,
+ /* 0x0075 0x031b */
+ 0x01b0, 0x0005, 0x0300, 0x0eb0, 0x0301, 0x0eb2, 0x0303, 0x0eb4,
+ 0x0309, 0x0eb6, 0x0323, 0x0eb8,
+ /* 0x0041 0x0323 */
+ 0x1ea0, 0x0002, 0x0302, 0x0eba, 0x0306, 0x0ebc,
+ /* 0x0042 0x0323 */
+ 0x1e04, 0x0000,
+ /* 0x0044 0x0323 */
+ 0x1e0c, 0x0000,
+ /* 0x0045 0x0323 */
+ 0x1eb8, 0x0001, 0x0302, 0x0ebe,
+ /* 0x0048 0x0323 */
+ 0x1e24, 0x0000,
+ /* 0x0049 0x0323 */
+ 0x1eca, 0x0000,
+ /* 0x004b 0x0323 */
+ 0x1e32, 0x0000,
+ /* 0x004c 0x0323 */
+ 0x1e36, 0x0001, 0x0304, 0x0ec0,
+ /* 0x004d 0x0323 */
+ 0x1e42, 0x0000,
+ /* 0x004e 0x0323 */
+ 0x1e46, 0x0000,
+ /* 0x004f 0x0323 */
+ 0x1ecc, 0x0001, 0x0302, 0x0ec2,
+ /* 0x0052 0x0323 */
+ 0x1e5a, 0x0001, 0x0304, 0x0ec4,
+ /* 0x0053 0x0323 */
+ 0x1e62, 0x0001, 0x0307, 0x0ec6,
+ /* 0x0054 0x0323 */
+ 0x1e6c, 0x0000,
+ /* 0x0055 0x0323 */
+ 0x1ee4, 0x0000,
+ /* 0x0056 0x0323 */
+ 0x1e7e, 0x0000,
+ /* 0x0057 0x0323 */
+ 0x1e88, 0x0000,
+ /* 0x0059 0x0323 */
+ 0x1ef4, 0x0000,
+ /* 0x005a 0x0323 */
+ 0x1e92, 0x0000,
+ /* 0x0061 0x0323 */
+ 0x1ea1, 0x0002, 0x0302, 0x0ec8, 0x0306, 0x0eca,
+ /* 0x0062 0x0323 */
+ 0x1e05, 0x0000,
+ /* 0x0064 0x0323 */
+ 0x1e0d, 0x0000,
+ /* 0x0065 0x0323 */
+ 0x1eb9, 0x0001, 0x0302, 0x0ecc,
+ /* 0x0068 0x0323 */
+ 0x1e25, 0x0000,
+ /* 0x0069 0x0323 */
+ 0x1ecb, 0x0000,
+ /* 0x006b 0x0323 */
+ 0x1e33, 0x0000,
+ /* 0x006c 0x0323 */
+ 0x1e37, 0x0001, 0x0304, 0x0ece,
+ /* 0x006d 0x0323 */
+ 0x1e43, 0x0000,
+ /* 0x006e 0x0323 */
+ 0x1e47, 0x0000,
+ /* 0x006f 0x0323 */
+ 0x1ecd, 0x0001, 0x0302, 0x0ed0,
+ /* 0x0072 0x0323 */
+ 0x1e5b, 0x0001, 0x0304, 0x0ed2,
+ /* 0x0073 0x0323 */
+ 0x1e63, 0x0001, 0x0307, 0x0ed4,
+ /* 0x0074 0x0323 */
+ 0x1e6d, 0x0000,
+ /* 0x0075 0x0323 */
+ 0x1ee5, 0x0000,
+ /* 0x0076 0x0323 */
+ 0x1e7f, 0x0000,
+ /* 0x0077 0x0323 */
+ 0x1e89, 0x0000,
+ /* 0x0079 0x0323 */
+ 0x1ef5, 0x0000,
+ /* 0x007a 0x0323 */
+ 0x1e93, 0x0000,
+ /* 0x0055 0x0324 */
+ 0x1e72, 0x0000,
+ /* 0x0075 0x0324 */
+ 0x1e73, 0x0000,
+ /* 0x0041 0x0325 */
+ 0x1e00, 0x0000,
+ /* 0x0061 0x0325 */
+ 0x1e01, 0x0000,
+ /* 0x0043 0x0327 */
+ 0x00c7, 0x0001, 0x0301, 0x0ed6,
+ /* 0x0044 0x0327 */
+ 0x1e10, 0x0000,
+ /* 0x0045 0x0327 */
+ 0x0000, 0x0001, 0x0306, 0x0ed8,
+ /* 0x0047 0x0327 */
+ 0x0122, 0x0000,
+ /* 0x0048 0x0327 */
+ 0x1e28, 0x0000,
+ /* 0x004b 0x0327 */
+ 0x0136, 0x0000,
+ /* 0x004c 0x0327 */
+ 0x013b, 0x0000,
+ /* 0x004e 0x0327 */
+ 0x0145, 0x0000,
+ /* 0x0052 0x0327 */
+ 0x0156, 0x0000,
+ /* 0x0053 0x0327 */
+ 0x015e, 0x0000,
+ /* 0x0054 0x0327 */
+ 0x0162, 0x0000,
+ /* 0x0063 0x0327 */
+ 0x00e7, 0x0001, 0x0301, 0x0eda,
+ /* 0x0064 0x0327 */
+ 0x1e11, 0x0000,
+ /* 0x0065 0x0327 */
+ 0x0000, 0x0001, 0x0306, 0x0edc,
+ /* 0x0067 0x0327 */
+ 0x0123, 0x0000,
+ /* 0x0068 0x0327 */
+ 0x1e29, 0x0000,
+ /* 0x006b 0x0327 */
+ 0x0137, 0x0000,
+ /* 0x006c 0x0327 */
+ 0x013c, 0x0000,
+ /* 0x006e 0x0327 */
+ 0x0146, 0x0000,
+ /* 0x0072 0x0327 */
+ 0x0157, 0x0000,
+ /* 0x0073 0x0327 */
+ 0x015f, 0x0000,
+ /* 0x0074 0x0327 */
+ 0x0163, 0x0000,
+ /* 0x0041 0x0328 */
+ 0x0104, 0x0000,
+ /* 0x0045 0x0328 */
+ 0x0118, 0x0000,
+ /* 0x0049 0x0328 */
+ 0x012e, 0x0000,
+ /* 0x004f 0x0328 */
+ 0x01ea, 0x0001, 0x0304, 0x0ede,
+ /* 0x0055 0x0328 */
+ 0x0172, 0x0000,
+ /* 0x0061 0x0328 */
+ 0x0105, 0x0000,
+ /* 0x0065 0x0328 */
+ 0x0119, 0x0000,
+ /* 0x0069 0x0328 */
+ 0x012f, 0x0000,
+ /* 0x006f 0x0328 */
+ 0x01eb, 0x0001, 0x0304, 0x0ee0,
+ /* 0x0075 0x0328 */
+ 0x0173, 0x0000,
+ /* 0x0044 0x032d */
+ 0x1e12, 0x0000,
+ /* 0x0045 0x032d */
+ 0x1e18, 0x0000,
+ /* 0x004c 0x032d */
+ 0x1e3c, 0x0000,
+ /* 0x004e 0x032d */
+ 0x1e4a, 0x0000,
+ /* 0x0054 0x032d */
+ 0x1e70, 0x0000,
+ /* 0x0055 0x032d */
+ 0x1e76, 0x0000,
+ /* 0x0064 0x032d */
+ 0x1e13, 0x0000,
+ /* 0x0065 0x032d */
+ 0x1e19, 0x0000,
+ /* 0x006c 0x032d */
+ 0x1e3d, 0x0000,
+ /* 0x006e 0x032d */
+ 0x1e4b, 0x0000,
+ /* 0x0074 0x032d */
+ 0x1e71, 0x0000,
+ /* 0x0075 0x032d */
+ 0x1e77, 0x0000,
+ /* 0x0048 0x032e */
+ 0x1e2a, 0x0000,
+ /* 0x0068 0x032e */
+ 0x1e2b, 0x0000,
+ /* 0x0045 0x0330 */
+ 0x1e1a, 0x0000,
+ /* 0x0049 0x0330 */
+ 0x1e2c, 0x0000,
+ /* 0x0055 0x0330 */
+ 0x1e74, 0x0000,
+ /* 0x0065 0x0330 */
+ 0x1e1b, 0x0000,
+ /* 0x0069 0x0330 */
+ 0x1e2d, 0x0000,
+ /* 0x0075 0x0330 */
+ 0x1e75, 0x0000,
+ /* 0x0042 0x0331 */
+ 0x1e06, 0x0000,
+ /* 0x0044 0x0331 */
+ 0x1e0e, 0x0000,
+ /* 0x004b 0x0331 */
+ 0x1e34, 0x0000,
+ /* 0x004c 0x0331 */
+ 0x1e3a, 0x0000,
+ /* 0x004e 0x0331 */
+ 0x1e48, 0x0000,
+ /* 0x0052 0x0331 */
+ 0x1e5e, 0x0000,
+ /* 0x0054 0x0331 */
+ 0x1e6e, 0x0000,
+ /* 0x005a 0x0331 */
+ 0x1e94, 0x0000,
+ /* 0x0062 0x0331 */
+ 0x1e07, 0x0000,
+ /* 0x0064 0x0331 */
+ 0x1e0f, 0x0000,
+ /* 0x0068 0x0331 */
+ 0x1e96, 0x0000,
+ /* 0x006b 0x0331 */
+ 0x1e35, 0x0000,
+ /* 0x006c 0x0331 */
+ 0x1e3b, 0x0000,
+ /* 0x006e 0x0331 */
+ 0x1e49, 0x0000,
+ /* 0x0072 0x0331 */
+ 0x1e5f, 0x0000,
+ /* 0x0074 0x0331 */
+ 0x1e6f, 0x0000,
+ /* 0x007a 0x0331 */
+ 0x1e95, 0x0000,
+ /* 0x00a8 0x0342 */
+ 0x1fc1, 0x0000,
+ /* 0x03b1 0x0342 */
+ 0x1fb6, 0x0000,
+ /* 0x03b7 0x0342 */
+ 0x1fc6, 0x0000,
+ /* 0x03b9 0x0342 */
+ 0x1fd6, 0x0000,
+ /* 0x03c5 0x0342 */
+ 0x1fe6, 0x0000,
+ /* 0x03c9 0x0342 */
+ 0x1ff6, 0x0000,
+ /* 0x1fbf 0x0342 */
+ 0x1fcf, 0x0000,
+ /* 0x1ffe 0x0342 */
+ 0x1fdf, 0x0000,
+ /* 0x0391 0x0345 */
+ 0x1fbc, 0x0002, 0x0313, 0x0ee2, 0x0314, 0x0eea,
+ /* 0x0397 0x0345 */
+ 0x1fcc, 0x0002, 0x0313, 0x0ef2, 0x0314, 0x0efa,
+ /* 0x03a9 0x0345 */
+ 0x1ffc, 0x0002, 0x0313, 0x0f02, 0x0314, 0x0f0a,
+ /* 0x03b1 0x0345 */
+ 0x1fb3, 0x0005, 0x0300, 0x0f12, 0x0301, 0x0f14, 0x0313, 0x0f16,
+ 0x0314, 0x0f1e, 0x0342, 0x0f26,
+ /* 0x03b7 0x0345 */
+ 0x1fc3, 0x0005, 0x0300, 0x0f28, 0x0301, 0x0f2a, 0x0313, 0x0f2c,
+ 0x0314, 0x0f34, 0x0342, 0x0f3c,
+ /* 0x03bf 0x0345 */
+ 0x0000, 0x0001, 0x0301, 0x0f3e,
+ /* 0x03c9 0x0345 */
+ 0x1ff3, 0x0004, 0x0300, 0x0f40, 0x0313, 0x0f42, 0x0314, 0x0f4a,
+ 0x0342, 0x0f52,
+ /* 0x05d0 0x05b7 */
+ 0xfb2e, 0x0000,
+ /* 0x05f2 0x05b7 */
+ 0xfb1f, 0x0000,
+ /* 0x05d0 0x05b8 */
+ 0xfb2f, 0x0000,
+ /* 0x05d5 0x05b9 */
+ 0xfb4b, 0x0000,
+ /* 0x05d0 0x05bc */
+ 0xfb30, 0x0000,
+ /* 0x05d1 0x05bc */
+ 0xfb31, 0x0000,
+ /* 0x05d2 0x05bc */
+ 0xfb32, 0x0000,
+ /* 0x05d3 0x05bc */
+ 0xfb33, 0x0000,
+ /* 0x05d4 0x05bc */
+ 0xfb34, 0x0000,
+ /* 0x05d5 0x05bc */
+ 0xfb35, 0x0000,
+ /* 0x05d6 0x05bc */
+ 0xfb36, 0x0000,
+ /* 0x05d8 0x05bc */
+ 0xfb38, 0x0000,
+ /* 0x05d9 0x05bc */
+ 0xfb39, 0x0000,
+ /* 0x05da 0x05bc */
+ 0xfb3a, 0x0000,
+ /* 0x05db 0x05bc */
+ 0xfb3b, 0x0000,
+ /* 0x05dc 0x05bc */
+ 0xfb3c, 0x0000,
+ /* 0x05de 0x05bc */
+ 0xfb3e, 0x0000,
+ /* 0x05e0 0x05bc */
+ 0xfb40, 0x0000,
+ /* 0x05e1 0x05bc */
+ 0xfb41, 0x0000,
+ /* 0x05e3 0x05bc */
+ 0xfb43, 0x0000,
+ /* 0x05e4 0x05bc */
+ 0xfb44, 0x0000,
+ /* 0x05e6 0x05bc */
+ 0xfb46, 0x0000,
+ /* 0x05e7 0x05bc */
+ 0xfb47, 0x0000,
+ /* 0x05e8 0x05bc */
+ 0xfb48, 0x0000,
+ /* 0x05e9 0x05bc */
+ 0xfb49, 0x0002, 0x05c1, 0x0f54, 0x05c2, 0x0f56,
+ /* 0x05ea 0x05bc */
+ 0xfb4a, 0x0000,
+ /* 0x05d1 0x05bf */
+ 0xfb4c, 0x0000,
+ /* 0x05db 0x05bf */
+ 0xfb4d, 0x0000,
+ /* 0x05e4 0x05bf */
+ 0xfb4e, 0x0000,
+ /* 0x05e9 0x05c1 */
+ 0xfb2a, 0x0000,
+ /* 0x05e9 0x05c2 */
+ 0xfb2b, 0x0000,
+ /* 0x0915 0x093c */
+ 0x0958, 0x0000,
+ /* 0x0916 0x093c */
+ 0x0959, 0x0000,
+ /* 0x0917 0x093c */
+ 0x095a, 0x0000,
+ /* 0x091c 0x093c */
+ 0x095b, 0x0000,
+ /* 0x0921 0x093c */
+ 0x095c, 0x0000,
+ /* 0x0922 0x093c */
+ 0x095d, 0x0000,
+ /* 0x0928 0x093c */
+ 0x0929, 0x0000,
+ /* 0x092b 0x093c */
+ 0x095e, 0x0000,
+ /* 0x092f 0x093c */
+ 0x095f, 0x0000,
+ /* 0x0930 0x093c */
+ 0x0931, 0x0000,
+ /* 0x0933 0x093c */
+ 0x0934, 0x0000,
+ /* 0x09a1 0x09bc */
+ 0x09dc, 0x0000,
+ /* 0x09a2 0x09bc */
+ 0x09dd, 0x0000,
+ /* 0x09ac 0x09bc */
+ 0x09b0, 0x0000,
+ /* 0x09af 0x09bc */
+ 0x09df, 0x0000,
+ /* 0x09c7 0x09be */
+ 0x09cb, 0x0000,
+ /* 0x09c7 0x09d7 */
+ 0x09cc, 0x0000,
+ /* 0x0a16 0x0a3c */
+ 0x0a59, 0x0000,
+ /* 0x0a17 0x0a3c */
+ 0x0a5a, 0x0000,
+ /* 0x0a1c 0x0a3c */
+ 0x0a5b, 0x0000,
+ /* 0x0a21 0x0a3c */
+ 0x0a5c, 0x0000,
+ /* 0x0a2b 0x0a3c */
+ 0x0a5e, 0x0000,
+ /* 0x0b21 0x0b3c */
+ 0x0b5c, 0x0000,
+ /* 0x0b22 0x0b3c */
+ 0x0b5d, 0x0000,
+ /* 0x0b2f 0x0b3c */
+ 0x0b5f, 0x0000,
+ /* 0x0b47 0x0b3e */
+ 0x0b4b, 0x0000,
+ /* 0x0b47 0x0b56 */
+ 0x0b48, 0x0000,
+ /* 0x0b47 0x0b57 */
+ 0x0b4c, 0x0000,
+ /* 0x0bc6 0x0bbe */
+ 0x0bca, 0x0000,
+ /* 0x0bc7 0x0bbe */
+ 0x0bcb, 0x0000,
+ /* 0x0b92 0x0bd7 */
+ 0x0b94, 0x0000,
+ /* 0x0bc6 0x0bd7 */
+ 0x0bcc, 0x0000,
+ /* 0x0c46 0x0c56 */
+ 0x0c48, 0x0000,
+ /* 0x0cc6 0x0cc2 */
+ 0x0cca, 0x0001, 0x0cd5, 0x0f58,
+ /* 0x0cbf 0x0cd5 */
+ 0x0cc0, 0x0000,
+ /* 0x0cc6 0x0cd5 */
+ 0x0cc7, 0x0000,
+ /* 0x0cc6 0x0cd6 */
+ 0x0cc8, 0x0000,
+ /* 0x0d46 0x0d3e */
+ 0x0d4a, 0x0000,
+ /* 0x0d47 0x0d3e */
+ 0x0d4b, 0x0000,
+ /* 0x0d46 0x0d57 */
+ 0x0d4c, 0x0000,
+ /* 0x0e4d 0x0e32 */
+ 0x0e33, 0x0000,
+ /* 0x0ecd 0x0eb2 */
+ 0x0eb3, 0x0000,
+ /* 0x0f72 0x0f71 */
+ 0x0f73, 0x0000,
+ /* 0x0f74 0x0f71 */
+ 0x0f75, 0x0000,
+ /* 0x0f80 0x0f71 */
+ 0x0f81, 0x0000,
+ /* 0x0fb2 0x0f80 */
+ 0x0f76, 0x0001, 0x0f71, 0x0f5a,
+ /* 0x0fb3 0x0f80 */
+ 0x0f78, 0x0001, 0x0f71, 0x0f5c,
+ /* 0x0f40 0x0fb5 */
+ 0x0f69, 0x0000,
+ /* 0x0f90 0x0fb5 */
+ 0x0fb9, 0x0000,
+ /* 0x0f42 0x0fb7 */
+ 0x0f43, 0x0000,
+ /* 0x0f4c 0x0fb7 */
+ 0x0f4d, 0x0000,
+ /* 0x0f51 0x0fb7 */
+ 0x0f52, 0x0000,
+ /* 0x0f56 0x0fb7 */
+ 0x0f57, 0x0000,
+ /* 0x0f5b 0x0fb7 */
+ 0x0f5c, 0x0000,
+ /* 0x0f92 0x0fb7 */
+ 0x0f93, 0x0000,
+ /* 0x0f9c 0x0fb7 */
+ 0x0f9d, 0x0000,
+ /* 0x0fa1 0x0fb7 */
+ 0x0fa2, 0x0000,
+ /* 0x0fa6 0x0fb7 */
+ 0x0fa7, 0x0000,
+ /* 0x0fab 0x0fb7 */
+ 0x0fac, 0x0000,
+ /* 0x3046 0x3099 */
+ 0x3094, 0x0000,
+ /* 0x304b 0x3099 */
+ 0x304c, 0x0000,
+ /* 0x304d 0x3099 */
+ 0x304e, 0x0000,
+ /* 0x304f 0x3099 */
+ 0x3050, 0x0000,
+ /* 0x3051 0x3099 */
+ 0x3052, 0x0000,
+ /* 0x3053 0x3099 */
+ 0x3054, 0x0000,
+ /* 0x3055 0x3099 */
+ 0x3056, 0x0000,
+ /* 0x3057 0x3099 */
+ 0x3058, 0x0000,
+ /* 0x3059 0x3099 */
+ 0x305a, 0x0000,
+ /* 0x305b 0x3099 */
+ 0x305c, 0x0000,
+ /* 0x305d 0x3099 */
+ 0x305e, 0x0000,
+ /* 0x305f 0x3099 */
+ 0x3060, 0x0000,
+ /* 0x3061 0x3099 */
+ 0x3062, 0x0000,
+ /* 0x3064 0x3099 */
+ 0x3065, 0x0000,
+ /* 0x3066 0x3099 */
+ 0x3067, 0x0000,
+ /* 0x3068 0x3099 */
+ 0x3069, 0x0000,
+ /* 0x306f 0x3099 */
+ 0x3070, 0x0000,
+ /* 0x3072 0x3099 */
+ 0x3073, 0x0000,
+ /* 0x3075 0x3099 */
+ 0x3076, 0x0000,
+ /* 0x3078 0x3099 */
+ 0x3079, 0x0000,
+ /* 0x307b 0x3099 */
+ 0x307c, 0x0000,
+ /* 0x309d 0x3099 */
+ 0x309e, 0x0000,
+ /* 0x30a6 0x3099 */
+ 0x30f4, 0x0000,
+ /* 0x30ab 0x3099 */
+ 0x30ac, 0x0000,
+ /* 0x30ad 0x3099 */
+ 0x30ae, 0x0000,
+ /* 0x30af 0x3099 */
+ 0x30b0, 0x0000,
+ /* 0x30b1 0x3099 */
+ 0x30b2, 0x0000,
+ /* 0x30b3 0x3099 */
+ 0x30b4, 0x0000,
+ /* 0x30b5 0x3099 */
+ 0x30b6, 0x0000,
+ /* 0x30b7 0x3099 */
+ 0x30b8, 0x0000,
+ /* 0x30b9 0x3099 */
+ 0x30ba, 0x0000,
+ /* 0x30bb 0x3099 */
+ 0x30bc, 0x0000,
+ /* 0x30bd 0x3099 */
+ 0x30be, 0x0000,
+ /* 0x30bf 0x3099 */
+ 0x30c0, 0x0000,
+ /* 0x30c1 0x3099 */
+ 0x30c2, 0x0000,
+ /* 0x30c4 0x3099 */
+ 0x30c5, 0x0000,
+ /* 0x30c6 0x3099 */
+ 0x30c7, 0x0000,
+ /* 0x30c8 0x3099 */
+ 0x30c9, 0x0000,
+ /* 0x30cf 0x3099 */
+ 0x30d0, 0x0000,
+ /* 0x30d2 0x3099 */
+ 0x30d3, 0x0000,
+ /* 0x30d5 0x3099 */
+ 0x30d6, 0x0000,
+ /* 0x30d8 0x3099 */
+ 0x30d9, 0x0000,
+ /* 0x30db 0x3099 */
+ 0x30dc, 0x0000,
+ /* 0x30ef 0x3099 */
+ 0x30f7, 0x0000,
+ /* 0x30f0 0x3099 */
+ 0x30f8, 0x0000,
+ /* 0x30f1 0x3099 */
+ 0x30f9, 0x0000,
+ /* 0x30f2 0x3099 */
+ 0x30fa, 0x0000,
+ /* 0x30fd 0x3099 */
+ 0x30fe, 0x0000,
+ /* 0x306f 0x309a */
+ 0x3071, 0x0000,
+ /* 0x3072 0x309a */
+ 0x3074, 0x0000,
+ /* 0x3075 0x309a */
+ 0x3077, 0x0000,
+ /* 0x3078 0x309a */
+ 0x307a, 0x0000,
+ /* 0x307b 0x309a */
+ 0x307d, 0x0000,
+ /* 0x30cf 0x309a */
+ 0x30d1, 0x0000,
+ /* 0x30d2 0x309a */
+ 0x30d4, 0x0000,
+ /* 0x30d5 0x309a */
+ 0x30d7, 0x0000,
+ /* 0x30d8 0x309a */
+ 0x30da, 0x0000,
+ /* 0x30db 0x309a */
+ 0x30dd, 0x0000,
+ /* 0x0307 0x0053 0x0301 */
+ 0x1e64, 0x0000,
+ /* 0x0307 0x0073 0x0301 */
+ 0x1e65, 0x0000,
+ /* 0x0300 0x0041 0x0302 */
+ 0x1ea6, 0x0000,
+ /* 0x0301 0x0041 0x0302 */
+ 0x1ea4, 0x0000,
+ /* 0x0303 0x0041 0x0302 */
+ 0x1eaa, 0x0000,
+ /* 0x0309 0x0041 0x0302 */
+ 0x1ea8, 0x0000,
+ /* 0x0300 0x0045 0x0302 */
+ 0x1ec0, 0x0000,
+ /* 0x0301 0x0045 0x0302 */
+ 0x1ebe, 0x0000,
+ /* 0x0303 0x0045 0x0302 */
+ 0x1ec4, 0x0000,
+ /* 0x0309 0x0045 0x0302 */
+ 0x1ec2, 0x0000,
+ /* 0x0300 0x004f 0x0302 */
+ 0x1ed2, 0x0000,
+ /* 0x0301 0x004f 0x0302 */
+ 0x1ed0, 0x0000,
+ /* 0x0303 0x004f 0x0302 */
+ 0x1ed6, 0x0000,
+ /* 0x0309 0x004f 0x0302 */
+ 0x1ed4, 0x0000,
+ /* 0x0300 0x0061 0x0302 */
+ 0x1ea7, 0x0000,
+ /* 0x0301 0x0061 0x0302 */
+ 0x1ea5, 0x0000,
+ /* 0x0303 0x0061 0x0302 */
+ 0x1eab, 0x0000,
+ /* 0x0309 0x0061 0x0302 */
+ 0x1ea9, 0x0000,
+ /* 0x0300 0x0065 0x0302 */
+ 0x1ec1, 0x0000,
+ /* 0x0301 0x0065 0x0302 */
+ 0x1ebf, 0x0000,
+ /* 0x0303 0x0065 0x0302 */
+ 0x1ec5, 0x0000,
+ /* 0x0309 0x0065 0x0302 */
+ 0x1ec3, 0x0000,
+ /* 0x0300 0x006f 0x0302 */
+ 0x1ed3, 0x0000,
+ /* 0x0301 0x006f 0x0302 */
+ 0x1ed1, 0x0000,
+ /* 0x0303 0x006f 0x0302 */
+ 0x1ed7, 0x0000,
+ /* 0x0309 0x006f 0x0302 */
+ 0x1ed5, 0x0000,
+ /* 0x0301 0x004f 0x0303 */
+ 0x1e4c, 0x0000,
+ /* 0x0308 0x004f 0x0303 */
+ 0x1e4e, 0x0000,
+ /* 0x0301 0x0055 0x0303 */
+ 0x1e78, 0x0000,
+ /* 0x0301 0x006f 0x0303 */
+ 0x1e4d, 0x0000,
+ /* 0x0308 0x006f 0x0303 */
+ 0x1e4f, 0x0000,
+ /* 0x0301 0x0075 0x0303 */
+ 0x1e79, 0x0000,
+ /* 0x0300 0x0045 0x0304 */
+ 0x1e14, 0x0000,
+ /* 0x0301 0x0045 0x0304 */
+ 0x1e16, 0x0000,
+ /* 0x0300 0x004f 0x0304 */
+ 0x1e50, 0x0000,
+ /* 0x0301 0x004f 0x0304 */
+ 0x1e52, 0x0000,
+ /* 0x0308 0x0055 0x0304 */
+ 0x1e7a, 0x0000,
+ /* 0x0300 0x0065 0x0304 */
+ 0x1e15, 0x0000,
+ /* 0x0301 0x0065 0x0304 */
+ 0x1e17, 0x0000,
+ /* 0x0300 0x006f 0x0304 */
+ 0x1e51, 0x0000,
+ /* 0x0301 0x006f 0x0304 */
+ 0x1e53, 0x0000,
+ /* 0x0308 0x0075 0x0304 */
+ 0x1e7b, 0x0000,
+ /* 0x0300 0x0041 0x0306 */
+ 0x1eb0, 0x0000,
+ /* 0x0301 0x0041 0x0306 */
+ 0x1eae, 0x0000,
+ /* 0x0303 0x0041 0x0306 */
+ 0x1eb4, 0x0000,
+ /* 0x0309 0x0041 0x0306 */
+ 0x1eb2, 0x0000,
+ /* 0x0300 0x0061 0x0306 */
+ 0x1eb1, 0x0000,
+ /* 0x0301 0x0061 0x0306 */
+ 0x1eaf, 0x0000,
+ /* 0x0303 0x0061 0x0306 */
+ 0x1eb5, 0x0000,
+ /* 0x0309 0x0061 0x0306 */
+ 0x1eb3, 0x0000,
+ /* 0x0304 0x0041 0x0307 */
+ 0x01e0, 0x0000,
+ /* 0x0304 0x0061 0x0307 */
+ 0x01e1, 0x0000,
+ /* 0x0304 0x0041 0x0308 */
+ 0x01de, 0x0000,
+ /* 0x0301 0x0049 0x0308 */
+ 0x1e2e, 0x0000,
+ /* 0x0300 0x0055 0x0308 */
+ 0x01db, 0x0000,
+ /* 0x0301 0x0055 0x0308 */
+ 0x01d7, 0x0000,
+ /* 0x0304 0x0055 0x0308 */
+ 0x01d5, 0x0000,
+ /* 0x030c 0x0055 0x0308 */
+ 0x01d9, 0x0000,
+ /* 0x0304 0x0061 0x0308 */
+ 0x01df, 0x0000,
+ /* 0x0301 0x0069 0x0308 */
+ 0x1e2f, 0x0000,
+ /* 0x0300 0x0075 0x0308 */
+ 0x01dc, 0x0000,
+ /* 0x0301 0x0075 0x0308 */
+ 0x01d8, 0x0000,
+ /* 0x0304 0x0075 0x0308 */
+ 0x01d6, 0x0000,
+ /* 0x030c 0x0075 0x0308 */
+ 0x01da, 0x0000,
+ /* 0x0300 0x03b9 0x0308 */
+ 0x1fd2, 0x0000,
+ /* 0x0301 0x03b9 0x0308 */
+ 0x1fd3, 0x0000,
+ /* 0x030d 0x03b9 0x0308 */
+ 0x0390, 0x0000,
+ /* 0x0342 0x03b9 0x0308 */
+ 0x1fd7, 0x0000,
+ /* 0x0300 0x03c5 0x0308 */
+ 0x1fe2, 0x0000,
+ /* 0x0301 0x03c5 0x0308 */
+ 0x1fe3, 0x0000,
+ /* 0x030d 0x03c5 0x0308 */
+ 0x03b0, 0x0000,
+ /* 0x0342 0x03c5 0x0308 */
+ 0x1fe7, 0x0000,
+ /* 0x0301 0x0041 0x030a */
+ 0x01fa, 0x0000,
+ /* 0x0301 0x0061 0x030a */
+ 0x01fb, 0x0000,
+ /* 0x0307 0x0053 0x030c */
+ 0x1e66, 0x0000,
+ /* 0x0307 0x0073 0x030c */
+ 0x1e67, 0x0000,
+ /* 0x0300 0x0391 0x0313 */
+ 0x1f0a, 0x0000,
+ /* 0x0301 0x0391 0x0313 */
+ 0x1f0c, 0x0000,
+ /* 0x0342 0x0391 0x0313 */
+ 0x1f0e, 0x0000,
+ /* 0x0300 0x0395 0x0313 */
+ 0x1f1a, 0x0000,
+ /* 0x0301 0x0395 0x0313 */
+ 0x1f1c, 0x0000,
+ /* 0x0300 0x0397 0x0313 */
+ 0x1f2a, 0x0000,
+ /* 0x0301 0x0397 0x0313 */
+ 0x1f2c, 0x0000,
+ /* 0x0342 0x0397 0x0313 */
+ 0x1f2e, 0x0000,
+ /* 0x0300 0x0399 0x0313 */
+ 0x1f3a, 0x0000,
+ /* 0x0301 0x0399 0x0313 */
+ 0x1f3c, 0x0000,
+ /* 0x0342 0x0399 0x0313 */
+ 0x1f3e, 0x0000,
+ /* 0x0300 0x039f 0x0313 */
+ 0x1f4a, 0x0000,
+ /* 0x0301 0x039f 0x0313 */
+ 0x1f4c, 0x0000,
+ /* 0x0300 0x03a9 0x0313 */
+ 0x1f6a, 0x0000,
+ /* 0x0301 0x03a9 0x0313 */
+ 0x1f6c, 0x0000,
+ /* 0x0342 0x03a9 0x0313 */
+ 0x1f6e, 0x0000,
+ /* 0x0300 0x03b1 0x0313 */
+ 0x1f02, 0x0000,
+ /* 0x0301 0x03b1 0x0313 */
+ 0x1f04, 0x0000,
+ /* 0x0342 0x03b1 0x0313 */
+ 0x1f06, 0x0000,
+ /* 0x0300 0x03b5 0x0313 */
+ 0x1f12, 0x0000,
+ /* 0x0301 0x03b5 0x0313 */
+ 0x1f14, 0x0000,
+ /* 0x0300 0x03b7 0x0313 */
+ 0x1f22, 0x0000,
+ /* 0x0301 0x03b7 0x0313 */
+ 0x1f24, 0x0000,
+ /* 0x0342 0x03b7 0x0313 */
+ 0x1f26, 0x0000,
+ /* 0x0300 0x03b9 0x0313 */
+ 0x1f32, 0x0000,
+ /* 0x0301 0x03b9 0x0313 */
+ 0x1f34, 0x0000,
+ /* 0x0342 0x03b9 0x0313 */
+ 0x1f36, 0x0000,
+ /* 0x0300 0x03bf 0x0313 */
+ 0x1f42, 0x0000,
+ /* 0x0301 0x03bf 0x0313 */
+ 0x1f44, 0x0000,
+ /* 0x0300 0x03c5 0x0313 */
+ 0x1f52, 0x0000,
+ /* 0x0301 0x03c5 0x0313 */
+ 0x1f54, 0x0000,
+ /* 0x0342 0x03c5 0x0313 */
+ 0x1f56, 0x0000,
+ /* 0x0300 0x03c9 0x0313 */
+ 0x1f62, 0x0000,
+ /* 0x0301 0x03c9 0x0313 */
+ 0x1f64, 0x0000,
+ /* 0x0342 0x03c9 0x0313 */
+ 0x1f66, 0x0000,
+ /* 0x0300 0x0391 0x0314 */
+ 0x1f0b, 0x0000,
+ /* 0x0301 0x0391 0x0314 */
+ 0x1f0d, 0x0000,
+ /* 0x0342 0x0391 0x0314 */
+ 0x1f0f, 0x0000,
+ /* 0x0300 0x0395 0x0314 */
+ 0x1f1b, 0x0000,
+ /* 0x0301 0x0395 0x0314 */
+ 0x1f1d, 0x0000,
+ /* 0x0300 0x0397 0x0314 */
+ 0x1f2b, 0x0000,
+ /* 0x0301 0x0397 0x0314 */
+ 0x1f2d, 0x0000,
+ /* 0x0342 0x0397 0x0314 */
+ 0x1f2f, 0x0000,
+ /* 0x0300 0x0399 0x0314 */
+ 0x1f3b, 0x0000,
+ /* 0x0301 0x0399 0x0314 */
+ 0x1f3d, 0x0000,
+ /* 0x0342 0x0399 0x0314 */
+ 0x1f3f, 0x0000,
+ /* 0x0300 0x039f 0x0314 */
+ 0x1f4b, 0x0000,
+ /* 0x0301 0x039f 0x0314 */
+ 0x1f4d, 0x0000,
+ /* 0x0300 0x03a5 0x0314 */
+ 0x1f5b, 0x0000,
+ /* 0x0301 0x03a5 0x0314 */
+ 0x1f5d, 0x0000,
+ /* 0x0342 0x03a5 0x0314 */
+ 0x1f5f, 0x0000,
+ /* 0x0300 0x03a9 0x0314 */
+ 0x1f6b, 0x0000,
+ /* 0x0301 0x03a9 0x0314 */
+ 0x1f6d, 0x0000,
+ /* 0x0342 0x03a9 0x0314 */
+ 0x1f6f, 0x0000,
+ /* 0x0300 0x03b1 0x0314 */
+ 0x1f03, 0x0000,
+ /* 0x0301 0x03b1 0x0314 */
+ 0x1f05, 0x0000,
+ /* 0x0342 0x03b1 0x0314 */
+ 0x1f07, 0x0000,
+ /* 0x0300 0x03b5 0x0314 */
+ 0x1f13, 0x0000,
+ /* 0x0301 0x03b5 0x0314 */
+ 0x1f15, 0x0000,
+ /* 0x0300 0x03b7 0x0314 */
+ 0x1f23, 0x0000,
+ /* 0x0301 0x03b7 0x0314 */
+ 0x1f25, 0x0000,
+ /* 0x0342 0x03b7 0x0314 */
+ 0x1f27, 0x0000,
+ /* 0x0300 0x03b9 0x0314 */
+ 0x1f33, 0x0000,
+ /* 0x0301 0x03b9 0x0314 */
+ 0x1f35, 0x0000,
+ /* 0x0342 0x03b9 0x0314 */
+ 0x1f37, 0x0000,
+ /* 0x0300 0x03bf 0x0314 */
+ 0x1f43, 0x0000,
+ /* 0x0301 0x03bf 0x0314 */
+ 0x1f45, 0x0000,
+ /* 0x0300 0x03c5 0x0314 */
+ 0x1f53, 0x0000,
+ /* 0x0301 0x03c5 0x0314 */
+ 0x1f55, 0x0000,
+ /* 0x0342 0x03c5 0x0314 */
+ 0x1f57, 0x0000,
+ /* 0x0300 0x03c9 0x0314 */
+ 0x1f63, 0x0000,
+ /* 0x0301 0x03c9 0x0314 */
+ 0x1f65, 0x0000,
+ /* 0x0342 0x03c9 0x0314 */
+ 0x1f67, 0x0000,
+ /* 0x0300 0x004f 0x031b */
+ 0x1edc, 0x0000,
+ /* 0x0301 0x004f 0x031b */
+ 0x1eda, 0x0000,
+ /* 0x0303 0x004f 0x031b */
+ 0x1ee0, 0x0000,
+ /* 0x0309 0x004f 0x031b */
+ 0x1ede, 0x0000,
+ /* 0x0323 0x004f 0x031b */
+ 0x1ee2, 0x0000,
+ /* 0x0300 0x0055 0x031b */
+ 0x1eea, 0x0000,
+ /* 0x0301 0x0055 0x031b */
+ 0x1ee8, 0x0000,
+ /* 0x0303 0x0055 0x031b */
+ 0x1eee, 0x0000,
+ /* 0x0309 0x0055 0x031b */
+ 0x1eec, 0x0000,
+ /* 0x0323 0x0055 0x031b */
+ 0x1ef0, 0x0000,
+ /* 0x0300 0x006f 0x031b */
+ 0x1edd, 0x0000,
+ /* 0x0301 0x006f 0x031b */
+ 0x1edb, 0x0000,
+ /* 0x0303 0x006f 0x031b */
+ 0x1ee1, 0x0000,
+ /* 0x0309 0x006f 0x031b */
+ 0x1edf, 0x0000,
+ /* 0x0323 0x006f 0x031b */
+ 0x1ee3, 0x0000,
+ /* 0x0300 0x0075 0x031b */
+ 0x1eeb, 0x0000,
+ /* 0x0301 0x0075 0x031b */
+ 0x1ee9, 0x0000,
+ /* 0x0303 0x0075 0x031b */
+ 0x1eef, 0x0000,
+ /* 0x0309 0x0075 0x031b */
+ 0x1eed, 0x0000,
+ /* 0x0323 0x0075 0x031b */
+ 0x1ef1, 0x0000,
+ /* 0x0302 0x0041 0x0323 */
+ 0x1eac, 0x0000,
+ /* 0x0306 0x0041 0x0323 */
+ 0x1eb6, 0x0000,
+ /* 0x0302 0x0045 0x0323 */
+ 0x1ec6, 0x0000,
+ /* 0x0304 0x004c 0x0323 */
+ 0x1e38, 0x0000,
+ /* 0x0302 0x004f 0x0323 */
+ 0x1ed8, 0x0000,
+ /* 0x0304 0x0052 0x0323 */
+ 0x1e5c, 0x0000,
+ /* 0x0307 0x0053 0x0323 */
+ 0x1e68, 0x0000,
+ /* 0x0302 0x0061 0x0323 */
+ 0x1ead, 0x0000,
+ /* 0x0306 0x0061 0x0323 */
+ 0x1eb7, 0x0000,
+ /* 0x0302 0x0065 0x0323 */
+ 0x1ec7, 0x0000,
+ /* 0x0304 0x006c 0x0323 */
+ 0x1e39, 0x0000,
+ /* 0x0302 0x006f 0x0323 */
+ 0x1ed9, 0x0000,
+ /* 0x0304 0x0072 0x0323 */
+ 0x1e5d, 0x0000,
+ /* 0x0307 0x0073 0x0323 */
+ 0x1e69, 0x0000,
+ /* 0x0301 0x0043 0x0327 */
+ 0x1e08, 0x0000,
+ /* 0x0306 0x0045 0x0327 */
+ 0x1e1c, 0x0000,
+ /* 0x0301 0x0063 0x0327 */
+ 0x1e09, 0x0000,
+ /* 0x0306 0x0065 0x0327 */
+ 0x1e1d, 0x0000,
+ /* 0x0304 0x004f 0x0328 */
+ 0x01ec, 0x0000,
+ /* 0x0304 0x006f 0x0328 */
+ 0x01ed, 0x0000,
+ /* 0x0313 0x0391 0x0345 */
+ 0x1f88, 0x0003, 0x0300, 0x0f5e, 0x0301, 0x0f60, 0x0342, 0x0f62,
+ /* 0x0314 0x0391 0x0345 */
+ 0x1f89, 0x0003, 0x0300, 0x0f64, 0x0301, 0x0f66, 0x0342, 0x0f68,
+ /* 0x0313 0x0397 0x0345 */
+ 0x1f98, 0x0003, 0x0300, 0x0f6a, 0x0301, 0x0f6c, 0x0342, 0x0f6e,
+ /* 0x0314 0x0397 0x0345 */
+ 0x1f99, 0x0003, 0x0300, 0x0f70, 0x0301, 0x0f72, 0x0342, 0x0f74,
+ /* 0x0313 0x03a9 0x0345 */
+ 0x1fa8, 0x0003, 0x0300, 0x0f76, 0x0301, 0x0f78, 0x0342, 0x0f7a,
+ /* 0x0314 0x03a9 0x0345 */
+ 0x1fa9, 0x0003, 0x0300, 0x0f7c, 0x0301, 0x0f7e, 0x0342, 0x0f80,
+ /* 0x0300 0x03b1 0x0345 */
+ 0x1fb2, 0x0000,
+ /* 0x0301 0x03b1 0x0345 */
+ 0x1fb4, 0x0000,
+ /* 0x0313 0x03b1 0x0345 */
+ 0x1f80, 0x0003, 0x0300, 0x0f82, 0x0301, 0x0f84, 0x0342, 0x0f86,
+ /* 0x0314 0x03b1 0x0345 */
+ 0x1f81, 0x0003, 0x0300, 0x0f88, 0x0301, 0x0f8a, 0x0342, 0x0f8c,
+ /* 0x0342 0x03b1 0x0345 */
+ 0x1fb7, 0x0000,
+ /* 0x0300 0x03b7 0x0345 */
+ 0x1fc2, 0x0000,
+ /* 0x0301 0x03b7 0x0345 */
+ 0x1fc4, 0x0000,
+ /* 0x0313 0x03b7 0x0345 */
+ 0x1f90, 0x0003, 0x0300, 0x0f8e, 0x0301, 0x0f90, 0x0342, 0x0f92,
+ /* 0x0314 0x03b7 0x0345 */
+ 0x1f91, 0x0003, 0x0300, 0x0f94, 0x0301, 0x0f96, 0x0342, 0x0f98,
+ /* 0x0342 0x03b7 0x0345 */
+ 0x1fc7, 0x0000,
+ /* 0x0301 0x03bf 0x0345 */
+ 0x1ff4, 0x0000,
+ /* 0x0300 0x03c9 0x0345 */
+ 0x1ff2, 0x0000,
+ /* 0x0313 0x03c9 0x0345 */
+ 0x1fa0, 0x0003, 0x0300, 0x0f9a, 0x0301, 0x0f9c, 0x0342, 0x0f9e,
+ /* 0x0314 0x03c9 0x0345 */
+ 0x1fa1, 0x0003, 0x0300, 0x0fa0, 0x0301, 0x0fa2, 0x0342, 0x0fa4,
+ /* 0x0342 0x03c9 0x0345 */
+ 0x1ff7, 0x0000,
+ /* 0x05c1 0x05e9 0x05bc */
+ 0xfb2c, 0x0000,
+ /* 0x05c2 0x05e9 0x05bc */
+ 0xfb2d, 0x0000,
+ /* 0x0cd5 0x0cc6 0x0cc2 */
+ 0x0ccb, 0x0000,
+ /* 0x0f71 0x0fb2 0x0f80 */
+ 0x0f77, 0x0000,
+ /* 0x0f71 0x0fb3 0x0f80 */
+ 0x0f79, 0x0000,
+ /* 0x0300 0x0313 0x0391 0x0345 */
+ 0x1f8a, 0x0000,
+ /* 0x0301 0x0313 0x0391 0x0345 */
+ 0x1f8c, 0x0000,
+ /* 0x0342 0x0313 0x0391 0x0345 */
+ 0x1f8e, 0x0000,
+ /* 0x0300 0x0314 0x0391 0x0345 */
+ 0x1f8b, 0x0000,
+ /* 0x0301 0x0314 0x0391 0x0345 */
+ 0x1f8d, 0x0000,
+ /* 0x0342 0x0314 0x0391 0x0345 */
+ 0x1f8f, 0x0000,
+ /* 0x0300 0x0313 0x0397 0x0345 */
+ 0x1f9a, 0x0000,
+ /* 0x0301 0x0313 0x0397 0x0345 */
+ 0x1f9c, 0x0000,
+ /* 0x0342 0x0313 0x0397 0x0345 */
+ 0x1f9e, 0x0000,
+ /* 0x0300 0x0314 0x0397 0x0345 */
+ 0x1f9b, 0x0000,
+ /* 0x0301 0x0314 0x0397 0x0345 */
+ 0x1f9d, 0x0000,
+ /* 0x0342 0x0314 0x0397 0x0345 */
+ 0x1f9f, 0x0000,
+ /* 0x0300 0x0313 0x03a9 0x0345 */
+ 0x1faa, 0x0000,
+ /* 0x0301 0x0313 0x03a9 0x0345 */
+ 0x1fac, 0x0000,
+ /* 0x0342 0x0313 0x03a9 0x0345 */
+ 0x1fae, 0x0000,
+ /* 0x0300 0x0314 0x03a9 0x0345 */
+ 0x1fab, 0x0000,
+ /* 0x0301 0x0314 0x03a9 0x0345 */
+ 0x1fad, 0x0000,
+ /* 0x0342 0x0314 0x03a9 0x0345 */
+ 0x1faf, 0x0000,
+ /* 0x0300 0x0313 0x03b1 0x0345 */
+ 0x1f82, 0x0000,
+ /* 0x0301 0x0313 0x03b1 0x0345 */
+ 0x1f84, 0x0000,
+ /* 0x0342 0x0313 0x03b1 0x0345 */
+ 0x1f86, 0x0000,
+ /* 0x0300 0x0314 0x03b1 0x0345 */
+ 0x1f83, 0x0000,
+ /* 0x0301 0x0314 0x03b1 0x0345 */
+ 0x1f85, 0x0000,
+ /* 0x0342 0x0314 0x03b1 0x0345 */
+ 0x1f87, 0x0000,
+ /* 0x0300 0x0313 0x03b7 0x0345 */
+ 0x1f92, 0x0000,
+ /* 0x0301 0x0313 0x03b7 0x0345 */
+ 0x1f94, 0x0000,
+ /* 0x0342 0x0313 0x03b7 0x0345 */
+ 0x1f96, 0x0000,
+ /* 0x0300 0x0314 0x03b7 0x0345 */
+ 0x1f93, 0x0000,
+ /* 0x0301 0x0314 0x03b7 0x0345 */
+ 0x1f95, 0x0000,
+ /* 0x0342 0x0314 0x03b7 0x0345 */
+ 0x1f97, 0x0000,
+ /* 0x0300 0x0313 0x03c9 0x0345 */
+ 0x1fa2, 0x0000,
+ /* 0x0301 0x0313 0x03c9 0x0345 */
+ 0x1fa4, 0x0000,
+ /* 0x0342 0x0313 0x03c9 0x0345 */
+ 0x1fa6, 0x0000,
+ /* 0x0300 0x0314 0x03c9 0x0345 */
+ 0x1fa3, 0x0000,
+ /* 0x0301 0x0314 0x03c9 0x0345 */
+ 0x1fa5, 0x0000,
+ /* 0x0342 0x0314 0x03c9 0x0345 */
+ 0x1fa7, 0x0000,
+};
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c
index 4821cd239d595..060c69048c3dd 100644
--- a/fs/hfsplus/unicode.c
+++ b/fs/hfsplus/unicode.c
@@ -19,9 +19,9 @@ static inline u16 case_fold(u16 c)
{
u16 tmp;
- tmp = case_fold_table[(c>>8)];
+ tmp = hfsplus_case_fold_table[c >> 8];
if (tmp)
- tmp = case_fold_table[tmp + (c & 0xFF)];
+ tmp = hfsplus_case_fold_table[tmp + (c & 0xff)];
else
tmp = c;
return tmp;
@@ -59,69 +59,175 @@ int hfsplus_unistrcmp(const struct hfsplus_unistr *s1, const struct hfsplus_unis
}
}
-int hfsplus_uni2asc(const struct hfsplus_unistr *ustr, char *astr, int *len)
+#define Hangul_SBase 0xac00
+#define Hangul_LBase 0x1100
+#define Hangul_VBase 0x1161
+#define Hangul_TBase 0x11a7
+#define Hangul_SCount 11172
+#define Hangul_LCount 19
+#define Hangul_VCount 21
+#define Hangul_TCount 28
+#define Hangul_NCount (Hangul_VCount * Hangul_TCount)
+
+
+static u16 *hfsplus_compose_lookup(u16 *p, u16 cc)
+{
+ int i, s, e;
+
+ s = 1;
+ e = p[1];
+ if (!e || cc < p[s * 2] || cc > p[e * 2])
+ return NULL;
+ do {
+ i = (s + e) / 2;
+ if (cc > p[i * 2])
+ s = i + 1;
+ else if (cc < p[i * 2])
+ e = i - 1;
+ else
+ return hfsplus_compose_table + p[i * 2 + 1];
+ } while (s <= e);
+ return NULL;
+}
+
+int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, char *astr, int *len_p)
{
const hfsplus_unichr *ip;
+ struct nls_table *nls = HFSPLUS_SB(sb).nls;
u8 *op;
- u16 ustrlen, cc;
- int size, tmp;
+ u16 cc, c0, c1;
+ u16 *ce1, *ce2;
+ int i, len, ustrlen, res, compose;
op = astr;
ip = ustr->unicode;
ustrlen = be16_to_cpu(ustr->length);
- tmp = *len;
- while (ustrlen > 0 && tmp > 0) {
- cc = be16_to_cpu(*ip);
- switch (cc) {
+ len = *len_p;
+ ce1 = NULL;
+ compose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE);
+
+ while (ustrlen > 0) {
+ c0 = be16_to_cpu(*ip++);
+ ustrlen--;
+ /* search for single decomposed char */
+ if (likely(compose))
+ ce1 = hfsplus_compose_lookup(hfsplus_compose_table, c0);
+ if (ce1 && (cc = ce1[0])) {
+ /* start of a possibly decomposed Hangul char */
+ if (cc != 0xffff)
+ goto done;
+ if (!ustrlen)
+ goto same;
+ c1 = be16_to_cpu(*ip) - Hangul_VBase;
+ if (c1 < Hangul_VCount) {
+ /* compose the Hangul char */
+ cc = (c0 - Hangul_LBase) * Hangul_VCount;
+ cc = (cc + c1) * Hangul_TCount;
+ cc += Hangul_SBase;
+ ip++;
+ ustrlen--;
+ if (!ustrlen)
+ goto done;
+ c1 = be16_to_cpu(*ip) - Hangul_TBase;
+ if (c1 > 0 && c1 < Hangul_TCount) {
+ cc += c1;
+ ip++;
+ ustrlen--;
+ }
+ goto done;
+ }
+ }
+ while (1) {
+ /* main loop for common case of not composed chars */
+ if (!ustrlen)
+ goto same;
+ c1 = be16_to_cpu(*ip);
+ if (likely(compose))
+ ce1 = hfsplus_compose_lookup(hfsplus_compose_table, c1);
+ if (ce1)
+ break;
+ switch (c0) {
+ case 0:
+ c0 = 0x2400;
+ break;
+ case '/':
+ c0 = ':';
+ break;
+ }
+ res = nls->uni2char(c0, op, len);
+ if (res < 0) {
+ if (res == -ENAMETOOLONG)
+ goto out;
+ *op = '?';
+ res = 1;
+ }
+ op += res;
+ len -= res;
+ c0 = c1;
+ ip++;
+ ustrlen--;
+ }
+ ce2 = hfsplus_compose_lookup(ce1, c0);
+ if (ce2) {
+ i = 1;
+ while (i < ustrlen) {
+ ce1 = hfsplus_compose_lookup(ce2, be16_to_cpu(ip[i]));
+ if (!ce1)
+ break;
+ i++;
+ ce2 = ce1;
+ }
+ if ((cc = ce2[0])) {
+ ip += i;
+ ustrlen -= i;
+ goto done;
+ }
+ }
+ same:
+ switch (c0) {
case 0:
cc = 0x2400;
break;
case '/':
cc = ':';
break;
+ default:
+ cc = c0;
}
- if (cc > 0x7f) {
- size = utf8_wctomb(op, cc, tmp);
- if (size == -1) {
- /* ignore */
- } else {
- op += size;
- tmp -= size;
- }
- } else {
- *op++ = (u8) cc;
- tmp--;
+ done:
+ res = nls->uni2char(cc, op, len);
+ if (res < 0) {
+ if (res == -ENAMETOOLONG)
+ goto out;
+ *op = '?';
+ res = 1;
}
- ip++;
- ustrlen--;
+ op += res;
+ len -= res;
}
- *len = (char *)op - astr;
- if (ustrlen)
- return -ENAMETOOLONG;
- return 0;
+ res = 0;
+out:
+ *len_p = (char *)op - astr;
+ return res;
}
-int hfsplus_asc2uni(struct hfsplus_unistr *ustr, const char *astr, int len)
+int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, const char *astr, int len)
{
- int tmp;
+ struct nls_table *nls = HFSPLUS_SB(sb).nls;
+ int size, off, decompose;
wchar_t c;
u16 outlen = 0;
- while (outlen <= HFSPLUS_MAX_STRLEN && len > 0) {
- if (*astr & 0x80) {
- tmp = utf8_mbtowc(&c, astr, len);
- if (tmp < 0) {
- astr++;
- len--;
- continue;
- } else {
- astr += tmp;
- len -= tmp;
- }
- } else {
- c = *astr++;
- len--;
+ decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE);
+
+ while (outlen < HFSPLUS_MAX_STRLEN && len > 0) {
+ size = nls->char2uni(astr, len, &c);
+ if (size <= 0) {
+ c = '?';
+ size = 1;
}
+ astr += size;
+ len -= size;
switch (c) {
case 0x2400:
c = 0;
@@ -130,8 +236,33 @@ int hfsplus_asc2uni(struct hfsplus_unistr *ustr, const char *astr, int len)
c = '/';
break;
}
- ustr->unicode[outlen] = cpu_to_be16(c);
- outlen++;
+ if (c >= 0xc0 && decompose) {
+ off = hfsplus_decompose_table[(c >> 12) & 0xf];
+ if (!off)
+ goto done;
+ if (off == 0xffff) {
+ goto done;
+ }
+ off = hfsplus_decompose_table[off + ((c >> 8) & 0xf)];
+ if (!off)
+ goto done;
+ off = hfsplus_decompose_table[off + ((c >> 4) & 0xf)];
+ if (!off)
+ goto done;
+ off = hfsplus_decompose_table[off + (c & 0xf)];
+ size = off & 3;
+ if (!size)
+ goto done;
+ off /= 4;
+ if (outlen + size > HFSPLUS_MAX_STRLEN)
+ break;
+ do {
+ ustr->unicode[outlen++] = cpu_to_be16(hfsplus_decompose_table[off++]);
+ } while (--size > 0);
+ continue;
+ }
+ done:
+ ustr->unicode[outlen++] = cpu_to_be16(c);
}
ustr->length = cpu_to_be16(outlen);
if (len > 0)
diff --git a/fs/hostfs/Makefile b/fs/hostfs/Makefile
index 59f7fd70665aa..d5beaffad43b7 100644
--- a/fs/hostfs/Makefile
+++ b/fs/hostfs/Makefile
@@ -5,13 +5,7 @@
hostfs-objs := hostfs_kern.o hostfs_user.o
-obj-y =
+obj-y :=
obj-$(CONFIG_HOSTFS) += hostfs.o
-SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
-
-USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(SINGLE_OBJS))
-USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
-
-$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+include arch/um/scripts/Makefile.rules
diff --git a/fs/hpfs/hpfs.h b/fs/hpfs/hpfs.h
index da40420c781cb..0e84c73cd9c4e 100644
--- a/fs/hpfs/hpfs.h
+++ b/fs/hpfs/hpfs.h
@@ -27,6 +27,8 @@ typedef secno dnode_secno; /* sector number of a dnode */
typedef secno fnode_secno; /* sector number of an fnode */
typedef secno anode_secno; /* sector number of an anode */
+typedef u32 time32_t; /* 32-bit time_t type */
+
/* sector 0 */
/* The boot block is very like a FAT boot block, except that the
@@ -84,9 +86,9 @@ struct hpfs_super_block
unsigned zero1; /* 0 */
secno badblocks; /* bad block list */
unsigned zero3; /* 0 */
- time_t last_chkdsk; /* date last checked, 0 if never */
+ time32_t last_chkdsk; /* date last checked, 0 if never */
/*unsigned zero4;*/ /* 0 */
- time_t last_optimize; /* date last optimized, 0 if never */
+ time32_t last_optimize; /* date last optimized, 0 if never */
secno n_dir_band; /* number of sectors in dir band */
secno dir_band_start; /* first sector in dir band */
secno dir_band_end; /* last sector in dir band */
@@ -287,10 +289,10 @@ struct hpfs_dirent {
unsigned not_8x3: 1; /* name is not 8.3 */
unsigned flag15: 1;
fnode_secno fnode; /* fnode giving allocation info */
- time_t write_date; /* mtime */
+ time32_t write_date; /* mtime */
unsigned file_size; /* file length, bytes */
- time_t read_date; /* atime */
- time_t creation_date; /* ctime */
+ time32_t read_date; /* atime */
+ time32_t creation_date; /* ctime */
unsigned ea_size; /* total EA length, bytes */
unsigned char no_of_acls : 3; /* number of ACL's */
unsigned char reserver : 5;
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h
index 6094185d6ebfd..6628c3b352cb4 100644
--- a/fs/hpfs/hpfs_fn.h
+++ b/fs/hpfs/hpfs_fn.h
@@ -325,13 +325,13 @@ unsigned hpfs_count_one_bitmap(struct super_block *, secno);
* local time (HPFS) to GMT (Unix)
*/
-static inline time_t local_to_gmt(struct super_block *s, time_t t)
+static inline time_t local_to_gmt(struct super_block *s, time32_t t)
{
extern struct timezone sys_tz;
return t + sys_tz.tz_minuteswest * 60 + hpfs_sb(s)->sb_timeshift;
}
-static inline time_t gmt_to_local(struct super_block *s, time_t t)
+static inline time32_t gmt_to_local(struct super_block *s, time_t t)
{
extern struct timezone sys_tz;
return t - sys_tz.tz_minuteswest * 60 - hpfs_sb(s)->sb_timeshift;
diff --git a/fs/hppfs/Makefile b/fs/hppfs/Makefile
index a2d5c4d05e30d..6890433f7595c 100644
--- a/fs/hppfs/Makefile
+++ b/fs/hppfs/Makefile
@@ -7,13 +7,3 @@ hppfs-objs := hppfs_kern.o
obj-y =
obj-$(CONFIG_HPPFS) += hppfs.o
-
-clean:
-
-modules:
-
-fastdep:
-
-dep:
-
-archmrproper: clean
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c
index 054b52949df1d..dac720c837abf 100644
--- a/fs/jbd/commit.c
+++ b/fs/jbd/commit.c
@@ -341,7 +341,7 @@ write_out_data:
BUFFER_TRACE(bh, "locked");
if (!inverted_lock(journal, bh))
goto write_out_data;
- __journal_unfile_buffer(jh);
+ __journal_temp_unlink_buffer(jh);
__journal_file_buffer(jh, commit_transaction,
BJ_Locked);
jbd_unlock_bh_state(bh);
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index be8a974ea8cc2..1e6f2e2ad4a33 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -1803,6 +1803,7 @@ static void __journal_remove_journal_head(struct buffer_head *bh)
if (jh->b_transaction == NULL &&
jh->b_next_transaction == NULL &&
jh->b_cp_transaction == NULL) {
+ J_ASSERT_JH(jh, jh->b_jlist == BJ_None);
J_ASSERT_BH(bh, buffer_jbd(bh));
J_ASSERT_BH(bh, jh2bh(jh) == bh);
BUFFER_TRACE(bh, "remove journal_head");
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index 4217f2acfa974..932e7c1ef4a1c 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -1031,7 +1031,12 @@ int journal_dirty_data(handle_t *handle, struct buffer_head *bh)
/* journal_clean_data_list() may have got there first */
if (jh->b_transaction != NULL) {
JBUFFER_TRACE(jh, "unfile from commit");
- __journal_unfile_buffer(jh);
+ __journal_temp_unlink_buffer(jh);
+ /* It still points to the committing
+ * transaction; move it to this one so
+ * that the refile assert checks are
+ * happy. */
+ jh->b_transaction = handle->h_transaction;
}
/* The buffer will be refiled below */
@@ -1045,7 +1050,8 @@ int journal_dirty_data(handle_t *handle, struct buffer_head *bh)
if (jh->b_jlist != BJ_SyncData && jh->b_jlist != BJ_Locked) {
JBUFFER_TRACE(jh, "not on correct data list: unfile");
J_ASSERT_JH(jh, jh->b_jlist != BJ_Shadow);
- __journal_unfile_buffer(jh);
+ __journal_temp_unlink_buffer(jh);
+ jh->b_transaction = handle->h_transaction;
JBUFFER_TRACE(jh, "file as data");
__journal_file_buffer(jh, handle->h_transaction,
BJ_SyncData);
@@ -1225,7 +1231,6 @@ int journal_forget (handle_t *handle, struct buffer_head *bh)
JBUFFER_TRACE(jh, "belongs to current transaction: unfile");
- __journal_unfile_buffer(jh);
drop_reserve = 1;
/*
@@ -1241,8 +1246,10 @@ int journal_forget (handle_t *handle, struct buffer_head *bh)
*/
if (jh->b_cp_transaction) {
+ __journal_temp_unlink_buffer(jh);
__journal_file_buffer(jh, transaction, BJ_Forget);
} else {
+ __journal_unfile_buffer(jh);
journal_remove_journal_head(bh);
__brelse(bh);
if (!buffer_jbd(bh)) {
@@ -1468,7 +1475,7 @@ __blist_del_buffer(struct journal_head **list, struct journal_head *jh)
*
* Called under j_list_lock. The journal may not be locked.
*/
-void __journal_unfile_buffer(struct journal_head *jh)
+void __journal_temp_unlink_buffer(struct journal_head *jh)
{
struct journal_head **list = NULL;
transaction_t *transaction;
@@ -1485,7 +1492,7 @@ void __journal_unfile_buffer(struct journal_head *jh)
switch (jh->b_jlist) {
case BJ_None:
- goto out;
+ return;
case BJ_SyncData:
list = &transaction->t_sync_datalist;
break;
@@ -1518,7 +1525,11 @@ void __journal_unfile_buffer(struct journal_head *jh)
jh->b_jlist = BJ_None;
if (test_clear_buffer_jbddirty(bh))
mark_buffer_dirty(bh); /* Expose it to the VM */
-out:
+}
+
+void __journal_unfile_buffer(struct journal_head *jh)
+{
+ __journal_temp_unlink_buffer(jh);
jh->b_transaction = NULL;
}
@@ -1774,10 +1785,10 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
JBUFFER_TRACE(jh, "checkpointed: add to BJ_Forget");
ret = __dispose_buffer(jh,
journal->j_running_transaction);
+ journal_put_journal_head(jh);
spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh);
spin_unlock(&journal->j_state_lock);
- journal_put_journal_head(jh);
return ret;
} else {
/* There is no currently-running transaction. So the
@@ -1788,10 +1799,10 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
JBUFFER_TRACE(jh, "give to committing trans");
ret = __dispose_buffer(jh,
journal->j_committing_transaction);
+ journal_put_journal_head(jh);
spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh);
spin_unlock(&journal->j_state_lock);
- journal_put_journal_head(jh);
return ret;
} else {
/* The orphan record's transaction has
@@ -1812,10 +1823,10 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
journal->j_running_transaction);
jh->b_next_transaction = NULL;
}
+ journal_put_journal_head(jh);
spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh);
spin_unlock(&journal->j_state_lock);
- journal_put_journal_head(jh);
return 0;
} else {
/* Good, the buffer belongs to the running transaction.
@@ -1928,7 +1939,7 @@ void __journal_file_buffer(struct journal_head *jh,
}
if (jh->b_transaction)
- __journal_unfile_buffer(jh);
+ __journal_temp_unlink_buffer(jh);
jh->b_transaction = transaction;
switch (jlist) {
@@ -2011,7 +2022,7 @@ void __journal_refile_buffer(struct journal_head *jh)
*/
was_dirty = test_clear_buffer_jbddirty(bh);
- __journal_unfile_buffer(jh);
+ __journal_temp_unlink_buffer(jh);
jh->b_transaction = jh->b_next_transaction;
jh->b_next_transaction = NULL;
__journal_file_buffer(jh, jh->b_transaction, BJ_Metadata);
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 8494023e48ebe..a4407619b1f16 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -312,6 +312,7 @@ static int nlm_wait_on_grace(wait_queue_head_t *queue)
prepare_to_wait(queue, &wait, TASK_INTERRUPTIBLE);
if (!signalled ()) {
schedule_timeout(NLMCLNT_GRACE_WAIT);
+ try_to_freeze(PF_FREEZE);
if (!signalled ())
status = 0;
}
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index de3f50afa4247..49f959796b665 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -641,7 +641,6 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status
} else {
/* Lock is now held by client, or has been rejected.
* In both cases, the block should be removed. */
- file->f_count++;
up(&file->f_sema);
if (status == NLM_LCK_GRANTED)
nlmsvc_delete_block(block, 0);
diff --git a/fs/mbcache.c b/fs/mbcache.c
index 801cc23478326..f9e4d2700cd81 100644
--- a/fs/mbcache.c
+++ b/fs/mbcache.c
@@ -225,7 +225,7 @@ mb_cache_shrink_fn(int nr_to_scan, unsigned int gfp_mask)
e_lru_list), gfp_mask);
}
out:
- return count;
+ return (count / 100) * sysctl_vfs_cache_pressure;
}
diff --git a/fs/mpage.c b/fs/mpage.c
index 11d3e56da0e6b..e7d8d1a776061 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -627,6 +627,15 @@ int
mpage_writepages(struct address_space *mapping,
struct writeback_control *wbc, get_block_t get_block)
{
+ return __mpage_writepages(mapping, wbc, get_block,
+ mapping->a_ops->writepage);
+}
+
+int
+__mpage_writepages(struct address_space *mapping,
+ struct writeback_control *wbc, get_block_t get_block,
+ writepage_t writepage_fn)
+{
struct backing_dev_info *bdi = mapping->backing_dev_info;
struct bio *bio = NULL;
sector_t last_block_in_bio = 0;
@@ -716,7 +725,7 @@ retry:
} else {
bio = __mpage_writepage(bio, page, get_block,
&last_block_in_bio, &ret, wbc,
- page->mapping->a_ops->writepage);
+ writepage_fn);
}
if (ret || (--(wbc->nr_to_write) <= 0))
done = 1;
@@ -744,6 +753,7 @@ retry:
return ret;
}
EXPORT_SYMBOL(mpage_writepages);
+EXPORT_SYMBOL(__mpage_writepages);
int mpage_writepage(struct page *page, get_block_t get_block,
struct writeback_control *wbc)
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 11d58469063a9..154f511c72457 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -266,9 +266,11 @@ static int msdos_add_entry(struct inode *dir, const unsigned char *name,
de.attr |= ATTR_HIDDEN;
de.lcase = 0;
fat_date_unix2dos(ts->tv_sec, &time, &date);
- de.time = de.ctime = time;
- de.date = de.cdate = de.adate = date;
+ de.cdate = de.adate = 0;
+ de.ctime = 0;
de.ctime_cs = 0;
+ de.time = time;
+ de.date = date;
de.start = cpu_to_le16(cluster);
de.starthi = cpu_to_le16(cluster >> 16);
de.size = 0;
@@ -671,6 +673,7 @@ static int msdos_fill_super(struct super_block *sb, void *data, int silent)
if (res)
return res;
+ sb->s_flags |= MS_NOATIME;
sb->s_root->d_op = &msdos_dentry_operations;
return 0;
}
diff --git a/fs/pipe.c b/fs/pipe.c
index 13db326e68b0b..25aa09f9d09d0 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -224,6 +224,7 @@ pipe_writev(struct file *filp, const struct iovec *_iov,
int do_wakeup;
struct iovec *iov = (struct iovec *)_iov;
size_t total_len;
+ ssize_t chars;
total_len = iov_length(iov, nr_segs);
/* Null write succeeds. */
@@ -242,24 +243,26 @@ pipe_writev(struct file *filp, const struct iovec *_iov,
}
/* We try to merge small writes */
- if (info->nrbufs && total_len < PAGE_SIZE) {
+ chars = total_len & (PAGE_SIZE-1); /* size of the last buffer */
+ if (info->nrbufs && chars != 0) {
int lastbuf = (info->curbuf + info->nrbufs - 1) & (PIPE_BUFFERS-1);
struct pipe_buffer *buf = info->bufs + lastbuf;
struct pipe_buf_operations *ops = buf->ops;
int offset = buf->offset + buf->len;
- if (ops->can_merge && offset + total_len <= PAGE_SIZE) {
+ if (ops->can_merge && offset + chars <= PAGE_SIZE) {
void *addr = ops->map(filp, info, buf);
- int error = pipe_iov_copy_from_user(offset + addr, iov, total_len);
+ int error = pipe_iov_copy_from_user(offset + addr, iov, chars);
ops->unmap(info, buf);
ret = error;
do_wakeup = 1;
if (error)
goto out;
- buf->len += total_len;
- ret = total_len;
- goto out;
+ buf->len += chars;
+ total_len -= chars;
+ ret = chars;
+ if (!total_len)
+ goto out;
}
-
}
for (;;) {
@@ -271,7 +274,6 @@ pipe_writev(struct file *filp, const struct iovec *_iov,
}
bufs = info->nrbufs;
if (bufs < PIPE_BUFFERS) {
- ssize_t chars;
int newbuf = (info->curbuf + bufs) & (PIPE_BUFFERS-1);
struct pipe_buffer *buf = info->bufs + newbuf;
struct page *page = info->tmp_page;
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 254a8eb6df15f..37668fe998ad0 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -432,7 +432,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
jiffies_to_clock_t(it_real_value),
start_time,
vsize,
- mm ? mm->rss : 0, /* you might want to shift this left 3 */
+ mm ? get_mm_counter(mm, rss) : 0, /* you might want to shift this left 3 */
rsslim,
mm ? mm->start_code : 0,
mm ? mm->end_code : 0,
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 49de0bd2e6236..28b4a0253a921 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -24,7 +24,7 @@ char *task_mem(struct mm_struct *mm, char *buffer)
"VmPTE:\t%8lu kB\n",
(mm->total_vm - mm->reserved_vm) << (PAGE_SHIFT-10),
mm->locked_vm << (PAGE_SHIFT-10),
- mm->rss << (PAGE_SHIFT-10),
+ get_mm_counter(mm, rss) << (PAGE_SHIFT-10),
data << (PAGE_SHIFT-10),
mm->stack_vm << (PAGE_SHIFT-10), text, lib,
(PTRS_PER_PTE*sizeof(pte_t)*mm->nr_ptes) >> 10);
@@ -39,11 +39,13 @@ unsigned long task_vsize(struct mm_struct *mm)
int task_statm(struct mm_struct *mm, int *shared, int *text,
int *data, int *resident)
{
- *shared = mm->rss - mm->anon_rss;
+ int rss = get_mm_counter(mm, rss);
+
+ *shared = rss - get_mm_counter(mm, anon_rss);
*text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK))
>> PAGE_SHIFT;
*data = mm->total_vm - mm->shared_vm;
- *resident = mm->rss;
+ *resident = rss;
return mm->total_vm;
}
diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h
index 88854a9dd150f..0c7b57bc043a6 100644
--- a/include/asm-alpha/pci.h
+++ b/include/asm-alpha/pci.h
@@ -223,6 +223,12 @@ pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr,
/* Nothing to do. */
}
+/* TODO: integrate with include/asm-generic/pci.h ? */
+static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
+{
+ return channel ? 15 : 14;
+}
+
extern void pcibios_resource_to_bus(struct pci_dev *, struct pci_bus_region *,
struct resource *);
diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h
index d27970940f03c..faae196d83773 100644
--- a/include/asm-alpha/pgtable.h
+++ b/include/asm-alpha/pgtable.h
@@ -340,6 +340,13 @@ extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
remap_pfn_range(vma, start, pfn, size, prot); \
})
+#define io_remap_pfn_range(vma, start, pfn, size, prot) \
+ remap_pfn_range(vma, start, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn) (pfn)
+#define GET_IOSPACE(pfn) 0
+#define GET_PFN(pfn) (pfn)
+
#define pte_ERROR(e) \
printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
#define pmd_ERROR(e) \
diff --git a/include/asm-alpha/spinlock.h b/include/asm-alpha/spinlock.h
index 5e35c5d7aa7f5..80780dba9986f 100644
--- a/include/asm-alpha/spinlock.h
+++ b/include/asm-alpha/spinlock.h
@@ -15,7 +15,7 @@
*/
typedef struct {
- volatile unsigned int lock /*__attribute__((aligned(32))) */;
+ volatile unsigned int lock;
#ifdef CONFIG_DEBUG_SPINLOCK
int on_cpu;
int line_no;
@@ -23,40 +23,26 @@ typedef struct {
struct task_struct * task;
const char *base_file;
#endif
-#ifdef CONFIG_PREEMPT
- unsigned int break_lock;
-#endif
} spinlock_t;
#ifdef CONFIG_DEBUG_SPINLOCK
-#define SPIN_LOCK_UNLOCKED (spinlock_t) {0, -1, 0, NULL, NULL, NULL}
-#define spin_lock_init(x) \
- ((x)->lock = 0, (x)->on_cpu = -1, (x)->previous = NULL, (x)->task = NULL)
+#define SPIN_LOCK_UNLOCKED (spinlock_t){ 0, -1, 0, NULL, NULL, NULL }
#else
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
-#define spin_lock_init(x) ((x)->lock = 0)
+#define SPIN_LOCK_UNLOCKED (spinlock_t){ 0 }
#endif
+#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
#define spin_is_locked(x) ((x)->lock != 0)
-#define spin_unlock_wait(x) ({ do { barrier(); } while ((x)->lock); })
-#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock)
+#define spin_unlock_wait(x) do { barrier(); } while ((x)->lock)
#ifdef CONFIG_DEBUG_SPINLOCK
extern void _raw_spin_unlock(spinlock_t * lock);
extern void debug_spin_lock(spinlock_t * lock, const char *, int);
extern int debug_spin_trylock(spinlock_t * lock, const char *, int);
-
-#define _raw_spin_lock(LOCK) debug_spin_lock(LOCK, __BASE_FILE__, __LINE__)
-#define _raw_spin_trylock(LOCK) debug_spin_trylock(LOCK, __BASE_FILE__, __LINE__)
-
-#define spin_lock_own(LOCK, LOCATION) \
-do { \
- if (!((LOCK)->lock && (LOCK)->on_cpu == smp_processor_id())) \
- printk("%s: called on %d from %p but lock %s on %d\n", \
- LOCATION, smp_processor_id(), \
- __builtin_return_address(0), \
- (LOCK)->lock ? "taken" : "freed", (LOCK)->on_cpu); \
-} while (0)
+#define _raw_spin_lock(LOCK) \
+ debug_spin_lock(LOCK, __BASE_FILE__, __LINE__)
+#define _raw_spin_trylock(LOCK) \
+ debug_spin_trylock(LOCK, __BASE_FILE__, __LINE__)
#else
static inline void _raw_spin_unlock(spinlock_t * lock)
{
@@ -68,19 +54,16 @@ static inline void _raw_spin_lock(spinlock_t * lock)
{
long tmp;
- /* Use sub-sections to put the actual loop at the end
- of this object file's text section so as to perfect
- branch prediction. */
__asm__ __volatile__(
"1: ldl_l %0,%1\n"
- " blbs %0,2f\n"
- " or %0,1,%0\n"
+ " bne %0,2f\n"
+ " lda %0,1\n"
" stl_c %0,%1\n"
" beq %0,2f\n"
" mb\n"
".subsection 2\n"
"2: ldl %0,%1\n"
- " blbs %0,2b\n"
+ " bne %0,2b\n"
" br 1b\n"
".previous"
: "=&r" (tmp), "=m" (lock->lock)
@@ -91,22 +74,29 @@ static inline int _raw_spin_trylock(spinlock_t *lock)
{
return !test_and_set_bit(0, &lock->lock);
}
-
-#define spin_lock_own(LOCK, LOCATION) ((void)0)
#endif /* CONFIG_DEBUG_SPINLOCK */
+#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock)
+
/***********************************************************/
typedef struct {
- volatile unsigned int write_lock:1, read_counter:31;
-#ifdef CONFIG_PREEMPT
- unsigned int break_lock;
-#endif
-} /*__attribute__((aligned(32)))*/ rwlock_t;
+ volatile unsigned int lock;
+} rwlock_t;
-#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
+#define RW_LOCK_UNLOCKED (rwlock_t){ 0 }
-#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0)
+#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0)
+
+static inline int read_can_lock(rwlock_t *lock)
+{
+ return (lock->lock & 1) == 0;
+}
+
+static inline int write_can_lock(rwlock_t *lock)
+{
+ return lock->lock == 0;
+}
#ifdef CONFIG_DEBUG_RWLOCK
extern void _raw_write_lock(rwlock_t * lock);
@@ -119,7 +109,7 @@ static inline void _raw_write_lock(rwlock_t * lock)
__asm__ __volatile__(
"1: ldl_l %1,%0\n"
" bne %1,6f\n"
- " or $31,1,%1\n"
+ " lda %1,1\n"
" stl_c %1,%0\n"
" beq %1,6f\n"
" mb\n"
@@ -142,7 +132,7 @@ static inline void _raw_read_lock(rwlock_t * lock)
" subl %1,2,%1\n"
" stl_c %1,%0\n"
" beq %1,6f\n"
- "4: mb\n"
+ " mb\n"
".subsection 2\n"
"6: ldl %1,%0\n"
" blbs %1,6b\n"
@@ -153,6 +143,28 @@ static inline void _raw_read_lock(rwlock_t * lock)
}
#endif /* CONFIG_DEBUG_RWLOCK */
+static inline int _raw_read_trylock(rwlock_t * lock)
+{
+ long regx;
+ int success;
+
+ __asm__ __volatile__(
+ "1: ldl_l %1,%0\n"
+ " lda %2,0\n"
+ " blbs %1,2f\n"
+ " subl %1,2,%2\n"
+ " stl_c %2,%0\n"
+ " beq %2,6f\n"
+ "2: mb\n"
+ ".subsection 2\n"
+ "6: br 1b\n"
+ ".previous"
+ : "=m" (*lock), "=&r" (regx), "=&r" (success)
+ : "m" (*lock) : "memory");
+
+ return success;
+}
+
static inline int _raw_write_trylock(rwlock_t * lock)
{
long regx;
@@ -162,10 +174,9 @@ static inline int _raw_write_trylock(rwlock_t * lock)
"1: ldl_l %1,%0\n"
" lda %2,0\n"
" bne %1,2f\n"
- " or $31,1,%1\n"
- " stl_c %1,%0\n"
- " beq %1,6f\n"
" lda %2,1\n"
+ " stl_c %2,%0\n"
+ " beq %2,6f\n"
"2: mb\n"
".subsection 2\n"
"6: br 1b\n"
@@ -179,7 +190,7 @@ static inline int _raw_write_trylock(rwlock_t * lock)
static inline void _raw_write_unlock(rwlock_t * lock)
{
mb();
- *(volatile int *)lock = 0;
+ lock->lock = 0;
}
static inline void _raw_read_unlock(rwlock_t * lock)
diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h
index c2455a7a32875..91ffb1f4cd102 100644
--- a/include/asm-arm/pgtable.h
+++ b/include/asm-arm/pgtable.h
@@ -419,6 +419,13 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
#define io_remap_page_range(vma,from,phys,size,prot) \
remap_pfn_range(vma, from, (phys) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma,from,pfn,size,prot) \
+ remap_pfn_range(vma, from, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn) (pfn)
+#define GET_IOSPACE(pfn) 0
+#define GET_PFN(pfn) (pfn)
+
#define pgtable_cache_init() do { } while (0)
#endif /* !__ASSEMBLY__ */
diff --git a/include/asm-arm/tlb.h b/include/asm-arm/tlb.h
index 0843a876b3ceb..b00ab7b8856b8 100644
--- a/include/asm-arm/tlb.h
+++ b/include/asm-arm/tlb.h
@@ -54,11 +54,11 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
{
struct mm_struct *mm = tlb->mm;
unsigned long freed = tlb->freed;
- int rss = mm->rss;
+ int rss = get_mm_counter(mm, rss);
if (rss < freed)
freed = rss;
- mm->rss = rss - freed;
+ add_mm_counter(mm, rss, -freed);
if (freed) {
flush_tlb_mm(mm);
diff --git a/include/asm-arm26/pgtable.h b/include/asm-arm26/pgtable.h
index 95d16abeb189e..af0b8907dc143 100644
--- a/include/asm-arm26/pgtable.h
+++ b/include/asm-arm26/pgtable.h
@@ -293,6 +293,13 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
#define io_remap_page_range(vma,from,phys,size,prot) \
remap_pfn_range(vma, from, (phys) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma,from,pfn,size,prot) \
+ remap_pfn_range(vma, from, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn) (pfn)
+#define GET_IOSPACE(pfn) 0
+#define GET_PFN(pfn) (pfn)
+
#endif /* !__ASSEMBLY__ */
#endif /* _ASMARM_PGTABLE_H */
diff --git a/include/asm-arm26/tlb.h b/include/asm-arm26/tlb.h
index 7a3ac8815c1d8..1316352a58f3d 100644
--- a/include/asm-arm26/tlb.h
+++ b/include/asm-arm26/tlb.h
@@ -37,11 +37,11 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
{
struct mm_struct *mm = tlb->mm;
unsigned long freed = tlb->freed;
- int rss = mm->rss;
+ int rss = get_mm_counter(mm, rss);
if (rss < freed)
freed = rss;
- mm->rss = rss - freed;
+ add_mm_counter(mm, rss, -freed);
if (freed) {
flush_tlb_mm(mm);
diff --git a/include/asm-cris/pgalloc.h b/include/asm-cris/pgalloc.h
index 7f313d563c28b..b202e62ed6e0b 100644
--- a/include/asm-cris/pgalloc.h
+++ b/include/asm-cris/pgalloc.h
@@ -1,7 +1,6 @@
#ifndef _CRIS_PGALLOC_H
#define _CRIS_PGALLOC_H
-#include <asm/page.h>
#include <linux/threads.h>
#include <linux/mm.h>
diff --git a/include/asm-frv/pgtable.h b/include/asm-frv/pgtable.h
index 9d44b7e4a2101..cc1373c4b7906 100644
--- a/include/asm-frv/pgtable.h
+++ b/include/asm-frv/pgtable.h
@@ -503,6 +503,13 @@ static inline int pte_file(pte_t pte)
#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn) (pfn)
+#define GET_IOSPACE(pfn) 0
+#define GET_PFN(pfn) (pfn)
+
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
diff --git a/include/asm-generic/cputime.h b/include/asm-generic/cputime.h
index 7943c66945be4..6f178563e336c 100644
--- a/include/asm-generic/cputime.h
+++ b/include/asm-generic/cputime.h
@@ -10,6 +10,8 @@ typedef unsigned long cputime_t;
#define cputime_max ((~0UL >> 1) - 1)
#define cputime_add(__a, __b) ((__a) + (__b))
#define cputime_sub(__a, __b) ((__a) - (__b))
+#define cputime_div(__a, __n) ((__a) / (__n))
+#define cputime_halve(__a) ((__a) >> 1)
#define cputime_eq(__a, __b) ((__a) == (__b))
#define cputime_gt(__a, __b) ((__a) > (__b))
#define cputime_ge(__a, __b) ((__a) >= (__b))
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index 46db1558d99cf..a3b28710d56cc 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -135,6 +135,10 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addres
#define pgd_offset_gate(mm, addr) pgd_offset(mm, addr)
#endif
+#ifndef __HAVE_ARCH_LAZY_MMU_PROT_UPDATE
+#define lazy_mmu_prot_update(pte) do { } while (0)
+#endif
+
/*
* When walking page tables, get the address of the next boundary, or
* the end address of the range if that comes earlier. Although end might
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
index 0dac231d565bf..faff403e10615 100644
--- a/include/asm-generic/tlb.h
+++ b/include/asm-generic/tlb.h
@@ -88,11 +88,11 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
{
int freed = tlb->freed;
struct mm_struct *mm = tlb->mm;
- int rss = mm->rss;
+ int rss = get_mm_counter(mm, rss);
if (rss < freed)
freed = rss;
- mm->rss = rss - freed;
+ add_mm_counter(mm, rss, -freed);
tlb_flush_mmu(tlb, start, end);
/* keep the page table cache within bounds */
diff --git a/include/asm-h8300/pgtable.h b/include/asm-h8300/pgtable.h
index 1fd6e7191d00c..69076eb314760 100644
--- a/include/asm-h8300/pgtable.h
+++ b/include/asm-h8300/pgtable.h
@@ -55,6 +55,13 @@ extern int is_in_rom(unsigned long);
#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn) (pfn)
+#define GET_IOSPACE(pfn) 0
+#define GET_PFN(pfn) (pfn)
+
/*
* All 32bit addresses are effectively valid for vmalloc...
* Sort of meaningless for non-VM targets.
diff --git a/include/asm-i386/hardirq.h b/include/asm-i386/hardirq.h
index 95db6fd1735d3..ee754d3597341 100644
--- a/include/asm-i386/hardirq.h
+++ b/include/asm-i386/hardirq.h
@@ -12,8 +12,13 @@ typedef struct {
unsigned int apic_timer_irqs; /* arch dependent */
} ____cacheline_aligned irq_cpustat_t;
-#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+DECLARE_PER_CPU(irq_cpustat_t, irq_stat);
+extern irq_cpustat_t irq_stat[];
+
+#define __ARCH_IRQ_STAT
+#define __IRQ_STAT(cpu, member) (per_cpu(irq_stat, cpu).member)
void ack_bad_irq(unsigned int irq);
+#include <linux/irq_cpustat.h>
#endif /* __ASM_HARDIRQ_H */
diff --git a/include/asm-i386/msr.h b/include/asm-i386/msr.h
index 3589c36b865cc..c76fce8badbbb 100644
--- a/include/asm-i386/msr.h
+++ b/include/asm-i386/msr.h
@@ -32,6 +32,21 @@ static inline void wrmsrl (unsigned long msr, unsigned long long val)
wrmsr (msr, lo, hi);
}
+/* wrmsr with exception handling */
+#define wrmsr_safe(msr,a,b) ({ int ret__; \
+ asm volatile("2: wrmsr ; xorl %0,%0\n" \
+ "1:\n\t" \
+ ".section .fixup,\"ax\"\n\t" \
+ "3: movl %4,%0 ; jmp 1b\n\t" \
+ ".previous\n\t" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 4\n\t" \
+ " .long 2b,3b\n\t" \
+ ".previous" \
+ : "=a" (ret__) \
+ : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT));\
+ ret__; })
+
#define rdtsc(low,high) \
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
diff --git a/include/asm-i386/pgalloc.h b/include/asm-i386/pgalloc.h
index 3d6a5d11eb509..0380c3dc1f7e8 100644
--- a/include/asm-i386/pgalloc.h
+++ b/include/asm-i386/pgalloc.h
@@ -2,7 +2,6 @@
#define _I386_PGALLOC_H
#include <linux/config.h>
-#include <asm/processor.h>
#include <asm/fixmap.h>
#include <linux/threads.h>
#include <linux/mm.h> /* for struct page */
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
index da4f252b7b849..488c2b4befa57 100644
--- a/include/asm-i386/pgtable.h
+++ b/include/asm-i386/pgtable.h
@@ -405,6 +405,13 @@ extern void noexec_setup(const char *str);
#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn) (pfn)
+#define GET_IOSPACE(pfn) 0
+#define GET_PFN(pfn) (pfn)
+
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h
index 1d33357d3158c..886867aea9470 100644
--- a/include/asm-i386/uaccess.h
+++ b/include/asm-i386/uaccess.h
@@ -217,6 +217,8 @@ extern void __put_user_8(void);
*
* Returns zero on success, or -EFAULT on error.
*/
+#ifdef CONFIG_X86_WP_WORKS_OK
+
#define put_user(x,ptr) \
({ int __ret_pu; \
__chk_user_ptr(ptr); \
@@ -230,6 +232,21 @@ extern void __put_user_8(void);
__ret_pu; \
})
+#else
+#define put_user(x,ptr) \
+({ \
+ int __ret_pu; \
+ __typeof__(*(ptr)) __pus_tmp = x; \
+ __ret_pu=0; \
+ if(unlikely(__copy_to_user_ll(ptr, &__pus_tmp, \
+ sizeof(*(ptr))) != 0)) \
+ __ret_pu=-EFAULT; \
+ __ret_pu; \
+ })
+
+
+#endif
+
/**
* __get_user: - Get a simple variable from user space, with less checking.
* @x: Variable to store result.
diff --git a/include/asm-ia64/page.h b/include/asm-ia64/page.h
index 24770c011fd87..24aab801a8caa 100644
--- a/include/asm-ia64/page.h
+++ b/include/asm-ia64/page.h
@@ -137,7 +137,7 @@ typedef union ia64_va {
# define htlbpage_to_page(x) (((unsigned long) REGION_NUMBER(x) << 61) \
| (REGION_OFFSET(x) >> (HPAGE_SHIFT-PAGE_SHIFT)))
# define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
-# define is_hugepage_only_range(addr, len) \
+# define is_hugepage_only_range(mm, addr, len) \
(REGION_NUMBER(addr) == REGION_HPAGE && \
REGION_NUMBER((addr)+(len)) == REGION_HPAGE)
extern unsigned int hpage_shift;
diff --git a/include/asm-ia64/pgalloc.h b/include/asm-ia64/pgalloc.h
index fda0dba0b1871..0f05dc8bd4601 100644
--- a/include/asm-ia64/pgalloc.h
+++ b/include/asm-ia64/pgalloc.h
@@ -21,7 +21,6 @@
#include <linux/threads.h>
#include <asm/mmu_context.h>
-#include <asm/processor.h>
/*
* Very stupidly, we used to get new pgd's and pmd's, init their contents
diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h
index 385b5d4da9256..1757a811f4361 100644
--- a/include/asm-ia64/pgtable.h
+++ b/include/asm-ia64/pgtable.h
@@ -411,6 +411,8 @@ pte_same (pte_t a, pte_t b)
return pte_val(a) == pte_val(b);
}
+#define update_mmu_cache(vma, address, pte) do { } while (0)
+
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
extern void paging_init (void);
@@ -447,6 +449,13 @@ extern void paging_init (void);
#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn) (pfn)
+#define GET_IOSPACE(pfn) 0
+#define GET_PFN(pfn) (pfn)
+
/*
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
@@ -472,7 +481,7 @@ extern void hugetlb_free_pgtables(struct mmu_gather *tlb,
* information. However, we use this routine to take care of any (delayed) i-cache
* flushing that may be necessary.
*/
-extern void update_mmu_cache (struct vm_area_struct *vma, unsigned long vaddr, pte_t pte);
+extern void lazy_mmu_prot_update (pte_t pte);
#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
/*
@@ -550,6 +559,7 @@ do { \
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
#define __HAVE_ARCH_PTE_SAME
#define __HAVE_ARCH_PGD_OFFSET_GATE
+#define __HAVE_ARCH_LAZY_MMU_PROT_UPDATE
/*
* Override for pgd_addr_end() to deal with the virtual address space holes
diff --git a/include/asm-ia64/tlb.h b/include/asm-ia64/tlb.h
index aec6e832ddbc0..3a9a6d1be75cf 100644
--- a/include/asm-ia64/tlb.h
+++ b/include/asm-ia64/tlb.h
@@ -161,11 +161,11 @@ tlb_finish_mmu (struct mmu_gather *tlb, unsigned long start, unsigned long end)
{
unsigned long freed = tlb->freed;
struct mm_struct *mm = tlb->mm;
- unsigned long rss = mm->rss;
+ unsigned long rss = get_mm_counter(mm, rss);
if (rss < freed)
freed = rss;
- mm->rss = rss - freed;
+ add_mm_counter(mm, rss, -freed);
/*
* Note: tlb->nr may be 0 at this point, so we can't rely on tlb->start_addr and
* tlb->end_addr.
diff --git a/include/asm-m32r/mmu.h b/include/asm-m32r/mmu.h
index 930093ac48303..9c00eb78ee502 100644
--- a/include/asm-m32r/mmu.h
+++ b/include/asm-m32r/mmu.h
@@ -1,25 +1,12 @@
#ifndef _ASM_M32R_MMU_H
#define _ASM_M32R_MMU_H
-/* $Id$ */
-
#include <linux/config.h>
#if !defined(CONFIG_MMU)
-struct mm_rblock_struct {
- int size;
- int refcount;
- void *kblock;
-};
-
-struct mm_tblock_struct {
- struct mm_rblock_struct *rblock;
- struct mm_tblock_struct *next;
-};
-
typedef struct {
- struct mm_tblock_struct tblock;
- unsigned long end_brk;
+ struct vm_list_struct *vmlist;
+ unsigned long end_brk;
} mm_context_t;
#else
@@ -32,4 +19,3 @@ typedef unsigned long mm_context_t[NR_CPUS];
#endif /* CONFIG_MMU */
#endif /* _ASM_M32R_MMU_H */
-
diff --git a/include/asm-m32r/pgalloc.h b/include/asm-m32r/pgalloc.h
index da6dd7bd75294..6da309b6fda7f 100644
--- a/include/asm-m32r/pgalloc.h
+++ b/include/asm-m32r/pgalloc.h
@@ -7,7 +7,6 @@
#include <linux/mm.h>
#include <asm/io.h>
-#include <asm/pgtable.h>
#define pmd_populate_kernel(mm, pmd, pte) \
set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
diff --git a/include/asm-m32r/pgtable.h b/include/asm-m32r/pgtable.h
index 1710d91d4e567..70a0eb68fdf6c 100644
--- a/include/asm-m32r/pgtable.h
+++ b/include/asm-m32r/pgtable.h
@@ -381,6 +381,13 @@ static inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn) (pfn)
+#define GET_IOSPACE(pfn) 0
+#define GET_PFN(pfn) (pfn)
+
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
diff --git a/include/asm-m32r/serial.h b/include/asm-m32r/serial.h
index bf14299310806..d0e56b1bf4511 100644
--- a/include/asm-m32r/serial.h
+++ b/include/asm-m32r/serial.h
@@ -1,10 +1,6 @@
#ifndef _ASM_M32R_SERIAL_H
#define _ASM_M32R_SERIAL_H
-/* $Id$ */
-
-/* orig : i386 2.4.18 */
-
/*
* include/asm-m32r/serial.h
*/
@@ -21,131 +17,31 @@
*/
#define BASE_BAUD ( 1843200 / 16 )
-/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
-#else
+/* Standard COM flags */
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
-#endif
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#define HUB6_FLAGS 0
-#define RS_TABLE_SIZE 64
-#else
-#define RS_TABLE_SIZE
-#endif
-
-#define MCA_COM_FLAGS (STD_COM_FLAGS|ASYNC_BOOT_ONLYMCA)
-
-/*
- * The following define the access methods for the HUB6 card. All
- * access is through two ports for all 24 possible chips. The card is
- * selected through the high 2 bits, the port on that card with the
- * "middle" 3 bits, and the register on that port with the bottom
- * 3 bits.
- *
- * While the access port and interrupt is configurable, the default
- * port locations are 0x302 for the port control register, and 0x303
- * for the data read/write register. Normally, the interrupt is at irq3
- * but can be anything from 3 to 7 inclusive. Note that using 3 will
- * require disabling com2.
- */
-
-#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
-#define STD_SERIAL_PORT_DEFNS \
- /* UART CLK PORT IRQ FLAGS */ \
- { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
- { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \
- { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \
- { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */
+/* Standard PORT definitions */
+#if defined(CONFIG_PLAT_USRV)
+#define STD_SERIAL_PORT_DEFNS \
+ /* 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 */
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define EXTRA_SERIAL_PORT_DEFNS \
- { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, /* ttyS4 */ \
- { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS }, /* ttyS5 */ \
- { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS }, /* ttyS6 */ \
- { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS }, /* ttyS7 */ \
- { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS }, /* ttyS8 */ \
- { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS }, /* ttyS9 */ \
- { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS }, /* ttyS10 */ \
- { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS }, /* ttyS11 */ \
- { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS }, /* ttyS12 */ \
- { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS }, /* ttyS13 */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS14 (spare) */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS15 (spare) */ \
- { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS }, /* ttyS16 */ \
- { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS }, /* ttyS17 */ \
- { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS }, /* ttyS18 */ \
- { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS }, /* ttyS19 */ \
- { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS }, /* ttyS20 */ \
- { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS }, /* ttyS21 */ \
- { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS }, /* ttyS22 */ \
- { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS }, /* ttyS23 */ \
- { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS }, /* ttyS24 */ \
- { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS }, /* ttyS25 */ \
- { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS }, /* ttyS26 */ \
- { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS }, /* ttyS27 */ \
- { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS }, /* ttyS28 */ \
- { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS }, /* ttyS29 */ \
- { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS }, /* ttyS30 */ \
- { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS }, /* ttyS31 */
-#else
-#define EXTRA_SERIAL_PORT_DEFNS
-#endif
-
-/* You can have up to four HUB6's in the system, but I've only
- * included two cards here for a total of twelve ports.
- */
-#if (defined(CONFIG_HUB6) && defined(CONFIG_SERIAL_MANY_PORTS))
-#define HUB6_SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) }, /* ttyS32 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) }, /* ttyS33 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) }, /* ttyS34 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) }, /* ttyS35 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) }, /* ttyS36 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) }, /* ttyS37 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) }, /* ttyS38 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) }, /* ttyS39 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) }, /* ttyS40 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) }, /* ttyS41 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) }, /* ttyS42 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) }, /* ttyS43 */
-#else
-#define HUB6_SERIAL_PORT_DFNS
-#endif
+#else /* !CONFIG_PLAT_USRV */
-#ifdef CONFIG_MCA
-#define MCA_SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, 0x3220, 3, MCA_COM_FLAGS }, \
- { 0, BASE_BAUD, 0x3228, 3, MCA_COM_FLAGS }, \
- { 0, BASE_BAUD, 0x4220, 3, MCA_COM_FLAGS }, \
- { 0, BASE_BAUD, 0x4228, 3, MCA_COM_FLAGS }, \
- { 0, BASE_BAUD, 0x5220, 3, MCA_COM_FLAGS }, \
- { 0, BASE_BAUD, 0x5228, 3, MCA_COM_FLAGS },
+#if defined(CONFIG_SERIAL_M32R_PLDSIO)
+#define STD_SERIAL_PORT_DEFNS \
+ { 0, BASE_BAUD, ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV, \
+ STD_COM_FLAGS }, /* ttyS0 */
#else
-#define MCA_SERIAL_PORT_DFNS
+#define STD_SERIAL_PORT_DEFNS \
+ { 0, BASE_BAUD, M32R_SIO_OFFSET, M32R_IRQ_SIO0_R, \
+ STD_COM_FLAGS }, /* ttyS0 */
#endif
-#ifndef CONFIG_PLAT_USRV
-#define SERIAL_PORT_DFNS \
- STD_SERIAL_PORT_DEFNS \
- EXTRA_SERIAL_PORT_DEFNS \
- HUB6_SERIAL_PORT_DFNS \
- MCA_SERIAL_PORT_DFNS
-
-#else /* CONFIG_PLAT_USRV */
+#endif /* !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 */
-#endif /* CONFIG_PLAT_USRV */
+#define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS
#endif /* _ASM_M32R_SERIAL_H */
diff --git a/include/asm-m68k/pgtable.h b/include/asm-m68k/pgtable.h
index 186585d45d8c8..0eef32778df25 100644
--- a/include/asm-m68k/pgtable.h
+++ b/include/asm-m68k/pgtable.h
@@ -144,6 +144,13 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn) (pfn)
+#define GET_IOSPACE(pfn) 0
+#define GET_PFN(pfn) (pfn)
+
/* MMU-specific headers */
#ifdef CONFIG_SUN3
diff --git a/include/asm-m68knommu/pgtable.h b/include/asm-m68knommu/pgtable.h
index 48980c21b67b7..e2a69fffa3708 100644
--- a/include/asm-m68knommu/pgtable.h
+++ b/include/asm-m68knommu/pgtable.h
@@ -59,6 +59,13 @@ extern int is_in_rom(unsigned long);
#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn) (pfn)
+#define GET_IOSPACE(pfn) 0
+#define GET_PFN(pfn) (pfn)
+
/*
* All 32bit addresses are effectively valid for vmalloc...
* Sort of meaningless for non-VM targets.
diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h
index 61983c3fc9c32..878843203d67a 100644
--- a/include/asm-mips/pgtable.h
+++ b/include/asm-mips/pgtable.h
@@ -367,11 +367,27 @@ static inline int io_remap_page_range(struct vm_area_struct *vma,
phys_t phys_addr_high = fixup_bigphys_addr(paddr, size);
return remap_pfn_range(vma, vaddr, phys_addr_high >> PAGE_SHIFT, size, prot);
}
+
+static inline int io_remap_pfn_range(struct vm_area_struct *vma,
+ unsigned long vaddr,
+ unsigned long pfn,
+ unsigned long size,
+ pgprot_t prot)
+{
+ phys_t phys_addr_high = fixup_bigphys_addr(pfn << PAGE_SHIFT, size);
+ return remap_pfn_range(vma, vaddr, pfn, size, prot);
+}
#else
#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
- remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+ remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
#endif
+#define MK_IOSPACE_PFN(space, pfn) (pfn)
+#define GET_IOSPACE(pfn) 0
+#define GET_PFN(pfn) (pfn)
+
#include <asm-generic/pgtable.h>
/*
diff --git a/include/asm-parisc/pgalloc.h b/include/asm-parisc/pgalloc.h
index 22b6ae6c45e03..6291d6692e5db 100644
--- a/include/asm-parisc/pgalloc.h
+++ b/include/asm-parisc/pgalloc.h
@@ -7,7 +7,6 @@
#include <asm/processor.h>
#include <asm/fixmap.h>
-#include <asm/pgtable.h>
#include <asm/cache.h>
/* Allocate the top level pgd (page directory)
diff --git a/include/asm-parisc/pgtable.h b/include/asm-parisc/pgtable.h
index 149c17aea2fe2..af353a9bce211 100644
--- a/include/asm-parisc/pgtable.h
+++ b/include/asm-parisc/pgtable.h
@@ -501,6 +501,13 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn) (pfn)
+#define GET_IOSPACE(pfn) 0
+#define GET_PFN(pfn) (pfn)
+
/* We provide our own get_unmapped_area to provide cache coherency */
#define HAVE_ARCH_UNMAPPED_AREA
diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h
index a9b16c8849c93..b78d40870c951 100644
--- a/include/asm-ppc/machdep.h
+++ b/include/asm-ppc/machdep.h
@@ -6,6 +6,7 @@
#include <linux/init.h>
#include <asm/setup.h>
+#include <asm/page.h>
#ifdef CONFIG_APUS
#include <asm-m68k/machdep.h>
@@ -15,6 +16,7 @@ struct pt_regs;
struct pci_bus;
struct pci_dev;
struct seq_file;
+struct file;
/* We export this macro for external modules like Alsa to know if
* ppc_md.feature_call is implemented or not
@@ -93,6 +95,12 @@ struct machdep_calls {
/* Called at then very end of pcibios_init() */
void (*pcibios_after_init)(void);
+ /* Get access protection for /dev/mem */
+ pgprot_t (*phys_mem_access_prot)(struct file *file,
+ unsigned long offset,
+ unsigned long size,
+ pgprot_t vma_prot);
+
/* this is for modules, since _machine can be a define -- Cort */
int ppc_machine;
diff --git a/include/asm-ppc/mpc10x.h b/include/asm-ppc/mpc10x.h
index 624debe1cc540..d8e7e2d6128e7 100644
--- a/include/asm-ppc/mpc10x.h
+++ b/include/asm-ppc/mpc10x.h
@@ -115,8 +115,8 @@
#define MPC10X_CFG_MAPB_OPTIONS_CFAE 0x80 /* CPU_FD_ALIAS_EN */
#define MPC10X_CFG_MAPB_OPTIONS_PFAE 0x40 /* PCI_FD_ALIAS_EN */
#define MPC10X_CFG_MAPB_OPTIONS_DR 0x20 /* DLL_RESET */
-#define MPC10X_CFG_MAPB_OPTIONS_PCICH 0x80 /* PCI_COMPATIBILITY_HOLE */
-#define MPC10X_CFG_MAPB_OPTIONS_PROCCH 0x40 /* PROC_COMPATIBILITY_HOLE */
+#define MPC10X_CFG_MAPB_OPTIONS_PCICH 0x08 /* PCI_COMPATIBILITY_HOLE */
+#define MPC10X_CFG_MAPB_OPTIONS_PROCCH 0x04 /* PROC_COMPATIBILITY_HOLE */
/* Define offsets for the memory controller registers in the config space */
#define MPC10X_MCTLR_MEM_START_1 0x80 /* Banks 0-3 */
diff --git a/include/asm-ppc/mv64x60_defs.h b/include/asm-ppc/mv64x60_defs.h
index 16b184a72a838..2f428746c02ba 100644
--- a/include/asm-ppc/mv64x60_defs.h
+++ b/include/asm-ppc/mv64x60_defs.h
@@ -347,7 +347,7 @@
#define MV64360_SRAM_ERR_DATA_HI 0x03a0
#define MV64360_SRAM_ERR_PARITY 0x03a8
-#define MV64360_SRAM_SIZE 0x00200000 /* 2 MB of SRAM */
+#define MV64360_SRAM_SIZE 0x00040000 /* 2Mb/256KB SRAM */
/*
*****************************************************************************
diff --git a/include/asm-ppc/page.h b/include/asm-ppc/page.h
index 57838e8e00f19..4789dc024240a 100644
--- a/include/asm-ppc/page.h
+++ b/include/asm-ppc/page.h
@@ -137,6 +137,8 @@ static inline void* ___va(unsigned long p)
#define ___va(paddr) ((paddr)+PPC_MEMOFFSET)
#endif
+extern int page_is_ram(unsigned long pfn);
+
#define __pa(x) ___pa((unsigned long)(x))
#define __va(x) ((void *)(___va((unsigned long)(x))))
diff --git a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h
index 4312793a1d41e..ce5ae6d048f51 100644
--- a/include/asm-ppc/pci.h
+++ b/include/asm-ppc/pci.h
@@ -97,6 +97,12 @@ pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
extern void pcibios_add_platform_entries(struct pci_dev *dev);
+struct file;
+extern pgprot_t pci_phys_mem_access_prot(struct file *file,
+ unsigned long offset,
+ unsigned long size,
+ pgprot_t prot);
+
#endif /* __KERNEL__ */
#endif /* __PPC_PCI_H */
diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
index 0ee34debaf5ab..19dfb7abaa218 100644
--- a/include/asm-ppc/pgtable.h
+++ b/include/asm-ppc/pgtable.h
@@ -623,6 +623,11 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
*/
#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED))
+struct file;
+extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
+ unsigned long size, pgprot_t vma_prot);
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+
#define __HAVE_ARCH_PTE_SAME
#define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HASHPTE) == 0)
@@ -735,11 +740,27 @@ static inline int io_remap_page_range(struct vm_area_struct *vma,
phys_addr_t paddr64 = fixup_bigphys_addr(paddr, size);
return remap_pfn_range(vma, vaddr, paddr64 >> PAGE_SHIFT, size, prot);
}
+
+static inline int io_remap_pfn_range(struct vm_area_struct *vma,
+ unsigned long vaddr,
+ unsigned long pfn,
+ unsigned long size,
+ pgprot_t prot)
+{
+ phys_addr_t paddr64 = fixup_bigphys_addr(pfn << PAGE_SHIFT, size);
+ return remap_pfn_range(vma, vaddr, paddr64 >> PAGE_SHIFT, size, prot);
+}
#else
#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
#endif
+#define MK_IOSPACE_PFN(space, pfn) (pfn)
+#define GET_IOSPACE(pfn) 0
+#define GET_PFN(pfn) (pfn)
+
/*
* No page table caches to initialise
*/
diff --git a/include/asm-ppc64/hvcall.h b/include/asm-ppc64/hvcall.h
index 6ce5ef9c1692d..4f668a4baff01 100644
--- a/include/asm-ppc64/hvcall.h
+++ b/include/asm-ppc64/hvcall.h
@@ -1,6 +1,8 @@
#ifndef _PPC64_HVCALL_H
#define _PPC64_HVCALL_H
+#define HVSC .long 0x44000022
+
#define H_Success 0
#define H_Busy 1 /* Hardware busy -- retry later */
#define H_Constrained 4 /* Resource request constrained to max allowed */
@@ -41,7 +43,7 @@
/* Flags */
#define H_LARGE_PAGE (1UL<<(63-16))
-#define H_EXACT (1UL<<(63-24)) /* Use exact PTE or return H_PTEG_FULL */
+#define H_EXACT (1UL<<(63-24)) /* Use exact PTE or return H_PTEG_FULL */
#define H_R_XLATE (1UL<<(63-25)) /* include a valid logical page num in the pte if the valid bit is set */
#define H_READ_4 (1UL<<(63-26)) /* Return 4 PTEs */
#define H_AVPN (1UL<<(63-32)) /* An avpn is provided as a sanity test */
@@ -54,8 +56,6 @@
#define H_PP1 (1UL<<(63-62))
#define H_PP2 (1UL<<(63-63))
-
-
/* pSeries hypervisor opcodes */
#define H_REMOVE 0x04
#define H_ENTER 0x08
@@ -108,6 +108,8 @@
#define H_FREE_VTERM 0x158
#define H_POLL_PENDING 0x1D8
+#ifndef __ASSEMBLY__
+
/* plpar_hcall() -- Generic call interface using above opcodes
*
* The actual call interface is a hypervisor call instruction with
@@ -125,8 +127,6 @@ long plpar_hcall(unsigned long opcode,
unsigned long *out2,
unsigned long *out3);
-#define HVSC ".long 0x44000022\n"
-
/* Same as plpar_hcall but for those opcodes that return no values
* other than status. Slightly more efficient.
*/
@@ -147,9 +147,6 @@ long plpar_hcall_8arg_2ret(unsigned long opcode,
unsigned long arg7,
unsigned long arg8,
unsigned long *out1);
-
-
-
/* plpar_hcall_4out()
*
@@ -166,4 +163,5 @@ long plpar_hcall_4out(unsigned long opcode,
unsigned long *out3,
unsigned long *out4);
+#endif /* __ASSEMBLY__ */
#endif /* _PPC64_HVCALL_H */
diff --git a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h
index 808d24e8d4e93..5d3cd9d042e29 100644
--- a/include/asm-ppc64/machdep.h
+++ b/include/asm-ppc64/machdep.h
@@ -21,6 +21,7 @@ struct pci_bus;
struct device_node;
struct iommu_table;
struct rtc_time;
+struct file;
#ifdef CONFIG_SMP
struct smp_ops_t {
@@ -131,6 +132,12 @@ struct machdep_calls {
/* Get legacy PCI/IDE interrupt mapping */
int (*pci_get_legacy_ide_irq)(struct pci_dev *dev, int channel);
+ /* Get access protection for /dev/mem */
+ pgprot_t (*phys_mem_access_prot)(struct file *file,
+ unsigned long offset,
+ unsigned long size,
+ pgprot_t vma_prot);
+
};
extern struct machdep_calls ppc_md;
diff --git a/include/asm-ppc64/paca.h b/include/asm-ppc64/paca.h
index f893406eec132..1a0223b5f3b8e 100644
--- a/include/asm-ppc64/paca.h
+++ b/include/asm-ppc64/paca.h
@@ -22,7 +22,6 @@
#include <asm/iSeries/ItLpRegSave.h>
#include <asm/mmu.h>
-extern struct paca_struct paca[];
register struct paca_struct *local_paca asm("r13");
#define get_paca() local_paca
@@ -115,4 +114,6 @@ struct paca_struct {
#endif
};
+extern struct paca_struct paca[];
+
#endif /* _PPC64_PACA_H */
diff --git a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h
index 58879e05e8a25..20e0f19324e8a 100644
--- a/include/asm-ppc64/page.h
+++ b/include/asm-ppc64/page.h
@@ -48,8 +48,8 @@
#define ARCH_HAS_HUGEPAGE_ONLY_RANGE
#define ARCH_HAS_PREPARE_HUGEPAGE_RANGE
-#define touches_hugepage_low_range(addr, len) \
- (LOW_ESID_MASK((addr), (len)) & current->mm->context.htlb_segs)
+#define touches_hugepage_low_range(mm, addr, len) \
+ (LOW_ESID_MASK((addr), (len)) & mm->context.htlb_segs)
#define touches_hugepage_high_range(addr, len) \
(((addr) > (TASK_HPAGE_BASE-(len))) && ((addr) < TASK_HPAGE_END))
@@ -61,9 +61,9 @@
#define within_hugepage_high_range(addr, len) (((addr) >= TASK_HPAGE_BASE) \
&& ((addr)+(len) <= TASK_HPAGE_END) && ((addr)+(len) >= (addr)))
-#define is_hugepage_only_range(addr, len) \
+#define is_hugepage_only_range(mm, addr, len) \
(touches_hugepage_high_range((addr), (len)) || \
- touches_hugepage_low_range((addr), (len)))
+ touches_hugepage_low_range((mm), (addr), (len)))
#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
#define in_hugepage_area(context, addr) \
diff --git a/include/asm-ppc64/pci.h b/include/asm-ppc64/pci.h
index 2435c80057818..6cd593f660a03 100644
--- a/include/asm-ppc64/pci.h
+++ b/include/asm-ppc64/pci.h
@@ -130,6 +130,13 @@ extern int pci_read_irq_line(struct pci_dev *dev);
extern void pcibios_add_platform_entries(struct pci_dev *dev);
+struct file;
+extern pgprot_t pci_phys_mem_access_prot(struct file *file,
+ unsigned long offset,
+ unsigned long size,
+ pgprot_t prot);
+
+
#endif /* __KERNEL__ */
#endif /* __PPC64_PCI_H */
diff --git a/include/asm-ppc64/pgalloc.h b/include/asm-ppc64/pgalloc.h
index f9c0366287a32..16232d7401730 100644
--- a/include/asm-ppc64/pgalloc.h
+++ b/include/asm-ppc64/pgalloc.h
@@ -5,9 +5,6 @@
#include <linux/slab.h>
#include <linux/cpumask.h>
#include <linux/percpu.h>
-#include <asm/processor.h>
-#include <asm/tlb.h>
-#include <asm/page.h>
extern kmem_cache_t *zero_cache;
diff --git a/include/asm-ppc64/pgtable.h b/include/asm-ppc64/pgtable.h
index 8a1a6dda6d5ad..8a79ece01aa50 100644
--- a/include/asm-ppc64/pgtable.h
+++ b/include/asm-ppc64/pgtable.h
@@ -472,6 +472,11 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
*/
#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED))
+struct file;
+extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
+ unsigned long size, pgprot_t vma_prot);
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+
#define __HAVE_ARCH_PTE_SAME
#define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)
@@ -527,6 +532,13 @@ extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn) (pfn)
+#define GET_IOSPACE(pfn) 0
+#define GET_PFN(pfn) (pfn)
+
void pgtable_cache_init(void);
extern void hpte_init_native(void);
diff --git a/include/asm-s390/ccwdev.h b/include/asm-s390/ccwdev.h
index fd73b5e03ce6a..3eb231af5d514 100644
--- a/include/asm-s390/ccwdev.h
+++ b/include/asm-s390/ccwdev.h
@@ -164,6 +164,8 @@ extern int ccw_device_clear(struct ccw_device *, unsigned long);
extern int read_dev_chars(struct ccw_device *cdev, void **buffer, int length);
extern int read_conf_data(struct ccw_device *cdev, void **buffer, int *length);
+extern int read_conf_data_lpm(struct ccw_device *cdev, void **buffer,
+ int *length, __u8 lpm);
extern int ccw_device_set_online(struct ccw_device *cdev);
extern int ccw_device_set_offline(struct ccw_device *cdev);
@@ -186,4 +188,5 @@ extern int _ccw_device_get_subchannel_number(struct ccw_device *);
extern struct device *s390_root_dev_register(const char *);
extern void s390_root_dev_unregister(struct device *);
+extern void *ccw_device_get_chp_desc(struct ccw_device *, int);
#endif /* _S390_CCWDEV_H_ */
diff --git a/include/asm-s390/cputime.h b/include/asm-s390/cputime.h
index 216d861337e6a..4b3ef7cad1158 100644
--- a/include/asm-s390/cputime.h
+++ b/include/asm-s390/cputime.h
@@ -9,6 +9,8 @@
#ifndef _S390_CPUTIME_H
#define _S390_CPUTIME_H
+#include <asm/div64.h>
+
/* We want to use micro-second resolution. */
typedef unsigned long long cputime_t;
@@ -40,6 +42,12 @@ __div(unsigned long long n, unsigned int base)
#define cputime_max ((~0UL >> 1) - 1)
#define cputime_add(__a, __b) ((__a) + (__b))
#define cputime_sub(__a, __b) ((__a) - (__b))
+#define cputime_div(__a, __n) ({ \
+ unsigned long long __div = (__a); \
+ do_div(__div,__n); \
+ __div; \
+})
+#define cputime_halve(__a) ((__a) >> 1)
#define cputime_eq(__a, __b) ((__a) == (__b))
#define cputime_gt(__a, __b) ((__a) > (__b))
#define cputime_ge(__a, __b) ((__a) >= (__b))
diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h
index 91effd7c5c9f6..3417dd71ab432 100644
--- a/include/asm-s390/pgalloc.h
+++ b/include/asm-s390/pgalloc.h
@@ -14,7 +14,6 @@
#define _S390_PGALLOC_H
#include <linux/config.h>
-#include <asm/processor.h>
#include <linux/threads.h>
#include <linux/gfp.h>
#include <linux/mm.h>
diff --git a/include/asm-sh/pgalloc.h b/include/asm-sh/pgalloc.h
index 1a998085f9619..f4f233f7a4f57 100644
--- a/include/asm-sh/pgalloc.h
+++ b/include/asm-sh/pgalloc.h
@@ -1,7 +1,6 @@
#ifndef __ASM_SH_PGALLOC_H
#define __ASM_SH_PGALLOC_H
-#include <asm/processor.h>
#include <linux/threads.h>
#include <linux/slab.h>
#include <linux/mm.h>
diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h
index e3592103f4d10..8a9689d5366f6 100644
--- a/include/asm-sh/pgtable.h
+++ b/include/asm-sh/pgtable.h
@@ -279,6 +279,13 @@ typedef pte_t *pte_addr_t;
#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn) (pfn)
+#define GET_IOSPACE(pfn) 0
+#define GET_PFN(pfn) (pfn)
+
/*
* No page table caches to initialise
*/
diff --git a/include/asm-sh64/pgalloc.h b/include/asm-sh64/pgalloc.h
index b843ec2478b1e..b25f5df5535c0 100644
--- a/include/asm-sh64/pgalloc.h
+++ b/include/asm-sh64/pgalloc.h
@@ -14,7 +14,6 @@
*
*/
-#include <asm/processor.h>
#include <linux/threads.h>
#include <linux/mm.h>
diff --git a/include/asm-sh64/pgtable.h b/include/asm-sh64/pgtable.h
index 8157a2a727ccd..45f70c0f4a5e6 100644
--- a/include/asm-sh64/pgtable.h
+++ b/include/asm-sh64/pgtable.h
@@ -482,6 +482,14 @@ extern void update_mmu_cache(struct vm_area_struct * vma,
#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn) (pfn)
+#define GET_IOSPACE(pfn) 0
+#define GET_PFN(pfn) (pfn)
+
#endif /* !__ASSEMBLY__ */
/*
diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h
index f45b1801be987..3d2418c28ff58 100644
--- a/include/asm-sparc/pgtable.h
+++ b/include/asm-sparc/pgtable.h
@@ -454,8 +454,20 @@ extern unsigned long *sparc_valid_addr_bitmap;
#define kern_addr_valid(addr) \
(test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap))
-extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long to,
+extern int io_remap_page_range(struct vm_area_struct *vma,
+ unsigned long from, unsigned long to,
unsigned long size, pgprot_t prot, int space);
+extern int io_remap_pfn_range(struct vm_area_struct *vma,
+ unsigned long from, unsigned long pfn,
+ unsigned long size, pgprot_t prot);
+
+/*
+ * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in
+ * its high 4 bits. These macros/functions put it there or get it from there.
+ */
+#define MK_IOSPACE_PFN(space, pfn) (pfn | (space << (BITS_PER_LONG - 4)))
+#define GET_IOSPACE(pfn) (pfn >> (BITS_PER_LONG - 4))
+#define GET_PFN(pfn) (pfn & 0x0fffffffUL)
#include <asm-generic/pgtable.h>
diff --git a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h
index 7ba8df8c4921c..167d514bdf6ee 100644
--- a/include/asm-sparc64/pgalloc.h
+++ b/include/asm-sparc64/pgalloc.h
@@ -7,9 +7,7 @@
#include <linux/sched.h>
#include <linux/mm.h>
-#include <asm/page.h>
#include <asm/spitfire.h>
-#include <asm/pgtable.h>
#include <asm/cpudata.h>
/* Page table allocation/freeing. */
diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
index 886dd0c7c4546..dfb8a88863186 100644
--- a/include/asm-sparc64/pgtable.h
+++ b/include/asm-sparc64/pgtable.h
@@ -16,6 +16,7 @@
#include <linux/config.h>
#include <linux/compiler.h>
+#include <asm/types.h>
#include <asm/spitfire.h>
#include <asm/asi.h>
#include <asm/system.h>
@@ -431,6 +432,17 @@ extern unsigned long *sparc64_valid_addr_bitmap;
extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from,
unsigned long offset,
unsigned long size, pgprot_t prot, int space);
+extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
+ unsigned long pfn,
+ unsigned long size, pgprot_t prot);
+
+/*
+ * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in
+ * its high 4 bits. These macros/functions put it there or get it from there.
+ */
+#define MK_IOSPACE_PFN(space, pfn) (pfn | (space << (BITS_PER_LONG - 4)))
+#define GET_IOSPACE(pfn) (pfn >> (BITS_PER_LONG - 4))
+#define GET_PFN(pfn) (pfn & 0x0fffffffffffffffUL)
/* Override for {pgd,pmd}_addr_end() to deal with the virtual address
* space hole. We simply sign extend bit 43.
diff --git a/include/asm-sparc64/tlb.h b/include/asm-sparc64/tlb.h
index 9ff2b61533d84..fa0ebf6786fc9 100644
--- a/include/asm-sparc64/tlb.h
+++ b/include/asm-sparc64/tlb.h
@@ -80,11 +80,11 @@ static inline void tlb_finish_mmu(struct mmu_gather *mp, unsigned long start, un
{
unsigned long freed = mp->freed;
struct mm_struct *mm = mp->mm;
- unsigned long rss = mm->rss;
+ unsigned long rss = get_mm_counter(mm, rss);
if (rss < freed)
freed = rss;
- mm->rss = rss - freed;
+ add_mm_counter(mm, rss, -freed);
tlb_flush_mmu(mp);
diff --git a/include/asm-um/archparam-i386.h b/include/asm-um/archparam-i386.h
index 5b5df118d9a5f..6f78de5b621b8 100644
--- a/include/asm-um/archparam-i386.h
+++ b/include/asm-um/archparam-i386.h
@@ -8,7 +8,7 @@
/********* Bits for asm-um/elf.h ************/
-#include "user.h"
+#include <asm/user.h>
extern char * elf_aux_platform;
#define ELF_PLATFORM (elf_aux_platform)
diff --git a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h
index ec58334fb2c78..038ba6fc88b8c 100644
--- a/include/asm-um/processor-generic.h
+++ b/include/asm-um/processor-generic.h
@@ -16,8 +16,6 @@ struct task_struct;
struct mm_struct;
-#define cpu_relax() barrier()
-
struct thread_struct {
int forking;
int nsyscalls;
diff --git a/include/asm-um/processor-i386.h b/include/asm-um/processor-i386.h
index 633cfad9cb0db..2deb8f1adbf12 100644
--- a/include/asm-um/processor-i386.h
+++ b/include/asm-um/processor-i386.h
@@ -19,6 +19,14 @@ struct arch_thread {
#include "asm/arch/user.h"
+/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
+static inline void rep_nop(void)
+{
+ __asm__ __volatile__("rep;nop": : :"memory");
+}
+
+#define cpu_relax() rep_nop()
+
/*
* Default implementation of macro that returns current
* instruction pointer ("program counter"). Stolen
diff --git a/include/asm-um/processor-x86_64.h b/include/asm-um/processor-x86_64.h
index 6bfd7870775e5..a1ae3a4cd9381 100644
--- a/include/asm-um/processor-x86_64.h
+++ b/include/asm-um/processor-x86_64.h
@@ -12,6 +12,14 @@
struct arch_thread {
};
+/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
+extern inline void rep_nop(void)
+{
+ __asm__ __volatile__("rep;nop": : :"memory");
+}
+
+#define cpu_relax() rep_nop()
+
#define INIT_ARCH_THREAD { }
#define current_text_addr() \
diff --git a/include/asm-um/setup.h b/include/asm-um/setup.h
index e5787bb80e79d..c85252e803c13 100644
--- a/include/asm-um/setup.h
+++ b/include/asm-um/setup.h
@@ -1,6 +1,9 @@
#ifndef SETUP_H_INCLUDED
#define SETUP_H_INCLUDED
-#define COMMAND_LINE_SIZE 512
+/* POSIX mandated with _POSIX_ARG_MAX that we can rely on 4096 chars in the
+ * command line, so this choice is ok.*/
+
+#define COMMAND_LINE_SIZE 4096
#endif /* SETUP_H_INCLUDED */
diff --git a/include/asm-um/signal.h b/include/asm-um/signal.h
index 211d1e8a81790..52ed92cbce4cd 100644
--- a/include/asm-um/signal.h
+++ b/include/asm-um/signal.h
@@ -11,6 +11,9 @@
#define do_signal do_signal_renamed
#include "asm/arch/signal.h"
#undef do_signal
+#undef ptrace_signal_deliver
+
+#define ptrace_signal_deliver(regs, cookie) do {} while(0)
#endif
diff --git a/include/asm-x86_64/io.h b/include/asm-x86_64/io.h
index cc2bdb5da0868..94202703fae2f 100644
--- a/include/asm-x86_64/io.h
+++ b/include/asm-x86_64/io.h
@@ -36,11 +36,7 @@
* - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*/
-#ifdef SLOW_IO_BY_JUMPING
-#define __SLOW_DOWN_IO "\njmp 1f\n1:\tjmp 1f\n1:"
-#else
#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
-#endif
#ifdef REALLY_SLOW_IO
#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
diff --git a/include/asm-x86_64/mmu_context.h b/include/asm-x86_64/mmu_context.h
index 410bd4067d346..b630d52bdfb1e 100644
--- a/include/asm-x86_64/mmu_context.h
+++ b/include/asm-x86_64/mmu_context.h
@@ -28,6 +28,11 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
}
#endif
+static inline void load_cr3(pgd_t *pgd)
+{
+ asm volatile("movq %0,%%cr3" :: "r" (__pa(pgd)) : "memory");
+}
+
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk)
{
@@ -40,7 +45,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
write_pda(active_mm, next);
#endif
set_bit(cpu, &next->cpu_vm_mask);
- asm volatile("movq %0,%%cr3" :: "r" (__pa(next->pgd)) : "memory");
+ load_cr3(next->pgd);
+
if (unlikely(next->context.ldt != prev->context.ldt))
load_LDT_nolock(&next->context, cpu);
}
@@ -54,7 +60,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
* tlb flush IPI delivery. We must reload CR3
* to make sure to use no freed page tables.
*/
- asm volatile("movq %0,%%cr3" :: "r" (__pa(next->pgd)) : "memory");
+ load_cr3(next->pgd);
load_LDT_nolock(&next->context, cpu);
}
}
diff --git a/include/asm-x86_64/mpspec.h b/include/asm-x86_64/mpspec.h
index 8557352dadcc7..331f6a3c72a2a 100644
--- a/include/asm-x86_64/mpspec.h
+++ b/include/asm-x86_64/mpspec.h
@@ -156,7 +156,7 @@ struct mpc_config_lintsrc
* 7 2 CPU MCA+PCI
*/
-#define MAX_MP_BUSSES 270
+#define MAX_MP_BUSSES 256
#define MAX_IRQ_SOURCES 256
enum mp_bustype {
MP_BUS_ISA = 1,
diff --git a/include/asm-x86_64/msr.h b/include/asm-x86_64/msr.h
index 8506956784197..2aac15a1290fc 100644
--- a/include/asm-x86_64/msr.h
+++ b/include/asm-x86_64/msr.h
@@ -28,8 +28,8 @@
#define wrmsrl(msr,val) wrmsr(msr,(__u32)((__u64)(val)),((__u64)(val))>>32)
-/* wrmsrl with exception handling */
-#define checking_wrmsrl(msr,val) ({ int ret__; \
+/* wrmsr with exception handling */
+#define wrmsr_safe(msr,a,b) ({ int ret__; \
asm volatile("2: wrmsr ; xorl %0,%0\n" \
"1:\n\t" \
".section .fixup,\"ax\"\n\t" \
@@ -40,9 +40,11 @@
" .quad 2b,3b\n\t" \
".previous" \
: "=a" (ret__) \
- : "c" (msr), "0" ((__u32)val), "d" ((val)>>32), "i" (-EFAULT));\
+ : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT));\
ret__; })
+#define checking_wrmsrl(msr,val) wrmsr_safe(msr,(u32)(val),(u32)((val)>>32))
+
#define rdtsc(low,high) \
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h
index 8edb69a7bc143..f43048035a033 100644
--- a/include/asm-x86_64/page.h
+++ b/include/asm-x86_64/page.h
@@ -63,10 +63,6 @@ typedef struct { unsigned long pgprot; } pgprot_t;
#define __pgd(x) ((pgd_t) { (x) } )
#define __pgprot(x) ((pgprot_t) { (x) } )
-extern unsigned long vm_stack_flags, vm_stack_flags32;
-extern unsigned long vm_data_default_flags, vm_data_default_flags32;
-extern unsigned long vm_force_exec32;
-
#define __START_KERNEL 0xffffffff80100000UL
#define __START_KERNEL_map 0xffffffff80000000UL
#define __PAGE_OFFSET 0xffff810000000000UL
diff --git a/include/asm-x86_64/pgalloc.h b/include/asm-x86_64/pgalloc.h
index cc0b2d52b1bb1..deadd146978b1 100644
--- a/include/asm-x86_64/pgalloc.h
+++ b/include/asm-x86_64/pgalloc.h
@@ -1,7 +1,6 @@
#ifndef _X86_64_PGALLOC_H
#define _X86_64_PGALLOC_H
-#include <asm/processor.h>
#include <asm/fixmap.h>
#include <asm/pda.h>
#include <linux/threads.h>
@@ -99,7 +98,8 @@ extern inline void pte_free(struct page *pte)
}
#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
-#define __pmd_free_tlb(tlb,x) pmd_free(x)
-#define __pud_free_tlb(tlb,x) pud_free(x)
+
+#define __pmd_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x))
+#define __pud_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x))
#endif /* _X86_64_PGALLOC_H */
diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h
index c0af27a623527..dc6b6f2604e80 100644
--- a/include/asm-x86_64/pgtable.h
+++ b/include/asm-x86_64/pgtable.h
@@ -407,6 +407,13 @@ extern int kern_addr_valid(unsigned long addr);
#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define MK_IOSPACE_PFN(space, pfn) (pfn)
+#define GET_IOSPACE(pfn) 0
+#define GET_PFN(pfn) (pfn)
+
#define HAVE_ARCH_UNMAPPED_AREA
#define pgtable_cache_init() do { } while (0)
diff --git a/include/asm-x86_64/segment.h b/include/asm-x86_64/segment.h
index 8dc82dc557fb2..44adaf18c11e3 100644
--- a/include/asm-x86_64/segment.h
+++ b/include/asm-x86_64/segment.h
@@ -24,10 +24,9 @@
#define GDT_ENTRY_TLS 1
#define GDT_ENTRY_TSS 8 /* needs two entries */
-#define GDT_ENTRY_LDT 10
-#define GDT_ENTRY_TLS_MIN 11
-#define GDT_ENTRY_TLS_MAX 13
-/* 14 free */
+#define GDT_ENTRY_LDT 10 /* needs two entries */
+#define GDT_ENTRY_TLS_MIN 12
+#define GDT_ENTRY_TLS_MAX 14
#define GDT_ENTRY_KERNELCS16 15
#define GDT_ENTRY_TLS_ENTRIES 3
diff --git a/include/asm-x86_64/uaccess.h b/include/asm-x86_64/uaccess.h
index 86395211ffddb..48f292752c96b 100644
--- a/include/asm-x86_64/uaccess.h
+++ b/include/asm-x86_64/uaccess.h
@@ -91,16 +91,11 @@ struct exception_table_entry
* accesses to the same area of user memory).
*/
-extern void __get_user_1(void);
-extern void __get_user_2(void);
-extern void __get_user_4(void);
-extern void __get_user_8(void);
-
#define __get_user_x(size,ret,x,ptr) \
__asm__ __volatile__("call __get_user_" #size \
:"=a" (ret),"=d" (x) \
- :"0" (ptr) \
- :"rbx")
+ :"c" (ptr) \
+ :"r8")
/* Careful: we have to cast the result to the type of the pointer for sign reasons */
#define get_user(x,ptr) \
@@ -122,14 +117,13 @@ extern void __put_user_1(void);
extern void __put_user_2(void);
extern void __put_user_4(void);
extern void __put_user_8(void);
-
extern void __put_user_bad(void);
#define __put_user_x(size,ret,x,ptr) \
__asm__ __volatile__("call __put_user_" #size \
:"=a" (ret) \
- :"0" (ptr),"d" (x) \
- :"rbx")
+ :"c" (ptr),"d" (x) \
+ :"r8")
#define put_user(x,ptr) \
__put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
@@ -152,10 +146,15 @@ extern void __put_user_bad(void);
#define __put_user_check(x,ptr,size) \
({ \
- int __pu_err = -EFAULT; \
+ int __pu_err; \
__typeof__(*(ptr)) __user *__pu_addr = (ptr); \
- if (likely(access_ok(VERIFY_WRITE,__pu_addr,size))) \
- __put_user_size((x),__pu_addr,(size),__pu_err); \
+ switch (size) { \
+ case 1: __put_user_x(1,__pu_err,x,__pu_addr); break; \
+ case 2: __put_user_x(2,__pu_err,x,__pu_addr); break; \
+ case 4: __put_user_x(4,__pu_err,x,__pu_addr); break; \
+ case 8: __put_user_x(8,__pu_err,x,__pu_addr); break; \
+ default: __put_user_bad(); \
+ } \
__pu_err; \
})
@@ -206,6 +205,10 @@ struct __large_struct { unsigned long buf[100]; };
__gu_err; \
})
+extern int __get_user_1(void);
+extern int __get_user_2(void);
+extern int __get_user_4(void);
+extern int __get_user_8(void);
extern int __get_user_bad(void);
#define __get_user_size(x,ptr,size,retval) \
diff --git a/include/linux/console.h b/include/linux/console.h
index 99fd8e4be694a..b9b183e986e5e 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -77,13 +77,17 @@ void give_up_console(const struct consw *sw);
#define CM_MOVE (3)
/*
- * The interface for a console, or any other device that
- * wants to capture console messages (printer driver?)
+ * The interface for a console, or any other device that wants to capture
+ * console messages (printer driver?)
+ *
+ * If a console driver is marked CON_BOOT then it will be auto-unregistered
+ * when the first real console is registered. This is for early-printk drivers.
*/
#define CON_PRINTBUFFER (1)
#define CON_CONSDEV (2) /* Last on the command line */
#define CON_ENABLED (4)
+#define CON_BOOT (8)
struct console
{
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
index 5d3cb0dff332f..2d9a500d994d6 100644
--- a/include/linux/cpuset.h
+++ b/include/linux/cpuset.h
@@ -34,7 +34,7 @@ static inline void cpuset_init_smp(void) {}
static inline void cpuset_fork(struct task_struct *p) {}
static inline void cpuset_exit(struct task_struct *p) {}
-static inline const cpumask_t cpuset_cpus_allowed(struct task_struct *p)
+static inline cpumask_t cpuset_cpus_allowed(struct task_struct *p)
{
return cpu_possible_map;
}
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h
index 6dc7e3eca1885..f7a7b86f6eef5 100644
--- a/include/linux/debugfs.h
+++ b/include/linux/debugfs.h
@@ -15,6 +15,8 @@
#ifndef _DEBUGFS_H_
#define _DEBUGFS_H_
+#include <linux/fs.h>
+
#if defined(CONFIG_DEBUG_FS)
struct dentry *debugfs_create_file(const char *name, mode_t mode,
struct dentry *parent, void *data,
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index f909e16a96456..4d478d8b2d069 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -357,6 +357,7 @@ struct ext3_inode {
#define EXT3_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */
#define EXT3_MOUNT_RESERVATION 0x10000 /* Preallocation */
#define EXT3_MOUNT_BARRIER 0x20000 /* Use block barriers */
+#define EXT3_MOUNT_NOBH 0x40000 /* No bufferheads */
/* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
#ifndef _LINUX_EXT2_FS_H
diff --git a/include/linux/generic_serial.h b/include/linux/generic_serial.h
index 326b2b9ea2338..0abe9d9a0069d 100644
--- a/include/linux/generic_serial.h
+++ b/include/linux/generic_serial.h
@@ -34,7 +34,7 @@ struct gs_port {
int xmit_head;
int xmit_tail;
int xmit_cnt;
- /* struct semaphore port_write_sem; */
+ struct semaphore port_write_sem;
int flags;
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
@@ -49,6 +49,7 @@ struct gs_port {
int baud_base;
int baud;
int custom_divisor;
+ spinlock_t driver_lock;
};
@@ -70,6 +71,7 @@ struct gs_port {
#define GS_DEBUG_STUFF 0x00000008
#define GS_DEBUG_CLOSE 0x00000010
#define GS_DEBUG_FLOW 0x00000020
+#define GS_DEBUG_WRITE 0x00000040
void gs_put_char(struct tty_struct *tty, unsigned char ch);
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 954af9d82768c..ae45676d27baf 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -36,7 +36,7 @@ extern const unsigned long hugetlb_zero, hugetlb_infinity;
extern int sysctl_hugetlb_shm_group;
#ifndef ARCH_HAS_HUGEPAGE_ONLY_RANGE
-#define is_hugepage_only_range(addr, len) 0
+#define is_hugepage_only_range(mm, addr, len) 0
#define hugetlb_free_pgtables(tlb, prev, start, end) do { } while (0)
#endif
@@ -71,7 +71,7 @@ static inline unsigned long hugetlb_total_pages(void)
#define is_aligned_hugepage_range(addr, len) 0
#define prepare_hugepage_range(addr, len) (-EINVAL)
#define pmd_huge(x) 0
-#define is_hugepage_only_range(addr, len) 0
+#define is_hugepage_only_range(mm, addr, len) 0
#define hugetlb_free_pgtables(tlb, prev, start, end) do { } while (0)
#define alloc_huge_page() ({ NULL; })
#define free_huge_page(p) ({ (void)(p); BUG(); })
diff --git a/include/linux/jbd.h b/include/linux/jbd.h
index 579ec0e59fd91..593407e865b1b 100644
--- a/include/linux/jbd.h
+++ b/include/linux/jbd.h
@@ -822,6 +822,7 @@ struct journal_s
*/
/* Filing buffers */
+extern void __journal_temp_unlink_buffer(struct journal_head *jh);
extern void journal_unfile_buffer(journal_t *, struct journal_head *);
extern void __journal_unfile_buffer(struct journal_head *);
extern void __journal_refile_buffer(struct journal_head *);
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 7bde43a23799a..7c1cba4a5278d 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -91,17 +91,21 @@ extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
extern long long simple_strtoll(const char *,char **,unsigned int);
extern int sprintf(char * buf, const char * fmt, ...)
__attribute__ ((format (printf, 2, 3)));
-extern int vsprintf(char *buf, const char *, va_list);
+extern int vsprintf(char *buf, const char *, va_list)
+ __attribute__ ((format (printf, 2, 0)));
extern int snprintf(char * buf, size_t size, const char * fmt, ...)
__attribute__ ((format (printf, 3, 4)));
-extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+ __attribute__ ((format (printf, 3, 0)));
extern int scnprintf(char * buf, size_t size, const char * fmt, ...)
__attribute__ ((format (printf, 3, 4)));
-extern int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
+extern int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+ __attribute__ ((format (printf, 3, 0)));
extern int sscanf(const char *, const char *, ...)
- __attribute__ ((format (scanf,2,3)));
-extern int vsscanf(const char *, const char *, va_list);
+ __attribute__ ((format (scanf, 2, 3)));
+extern int vsscanf(const char *, const char *, va_list)
+ __attribute__ ((format (scanf, 2, 0)));
extern int get_option(char **str, int *pint);
extern char *get_options(const char *str, int nints, int *ints);
@@ -111,7 +115,8 @@ extern int __kernel_text_address(unsigned long addr);
extern int kernel_text_address(unsigned long addr);
extern int session_of_pgrp(int pgrp);
-asmlinkage int vprintk(const char *fmt, va_list args);
+asmlinkage int vprintk(const char *fmt, va_list args)
+ __attribute__ ((format (printf, 1, 0)));
asmlinkage int printk(const char * fmt, ...)
__attribute__ ((format (printf, 1, 2)));
diff --git a/include/linux/mpage.h b/include/linux/mpage.h
index 3ca880463c474..dea1b0083661c 100644
--- a/include/linux/mpage.h
+++ b/include/linux/mpage.h
@@ -20,6 +20,9 @@ int mpage_writepages(struct address_space *mapping,
struct writeback_control *wbc, get_block_t get_block);
int mpage_writepage(struct page *page, get_block_t *get_block,
struct writeback_control *wbc);
+int __mpage_writepages(struct address_space *mapping,
+ struct writeback_control *wbc, get_block_t get_block,
+ writepage_t writepage);
static inline int
generic_writepages(struct address_space *mapping, struct writeback_control *wbc)
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 4f15fbae32286..a5ae03ad495c4 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1526,6 +1526,10 @@
#define PCI_DEVICE_ID_DIGI_DF_M_E 0x0071
#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_A 0x0072
#define PCI_DEVICE_ID_DIGI_DF_M_A 0x0073
+#define PCI_DEVICE_ID_NEO_2DB9 0x00C8
+#define PCI_DEVICE_ID_NEO_2DB9PRI 0x00C9
+#define PCI_DEVICE_ID_NEO_2RJ45 0x00CA
+#define PCI_DEVICE_ID_NEO_2RJ45PRI 0x00CB
#define PCI_VENDOR_ID_MUTECH 0x1159
#define PCI_DEVICE_ID_MUTECH_MV1000 0x0001
@@ -2528,13 +2532,15 @@
#define PCI_VENDOR_ID_NETMOS 0x9710
#define PCI_DEVICE_ID_NETMOS_9705 0x9705
+#define PCI_DEVICE_ID_NETMOS_9715 0x9715
#define PCI_DEVICE_ID_NETMOS_9735 0x9735
+#define PCI_DEVICE_ID_NETMOS_9745 0x9745
+#define PCI_DEVICE_ID_NETMOS_9755 0x9755
#define PCI_DEVICE_ID_NETMOS_9805 0x9805
#define PCI_DEVICE_ID_NETMOS_9815 0x9815
#define PCI_DEVICE_ID_NETMOS_9835 0x9835
+#define PCI_DEVICE_ID_NETMOS_9845 0x9845
#define PCI_DEVICE_ID_NETMOS_9855 0x9855
-#define PCI_DEVICE_ID_NETMOS_9755 0x9755
-#define PCI_DEVICE_ID_NETMOS_9715 0x9715
#define PCI_SUBVENDOR_ID_EXSYS 0xd84d
#define PCI_SUBDEVICE_ID_EXSYS_4014 0x4014
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 814ee929cd67e..a30e91f40da67 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -204,6 +204,12 @@ arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr,
extern void arch_unmap_area(struct vm_area_struct *area);
extern void arch_unmap_area_topdown(struct vm_area_struct *area);
+#define set_mm_counter(mm, member, value) (mm)->_##member = (value)
+#define get_mm_counter(mm, member) ((mm)->_##member)
+#define add_mm_counter(mm, member, value) (mm)->_##member += (value)
+#define inc_mm_counter(mm, member) (mm)->_##member++
+#define dec_mm_counter(mm, member) (mm)->_##member--
+typedef unsigned long mm_counter_t;
struct mm_struct {
struct vm_area_struct * mmap; /* list of VMAs */
@@ -220,7 +226,7 @@ struct mm_struct {
atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */
int map_count; /* number of VMAs */
struct rw_semaphore mmap_sem;
- spinlock_t page_table_lock; /* Protects page tables, mm->rss, mm->anon_rss */
+ spinlock_t page_table_lock; /* Protects page tables and some counters */
struct list_head mmlist; /* List of maybe swapped mm's. These are globally strung
* together off init_mm.mmlist, and are protected
@@ -230,9 +236,13 @@ struct mm_struct {
unsigned long start_code, end_code, start_data, end_data;
unsigned long start_brk, brk, start_stack;
unsigned long arg_start, arg_end, env_start, env_end;
- unsigned long rss, anon_rss, total_vm, locked_vm, shared_vm;
+ unsigned long total_vm, locked_vm, shared_vm;
unsigned long exec_vm, stack_vm, reserved_vm, def_flags, nr_ptes;
+ /* Special counters protected by the page_table_lock */
+ mm_counter_t _rss;
+ mm_counter_t _anon_rss;
+
unsigned long saved_auxv[42]; /* for /proc/PID/auxv */
unsigned dumpable:1;
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index a456436aabb31..c3fb5984f250a 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -113,6 +113,12 @@
/* Samsung S3C2400 SoC */
#define PORT_S3C2400 67
+/* M32R SIO */
+#define PORT_M32R_SIO 68
+
+/*Digi jsm */
+#define PORT_JSM 65
+
#ifdef __KERNEL__
#include <linux/config.h>
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 33917ccee13bf..2bf0d5fabcdb9 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -34,8 +34,6 @@ typedef struct pbe {
#define SWAP_FILENAME_MAXLENGTH 32
-#define SUSPEND_PD_PAGES(x) (((x)*sizeof(struct pbe))/PAGE_SIZE+1)
-
extern dev_t swsusp_resume_device;
/* mm/vmscan.c */
diff --git a/init/Kconfig b/init/Kconfig
index d0404f9351b55..abe2682a6ca68 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -55,6 +55,14 @@ config LOCK_KERNEL
depends on SMP || PREEMPT
default y
+config INIT_ENV_ARG_LIMIT
+ int
+ default 32 if !USERMODE
+ default 128 if USERMODE
+ help
+ This is the value of the two limits on the number of argument and of
+ env.var passed to init from the kernel command line.
+
endmenu
menu "General setup"
@@ -413,7 +421,7 @@ config OBSOLETE_MODPARM
config MODVERSIONS
bool "Module versioning support (EXPERIMENTAL)"
- depends on MODULES && EXPERIMENTAL && !USERMODE
+ depends on MODULES && EXPERIMENTAL && !UML
help
Usually, you have to use modules compiled with your kernel.
Saying Y here makes it sometimes possible to use modules
diff --git a/init/main.c b/init/main.c
index dfa5cc66b3d9c..40bf367ffdf19 100644
--- a/init/main.c
+++ b/init/main.c
@@ -110,8 +110,8 @@ EXPORT_SYMBOL(system_state);
/*
* Boot command-line arguments
*/
-#define MAX_INIT_ARGS 32
-#define MAX_INIT_ENVS 32
+#define MAX_INIT_ARGS CONFIG_INIT_ENV_ARG_LIMIT
+#define MAX_INIT_ENVS CONFIG_INIT_ENV_ARG_LIMIT
extern void time_init(void);
/* Default late time init is NULL. archs can override this later. */
diff --git a/kernel/acct.c b/kernel/acct.c
index 035669624b6ce..4168f631868e1 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -542,7 +542,7 @@ void acct_update_integrals(struct task_struct *tsk)
if (delta == 0)
return;
tsk->acct_stimexpd = tsk->stime;
- tsk->acct_rss_mem1 += delta * tsk->mm->rss;
+ tsk->acct_rss_mem1 += delta * get_mm_counter(tsk->mm, rss);
tsk->acct_vm_mem1 += delta * tsk->mm->total_vm;
}
}
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 44c03c666b019..cd942ce30b738 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -505,6 +505,35 @@ static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask)
}
/*
+ * Refresh current tasks mems_allowed and mems_generation from
+ * current tasks cpuset. Call with cpuset_sem held.
+ *
+ * Be sure to call refresh_mems() on any cpuset operation which
+ * (1) holds cpuset_sem, and (2) might possibly alloc memory.
+ * Call after obtaining cpuset_sem lock, before any possible
+ * allocation. Otherwise one risks trying to allocate memory
+ * while the task cpuset_mems_generation is not the same as
+ * the mems_generation in its cpuset, which would deadlock on
+ * cpuset_sem in cpuset_update_current_mems_allowed().
+ *
+ * Since we hold cpuset_sem, once refresh_mems() is called, the
+ * test (current->cpuset_mems_generation != cs->mems_generation)
+ * in cpuset_update_current_mems_allowed() will remain false,
+ * until we drop cpuset_sem. Anyone else who would change our
+ * cpusets mems_generation needs to lock cpuset_sem first.
+ */
+
+static void refresh_mems(void)
+{
+ struct cpuset *cs = current->cpuset;
+
+ if (current->cpuset_mems_generation != cs->mems_generation) {
+ guarantee_online_mems(cs, &current->mems_allowed);
+ current->cpuset_mems_generation = cs->mems_generation;
+ }
+}
+
+/*
* is_cpuset_subset(p, q) - Is cpuset p a subset of cpuset q?
*
* One cpuset is a subset of another if all its allowed CPUs and
@@ -1224,6 +1253,7 @@ static long cpuset_create(struct cpuset *parent, const char *name, int mode)
return -ENOMEM;
down(&cpuset_sem);
+ refresh_mems();
cs->flags = 0;
if (notify_on_release(parent))
set_bit(CS_NOTIFY_ON_RELEASE, &cs->flags);
@@ -1277,6 +1307,7 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry)
/* the vfs holds both inode->i_sem already */
down(&cpuset_sem);
+ refresh_mems();
if (atomic_read(&cs->count) > 0) {
up(&cpuset_sem);
return -EBUSY;
@@ -1433,8 +1464,7 @@ void cpuset_update_current_mems_allowed()
return; /* task is exiting */
if (current->cpuset_mems_generation != cs->mems_generation) {
down(&cpuset_sem);
- guarantee_online_mems(cs, &current->mems_allowed);
- current->cpuset_mems_generation = cs->mems_generation;
+ refresh_mems();
up(&cpuset_sem);
}
}
diff --git a/kernel/fork.c b/kernel/fork.c
index 5b67b3ebf3c09..f42a17f88699b 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -195,8 +195,8 @@ static inline int dup_mmap(struct mm_struct * mm, struct mm_struct * oldmm)
mm->mmap_cache = NULL;
mm->free_area_cache = oldmm->mmap_base;
mm->map_count = 0;
- mm->rss = 0;
- mm->anon_rss = 0;
+ set_mm_counter(mm, rss, 0);
+ set_mm_counter(mm, anon_rss, 0);
cpus_clear(mm->cpu_vm_mask);
mm->mm_rb = RB_ROOT;
rb_link = &mm->mm_rb.rb_node;
@@ -492,7 +492,7 @@ static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
if (retval)
goto free_pt;
- mm->hiwater_rss = mm->rss;
+ mm->hiwater_rss = get_mm_counter(mm,rss);
mm->hiwater_vm = mm->total_vm;
good_mm:
diff --git a/kernel/futex.c b/kernel/futex.c
index 7f9f4a012190b..7b54a672d0add 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -97,7 +97,6 @@ struct futex_q {
*/
struct futex_hash_bucket {
spinlock_t lock;
- unsigned int nqueued;
struct list_head chain;
};
@@ -265,7 +264,6 @@ static inline int get_futex_value_locked(int *dest, int __user *from)
inc_preempt_count();
ret = __copy_from_user_inatomic(dest, from, sizeof(int));
dec_preempt_count();
- preempt_check_resched();
return ret ? -EFAULT : 0;
}
@@ -339,7 +337,6 @@ static int futex_requeue(unsigned long uaddr1, unsigned long uaddr2,
struct list_head *head1;
struct futex_q *this, *next;
int ret, drop_count = 0;
- unsigned int nqueued;
retry:
down_read(&current->mm->mmap_sem);
@@ -354,23 +351,22 @@ static int futex_requeue(unsigned long uaddr1, unsigned long uaddr2,
bh1 = hash_futex(&key1);
bh2 = hash_futex(&key2);
- nqueued = bh1->nqueued;
+ if (bh1 < bh2)
+ spin_lock(&bh1->lock);
+ spin_lock(&bh2->lock);
+ if (bh1 > bh2)
+ spin_lock(&bh1->lock);
+
if (likely(valp != NULL)) {
int curval;
- /* In order to avoid doing get_user while
- holding bh1->lock and bh2->lock, nqueued
- (monotonically increasing field) must be first
- read, then *uaddr1 fetched from userland and
- after acquiring lock nqueued field compared with
- the stored value. The smp_mb () below
- makes sure that bh1->nqueued is read from memory
- before *uaddr1. */
- smp_mb();
-
ret = get_futex_value_locked(&curval, (int __user *)uaddr1);
if (unlikely(ret)) {
+ spin_unlock(&bh1->lock);
+ if (bh1 != bh2)
+ spin_unlock(&bh2->lock);
+
/* If we would have faulted, release mmap_sem, fault
* it in and start all over again.
*/
@@ -385,21 +381,10 @@ static int futex_requeue(unsigned long uaddr1, unsigned long uaddr2,
}
if (curval != *valp) {
ret = -EAGAIN;
- goto out;
+ goto out_unlock;
}
}
- if (bh1 < bh2)
- spin_lock(&bh1->lock);
- spin_lock(&bh2->lock);
- if (bh1 > bh2)
- spin_lock(&bh1->lock);
-
- if (unlikely(nqueued != bh1->nqueued && valp != NULL)) {
- ret = -EAGAIN;
- goto out_unlock;
- }
-
head1 = &bh1->chain;
list_for_each_entry_safe(this, next, head1, list) {
if (!match_futex (&this->key, &key1))
@@ -435,13 +420,9 @@ out:
return ret;
}
-/*
- * queue_me and unqueue_me must be called as a pair, each
- * exactly once. They are called with the hashed spinlock held.
- */
-
/* The key must be already stored in q->key. */
-static void queue_me(struct futex_q *q, int fd, struct file *filp)
+static inline struct futex_hash_bucket *
+queue_lock(struct futex_q *q, int fd, struct file *filp)
{
struct futex_hash_bucket *bh;
@@ -455,11 +436,35 @@ static void queue_me(struct futex_q *q, int fd, struct file *filp)
q->lock_ptr = &bh->lock;
spin_lock(&bh->lock);
- bh->nqueued++;
+ return bh;
+}
+
+static inline void __queue_me(struct futex_q *q, struct futex_hash_bucket *bh)
+{
list_add_tail(&q->list, &bh->chain);
spin_unlock(&bh->lock);
}
+static inline void
+queue_unlock(struct futex_q *q, struct futex_hash_bucket *bh)
+{
+ spin_unlock(&bh->lock);
+ drop_key_refs(&q->key);
+}
+
+/*
+ * queue_me and unqueue_me must be called as a pair, each
+ * exactly once. They are called with the hashed spinlock held.
+ */
+
+/* The key must be already stored in q->key. */
+static void queue_me(struct futex_q *q, int fd, struct file *filp)
+{
+ struct futex_hash_bucket *bh;
+ bh = queue_lock(q, fd, filp);
+ __queue_me(q, bh);
+}
+
/* Return 1 if we were still queued (ie. 0 means we were woken) */
static int unqueue_me(struct futex_q *q)
{
@@ -503,6 +508,7 @@ static int futex_wait(unsigned long uaddr, int val, unsigned long time)
DECLARE_WAITQUEUE(wait, current);
int ret, curval;
struct futex_q q;
+ struct futex_hash_bucket *bh;
retry:
down_read(&current->mm->mmap_sem);
@@ -511,7 +517,7 @@ static int futex_wait(unsigned long uaddr, int val, unsigned long time)
if (unlikely(ret != 0))
goto out_release_sem;
- queue_me(&q, -1, NULL);
+ bh = queue_lock(&q, -1, NULL);
/*
* Access the page AFTER the futex is queued.
@@ -537,14 +543,13 @@ static int futex_wait(unsigned long uaddr, int val, unsigned long time)
ret = get_futex_value_locked(&curval, (int __user *)uaddr);
if (unlikely(ret)) {
+ queue_unlock(&q, bh);
+
/* If we would have faulted, release mmap_sem, fault it in and
* start all over again.
*/
up_read(&current->mm->mmap_sem);
- if (!unqueue_me(&q)) /* There's a chance we got woken already */
- return 0;
-
ret = get_user(curval, (int __user *)uaddr);
if (!ret)
@@ -553,9 +558,13 @@ static int futex_wait(unsigned long uaddr, int val, unsigned long time)
}
if (curval != val) {
ret = -EWOULDBLOCK;
- goto out_unqueue;
+ queue_unlock(&q, bh);
+ goto out_release_sem;
}
+ /* Only actually queue if *uaddr contained val. */
+ __queue_me(&q, bh);
+
/*
* Now the futex is queued and we have checked the data, we
* don't want to hold mmap_sem while we sleep.
@@ -596,10 +605,6 @@ static int futex_wait(unsigned long uaddr, int val, unsigned long time)
* have handled it for us already. */
return -EINTR;
- out_unqueue:
- /* If we were woken (and unqueued), we succeeded, whatever. */
- if (!unqueue_me(&q))
- ret = 0;
out_release_sem:
up_read(&current->mm->mmap_sem);
return ret;
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 33fe32e114cb4..85d08daa6600e 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -19,6 +19,13 @@ static struct proc_dir_entry *root_irq_dir, *irq_dir[NR_IRQS];
*/
static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
+void __attribute__((weak))
+proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
+{
+ irq_affinity[irq] = mask_val;
+ irq_desc[irq].handler->set_affinity(irq, mask_val);
+}
+
static int irq_affinity_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
@@ -53,8 +60,7 @@ static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
if (cpus_empty(tmp))
return -EINVAL;
- irq_affinity[irq] = new_value;
- irq_desc[irq].handler->set_affinity(irq, new_value);
+ proc_set_irq_affinity(irq, new_value);
return full_count;
}
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 4a331aed08660..1d5dd1337bd1c 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -79,7 +79,7 @@ int register_kprobe(struct kprobe *p)
unsigned long flags = 0;
if ((ret = arch_prepare_kprobe(p)) != 0) {
- goto out;
+ goto rm_kprobe;
}
spin_lock_irqsave(&kprobe_lock, flags);
INIT_HLIST_NODE(&p->hlist);
@@ -96,8 +96,9 @@ int register_kprobe(struct kprobe *p)
*p->addr = BREAKPOINT_INSTRUCTION;
flush_icache_range((unsigned long) p->addr,
(unsigned long) p->addr + sizeof(kprobe_opcode_t));
- out:
+out:
spin_unlock_irqrestore(&kprobe_lock, flags);
+rm_kprobe:
if (ret == -EEXIST)
arch_remove_kprobe(p);
return ret;
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index 5dfd280631aeb..ad85d3f0dcc45 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -38,7 +38,7 @@ timespec_to_sample(clockid_t which_clock, const struct timespec *tp)
if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
ret.sched = tp->tv_sec * NSEC_PER_SEC + tp->tv_nsec;
} else {
- ret.cpu = timespec_to_jiffies(tp);
+ ret.cpu = timespec_to_cputime(tp);
}
return ret;
}
@@ -94,28 +94,46 @@ static inline union cpu_time_count cpu_time_sub(clockid_t which_clock,
static inline void bump_cpu_timer(struct k_itimer *timer,
union cpu_time_count now)
{
+ int i;
+
if (timer->it.cpu.incr.sched == 0)
return;
if (CPUCLOCK_WHICH(timer->it_clock) == CPUCLOCK_SCHED) {
- long long delta;
- delta = now.sched - timer->it.cpu.expires.sched;
- if (delta >= 0) {
- do_div(delta, timer->it.cpu.incr.sched);
- delta++;
- timer->it.cpu.expires.sched +=
- delta * timer->it.cpu.incr.sched;
- timer->it_overrun += (int) delta;
+ unsigned long long delta, incr;
+
+ if (now.sched < timer->it.cpu.expires.sched)
+ return;
+ incr = timer->it.cpu.incr.sched;
+ delta = now.sched + incr - timer->it.cpu.expires.sched;
+ /* Don't use (incr*2 < delta), incr*2 might overflow. */
+ for (i = 0; incr < delta - incr; i++)
+ incr = incr << 1;
+ for (; i >= 0; incr >>= 1, i--) {
+ if (delta <= incr)
+ continue;
+ timer->it.cpu.expires.sched += incr;
+ timer->it_overrun += 1 << i;
+ delta -= incr;
}
- } else if (cputime_le(now.cpu, timer->it.cpu.expires.cpu)) {
- cputime_t delta = cputime_sub(now.cpu,
- timer->it.cpu.expires.cpu);
- if (cputime_ge(delta, cputime_zero)) {
- long orun = 1 + (delta / timer->it.cpu.incr.cpu);
+ } else {
+ cputime_t delta, incr;
+
+ if (cputime_lt(now.cpu, timer->it.cpu.expires.cpu))
+ return;
+ incr = timer->it.cpu.incr.cpu;
+ delta = cputime_sub(cputime_add(now.cpu, incr),
+ timer->it.cpu.expires.cpu);
+ /* Don't use (incr*2 < delta), incr*2 might overflow. */
+ for (i = 0; cputime_lt(incr, cputime_sub(delta, incr)); i++)
+ incr = cputime_add(incr, incr);
+ for (; i >= 0; incr = cputime_halve(incr), i--) {
+ if (cputime_le(delta, incr))
+ continue;
timer->it.cpu.expires.cpu =
- cputime_add(timer->it.cpu.expires.cpu,
- orun * timer->it.cpu.incr.cpu);
- timer->it_overrun += orun;
+ cputime_add(timer->it.cpu.expires.cpu, incr);
+ timer->it_overrun += 1 << i;
+ delta = cputime_sub(delta, incr);
}
}
}
@@ -479,8 +497,8 @@ static void process_timer_rebalance(struct task_struct *p,
BUG();
break;
case CPUCLOCK_PROF:
- left = cputime_sub(expires.cpu, val.cpu)
- / nthreads;
+ left = cputime_div(cputime_sub(expires.cpu, val.cpu),
+ nthreads);
do {
if (!unlikely(t->exit_state)) {
ticks = cputime_add(prof_ticks(t), left);
@@ -494,8 +512,8 @@ static void process_timer_rebalance(struct task_struct *p,
} while (t != p);
break;
case CPUCLOCK_VIRT:
- left = cputime_sub(expires.cpu, val.cpu)
- / nthreads;
+ left = cputime_div(cputime_sub(expires.cpu, val.cpu),
+ nthreads);
do {
if (!unlikely(t->exit_state)) {
ticks = cputime_add(virt_ticks(t), left);
@@ -587,17 +605,25 @@ static void arm_timer(struct k_itimer *timer, union cpu_time_count now)
switch (CPUCLOCK_WHICH(timer->it_clock)) {
default:
BUG();
-#define UPDATE_CLOCK(WHICH, c, n) \
- case CPUCLOCK_##WHICH: \
- if (p->it_##c##_expires == 0 || \
- p->it_##c##_expires > nt->expires.n) { \
- p->it_##c##_expires = nt->expires.n; \
- } \
- break
- UPDATE_CLOCK(PROF, prof, cpu);
- UPDATE_CLOCK(VIRT, virt, cpu);
- UPDATE_CLOCK(SCHED, sched, sched);
-#undef UPDATE_CLOCK
+ case CPUCLOCK_PROF:
+ if (cputime_eq(p->it_prof_expires,
+ cputime_zero) ||
+ cputime_gt(p->it_prof_expires,
+ nt->expires.cpu))
+ p->it_prof_expires = nt->expires.cpu;
+ break;
+ case CPUCLOCK_VIRT:
+ if (cputime_eq(p->it_virt_expires,
+ cputime_zero) ||
+ cputime_gt(p->it_virt_expires,
+ nt->expires.cpu))
+ p->it_virt_expires = nt->expires.cpu;
+ break;
+ case CPUCLOCK_SCHED:
+ if (p->it_sched_expires == 0 ||
+ p->it_sched_expires > nt->expires.sched)
+ p->it_sched_expires = nt->expires.sched;
+ break;
}
} else {
/*
@@ -934,7 +960,7 @@ static void check_thread_timers(struct task_struct *tsk,
{
struct list_head *timers = tsk->cpu_timers;
- tsk->it_prof_expires = 0;
+ tsk->it_prof_expires = cputime_zero;
while (!list_empty(timers)) {
struct cpu_timer_list *t = list_entry(timers->next,
struct cpu_timer_list,
@@ -948,7 +974,7 @@ static void check_thread_timers(struct task_struct *tsk,
}
++timers;
- tsk->it_virt_expires = 0;
+ tsk->it_virt_expires = cputime_zero;
while (!list_empty(timers)) {
struct cpu_timer_list *t = list_entry(timers->next,
struct cpu_timer_list,
@@ -1044,7 +1070,7 @@ static void check_process_timers(struct task_struct *tsk,
}
++timers;
- sched_expires = cputime_zero;
+ sched_expires = 0;
while (!list_empty(timers)) {
struct cpu_timer_list *t = list_entry(timers->next,
struct cpu_timer_list,
@@ -1132,9 +1158,11 @@ static void check_process_timers(struct task_struct *tsk,
unsigned long long sched_left, sched;
const unsigned int nthreads = atomic_read(&sig->live);
- prof_left = cputime_sub(prof_expires,
- cputime_add(utime, stime)) / nthreads;
- virt_left = cputime_sub(virt_expires, utime) / nthreads;
+ prof_left = cputime_sub(prof_expires, utime);
+ prof_left = cputime_sub(prof_left, stime);
+ prof_left = cputime_div(prof_left, nthreads);
+ virt_left = cputime_sub(virt_expires, utime);
+ virt_left = cputime_div(virt_left, nthreads);
if (sched_expires) {
sched_left = sched_expires - sched_time;
do_div(sched_left, nthreads);
@@ -1245,7 +1273,7 @@ void run_posix_cpu_timers(struct task_struct *tsk)
BUG_ON(!irqs_disabled());
#define UNEXPIRED(clock) \
- (tsk->it_##clock##_expires == 0 || \
+ (cputime_eq(tsk->it_##clock##_expires, cputime_zero) || \
cputime_lt(clock##_ticks(tsk), tsk->it_##clock##_expires))
if (UNEXPIRED(prof) && UNEXPIRED(virt) &&
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 5f0fbcf511ba3..fd316c2722604 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -46,6 +46,7 @@
#include <linux/syscalls.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
+#include <linux/module.h>
#ifndef div_long_long_rem
#include <asm/div64.h>
@@ -460,6 +461,7 @@ int posix_timer_event(struct k_itimer *timr,int si_private)
timr->it_process);
}
}
+EXPORT_SYMBOL_GPL(posix_timer_event);
/*
* This function gets called when a POSIX.1b interval timer expires. It
@@ -555,6 +557,7 @@ void register_posix_clock(clockid_t clock_id, struct k_clock *new_clock)
posix_clocks[clock_id] = *new_clock;
}
+EXPORT_SYMBOL_GPL(register_posix_clock);
static struct k_itimer * alloc_posix_timer(void)
{
@@ -935,6 +938,10 @@ static int adjust_abs_time(struct k_clock *clock, struct timespec *tp,
*/
if (oc.tv_sec < 0)
oc.tv_sec = oc.tv_nsec = 0;
+
+ if (oc.tv_sec | oc.tv_nsec)
+ set_normalized_timespec(&oc, oc.tv_sec,
+ oc.tv_nsec + clock->res);
tstojiffie(&oc, clock->res, exp);
/*
@@ -1246,16 +1253,17 @@ int do_posix_clock_monotonic_gettime(struct timespec *tp)
return do_posix_clock_monotonic_get(CLOCK_MONOTONIC, tp);
}
-
int do_posix_clock_nosettime(clockid_t clockid, struct timespec *tp)
{
return -EINVAL;
}
+EXPORT_SYMBOL_GPL(do_posix_clock_nosettime);
int do_posix_clock_notimer_create(struct k_itimer *timer)
{
return -EINVAL;
}
+EXPORT_SYMBOL_GPL(do_posix_clock_notimer_create);
int do_posix_clock_nonanosleep(clockid_t clock, int flags, struct timespec *t)
{
@@ -1265,6 +1273,7 @@ int do_posix_clock_nonanosleep(clockid_t clock, int flags, struct timespec *t)
return -ENOTSUP;
#endif
}
+EXPORT_SYMBOL_GPL(do_posix_clock_nonanosleep);
asmlinkage long
sys_clock_settime(clockid_t which_clock, const struct timespec __user *tp)
@@ -1502,7 +1511,6 @@ static int common_nsleep(clockid_t which_clock,
if (abs || !rq_time) {
adjust_abs_time(&posix_clocks[which_clock], &t, abs,
&rq_time, &dum);
- rq_time += (t.tv_sec || t.tv_nsec);
}
left = rq_time - get_jiffies_64();
diff --git a/kernel/power/main.c b/kernel/power/main.c
index b0315cbad9b91..7960ddf04a57f 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -65,8 +65,10 @@ static int suspend_prepare(suspend_state_t state)
goto Thaw;
}
- if ((error = device_suspend(PMSG_SUSPEND)))
+ if ((error = device_suspend(PMSG_SUSPEND))) {
+ printk(KERN_ERR "Some devices failed to suspend\n");
goto Finish;
+ }
return 0;
Finish:
if (pm_ops->finish)
@@ -85,8 +87,10 @@ static int suspend_enter(suspend_state_t state)
local_irq_save(flags);
- if ((error = device_power_down(PMSG_SUSPEND)))
+ if ((error = device_power_down(PMSG_SUSPEND))) {
+ printk(KERN_ERR "Some devices failed to power down\n");
goto Done;
+ }
error = pm_ops->enter(state);
device_power_up();
Done:
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index cf555c10d3b5b..ae5bebc3b18fa 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -98,7 +98,6 @@ unsigned int nr_copy_pages __nosavedata = 0;
*/
suspend_pagedir_t *pagedir_nosave __nosavedata = NULL;
static suspend_pagedir_t *pagedir_save;
-static int pagedir_order __nosavedata = 0;
#define SWSUSP_SIG "S1SUSPEND"
@@ -893,34 +892,29 @@ int swsusp_suspend(void)
* at resume time, and evil weirdness ensues.
*/
if ((error = device_power_down(PMSG_FREEZE))) {
+ printk(KERN_ERR "Some devices failed to power down, aborting suspend\n");
local_irq_enable();
+ swsusp_free();
return error;
}
save_processor_state();
- error = swsusp_arch_suspend();
+ if ((error = swsusp_arch_suspend()))
+ swsusp_free();
/* Restore control flow magically appears here */
restore_processor_state();
+ BUG_ON (nr_copy_pages_check != nr_copy_pages);
restore_highmem();
device_power_up();
local_irq_enable();
return error;
}
-
-asmlinkage int swsusp_restore(void)
-{
- BUG_ON (nr_copy_pages_check != nr_copy_pages);
-
- /* Even mappings of "global" things (vmalloc) need to be fixed */
- __flush_tlb_global();
- return 0;
-}
-
int swsusp_resume(void)
{
int error;
local_irq_disable();
- device_power_down(PMSG_FREEZE);
+ if (device_power_down(PMSG_FREEZE))
+ printk(KERN_ERR "Some devices failed to power down, very bad\n");
/* We'll ignore saved state, but this gets preempt count (etc) right */
save_processor_state();
error = swsusp_arch_resume();
@@ -1219,7 +1213,6 @@ static int check_header(void)
return -EPERM;
}
nr_copy_pages = swsusp_info.image_pages;
- pagedir_order = get_bitmask_order(SUSPEND_PD_PAGES(nr_copy_pages));
return error;
}
@@ -1238,7 +1231,7 @@ static int check_sig(void)
*/
error = bio_write_page(0, &swsusp_header);
} else {
- pr_debug(KERN_ERR "swsusp: Suspend partition has wrong signature?\n");
+ printk(KERN_ERR "swsusp: Suspend partition has wrong signature?\n");
return -EINVAL;
}
if (!error)
diff --git a/kernel/printk.c b/kernel/printk.c
index e5a2222f477e3..5d5754964bf40 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -861,6 +861,11 @@ void register_console(struct console * console)
if (!(console->flags & CON_ENABLED))
return;
+ if (console_drivers && (console_drivers->flags & CON_BOOT)) {
+ unregister_console(console_drivers);
+ console->flags &= ~CON_PRINTBUFFER;
+ }
+
/*
* Put this console in the list - keep the
* preferred driver at the head of the list.
diff --git a/kernel/sched.c b/kernel/sched.c
index c32f9389978ff..dff94ba6df386 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -3741,14 +3741,11 @@ EXPORT_SYMBOL(cond_resched);
*/
int cond_resched_lock(spinlock_t * lock)
{
-#if defined(CONFIG_SMP) && defined(CONFIG_PREEMPT)
- if (lock->break_lock) {
- lock->break_lock = 0;
+ if (need_lockbreak(lock)) {
spin_unlock(lock);
cpu_relax();
spin_lock(lock);
}
-#endif
if (need_resched()) {
_raw_spin_unlock(lock);
preempt_enable_no_resched();
diff --git a/kernel/signal.c b/kernel/signal.c
index 8dc483007847c..f00a1d610f0bb 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2219,6 +2219,8 @@ sys_rt_sigtimedwait(const sigset_t __user *uthese,
current->state = TASK_INTERRUPTIBLE;
timeout = schedule_timeout(timeout);
+ if (current->flags & PF_FREEZE)
+ refrigerator(PF_FREEZE);
spin_lock_irq(&current->sighand->siglock);
sig = dequeue_signal(current, &these, &info);
current->blocked = current->real_blocked;
diff --git a/kernel/spinlock.c b/kernel/spinlock.c
index b8e76ca8a001f..e15ed17863f16 100644
--- a/kernel/spinlock.c
+++ b/kernel/spinlock.c
@@ -187,6 +187,7 @@ void __lockfunc _##op##_lock(locktype##_t *lock) \
cpu_relax(); \
preempt_disable(); \
} \
+ (lock)->break_lock = 0; \
} \
\
EXPORT_SYMBOL(_##op##_lock); \
@@ -209,6 +210,7 @@ unsigned long __lockfunc _##op##_lock_irqsave(locktype##_t *lock) \
cpu_relax(); \
preempt_disable(); \
} \
+ (lock)->break_lock = 0; \
return flags; \
} \
\
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index e31b1cb8e5030..c39ed70af1740 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -6,6 +6,7 @@
#include <linux/syscalls.h>
#include <asm/atomic.h>
#include <asm/semaphore.h>
+#include <asm/uaccess.h>
/* Since we effect priority and affinity (both of which are visible
* to, and settable by outside processes) we do indirection via a
@@ -86,9 +87,13 @@ static int stop_machine(void)
{
int i, ret = 0;
struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+ mm_segment_t old_fs = get_fs();
/* One high-prio thread per cpu. We'll do this one. */
- sys_sched_setscheduler(current->pid, SCHED_FIFO, &param);
+ set_fs(KERNEL_DS);
+ sys_sched_setscheduler(current->pid, SCHED_FIFO,
+ (struct sched_param __user *)&param);
+ set_fs(old_fs);
atomic_set(&stopmachine_thread_ack, 0);
stopmachine_num_threads = 0;
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 623eaf5175347..1802a311dd3f8 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -83,3 +83,4 @@ cond_syscall(sys_pciconfig_write);
cond_syscall(sys_pciconfig_iobase);
cond_syscall(sys32_ipc);
cond_syscall(sys32_sysctl);
+cond_syscall(ppc_rtas);
diff --git a/kernel/time.c b/kernel/time.c
index d5400f6af052d..96fd0f499631d 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -34,6 +34,7 @@
#include <linux/syscalls.h>
#include <linux/security.h>
#include <linux/fs.h>
+#include <linux/module.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -215,6 +216,14 @@ long pps_stbcnt; /* stability limit exceeded */
/* hook for a loadable hardpps kernel module */
void (*hardpps_ptr)(struct timeval *);
+/* we call this to notify the arch when the clock is being
+ * controlled. If no such arch routine, do nothing.
+ */
+void __attribute__ ((weak)) notify_arch_cmos_timer(void)
+{
+ return;
+}
+
/* adjtimex mainly allows reading (and writing, if superuser) of
* kernel time-keeping variables. used by xntpd.
*/
@@ -398,6 +407,7 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0
txc->stbcnt = pps_stbcnt;
write_sequnlock_irq(&xtime_lock);
do_gettimeofday(&txc->time);
+ notify_arch_cmos_timer();
return(result);
}
@@ -494,6 +504,7 @@ void getnstimeofday (struct timespec *tv)
tv->tv_sec = sec;
tv->tv_nsec = nsec;
}
+EXPORT_SYMBOL_GPL(getnstimeofday);
int do_settimeofday (struct timespec *tv)
{
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index de912ff2d4d47..bceee34aa9791 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -17,7 +17,7 @@ config DEBUG_KERNEL
config MAGIC_SYSRQ
bool "Magic SysRq key"
- depends on DEBUG_KERNEL
+ depends on DEBUG_KERNEL && !UML
help
If you say Y here, you will have some control over the system even
if the system crashes for example during kernel debugging (e.g., you
diff --git a/mm/filemap.c b/mm/filemap.c
index 52e327480504a..553681db603d4 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1167,7 +1167,8 @@ static int fastcall page_cache_read(struct file * file, unsigned long offset)
* it in the page cache, and handles the special cases reasonably without
* having a lot of duplicated code.
*/
-struct page * filemap_nopage(struct vm_area_struct * area, unsigned long address, int *type)
+struct page *filemap_nopage(struct vm_area_struct *area,
+ unsigned long address, int *type)
{
int error;
struct file *file = area->vm_file;
@@ -1175,11 +1176,10 @@ struct page * filemap_nopage(struct vm_area_struct * area, unsigned long address
struct file_ra_state *ra = &file->f_ra;
struct inode *inode = mapping->host;
struct page *page;
- unsigned long size, pgoff, endoff;
+ unsigned long size, pgoff;
int did_readaround = 0, majmin = VM_FAULT_MINOR;
- pgoff = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
- endoff = ((area->vm_end - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
+ pgoff = ((address-area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
retry_all:
size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
@@ -1191,13 +1191,6 @@ retry_all:
goto no_cached_page;
/*
- * The "size" of the file, as far as mmap is concerned, isn't bigger
- * than the mapping
- */
- if (size > endoff)
- size = endoff;
-
- /*
* The readahead code wants to be told about each and every page
* so it can build and shrink its windows appropriately
*
diff --git a/mm/fremap.c b/mm/fremap.c
index 55bdaacff231f..3235fb77c1331 100644
--- a/mm/fremap.c
+++ b/mm/fremap.c
@@ -39,7 +39,7 @@ static inline void zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
set_page_dirty(page);
page_remove_rmap(page);
page_cache_release(page);
- mm->rss--;
+ dec_mm_counter(mm, rss);
}
}
} else {
@@ -92,7 +92,7 @@ int install_page(struct mm_struct *mm, struct vm_area_struct *vma,
zap_pte(mm, vma, addr, pte);
- mm->rss++;
+ inc_mm_counter(mm,rss);
flush_icache_page(vma, page);
set_pte_at(mm, addr, pte, mk_pte(page, prot));
page_add_file_rmap(page);
diff --git a/mm/memory.c b/mm/memory.c
index db09f2089ed27..fb6e5deb873a8 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -309,9 +309,9 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
pte = pte_mkclean(pte);
pte = pte_mkold(pte);
get_page(page);
- dst_mm->rss++;
+ inc_mm_counter(dst_mm, rss);
if (PageAnon(page))
- dst_mm->anon_rss++;
+ inc_mm_counter(dst_mm, anon_rss);
set_pte_at(dst_mm, addr, dst_pte, pte);
page_dup_rmap(page);
}
@@ -475,7 +475,7 @@ static void zap_pte_range(struct mmu_gather *tlb, pmd_t *pmd,
if (pte_dirty(ptent))
set_page_dirty(page);
if (PageAnon(page))
- tlb->mm->anon_rss--;
+ dec_mm_counter(tlb->mm, anon_rss);
else if (pte_young(ptent))
mark_page_accessed(page);
tlb->freed++;
@@ -1134,6 +1134,7 @@ static inline void break_cow(struct vm_area_struct * vma, struct page * new_page
vma);
ptep_establish(vma, address, page_table, entry);
update_mmu_cache(vma, address, entry);
+ lazy_mmu_prot_update(entry);
}
/*
@@ -1186,6 +1187,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
vma);
ptep_set_access_flags(vma, address, page_table, entry, 1);
update_mmu_cache(vma, address, entry);
+ lazy_mmu_prot_update(entry);
pte_unmap(page_table);
spin_unlock(&mm->page_table_lock);
return VM_FAULT_MINOR;
@@ -1219,9 +1221,9 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
page_table = pte_offset_map(pmd, address);
if (likely(pte_same(*page_table, pte))) {
if (PageAnon(old_page))
- mm->anon_rss--;
+ dec_mm_counter(mm, anon_rss);
if (PageReserved(old_page))
- ++mm->rss;
+ inc_mm_counter(mm, rss);
else
page_remove_rmap(old_page);
flush_cache_page(vma, address, pfn);
@@ -1627,7 +1629,7 @@ static int do_swap_page(struct mm_struct * mm,
if (vm_swap_full())
remove_exclusive_swap_page(page);
- mm->rss++;
+ inc_mm_counter(mm, rss);
pte = mk_pte(page, vma->vm_page_prot);
if (write_access && can_share_swap_page(page)) {
pte = maybe_mkwrite(pte_mkdirty(pte), vma);
@@ -1648,6 +1650,7 @@ static int do_swap_page(struct mm_struct * mm,
/* No need to invalidate - it was non-present before */
update_mmu_cache(vma, address, pte);
+ lazy_mmu_prot_update(pte);
pte_unmap(page_table);
spin_unlock(&mm->page_table_lock);
out:
@@ -1691,7 +1694,7 @@ do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
spin_unlock(&mm->page_table_lock);
goto out;
}
- mm->rss++;
+ inc_mm_counter(mm, rss);
entry = maybe_mkwrite(pte_mkdirty(mk_pte(page,
vma->vm_page_prot)),
vma);
@@ -1705,6 +1708,7 @@ do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
/* No need to invalidate - it was non-present before */
update_mmu_cache(vma, addr, entry);
+ lazy_mmu_prot_update(entry);
spin_unlock(&mm->page_table_lock);
out:
return VM_FAULT_MINOR;
@@ -1807,7 +1811,7 @@ retry:
/* Only go through if we didn't race with anybody else... */
if (pte_none(*page_table)) {
if (!PageReserved(new_page))
- ++mm->rss;
+ inc_mm_counter(mm, rss);
flush_icache_page(vma, new_page);
entry = mk_pte(new_page, vma->vm_page_prot);
@@ -1830,6 +1834,7 @@ retry:
/* no need to invalidate: a not-present page shouldn't be cached */
update_mmu_cache(vma, address, entry);
+ lazy_mmu_prot_update(entry);
spin_unlock(&mm->page_table_lock);
out:
return ret;
@@ -1924,6 +1929,7 @@ static inline int handle_pte_fault(struct mm_struct *mm,
entry = pte_mkyoung(entry);
ptep_set_access_flags(vma, address, pte, entry, write_access);
update_mmu_cache(vma, address, entry);
+ lazy_mmu_prot_update(entry);
pte_unmap(pte);
spin_unlock(&mm->page_table_lock);
return VM_FAULT_MINOR;
@@ -2112,8 +2118,10 @@ EXPORT_SYMBOL(vmalloc_to_pfn);
void update_mem_hiwater(struct task_struct *tsk)
{
if (tsk->mm) {
- if (tsk->mm->hiwater_rss < tsk->mm->rss)
- tsk->mm->hiwater_rss = tsk->mm->rss;
+ unsigned long rss = get_mm_counter(tsk->mm, rss);
+
+ if (tsk->mm->hiwater_rss < rss)
+ tsk->mm->hiwater_rss = rss;
if (tsk->mm->hiwater_vm < tsk->mm->total_vm)
tsk->mm->hiwater_vm = tsk->mm->total_vm;
}
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 6a2ae9718e943..a3b44a671cec2 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -788,12 +788,16 @@ alloc_page_vma(unsigned int __nocast gfp, struct vm_area_struct *vma, unsigned l
* Allocate a page from the kernel page pool. When not in
* interrupt context and apply the current process NUMA policy.
* Returns NULL when no page can be allocated.
+ *
+ * Don't call cpuset_update_current_mems_allowed() unless
+ * 1) it's ok to take cpuset_sem (can WAIT), and
+ * 2) allocating for current task (not interrupt).
*/
struct page *alloc_pages_current(unsigned int __nocast gfp, unsigned order)
{
struct mempolicy *pol = current->mempolicy;
- if (!in_interrupt())
+ if ((gfp & __GFP_WAIT) && !in_interrupt())
cpuset_update_current_mems_allowed();
if (!pol || in_interrupt())
pol = &default_policy;
diff --git a/mm/mmap.c b/mm/mmap.c
index 6629454f98396..a95ebda274462 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -896,16 +896,16 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
prot |= PROT_EXEC;
if (!len)
- return addr;
+ return -EINVAL;
/* Careful about overflows.. */
len = PAGE_ALIGN(len);
if (!len || len > TASK_SIZE)
- return -EINVAL;
+ return -ENOMEM;
/* offset overflow? */
if ((pgoff + (len >> PAGE_SHIFT)) < pgoff)
- return -EINVAL;
+ return -EOVERFLOW;
/* Too many mappings? */
if (mm->map_count > sysctl_max_map_count)
@@ -1316,7 +1316,7 @@ get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
* reserved hugepage range. For some archs like IA-64,
* there is a separate region for hugepages.
*/
- ret = is_hugepage_only_range(addr, len);
+ ret = is_hugepage_only_range(current->mm, addr, len);
}
if (ret)
return -EINVAL;
@@ -1687,7 +1687,7 @@ static void unmap_region(struct mm_struct *mm,
unmap_vmas(&tlb, mm, vma, start, end, &nr_accounted, NULL);
vm_unacct_memory(nr_accounted);
- if (is_hugepage_only_range(start, end - start))
+ if (is_hugepage_only_range(mm, start, end - start))
hugetlb_free_pgtables(tlb, prev, start, end);
else
free_pgtables(tlb, prev, start, end);
@@ -1978,7 +1978,7 @@ void exit_mmap(struct mm_struct *mm)
vma = mm->mmap;
mm->mmap = mm->mmap_cache = NULL;
mm->mm_rb = RB_ROOT;
- mm->rss = 0;
+ set_mm_counter(mm, rss, 0);
mm->total_vm = 0;
mm->locked_vm = 0;
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 7730c90f0e0b4..e9fbd013ad9af 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -39,8 +39,9 @@ static void change_pte_range(struct mm_struct *mm, pmd_t *pmd,
* bits by wiping the pte and then setting the new pte
* into place.
*/
- ptent = ptep_get_and_clear(mm, addr, pte);
- set_pte_at(mm, addr, pte, pte_modify(ptent, newprot));
+ ptent = pte_modify(ptep_get_and_clear(mm, addr, pte), newprot);
+ set_pte_at(mm, addr, pte, ptent);
+ lazy_mmu_prot_update(ptent);
}
} while (pte++, addr += PAGE_SIZE, addr != end);
pte_unmap(pte - 1);
@@ -189,14 +190,14 @@ sys_mprotect(unsigned long start, size_t len, unsigned long prot)
if (start & ~PAGE_MASK)
return -EINVAL;
+ if (!len)
+ return 0;
len = PAGE_ALIGN(len);
end = start + len;
- if (end < start)
+ if (end <= start)
return -ENOMEM;
if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM))
return -EINVAL;
- if (end == start)
- return 0;
reqprot = prot;
/*
diff --git a/mm/nommu.c b/mm/nommu.c
index f72d40c31a968..a9cf49a0e0350 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -961,9 +961,11 @@ void arch_unmap_area(struct vm_area_struct *area)
void update_mem_hiwater(struct task_struct *tsk)
{
+ unsigned long rss = get_mm_counter(tsk->mm, rss);
+
if (likely(tsk->mm)) {
- if (tsk->mm->hiwater_rss < tsk->mm->rss)
- tsk->mm->hiwater_rss = tsk->mm->rss;
+ if (tsk->mm->hiwater_rss < rss)
+ tsk->mm->hiwater_rss = rss;
if (tsk->mm->hiwater_vm < tsk->mm->total_vm)
tsk->mm->hiwater_vm = tsk->mm->total_vm;
}
diff --git a/mm/rmap.c b/mm/rmap.c
index 521fa4fa17bf1..884d6d1928bce 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -257,7 +257,7 @@ static int page_referenced_one(struct page *page,
pte_t *pte;
int referenced = 0;
- if (!mm->rss)
+ if (!get_mm_counter(mm, rss))
goto out;
address = vma_address(page, vma);
if (address == -EFAULT)
@@ -436,7 +436,7 @@ void page_add_anon_rmap(struct page *page,
BUG_ON(PageReserved(page));
BUG_ON(!anon_vma);
- vma->vm_mm->anon_rss++;
+ inc_mm_counter(vma->vm_mm, anon_rss);
anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
index = (address - vma->vm_start) >> PAGE_SHIFT;
@@ -509,7 +509,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma)
pte_t pteval;
int ret = SWAP_AGAIN;
- if (!mm->rss)
+ if (!get_mm_counter(mm, rss))
goto out;
address = vma_address(page, vma);
if (address == -EFAULT)
@@ -595,10 +595,10 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma)
}
set_pte_at(mm, address, pte, swp_entry_to_pte(entry));
BUG_ON(pte_file(*pte));
- mm->anon_rss--;
+ dec_mm_counter(mm, anon_rss);
}
- mm->rss--;
+ inc_mm_counter(mm, rss);
page_remove_rmap(page);
page_cache_release(page);
@@ -703,7 +703,7 @@ static void try_to_unmap_cluster(unsigned long cursor,
page_remove_rmap(page);
page_cache_release(page);
- mm->rss--;
+ dec_mm_counter(mm, rss);
(*mapcount)--;
}
@@ -802,7 +802,7 @@ static int try_to_unmap_file(struct page *page)
if (vma->vm_flags & (VM_LOCKED|VM_RESERVED))
continue;
cursor = (unsigned long) vma->vm_private_data;
- while (vma->vm_mm->rss &&
+ while (get_mm_counter(vma->vm_mm, rss) &&
cursor < max_nl_cursor &&
cursor < vma->vm_end - vma->vm_start) {
try_to_unmap_cluster(cursor, &mapcount, vma);
diff --git a/mm/slab.c b/mm/slab.c
index 15cad0b395267..ec660d85ddd76 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -507,10 +507,9 @@ static int slab_break_gfp_order = BREAK_GFP_ORDER_LO;
struct cache_sizes malloc_sizes[] = {
#define CACHE(x) { .cs_size = (x) },
#include <linux/kmalloc_sizes.h>
- { 0, }
+ CACHE(ULONG_MAX)
#undef CACHE
};
-
EXPORT_SYMBOL(malloc_sizes);
/* Must match cache_sizes above. Out of line to keep cache footprint low. */
@@ -574,7 +573,7 @@ static void free_block(kmem_cache_t* cachep, void** objpp, int len);
static void enable_cpucache (kmem_cache_t *cachep);
static void cache_reap (void *unused);
-static inline void ** ac_entry(struct array_cache *ac)
+static inline void **ac_entry(struct array_cache *ac)
{
return (void**)(ac+1);
}
@@ -584,24 +583,32 @@ static inline struct array_cache *ac_data(kmem_cache_t *cachep)
return cachep->array[smp_processor_id()];
}
-static kmem_cache_t * kmem_find_general_cachep (size_t size, int gfpflags)
+static inline kmem_cache_t *kmem_find_general_cachep(size_t size, int gfpflags)
{
struct cache_sizes *csizep = malloc_sizes;
- /* This function could be moved to the header file, and
- * made inline so consumers can quickly determine what
- * cache pointer they require.
+#if DEBUG
+ /* This happens if someone tries to call
+ * kmem_cache_create(), or __kmalloc(), before
+ * the generic caches are initialized.
+ */
+ BUG_ON(csizep->cs_cachep == NULL);
+#endif
+ while (size > csizep->cs_size)
+ csizep++;
+
+ /*
+ * Really subtile: The last entry with cs->cs_size==ULONG_MAX
+ * has cs_{dma,}cachep==NULL. Thus no special case
+ * for large kmalloc calls required.
*/
- for ( ; csizep->cs_size; csizep++) {
- if (size > csizep->cs_size)
- continue;
- break;
- }
- return (gfpflags & GFP_DMA) ? csizep->cs_dmacachep : csizep->cs_cachep;
+ if (unlikely(gfpflags & GFP_DMA))
+ return csizep->cs_dmacachep;
+ return csizep->cs_cachep;
}
/* Cal the num objs, wastage, and bytes left over for a given slab size. */
-static void cache_estimate (unsigned long gfporder, size_t size, size_t align,
+static void cache_estimate(unsigned long gfporder, size_t size, size_t align,
int flags, size_t *left_over, unsigned int *num)
{
int i;
@@ -659,7 +666,8 @@ static void __devinit start_cpu_timer(int cpu)
}
}
-static struct array_cache *alloc_arraycache(int cpu, int entries, int batchcount)
+static struct array_cache *alloc_arraycache(int cpu, int entries,
+ int batchcount)
{
int memsize = sizeof(void*)*entries+sizeof(struct array_cache);
struct array_cache *nc = NULL;
@@ -682,8 +690,7 @@ static struct array_cache *alloc_arraycache(int cpu, int entries, int batchcount
}
static int __devinit cpuup_callback(struct notifier_block *nfb,
- unsigned long action,
- void *hcpu)
+ unsigned long action, void *hcpu)
{
long cpu = (long)hcpu;
kmem_cache_t* cachep;
@@ -796,7 +803,7 @@ void __init kmem_cache_init(void)
sizes = malloc_sizes;
names = cache_names;
- while (sizes->cs_size) {
+ while (sizes->cs_size != ULONG_MAX) {
/* For performance, all the general caches are L1 aligned.
* This should be particularly beneficial on SMP boxes, as it
* eliminates "false sharing".
@@ -950,7 +957,8 @@ static void kmem_rcu_free(struct rcu_head *head)
#if DEBUG
#ifdef CONFIG_DEBUG_PAGEALLOC
-static void store_stackinfo(kmem_cache_t *cachep, unsigned long *addr, unsigned long caller)
+static void store_stackinfo(kmem_cache_t *cachep, unsigned long *addr,
+ unsigned long caller)
{
int size = obj_reallen(cachep);
@@ -1608,7 +1616,6 @@ int kmem_cache_shrink(kmem_cache_t *cachep)
return __cache_shrink(cachep);
}
-
EXPORT_SYMBOL(kmem_cache_shrink);
/**
@@ -1628,7 +1635,7 @@ EXPORT_SYMBOL(kmem_cache_shrink);
* The caller must guarantee that noone will allocate memory from the cache
* during the kmem_cache_destroy().
*/
-int kmem_cache_destroy (kmem_cache_t * cachep)
+int kmem_cache_destroy(kmem_cache_t * cachep)
{
int i;
@@ -1673,11 +1680,10 @@ int kmem_cache_destroy (kmem_cache_t * cachep)
return 0;
}
-
EXPORT_SYMBOL(kmem_cache_destroy);
/* Get the memory for a slab management obj. */
-static struct slab* alloc_slabmgmt (kmem_cache_t *cachep,
+static struct slab* alloc_slabmgmt(kmem_cache_t *cachep,
void *objp, int colour_off, unsigned int __nocast local_flags)
{
struct slab *slabp;
@@ -1703,8 +1709,8 @@ static inline kmem_bufctl_t *slab_bufctl(struct slab *slabp)
return (kmem_bufctl_t *)(slabp+1);
}
-static void cache_init_objs (kmem_cache_t * cachep,
- struct slab * slabp, unsigned long ctor_flags)
+static void cache_init_objs(kmem_cache_t *cachep,
+ struct slab *slabp, unsigned long ctor_flags)
{
int i;
@@ -1779,7 +1785,7 @@ static void set_slab_attr(kmem_cache_t *cachep, struct slab *slabp, void *objp)
* Grow (by 1) the number of slabs within a cache. This is called by
* kmem_cache_alloc() when there are no active objs left in a cache.
*/
-static int cache_grow (kmem_cache_t * cachep, unsigned int __nocast flags, int nodeid)
+static int cache_grow(kmem_cache_t *cachep, unsigned int __nocast flags, int nodeid)
{
struct slab *slabp;
void *objp;
@@ -1884,7 +1890,8 @@ static void kfree_debugcheck(const void *objp)
}
}
-static void *cache_free_debugcheck (kmem_cache_t * cachep, void * objp, void *caller)
+static void *cache_free_debugcheck(kmem_cache_t *cachep, void *objp,
+ void *caller)
{
struct page *page;
unsigned int objnr;
@@ -1952,18 +1959,17 @@ static void *cache_free_debugcheck (kmem_cache_t * cachep, void * objp, void *ca
static void check_slabp(kmem_cache_t *cachep, struct slab *slabp)
{
- int i;
+ kmem_bufctl_t i;
int entries = 0;
check_spinlock_acquired(cachep);
/* Check slab's freelist to see if this obj is there. */
for (i = slabp->free; i != BUFCTL_END; i = slab_bufctl(slabp)[i]) {
entries++;
- if (entries > cachep->num || i < 0 || i >= cachep->num)
+ if (entries > cachep->num || i >= cachep->num)
goto bad;
}
if (entries != cachep->num - slabp->inuse) {
- int i;
bad:
printk(KERN_ERR "slab: Internal list corruption detected in cache '%s'(%d), slabp %p(%d). Hexdump:\n",
cachep->name, cachep->num, slabp, slabp->inuse);
@@ -1982,7 +1988,7 @@ bad:
#define check_slabp(x,y) do { } while(0)
#endif
-static void* cache_alloc_refill(kmem_cache_t* cachep, unsigned int __nocast flags)
+static void *cache_alloc_refill(kmem_cache_t *cachep, unsigned int __nocast flags)
{
int batchcount;
struct kmem_list3 *l3;
@@ -2134,7 +2140,7 @@ cache_alloc_debugcheck_after(kmem_cache_t *cachep,
#endif
-static inline void * __cache_alloc (kmem_cache_t *cachep, unsigned int __nocast flags)
+static inline void *__cache_alloc(kmem_cache_t *cachep, unsigned int __nocast flags)
{
unsigned long save_flags;
void* objp;
@@ -2213,7 +2219,7 @@ static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects)
}
}
-static void cache_flusharray (kmem_cache_t* cachep, struct array_cache *ac)
+static void cache_flusharray(kmem_cache_t *cachep, struct array_cache *ac)
{
int batchcount;
@@ -2270,7 +2276,7 @@ free_done:
*
* Called with disabled ints.
*/
-static inline void __cache_free (kmem_cache_t *cachep, void* objp)
+static inline void __cache_free(kmem_cache_t *cachep, void *objp)
{
struct array_cache *ac = ac_data(cachep);
@@ -2296,11 +2302,10 @@ static inline void __cache_free (kmem_cache_t *cachep, void* objp)
* Allocate an object from this cache. The flags are only relevant
* if the cache has no available objects.
*/
-void * kmem_cache_alloc (kmem_cache_t *cachep, unsigned int __nocast flags)
+void *kmem_cache_alloc(kmem_cache_t *cachep, unsigned int __nocast flags)
{
return __cache_alloc(cachep, flags);
}
-
EXPORT_SYMBOL(kmem_cache_alloc);
/**
@@ -2453,26 +2458,15 @@ EXPORT_SYMBOL(kmem_cache_alloc_node);
* platforms. For example, on i386, it means that the memory must come
* from the first 16MB.
*/
-void * __kmalloc (size_t size, unsigned int __nocast flags)
+void *__kmalloc(size_t size, unsigned int __nocast flags)
{
- struct cache_sizes *csizep = malloc_sizes;
+ kmem_cache_t *cachep;
- for (; csizep->cs_size; csizep++) {
- if (size > csizep->cs_size)
- continue;
-#if DEBUG
- /* This happens if someone tries to call
- * kmem_cache_create(), or kmalloc(), before
- * the generic caches are initialized.
- */
- BUG_ON(csizep->cs_cachep == NULL);
-#endif
- return __cache_alloc(flags & GFP_DMA ?
- csizep->cs_dmacachep : csizep->cs_cachep, flags);
- }
- return NULL;
+ cachep = kmem_find_general_cachep(size, flags);
+ if (unlikely(cachep == NULL))
+ return NULL;
+ return __cache_alloc(cachep, flags);
}
-
EXPORT_SYMBOL(__kmalloc);
#ifdef CONFIG_SMP
@@ -2516,7 +2510,6 @@ unwind_oom:
kfree(pdata);
return NULL;
}
-
EXPORT_SYMBOL(__alloc_percpu);
#endif
@@ -2528,7 +2521,7 @@ EXPORT_SYMBOL(__alloc_percpu);
* Free an object which was previously allocated from this
* cache.
*/
-void kmem_cache_free (kmem_cache_t *cachep, void *objp)
+void kmem_cache_free(kmem_cache_t *cachep, void *objp)
{
unsigned long flags;
@@ -2536,7 +2529,6 @@ void kmem_cache_free (kmem_cache_t *cachep, void *objp)
__cache_free(cachep, objp);
local_irq_restore(flags);
}
-
EXPORT_SYMBOL(kmem_cache_free);
/**
@@ -2557,7 +2549,6 @@ void *kcalloc(size_t n, size_t size, unsigned int __nocast flags)
memset(ret, 0, n * size);
return ret;
}
-
EXPORT_SYMBOL(kcalloc);
/**
@@ -2567,12 +2558,12 @@ EXPORT_SYMBOL(kcalloc);
* Don't free memory not originally allocated by kmalloc()
* or you will run into trouble.
*/
-void kfree (const void *objp)
+void kfree(const void *objp)
{
kmem_cache_t *c;
unsigned long flags;
- if (!objp)
+ if (unlikely(!objp))
return;
local_irq_save(flags);
kfree_debugcheck(objp);
@@ -2580,7 +2571,6 @@ void kfree (const void *objp)
__cache_free(c, (void*)objp);
local_irq_restore(flags);
}
-
EXPORT_SYMBOL(kfree);
#ifdef CONFIG_SMP
@@ -2604,7 +2594,6 @@ free_percpu(const void *objp)
}
kfree(p);
}
-
EXPORT_SYMBOL(free_percpu);
#endif
@@ -2612,7 +2601,6 @@ unsigned int kmem_cache_size(kmem_cache_t *cachep)
{
return obj_reallen(cachep);
}
-
EXPORT_SYMBOL(kmem_cache_size);
struct ccupdate_struct {
@@ -2633,7 +2621,8 @@ static void do_ccupdate_local(void *info)
}
-static int do_tune_cpucache (kmem_cache_t* cachep, int limit, int batchcount, int shared)
+static int do_tune_cpucache(kmem_cache_t *cachep, int limit, int batchcount,
+ int shared)
{
struct ccupdate_struct new;
struct array_cache *new_shared;
@@ -2688,7 +2677,7 @@ static int do_tune_cpucache (kmem_cache_t* cachep, int limit, int batchcount, in
}
-static void enable_cpucache (kmem_cache_t *cachep)
+static void enable_cpucache(kmem_cache_t *cachep)
{
int err;
int limit, shared;
diff --git a/mm/swapfile.c b/mm/swapfile.c
index e2294292792b1..a60e0075d55bd 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -422,7 +422,7 @@ void free_swap_and_cache(swp_entry_t entry)
static void unuse_pte(struct vm_area_struct *vma, pte_t *pte,
unsigned long addr, swp_entry_t entry, struct page *page)
{
- vma->vm_mm->rss++;
+ inc_mm_counter(vma->vm_mm, rss);
get_page(page);
set_pte_at(vma->vm_mm, addr, pte,
pte_mkold(mk_pte(page, vma->vm_page_prot)));
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 7b862a98e7174..4003c0518d28e 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -546,14 +546,56 @@ keep:
}
/*
- * zone->lru_lock is heavily contented. We relieve it by quickly privatising
- * a batch of pages and working on them outside the lock. Any pages which were
- * not freed will be added back to the LRU.
+ * zone->lru_lock is heavily contended. Some of the functions that
+ * shrink the lists perform better by taking out a batch of pages
+ * and working on them outside the LRU lock.
*
- * shrink_cache() adds the number of pages reclaimed to sc->nr_reclaimed
+ * For pagecache intensive workloads, this function is the hottest
+ * spot in the kernel (apart from copy_*_user functions).
+ *
+ * Appropriate locks must be held before calling this function.
+ *
+ * @nr_to_scan: The number of pages to look through on the list.
+ * @src: The LRU list to pull pages off.
+ * @dst: The temp list to put pages on to.
+ * @scanned: The number of pages that were scanned.
*
- * For pagecache intensive workloads, the first loop here is the hottest spot
- * in the kernel (apart from the copy_*_user functions).
+ * returns how many pages were moved onto *@dst.
+ */
+static int isolate_lru_pages(int nr_to_scan, struct list_head *src,
+ struct list_head *dst, int *scanned)
+{
+ int nr_taken = 0;
+ struct page *page;
+ int scan = 0;
+
+ while (scan++ < nr_to_scan && !list_empty(src)) {
+ page = lru_to_page(src);
+ prefetchw_prev_lru_page(page, src, flags);
+
+ if (!TestClearPageLRU(page))
+ BUG();
+ list_del(&page->lru);
+ if (get_page_testone(page)) {
+ /*
+ * It is being freed elsewhere
+ */
+ __put_page(page);
+ SetPageLRU(page);
+ list_add(&page->lru, src);
+ continue;
+ } else {
+ list_add(&page->lru, dst);
+ nr_taken++;
+ }
+ }
+
+ *scanned = scan;
+ return nr_taken;
+}
+
+/*
+ * shrink_cache() adds the number of pages reclaimed to sc->nr_reclaimed
*/
static void shrink_cache(struct zone *zone, struct scan_control *sc)
{
@@ -567,32 +609,13 @@ static void shrink_cache(struct zone *zone, struct scan_control *sc)
spin_lock_irq(&zone->lru_lock);
while (max_scan > 0) {
struct page *page;
- int nr_taken = 0;
- int nr_scan = 0;
+ int nr_taken;
+ int nr_scan;
int nr_freed;
- while (nr_scan++ < sc->swap_cluster_max &&
- !list_empty(&zone->inactive_list)) {
- page = lru_to_page(&zone->inactive_list);
-
- prefetchw_prev_lru_page(page,
- &zone->inactive_list, flags);
-
- if (!TestClearPageLRU(page))
- BUG();
- list_del(&page->lru);
- if (get_page_testone(page)) {
- /*
- * It is being freed elsewhere
- */
- __put_page(page);
- SetPageLRU(page);
- list_add(&page->lru, &zone->inactive_list);
- continue;
- }
- list_add(&page->lru, &page_list);
- nr_taken++;
- }
+ nr_taken = isolate_lru_pages(sc->swap_cluster_max,
+ &zone->inactive_list,
+ &page_list, &nr_scan);
zone->nr_inactive -= nr_taken;
zone->pages_scanned += nr_scan;
spin_unlock_irq(&zone->lru_lock);
@@ -658,7 +681,7 @@ refill_inactive_zone(struct zone *zone, struct scan_control *sc)
{
int pgmoved;
int pgdeactivate = 0;
- int pgscanned = 0;
+ int pgscanned;
int nr_pages = sc->nr_to_scan;
LIST_HEAD(l_hold); /* The pages which were snipped off */
LIST_HEAD(l_inactive); /* Pages to go onto the inactive_list */
@@ -671,30 +694,9 @@ refill_inactive_zone(struct zone *zone, struct scan_control *sc)
long swap_tendency;
lru_add_drain();
- pgmoved = 0;
spin_lock_irq(&zone->lru_lock);
- while (pgscanned < nr_pages && !list_empty(&zone->active_list)) {
- page = lru_to_page(&zone->active_list);
- prefetchw_prev_lru_page(page, &zone->active_list, flags);
- if (!TestClearPageLRU(page))
- BUG();
- list_del(&page->lru);
- if (get_page_testone(page)) {
- /*
- * It was already free! release_pages() or put_page()
- * are about to remove it from the LRU and free it. So
- * put the refcount back and put the page back on the
- * LRU
- */
- __put_page(page);
- SetPageLRU(page);
- list_add(&page->lru, &zone->active_list);
- } else {
- list_add(&page->lru, &l_hold);
- pgmoved++;
- }
- pgscanned++;
- }
+ pgmoved = isolate_lru_pages(nr_pages, &zone->active_list,
+ &l_hold, &pgscanned);
zone->pages_scanned += pgscanned;
zone->nr_active -= pgmoved;
spin_unlock_irq(&zone->lru_lock);
diff --git a/net/rxrpc/krxiod.c b/net/rxrpc/krxiod.c
index c987395e57838..2b537f425a17d 100644
--- a/net/rxrpc/krxiod.c
+++ b/net/rxrpc/krxiod.c
@@ -138,6 +138,8 @@ static int rxrpc_krxiod(void *arg)
_debug("### End Work");
+ try_to_freeze(PF_FREEZE);
+
/* discard pending signals */
rxrpc_discard_my_signals();
diff --git a/net/rxrpc/krxsecd.c b/net/rxrpc/krxsecd.c
index 117aa91537a1b..6020c89d92288 100644
--- a/net/rxrpc/krxsecd.c
+++ b/net/rxrpc/krxsecd.c
@@ -107,6 +107,8 @@ static int rxrpc_krxsecd(void *arg)
_debug("### End Inbound Calls");
+ try_to_freeze(PF_FREEZE);
+
/* discard pending signals */
rxrpc_discard_my_signals();
diff --git a/net/rxrpc/krxtimod.c b/net/rxrpc/krxtimod.c
index 0d9e9d2f8eed6..249c2b0290bbf 100644
--- a/net/rxrpc/krxtimod.c
+++ b/net/rxrpc/krxtimod.c
@@ -90,6 +90,8 @@ static int krxtimod(void *arg)
complete_and_exit(&krxtimod_dead, 0);
}
+ try_to_freeze(PF_FREEZE);
+
/* discard pending signals */
rxrpc_discard_my_signals();
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 7794c16d84bb2..05907035bc961 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1186,6 +1186,7 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
arg->len = (pages-1)*PAGE_SIZE;
arg->tail[0].iov_len = 0;
+ try_to_freeze(PF_FREEZE);
if (signalled())
return -EINTR;
diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl
index 13ab0bef7e037..dadfa20ffec01 100644
--- a/scripts/checkstack.pl
+++ b/scripts/checkstack.pl
@@ -79,8 +79,8 @@ my (@stack, $re, $x, $xs);
sub bysize($) {
my ($asize, $bsize);
- ($asize = $a) =~ s/.* +(.*)$/$1/;
- ($bsize = $b) =~ s/.* +(.*)$/$1/;
+ ($asize = $a) =~ s/.*: *(.*)$/$1/;
+ ($bsize = $b) =~ s/.*: *(.*)$/$1/;
$bsize <=> $asize
}
diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c
index c5cf71535a9f4..6fdbe6e3ce0dc 100644
--- a/scripts/kconfig/gconf.c
+++ b/scripts/kconfig/gconf.c
@@ -11,6 +11,7 @@
#endif
#include "lkc.h"
+#include "images.c"
#include <glade/glade.h>
#include <gtk/gtk.h>
@@ -186,6 +187,8 @@ void init_main_window(const gchar * glade_file)
GtkWidget *widget;
GtkTextBuffer *txtbuf;
char title[256];
+ GdkPixmap *pixmap;
+ GdkBitmap *mask;
GtkStyle *style;
xml = glade_xml_new(glade_file, "window1", NULL);
@@ -218,6 +221,36 @@ void init_main_window(const gchar * glade_file)
style = gtk_widget_get_style(main_wnd);
widget = glade_xml_get_widget(xml, "toolbar1");
+ pixmap = gdk_pixmap_create_from_xpm_d(main_wnd->window, &mask,
+ &style->bg[GTK_STATE_NORMAL],
+ (gchar **) xpm_single_view);
+ gtk_image_set_from_pixmap(GTK_IMAGE
+ (((GtkToolbarChild
+ *) (g_list_nth(GTK_TOOLBAR(widget)->
+ children,
+ 5)->data))->icon),
+ pixmap, mask);
+ pixmap =
+ gdk_pixmap_create_from_xpm_d(main_wnd->window, &mask,
+ &style->bg[GTK_STATE_NORMAL],
+ (gchar **) xpm_split_view);
+ gtk_image_set_from_pixmap(GTK_IMAGE
+ (((GtkToolbarChild
+ *) (g_list_nth(GTK_TOOLBAR(widget)->
+ children,
+ 6)->data))->icon),
+ pixmap, mask);
+ pixmap =
+ gdk_pixmap_create_from_xpm_d(main_wnd->window, &mask,
+ &style->bg[GTK_STATE_NORMAL],
+ (gchar **) xpm_tree_view);
+ gtk_image_set_from_pixmap(GTK_IMAGE
+ (((GtkToolbarChild
+ *) (g_list_nth(GTK_TOOLBAR(widget)->
+ children,
+ 7)->data))->icon),
+ pixmap, mask);
+
switch (view_mode) {
case SINGLE_VIEW:
widget = glade_xml_get_widget(xml, "button4");
@@ -1139,42 +1172,6 @@ on_treeview1_button_press_event(GtkWidget * widget,
}
-/* Conf management */
-
-static const char *xpm_menu[] = {
-"12 12 2 1",
-" c white",
-". c black",
-" ",
-" ",
-" . ",
-" .. ",
-" ... ",
-" .... ",
-" ..... ",
-" .... ",
-" ... ",
-" .. ",
-" . ",
-" "};
-
-static const char *xpm_void[] = {
-"12 12 2 1",
-" c white",
-". c black",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" "};
-
/* Fill a row of strings */
static gchar **fill_row(struct menu *menu)
{
diff --git a/scripts/kconfig/gconf.glade b/scripts/kconfig/gconf.glade
index 5ed75a7aeece8..1e1736d81ee95 100644
--- a/scripts/kconfig/gconf.glade
+++ b/scripts/kconfig/gconf.glade
@@ -310,13 +310,13 @@
<property name="tooltips">True</property>
<child>
- <widget class="GtkToolButton" id="button1">
+ <widget class="button" id="button1">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Goes up of one level (single view)</property>
<property name="label" translatable="yes">Back</property>
<property name="use_underline">True</property>
- <property name="stock-id">gtk-undo</property>
- <signal name="clicked" handler="on_back_pressed"/>
+ <property name="stock_pixmap">gtk-undo</property>
+ <signal name="pressed" handler="on_back_pressed"/>
</widget>
</child>
@@ -327,24 +327,24 @@
</child>
<child>
- <widget class="GtkToolButton" id="button2">
+ <widget class="button" id="button2">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Load a config file</property>
<property name="label" translatable="yes">Load</property>
<property name="use_underline">True</property>
- <property name="stock-id">gtk-open</property>
- <signal name="clicked" handler="on_load_pressed"/>
+ <property name="stock_pixmap">gtk-open</property>
+ <signal name="pressed" handler="on_load_pressed"/>
</widget>
</child>
<child>
- <widget class="GtkToolButton" id="button3">
+ <widget class="button" id="button3">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Save a config file</property>
<property name="label" translatable="yes">Save</property>
<property name="use_underline">True</property>
- <property name="stock-id">gtk-save</property>
- <signal name="clicked" handler="on_save_pressed"/>
+ <property name="stock_pixmap">gtk-save</property>
+ <signal name="pressed" handler="on_save_pressed"/>
</widget>
</child>
@@ -355,34 +355,34 @@
</child>
<child>
- <widget class="GtkToolButton" id="button4">
+ <widget class="button" id="button4">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Single view</property>
<property name="label" translatable="yes">Single</property>
<property name="use_underline">True</property>
- <property name="stock-id">gtk-indent</property>
+ <property name="stock_pixmap">gtk-missing-image</property>
<signal name="clicked" handler="on_single_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:39 GMT"/>
</widget>
</child>
<child>
- <widget class="GtkToolButton" id="button5">
+ <widget class="button" id="button5">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Split view</property>
<property name="label" translatable="yes">Split</property>
<property name="use_underline">True</property>
- <property name="stock-id">gtk-copy</property>
+ <property name="stock_pixmap">gtk-missing-image</property>
<signal name="clicked" handler="on_split_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:45 GMT"/>
</widget>
</child>
<child>
- <widget class="GtkToolButton" id="button6">
+ <widget class="button" id="button6">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Full view</property>
<property name="label" translatable="yes">Full</property>
<property name="use_underline">True</property>
- <property name="stock-id">gtk-justify-left</property>
+ <property name="stock_pixmap">gtk-missing-image</property>
<signal name="clicked" handler="on_full_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:50 GMT"/>
</widget>
</child>
@@ -394,24 +394,22 @@
</child>
<child>
- <widget class="GtkToolButton" id="button7">
+ <widget class="button" id="button7">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Collapse the whole tree in the right frame</property>
<property name="label" translatable="yes">Collapse</property>
<property name="use_underline">True</property>
- <property name="stock-id">gtk-zoom-out</property>
- <signal name="clicked" handler="on_collapse_pressed"/>
+ <signal name="pressed" handler="on_collapse_pressed"/>
</widget>
</child>
<child>
- <widget class="GtkToolButton" id="button8">
+ <widget class="button" id="button8">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Expand the whole tree in the right frame</property>
<property name="label" translatable="yes">Expand</property>
<property name="use_underline">True</property>
- <property name="stock-id">gtk-zoom-in</property>
- <signal name="clicked" handler="on_expand_pressed"/>
+ <signal name="pressed" handler="on_expand_pressed"/>
</widget>
</child>
</widget>
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index fc683fadae5ff..fe6285e5c68f8 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -139,7 +139,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
* @tclass: target security class
* @av: access vector
*/
-void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
+static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
{
const char **common_pts = NULL;
u32 common_base = 0;
@@ -199,7 +199,7 @@ void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
* @tsid: target security identifier
* @tclass: target security class
*/
-void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tclass)
+static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tclass)
{
int rc;
char *scontext;
@@ -828,136 +828,6 @@ out:
return rc;
}
-static int avc_update_cache(u32 event, u32 ssid, u32 tsid,
- u16 tclass, u32 perms)
-{
- struct avc_node *node;
- int i;
-
- rcu_read_lock();
-
- if (ssid == SECSID_WILD || tsid == SECSID_WILD) {
- /* apply to all matching nodes */
- for (i = 0; i < AVC_CACHE_SLOTS; i++) {
- list_for_each_entry_rcu(node, &avc_cache.slots[i], list) {
- if (avc_sidcmp(ssid, node->ae.ssid) &&
- avc_sidcmp(tsid, node->ae.tsid) &&
- tclass == node->ae.tclass ) {
- avc_update_node(event, perms, node->ae.ssid,
- node->ae.tsid, node->ae.tclass);
- }
- }
- }
- } else {
- /* apply to one node */
- avc_update_node(event, perms, ssid, tsid, tclass);
- }
-
- rcu_read_unlock();
-
- return 0;
-}
-
-static int avc_control(u32 event, u32 ssid, u32 tsid,
- u16 tclass, u32 perms,
- u32 seqno, u32 *out_retained)
-{
- struct avc_callback_node *c;
- u32 tretained = 0, cretained = 0;
- int rc = 0;
-
- /*
- * try_revoke only removes permissions from the cache
- * state if they are not retained by the object manager.
- * Hence, try_revoke must wait until after the callbacks have
- * been invoked to update the cache state.
- */
- if (event != AVC_CALLBACK_TRY_REVOKE)
- avc_update_cache(event,ssid,tsid,tclass,perms);
-
- for (c = avc_callbacks; c; c = c->next)
- {
- if ((c->events & event) &&
- avc_sidcmp(c->ssid, ssid) &&
- avc_sidcmp(c->tsid, tsid) &&
- c->tclass == tclass &&
- (c->perms & perms)) {
- cretained = 0;
- rc = c->callback(event, ssid, tsid, tclass,
- (c->perms & perms),
- &cretained);
- if (rc)
- goto out;
- tretained |= cretained;
- }
- }
-
- if (event == AVC_CALLBACK_TRY_REVOKE) {
- /* revoke any unretained permissions */
- perms &= ~tretained;
- avc_update_cache(event,ssid,tsid,tclass,perms);
- *out_retained = tretained;
- }
-
- avc_latest_notif_update(seqno, 0);
-
-out:
- return rc;
-}
-
-/**
- * avc_ss_grant - Grant previously denied permissions.
- * @ssid: source security identifier or %SECSID_WILD
- * @tsid: target security identifier or %SECSID_WILD
- * @tclass: target security class
- * @perms: permissions to grant
- * @seqno: policy sequence number
- */
-int avc_ss_grant(u32 ssid, u32 tsid, u16 tclass,
- u32 perms, u32 seqno)
-{
- return avc_control(AVC_CALLBACK_GRANT,
- ssid, tsid, tclass, perms, seqno, NULL);
-}
-
-/**
- * avc_ss_try_revoke - Try to revoke previously granted permissions.
- * @ssid: source security identifier or %SECSID_WILD
- * @tsid: target security identifier or %SECSID_WILD
- * @tclass: target security class
- * @perms: permissions to grant
- * @seqno: policy sequence number
- * @out_retained: subset of @perms that are retained
- *
- * Try to revoke previously granted permissions, but
- * only if they are not retained as migrated permissions.
- * Return the subset of permissions that are retained via @out_retained.
- */
-int avc_ss_try_revoke(u32 ssid, u32 tsid, u16 tclass,
- u32 perms, u32 seqno, u32 *out_retained)
-{
- return avc_control(AVC_CALLBACK_TRY_REVOKE,
- ssid, tsid, tclass, perms, seqno, out_retained);
-}
-
-/**
- * avc_ss_revoke - Revoke previously granted permissions.
- * @ssid: source security identifier or %SECSID_WILD
- * @tsid: target security identifier or %SECSID_WILD
- * @tclass: target security class
- * @perms: permissions to grant
- * @seqno: policy sequence number
- *
- * Revoke previously granted permissions, even if
- * they are retained as migrated permissions.
- */
-int avc_ss_revoke(u32 ssid, u32 tsid, u16 tclass,
- u32 perms, u32 seqno)
-{
- return avc_control(AVC_CALLBACK_REVOKE,
- ssid, tsid, tclass, perms, seqno, NULL);
-}
-
/**
* avc_ss_reset - Flush the cache and revalidate migrated permissions.
* @seqno: policy sequence number
@@ -991,46 +861,6 @@ out:
}
/**
- * avc_ss_set_auditallow - Enable or disable auditing of granted permissions.
- * @ssid: source security identifier or %SECSID_WILD
- * @tsid: target security identifier or %SECSID_WILD
- * @tclass: target security class
- * @perms: permissions to grant
- * @seqno: policy sequence number
- * @enable: enable flag.
- */
-int avc_ss_set_auditallow(u32 ssid, u32 tsid, u16 tclass,
- u32 perms, u32 seqno, u32 enable)
-{
- if (enable)
- return avc_control(AVC_CALLBACK_AUDITALLOW_ENABLE,
- ssid, tsid, tclass, perms, seqno, NULL);
- else
- return avc_control(AVC_CALLBACK_AUDITALLOW_DISABLE,
- ssid, tsid, tclass, perms, seqno, NULL);
-}
-
-/**
- * avc_ss_set_auditdeny - Enable or disable auditing of denied permissions.
- * @ssid: source security identifier or %SECSID_WILD
- * @tsid: target security identifier or %SECSID_WILD
- * @tclass: target security class
- * @perms: permissions to grant
- * @seqno: policy sequence number
- * @enable: enable flag.
- */
-int avc_ss_set_auditdeny(u32 ssid, u32 tsid, u16 tclass,
- u32 perms, u32 seqno, u32 enable)
-{
- if (enable)
- return avc_control(AVC_CALLBACK_AUDITDENY_ENABLE,
- ssid, tsid, tclass, perms, seqno, NULL);
- else
- return avc_control(AVC_CALLBACK_AUDITDENY_DISABLE,
- ssid, tsid, tclass, perms, seqno, NULL);
-}
-
-/**
* avc_has_perm_noaudit - Check permissions but perform no auditing.
* @ssid: source security identifier
* @tsid: target security identifier
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 63e47c020a0f1..8c5dd09a89b40 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -67,6 +67,7 @@
#include <linux/hugetlb.h>
#include <linux/personality.h>
#include <linux/sysctl.h>
+#include <linux/audit.h>
#include "avc.h"
#include "objsec.h"
@@ -829,7 +830,9 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
__FUNCTION__, context, -rc,
inode->i_sb->s_id, inode->i_ino);
kfree(context);
- goto out;
+ /* Leave with the unlabeled SID */
+ rc = 0;
+ break;
}
}
kfree(context);
@@ -921,9 +924,9 @@ static inline u32 signal_to_av(int sig)
/* Check permission betweeen a pair of tasks, e.g. signal checks,
fork check, ptrace check, etc. */
-int task_has_perm(struct task_struct *tsk1,
- struct task_struct *tsk2,
- u32 perms)
+static int task_has_perm(struct task_struct *tsk1,
+ struct task_struct *tsk2,
+ u32 perms)
{
struct task_security_struct *tsec1, *tsec2;
@@ -934,8 +937,8 @@ int task_has_perm(struct task_struct *tsk1,
}
/* Check whether a task is allowed to use a capability. */
-int task_has_capability(struct task_struct *tsk,
- int cap)
+static int task_has_capability(struct task_struct *tsk,
+ int cap)
{
struct task_security_struct *tsec;
struct avc_audit_data ad;
@@ -951,8 +954,8 @@ int task_has_capability(struct task_struct *tsk,
}
/* Check whether a task is allowed to use a system operation. */
-int task_has_system(struct task_struct *tsk,
- u32 perms)
+static int task_has_system(struct task_struct *tsk,
+ u32 perms)
{
struct task_security_struct *tsec;
@@ -965,10 +968,10 @@ int task_has_system(struct task_struct *tsk,
/* Check whether a task has a particular permission to an inode.
The 'adp' parameter is optional and allows other audit
data to be passed (e.g. the dentry). */
-int inode_has_perm(struct task_struct *tsk,
- struct inode *inode,
- u32 perms,
- struct avc_audit_data *adp)
+static int inode_has_perm(struct task_struct *tsk,
+ struct inode *inode,
+ u32 perms,
+ struct avc_audit_data *adp)
{
struct task_security_struct *tsec;
struct inode_security_struct *isec;
@@ -1190,10 +1193,10 @@ static inline int may_rename(struct inode *old_dir,
}
/* Check whether a task can perform a filesystem operation. */
-int superblock_has_perm(struct task_struct *tsk,
- struct super_block *sb,
- u32 perms,
- struct avc_audit_data *ad)
+static int superblock_has_perm(struct task_struct *tsk,
+ struct super_block *sb,
+ u32 perms,
+ struct avc_audit_data *ad)
{
struct task_security_struct *tsec;
struct superblock_security_struct *sbsec;
@@ -1250,7 +1253,7 @@ static inline u32 file_to_av(struct file *file)
}
/* Set an inode's SID to a specified value. */
-int inode_security_set_sid(struct inode *inode, u32 sid)
+static int inode_security_set_sid(struct inode *inode, u32 sid)
{
struct inode_security_struct *isec = inode->i_security;
struct superblock_security_struct *sbsec = inode->i_sb->s_security;
@@ -3091,7 +3094,53 @@ out:
static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
{
- return socket_has_perm(current, sock, SOCKET__CONNECT);
+ struct inode_security_struct *isec;
+ int err;
+
+ err = socket_has_perm(current, sock, SOCKET__CONNECT);
+ if (err)
+ return err;
+
+ /*
+ * If a TCP socket, check name_connect permission for the port.
+ */
+ isec = SOCK_INODE(sock)->i_security;
+ if (isec->sclass == SECCLASS_TCP_SOCKET) {
+ struct sock *sk = sock->sk;
+ struct avc_audit_data ad;
+ struct sockaddr_in *addr4 = NULL;
+ struct sockaddr_in6 *addr6 = NULL;
+ unsigned short snum;
+ u32 sid;
+
+ if (sk->sk_family == PF_INET) {
+ addr4 = (struct sockaddr_in *)address;
+ if (addrlen != sizeof(struct sockaddr_in))
+ return -EINVAL;
+ snum = ntohs(addr4->sin_port);
+ } else {
+ addr6 = (struct sockaddr_in6 *)address;
+ if (addrlen != sizeof(struct sockaddr_in6))
+ return -EINVAL;
+ snum = ntohs(addr6->sin6_port);
+ }
+
+ err = security_port_sid(sk->sk_family, sk->sk_type,
+ sk->sk_protocol, snum, &sid);
+ if (err)
+ goto out;
+
+ AVC_AUDIT_DATA_INIT(&ad,NET);
+ ad.u.net.dport = htons(snum);
+ ad.u.net.family = sk->sk_family;
+ err = avc_has_perm(isec->sid, sid, isec->sclass,
+ TCP_SOCKET__NAME_CONNECT, &ad);
+ if (err)
+ goto out;
+ }
+
+out:
+ return err;
}
static int selinux_socket_listen(struct socket *sock, int backlog)
@@ -3383,6 +3432,15 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
if (err) {
+ if (err == -EINVAL) {
+ audit_log(current->audit_context,
+ "SELinux: unrecognized netlink message"
+ " type=%hu for sclass=%hu\n",
+ nlh->nlmsg_type, isec->sclass);
+ if (!selinux_enforcing)
+ err = 0;
+ }
+
/* Ignore */
if (err == -ENOENT)
err = 0;
@@ -4019,7 +4077,7 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
}
/* module stacking operations */
-int selinux_register_security (const char *name, struct security_operations *ops)
+static int selinux_register_security (const char *name, struct security_operations *ops)
{
if (secondary_ops != original_ops) {
printk(KERN_INFO "%s: There is already a secondary security "
@@ -4036,7 +4094,7 @@ int selinux_register_security (const char *name, struct security_operations *ops
return 0;
}
-int selinux_unregister_security (const char *name, struct security_operations *ops)
+static int selinux_unregister_security (const char *name, struct security_operations *ops)
{
if (ops != secondary_ops) {
printk (KERN_INFO "%s: trying to unregister a security module "
@@ -4203,7 +4261,7 @@ static int selinux_setprocattr(struct task_struct *p,
return size;
}
-struct security_operations selinux_ops = {
+static struct security_operations selinux_ops = {
.ptrace = selinux_ptrace,
.capget = selinux_capget,
.capset_check = selinux_capset_check,
@@ -4352,7 +4410,7 @@ struct security_operations selinux_ops = {
#endif
};
-__init int selinux_init(void)
+static __init int selinux_init(void)
{
struct task_security_struct *tsec;
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
index 32fbeeffaca4a..903e8b3cc2e9d 100644
--- a/security/selinux/include/av_perm_to_string.h
+++ b/security/selinux/include/av_perm_to_string.h
@@ -25,6 +25,7 @@
S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NEWCONN, "newconn")
S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__ACCEPTFROM, "acceptfrom")
S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NODE_BIND, "node_bind")
+ S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NAME_CONNECT, "name_connect")
S_(SECCLASS_UDP_SOCKET, UDP_SOCKET__NODE_BIND, "node_bind")
S_(SECCLASS_RAWIP_SOCKET, RAWIP_SOCKET__NODE_BIND, "node_bind")
S_(SECCLASS_NODE, NODE__TCP_RECV, "tcp_recv")
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
index 6b06f5e3a5d10..b0a12ac8f7eeb 100644
--- a/security/selinux/include/av_permissions.h
+++ b/security/selinux/include/av_permissions.h
@@ -253,6 +253,7 @@
#define TCP_SOCKET__NEWCONN 0x00800000UL
#define TCP_SOCKET__ACCEPTFROM 0x01000000UL
#define TCP_SOCKET__NODE_BIND 0x02000000UL
+#define TCP_SOCKET__NAME_CONNECT 0x04000000UL
#define UDP_SOCKET__IOCTL 0x00000001UL
#define UDP_SOCKET__READ 0x00000002UL
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index ca2fdf557b222..960ef18ddc411 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -93,13 +93,6 @@ struct avc_cache_stats
};
/*
- * AVC display support
- */
-struct audit_buffer;
-void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);
-void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tclass);
-
-/*
* AVC operations
*/
diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h
index 8fc999745e24e..450a2831e2e32 100644
--- a/security/selinux/include/avc_ss.h
+++ b/security/selinux/include/avc_ss.h
@@ -8,20 +8,7 @@
#include "flask.h"
-int avc_ss_grant(u32 ssid, u32 tsid, u16 tclass, u32 perms, u32 seqno);
-
-int avc_ss_try_revoke(u32 ssid, u32 tsid, u16 tclass, u32 perms, u32 seqno,
- u32 *out_retained);
-
-int avc_ss_revoke(u32 ssid, u32 tsid, u16 tclass, u32 perms, u32 seqno);
-
int avc_ss_reset(u32 seqno);
-int avc_ss_set_auditallow(u32 ssid, u32 tsid, u16 tclass, u32 perms,
- u32 seqno, u32 enable);
-
-int avc_ss_set_auditdeny(u32 ssid, u32 tsid, u16 tclass, u32 perms,
- u32 seqno, u32 enable);
-
#endif /* _SELINUX_AVC_SS_H_ */
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 350b2417d8a89..887937c8134a4 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -107,8 +107,6 @@ struct sk_security_struct {
u32 peer_sid; /* SID of peer */
};
-extern int inode_security_set_sid(struct inode *inode, u32 sid);
-
extern unsigned int selinux_checkreqprot;
#endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index b9f81b17ee197..07221568b5059 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -54,8 +54,8 @@ static int *bool_pending_values = NULL;
extern void selnl_notify_setenforce(int val);
/* Check whether a task is allowed to use a security operation. */
-int task_has_security(struct task_struct *tsk,
- u32 perms)
+static int task_has_security(struct task_struct *tsk,
+ u32 perms)
{
struct task_security_struct *tsec;
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index 609ca16be799f..f238c034c44e2 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -31,7 +31,8 @@
static kmem_cache_t *avtab_node_cachep;
static struct avtab_node*
-avtab_insert_node(struct avtab *h, int hvalue, struct avtab_node * prev, struct avtab_node * cur,
+avtab_insert_node(struct avtab *h, int hvalue,
+ struct avtab_node * prev, struct avtab_node * cur,
struct avtab_key *key, struct avtab_datum *datum)
{
struct avtab_node * newnode;
@@ -53,7 +54,7 @@ avtab_insert_node(struct avtab *h, int hvalue, struct avtab_node * prev, struct
return newnode;
}
-int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
+static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
{
int hvalue;
struct avtab_node *prev, *cur, *newnode;
@@ -237,30 +238,6 @@ void avtab_destroy(struct avtab *h)
}
-int avtab_map(struct avtab *h,
- int (*apply) (struct avtab_key *k,
- struct avtab_datum *d,
- void *args),
- void *args)
-{
- int i, ret;
- struct avtab_node *cur;
-
- if (!h)
- return 0;
-
- for (i = 0; i < AVTAB_SIZE; i++) {
- cur = h->htable[i];
- while (cur != NULL) {
- ret = apply(&cur->key, &cur->datum, args);
- if (ret)
- return ret;
- cur = cur->next;
- }
- }
- return 0;
-}
-
int avtab_init(struct avtab *h)
{
int i;
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h
index f636ac844a485..519d4f6dc655e 100644
--- a/security/selinux/ss/avtab.h
+++ b/security/selinux/ss/avtab.h
@@ -58,14 +58,8 @@ struct avtab {
};
int avtab_init(struct avtab *);
-int avtab_insert(struct avtab *h, struct avtab_key *k, struct avtab_datum *d);
struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k, int specified);
void avtab_destroy(struct avtab *h);
-int avtab_map(struct avtab *h,
- int (*apply) (struct avtab_key *k,
- struct avtab_datum *d,
- void *args),
- void *args);
void avtab_hash_eval(struct avtab *h, char *tag);
int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey);
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index 372e6a729b61b..b53441184aca7 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -208,7 +208,7 @@ int cond_index_bool(void *key, void *datum, void *datap)
return 0;
}
-int bool_isvalid(struct cond_bool_datum *b)
+static int bool_isvalid(struct cond_bool_datum *b)
{
if (!(b->state == 0 || b->state == 1))
return 0;
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index ad34294aa368a..d8ce9cc0b9f15 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -9,49 +9,6 @@
#include "ebitmap.h"
#include "policydb.h"
-int ebitmap_or(struct ebitmap *dst, struct ebitmap *e1, struct ebitmap *e2)
-{
- struct ebitmap_node *n1, *n2, *new, *prev;
-
- ebitmap_init(dst);
-
- n1 = e1->node;
- n2 = e2->node;
- prev = NULL;
- while (n1 || n2) {
- new = kmalloc(sizeof(*new), GFP_ATOMIC);
- if (!new) {
- ebitmap_destroy(dst);
- return -ENOMEM;
- }
- memset(new, 0, sizeof(*new));
- if (n1 && n2 && n1->startbit == n2->startbit) {
- new->startbit = n1->startbit;
- new->map = n1->map | n2->map;
- n1 = n1->next;
- n2 = n2->next;
- } else if (!n2 || (n1 && n1->startbit < n2->startbit)) {
- new->startbit = n1->startbit;
- new->map = n1->map;
- n1 = n1->next;
- } else {
- new->startbit = n2->startbit;
- new->map = n2->map;
- n2 = n2->next;
- }
-
- new->next = NULL;
- if (prev)
- prev->next = new;
- else
- dst->node = new;
- prev = new;
- }
-
- dst->highbit = (e1->highbit > e2->highbit) ? e1->highbit : e2->highbit;
- return 0;
-}
-
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
{
struct ebitmap_node *n1, *n2;
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index 321764c23cf58..471370233fd9e 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -38,7 +38,6 @@ static inline void ebitmap_init(struct ebitmap *e)
}
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
-int ebitmap_or(struct ebitmap *dst, struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c
index 2a6752a8d016b..26661fcc00ce3 100644
--- a/security/selinux/ss/hashtab.c
+++ b/security/selinux/ss/hashtab.c
@@ -73,81 +73,6 @@ int hashtab_insert(struct hashtab *h, void *key, void *datum)
return 0;
}
-int hashtab_remove(struct hashtab *h, void *key,
- void (*destroy)(void *k, void *d, void *args),
- void *args)
-{
- u32 hvalue;
- struct hashtab_node *cur, *last;
-
- if (!h)
- return -EINVAL;
-
- hvalue = h->hash_value(h, key);
- last = NULL;
- cur = h->htable[hvalue];
- while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
- last = cur;
- cur = cur->next;
- }
-
- if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
- return -ENOENT;
-
- if (last == NULL)
- h->htable[hvalue] = cur->next;
- else
- last->next = cur->next;
-
- if (destroy)
- destroy(cur->key, cur->datum, args);
- kfree(cur);
- h->nel--;
- return 0;
-}
-
-int hashtab_replace(struct hashtab *h, void *key, void *datum,
- void (*destroy)(void *k, void *d, void *args),
- void *args)
-{
- u32 hvalue;
- struct hashtab_node *prev, *cur, *newnode;
-
- if (!h)
- return -EINVAL;
-
- hvalue = h->hash_value(h, key);
- prev = NULL;
- cur = h->htable[hvalue];
- while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
- prev = cur;
- cur = cur->next;
- }
-
- if (cur && (h->keycmp(h, key, cur->key) == 0)) {
- if (destroy)
- destroy(cur->key, cur->datum, args);
- cur->key = key;
- cur->datum = datum;
- } else {
- newnode = kmalloc(sizeof(*newnode), GFP_KERNEL);
- if (newnode == NULL)
- return -ENOMEM;
- memset(newnode, 0, sizeof(*newnode));
- newnode->key = key;
- newnode->datum = datum;
- if (prev) {
- newnode->next = prev->next;
- prev->next = newnode;
- } else {
- newnode->next = h->htable[hvalue];
- h->htable[hvalue] = newnode;
- }
- }
-
- return 0;
-}
-
void *hashtab_search(struct hashtab *h, void *key)
{
u32 hvalue;
@@ -215,44 +140,6 @@ int hashtab_map(struct hashtab *h,
}
-void hashtab_map_remove_on_error(struct hashtab *h,
- int (*apply)(void *k, void *d, void *args),
- void (*destroy)(void *k, void *d, void *args),
- void *args)
-{
- u32 i;
- int ret;
- struct hashtab_node *last, *cur, *temp;
-
- if (!h)
- return;
-
- for (i = 0; i < h->size; i++) {
- last = NULL;
- cur = h->htable[i];
- while (cur != NULL) {
- ret = apply(cur->key, cur->datum, args);
- if (ret) {
- if (last)
- last->next = cur->next;
- else
- h->htable[i] = cur->next;
-
- temp = cur;
- cur = cur->next;
- if (destroy)
- destroy(temp->key, temp->datum, args);
- kfree(temp);
- h->nel--;
- } else {
- last = cur;
- cur = cur->next;
- }
- }
- }
- return;
-}
-
void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
{
u32 i, chain_len, slots_used, max_chain_len;
diff --git a/security/selinux/ss/hashtab.h b/security/selinux/ss/hashtab.h
index 10c3be19605fd..4cc85816a718a 100644
--- a/security/selinux/ss/hashtab.h
+++ b/security/selinux/ss/hashtab.h
@@ -54,33 +54,6 @@ struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key),
int hashtab_insert(struct hashtab *h, void *k, void *d);
/*
- * Removes the entry with the specified key from the hash table.
- * Applies the specified destroy function to (key,datum,args) for
- * the entry.
- *
- * Returns -ENOENT if no entry has the specified key,
- * -EINVAL for general errors or
- *0 otherwise.
- */
-int hashtab_remove(struct hashtab *h, void *k,
- void (*destroy)(void *k, void *d, void *args),
- void *args);
-
-/*
- * Insert or replace the specified (key, datum) pair in the specified
- * hash table. If an entry for the specified key already exists,
- * then the specified destroy function is applied to (key,datum,args)
- * for the entry prior to replacing the entry's contents.
- *
- * Returns -ENOMEM if insufficient space is available,
- * -EINVAL for general errors or
- * 0 otherwise.
- */
-int hashtab_replace(struct hashtab *h, void *k, void *d,
- void (*destroy)(void *k, void *d, void *args),
- void *args);
-
-/*
* Searches for the entry with the specified key in the hash table.
*
* Returns NULL if no entry has the specified key or
@@ -108,17 +81,6 @@ int hashtab_map(struct hashtab *h,
int (*apply)(void *k, void *d, void *args),
void *args);
-/*
- * Same as hashtab_map, except that if apply returns a non-zero status,
- * then the (key,datum) pair will be removed from the hashtab and the
- * destroy function will be applied to (key,datum,args).
- */
-void hashtab_map_remove_on_error(struct hashtab *h,
- int (*apply)(void *k, void *d, void *args),
- void (*destroy)(void *k, void *d, void *args),
- void *args);
-
-
/* Fill info with some hash table statistics */
void hashtab_stat(struct hashtab *h, struct hashtab_info *info);
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 1663dbc3a0bd3..14190efbf333b 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -110,7 +110,7 @@ static struct policydb_compat_info *policydb_lookup_compat(int version)
/*
* Initialize the role table.
*/
-int roles_init(struct policydb *p)
+static int roles_init(struct policydb *p)
{
char *key = NULL;
int rc;
@@ -149,7 +149,7 @@ out_free_role:
/*
* Initialize a policy database structure.
*/
-int policydb_init(struct policydb *p)
+static int policydb_init(struct policydb *p)
{
int i, rc;
@@ -321,7 +321,7 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
*
* Caller must clean up upon failure.
*/
-int policydb_index_classes(struct policydb *p)
+static int policydb_index_classes(struct policydb *p)
{
int rc;
@@ -378,7 +378,7 @@ static void symtab_hash_eval(struct symtab *s)
*
* Caller must clean up on failure.
*/
-int policydb_index_others(struct policydb *p)
+static int policydb_index_others(struct policydb *p)
{
int i, rc = 0;
@@ -566,7 +566,7 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
cat_destroy,
};
-void ocontext_destroy(struct ocontext *c, int i)
+static void ocontext_destroy(struct ocontext *c, int i)
{
context_destroy(&c->context[0]);
context_destroy(&c->context[1]);
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index 299d7711d7b10..2470e2a1a1c3c 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -240,9 +240,6 @@ struct policydb {
unsigned int policyvers;
};
-extern int policydb_init(struct policydb *p);
-extern int policydb_index_classes(struct policydb *p);
-extern int policydb_index_others(struct policydb *p);
extern void policydb_destroy(struct policydb *p);
extern int policydb_load_isids(struct policydb *p, struct sidtab *s);
extern int policydb_context_isvalid(struct policydb *p, struct context *c);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index e2c8678595452..5a820cf88c9c9 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -52,7 +52,7 @@ static DECLARE_MUTEX(load_sem);
#define LOAD_LOCK down(&load_sem)
#define LOAD_UNLOCK up(&load_sem)
-struct sidtab sidtab;
+static struct sidtab sidtab;
struct policydb policydb;
int ss_initialized = 0;
@@ -64,9 +64,9 @@ int ss_initialized = 0;
*/
static u32 latest_granting = 0;
-/* Forward declarations. */
-int context_struct_to_string(struct context *context, char **scontext,
- u32 *scontext_len);
+/* Forward declaration. */
+static int context_struct_to_string(struct context *context, char **scontext,
+ u32 *scontext_len);
/*
* Return the boolean value of a constraint expression
@@ -79,10 +79,10 @@ int context_struct_to_string(struct context *context, char **scontext,
* of the process performing the transition. All other callers of
* constraint_expr_eval should pass in NULL for xcontext.
*/
-int constraint_expr_eval(struct context *scontext,
- struct context *tcontext,
- struct context *xcontext,
- struct constraint_expr *cexpr)
+static int constraint_expr_eval(struct context *scontext,
+ struct context *tcontext,
+ struct context *xcontext,
+ struct constraint_expr *cexpr)
{
u32 val1, val2;
struct context *c;
@@ -515,7 +515,7 @@ out:
* to point to this string and set `*scontext_len' to
* the length of the string.
*/
-int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len)
+static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len)
{
char *scontextp;
diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h
index c7030aee83d33..e8d907e903cdb 100644
--- a/security/selinux/ss/services.h
+++ b/security/selinux/ss/services.h
@@ -9,12 +9,6 @@
#include "policydb.h"
#include "sidtab.h"
-/*
- * The security server uses two global data structures
- * when providing its services: the SID table (sidtab)
- * and the policy database (policydb).
- */
-extern struct sidtab sidtab;
extern struct policydb policydb;
#endif /* _SS_SERVICES_H_ */
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index 77d000246f137..871c33bd07413 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -87,42 +87,6 @@ out:
return rc;
}
-int sidtab_remove(struct sidtab *s, u32 sid)
-{
- int hvalue, rc = 0;
- struct sidtab_node *cur, *last;
-
- if (!s) {
- rc = -ENOENT;
- goto out;
- }
-
- hvalue = SIDTAB_HASH(sid);
- last = NULL;
- cur = s->htable[hvalue];
- while (cur != NULL && sid > cur->sid) {
- last = cur;
- cur = cur->next;
- }
-
- if (cur == NULL || sid != cur->sid) {
- rc = -ENOENT;
- goto out;
- }
-
- if (last == NULL)
- s->htable[hvalue] = cur->next;
- else
- last->next = cur->next;
-
- context_destroy(&cur->context);
-
- kfree(cur);
- s->nel--;
-out:
- return rc;
-}
-
struct context *sidtab_search(struct sidtab *s, u32 sid)
{
int hvalue;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 2ee75e0335ac7..0bee7c9c1fee2 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -3097,8 +3097,8 @@ int snd_pcm_lib_mmap_iomem(snd_pcm_substream_t *substream, struct vm_area_struct
area->vm_flags |= VM_IO;
size = area->vm_end - area->vm_start;
offset = area->vm_pgoff << PAGE_SHIFT;
- if (io_remap_page_range(area, area->vm_start,
- substream->runtime->dma_addr + offset,
+ if (io_remap_pfn_range(area, area->vm_start,
+ (substream->runtime->dma_addr + offset) >> PAGE_SHIFT,
size, area->vm_page_prot))
return -EAGAIN;
atomic_inc(&substream->runtime->mmap_count);
diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
index 89f52a7d466a1..5281b88987f35 100644
--- a/sound/oss/dmasound/dmasound_awacs.c
+++ b/sound/oss/dmasound/dmasound_awacs.c
@@ -2987,10 +2987,13 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev);
set_hw_byteswap(io) ; /* figure out if the h/w can do it */
- /* get default volume from nvram
- * vol = (~nvram_read_byte(0x1308) & 7) << 1;
- */
+#ifdef CONFIG_NVRAM
+ /* get default volume from nvram */
vol = ((pmac_xpram_read( 8 ) & 7 ) << 1 );
+#else
+ vol = 0;
+#endif
+
/* set up tracking values */
spk_vol = vol * 100 ;
spk_vol /= 7 ; /* get set value to a percentage */