Merge branch 'upstream-davem' of master.kernel.org:/pub/scm/linux/kernel/git/linville...
authorDavid S. Miller <davem@sunset.davemloft.net>
Thu, 19 Jul 2007 01:21:44 +0000 (18:21 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Thu, 19 Jul 2007 01:21:44 +0000 (18:21 -0700)
579 files changed:
Documentation/dvb/bt8xx.txt
Documentation/dvb/get_dvb_firmware
Documentation/dvb/opera-firmware.txt [new file with mode: 0644]
Documentation/video4linux/CARDLIST.bttv
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
Documentation/video4linux/sn9c102.txt
Documentation/video4linux/zr364xx.txt
MAINTAINERS
arch/alpha/kernel/smp.c
arch/alpha/lib/checksum.c
arch/avr32/Kconfig
arch/avr32/boards/atstk1000/Kconfig [new file with mode: 0644]
arch/avr32/boards/atstk1000/atstk1002.c
arch/avr32/kernel/setup.c
arch/avr32/mach-at32ap/Makefile
arch/avr32/mach-at32ap/at32ap.c
arch/avr32/mach-at32ap/at32ap7000.c
arch/avr32/mach-at32ap/cpufreq.c [new file with mode: 0644]
arch/avr32/mach-at32ap/extint.c
arch/avr32/mach-at32ap/pm.h [new file with mode: 0644]
arch/avr32/mach-at32ap/sm.h [deleted file]
arch/frv/kernel/setup.c
arch/i386/Kconfig
arch/i386/Makefile
arch/i386/boot/Makefile
arch/i386/boot/boot.h
arch/i386/boot/compressed/relocs.c
arch/i386/boot/cpucheck.c
arch/i386/boot/mca.c
arch/i386/boot/pm.c
arch/i386/boot/tools/build.c
arch/i386/boot/tty.c
arch/i386/boot/video.c
arch/i386/boot/video.h
arch/i386/boot/voyager.c
arch/i386/kernel/asm-offsets.c
arch/i386/kernel/cpu/mcheck/therm_throt.c
arch/i386/kernel/efi.c
arch/i386/kernel/entry.S
arch/i386/kernel/head.S
arch/i386/kernel/paravirt.c
arch/i386/kernel/ptrace.c
arch/i386/kernel/setup.c
arch/i386/kernel/smp.c
arch/i386/kernel/smpboot.c
arch/i386/kernel/smpcommon.c
arch/i386/kernel/syscall_table.S
arch/i386/kernel/traps.c
arch/i386/kernel/tsc.c
arch/i386/kernel/vmi.c
arch/i386/kernel/vmiclock.c
arch/i386/kernel/vmlinux.lds.S
arch/i386/kernel/vsyscall-note.S
arch/i386/mach-voyager/voyager_thread.c
arch/i386/mm/init.c
arch/i386/mm/pageattr.c
arch/i386/xen/Kconfig [new file with mode: 0644]
arch/i386/xen/Makefile [new file with mode: 0644]
arch/i386/xen/enlighten.c [new file with mode: 0644]
arch/i386/xen/events.c [new file with mode: 0644]
arch/i386/xen/features.c [new file with mode: 0644]
arch/i386/xen/manage.c [new file with mode: 0644]
arch/i386/xen/mmu.c [new file with mode: 0644]
arch/i386/xen/mmu.h [new file with mode: 0644]
arch/i386/xen/multicalls.c [new file with mode: 0644]
arch/i386/xen/multicalls.h [new file with mode: 0644]
arch/i386/xen/setup.c [new file with mode: 0644]
arch/i386/xen/smp.c [new file with mode: 0644]
arch/i386/xen/time.c [new file with mode: 0644]
arch/i386/xen/xen-asm.S [new file with mode: 0644]
arch/i386/xen/xen-head.S [new file with mode: 0644]
arch/i386/xen/xen-ops.h [new file with mode: 0644]
arch/ia64/hp/common/sba_iommu.c
arch/ia64/hp/sim/boot/fw-emu.c
arch/ia64/hp/sim/simserial.c
arch/ia64/kernel/fsys.S
arch/ia64/lib/checksum.c
arch/ia64/sn/kernel/sn2/sn_hwperf.c
arch/m68k/lib/checksum.c
arch/mips/basler/excite/excite_setup.c
arch/mips/gt64120/wrppmc/setup.c
arch/mips/mips-boards/atlas/atlas_setup.c
arch/mips/mips-boards/sead/sead_setup.c
arch/mips/mipssim/sim_setup.c
arch/mips/pmc-sierra/msp71xx/msp_serial.c
arch/mips/pmc-sierra/yosemite/setup.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/sys_ppc32.c
arch/ppc/platforms/4xx/bamboo.c
arch/ppc/platforms/4xx/bubinga.c
arch/ppc/platforms/4xx/cpci405.c
arch/ppc/platforms/4xx/ebony.c
arch/ppc/platforms/4xx/luan.c
arch/ppc/platforms/4xx/ocotea.c
arch/ppc/platforms/4xx/taishan.c
arch/ppc/platforms/4xx/yucca.c
arch/ppc/platforms/85xx/sbc8560.c
arch/ppc/platforms/chestnut.c
arch/ppc/platforms/ev64260.c
arch/ppc/platforms/radstone_ppc7d.c
arch/ppc/platforms/spruce.c
arch/s390/defconfig
arch/s390/kernel/dis.c
arch/s390/kernel/stacktrace.c
arch/sh64/lib/c-checksum.c
arch/sparc/Kconfig
arch/sparc64/Kconfig
arch/sparc64/defconfig
arch/sparc64/kernel/ds.c
arch/sparc64/kernel/hvtramp.S
arch/sparc64/kernel/mdesc.c
arch/sparc64/kernel/signal.c
arch/sparc64/kernel/vio.c
arch/sparc64/kernel/viohs.c
arch/um/drivers/pcap_user.c
arch/x86_64/ia32/ia32entry.S
arch/x86_64/ia32/sys_ia32.c
arch/x86_64/kernel/early_printk.c
arch/x86_64/kernel/mce.c
arch/x86_64/kernel/ptrace.c
arch/x86_64/kernel/smp.c
block/Kconfig
block/bsg.c
drivers/Makefile
drivers/acpi/thermal.c
drivers/ata/sata_mv.c
drivers/atm/Kconfig
drivers/atm/ambassador.c
drivers/atm/eni.c
drivers/atm/firestream.c
drivers/atm/idt77252.c
drivers/atm/lanai.c
drivers/atm/nicstarmac.c
drivers/atm/zatm.c
drivers/block/Kconfig
drivers/block/Makefile
drivers/block/sunvdc.c
drivers/block/xen-blkfront.c [new file with mode: 0644]
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/cyclades.c
drivers/char/decserial.c [deleted file]
drivers/char/hvc_xen.c [new file with mode: 0644]
drivers/char/watchdog/Kconfig
drivers/char/watchdog/Makefile
drivers/char/watchdog/at32ap700x_wdt.c [new file with mode: 0644]
drivers/char/watchdog/ep93xx_wdt.c
drivers/char/watchdog/mixcomwd.c
drivers/char/watchdog/pnx4008_wdt.c
drivers/char/watchdog/s3c2410_wdt.c
drivers/ide/ide.c
drivers/infiniband/hw/mthca/mthca_qp.c
drivers/isdn/hisax/bkm_a4t.c
drivers/isdn/hisax/config.c
drivers/isdn/hisax/enternow_pci.c
drivers/isdn/hisax/hfc_pci.c
drivers/isdn/hisax/nj_s.c
drivers/isdn/hisax/nj_u.c
drivers/kvm/Kconfig
drivers/kvm/kvm.h
drivers/kvm/kvm_main.c
drivers/kvm/mmu.c
drivers/kvm/paging_tmpl.h
drivers/kvm/svm.c
drivers/kvm/svm.h
drivers/kvm/vmx.c
drivers/kvm/x86_emulate.c
drivers/macintosh/therm_pm72.c
drivers/macintosh/windfarm_core.c
drivers/md/dm-exception-store.c
drivers/media/Kconfig
drivers/media/common/ir-functions.c
drivers/media/common/saa7146_core.c
drivers/media/common/saa7146_video.c
drivers/media/dvb/b2c2/Kconfig
drivers/media/dvb/b2c2/Makefile
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
drivers/media/dvb/bt8xx/Kconfig
drivers/media/dvb/bt8xx/Makefile
drivers/media/dvb/bt8xx/dst.c
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/dvb/cinergyT2/Makefile
drivers/media/dvb/cinergyT2/cinergyT2.c
drivers/media/dvb/dvb-core/dmxdev.c
drivers/media/dvb/dvb-core/dvb_ca_en50221.c
drivers/media/dvb/dvb-core/dvb_demux.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-core/dvb_net.c
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/Makefile
drivers/media/dvb/dvb-usb/af9005-fe.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/af9005-remote.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/af9005-script.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/af9005.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/af9005.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/dibusb-common.c
drivers/media/dvb/dvb-usb/dibusb-mb.c
drivers/media/dvb/dvb-usb/dibusb.h
drivers/media/dvb/dvb-usb/digitv.c
drivers/media/dvb/dvb-usb/digitv.h
drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dvb-usb-remote.c
drivers/media/dvb/dvb-usb/dvb-usb.h
drivers/media/dvb/dvb-usb/gl861.c
drivers/media/dvb/dvb-usb/m920x.c
drivers/media/dvb/dvb-usb/m920x.h
drivers/media/dvb/dvb-usb/opera1.c
drivers/media/dvb/dvb-usb/umt-010.c
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/cx22702.c
drivers/media/dvb/frontends/cx24123.c
drivers/media/dvb/frontends/dvb-pll.c
drivers/media/dvb/frontends/dvb-pll.h
drivers/media/dvb/frontends/nxt200x.c
drivers/media/dvb/frontends/nxt200x.h
drivers/media/dvb/frontends/or51132.c
drivers/media/dvb/frontends/or51211.c
drivers/media/dvb/frontends/stv0299.c
drivers/media/dvb/frontends/tda10023.c
drivers/media/dvb/pluto2/Makefile
drivers/media/dvb/ttpci/Kconfig
drivers/media/dvb/ttpci/Makefile
drivers/media/dvb/ttpci/av7110.c
drivers/media/dvb/ttpci/av7110.h
drivers/media/dvb/ttpci/av7110_av.c
drivers/media/dvb/ttpci/av7110_ca.c
drivers/media/dvb/ttpci/av7110_hw.c
drivers/media/dvb/ttpci/av7110_hw.h
drivers/media/dvb/ttpci/av7110_ir.c
drivers/media/dvb/ttpci/av7110_v4l.c
drivers/media/dvb/ttpci/budget-av.c
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/dvb/ttusb-budget/Makefile
drivers/media/dvb/ttusb-dec/Makefile
drivers/media/radio/Kconfig
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-aztech.c
drivers/media/radio/radio-gemtek-pci.c
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-rtrack2.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-terratec.c
drivers/media/radio/radio-trust.c
drivers/media/radio/radio-typhoon.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adv7170.c
drivers/media/video/adv7175.c
drivers/media/video/bt819.c
drivers/media/video/bt856.c
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv-input.c
drivers/media/video/bt8xx/bttv.h
drivers/media/video/bt8xx/bttvp.h
drivers/media/video/cpia2/cpia2_core.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cx88/Kconfig
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-i2c.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-vp3054-i2c.c
drivers/media/video/cx88/cx88-vp3054-i2c.h
drivers/media/video/cx88/cx88.h
drivers/media/video/et61x251/Kconfig
drivers/media/video/et61x251/et61x251.h
drivers/media/video/et61x251/et61x251_core.c
drivers/media/video/et61x251/et61x251_sensor.h
drivers/media/video/et61x251/et61x251_tas5130d1b.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-firmware.c
drivers/media/video/ivtv/ivtv-gpio.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-irq.c
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/ivtv/ivtv-vbi.c
drivers/media/video/msp3400-driver.c
drivers/media/video/mt20xx.c
drivers/media/video/ov7670.c
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc.h
drivers/media/video/saa7111.c
drivers/media/video/saa7114.c
drivers/media/video/saa7134/Kconfig
drivers/media/video/saa7134/saa7134-alsa.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-tvaudio.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/saa7185.c
drivers/media/video/sn9c102/sn9c102.h
drivers/media/video/sn9c102/sn9c102_core.c
drivers/media/video/sn9c102/sn9c102_ov7630.c
drivers/media/video/sn9c102/sn9c102_ov7660.c
drivers/media/video/stradis.c
drivers/media/video/stv680.c
drivers/media/video/tda8290.c
drivers/media/video/tda9887.c
drivers/media/video/tea5761.c [new file with mode: 0644]
drivers/media/video/tea5767.c
drivers/media/video/tuner-core.c
drivers/media/video/tuner-driver.h [new file with mode: 0644]
drivers/media/video/tuner-simple.c
drivers/media/video/tuner-types.c
drivers/media/video/tveeprom.c
drivers/media/video/tvp5150.c
drivers/media/video/usbvideo/konicawc.c
drivers/media/video/usbvideo/quickcam_messenger.c
drivers/media/video/usbvideo/vicam.c
drivers/media/video/usbvision/usbvision-cards.c
drivers/media/video/usbvision/usbvision-core.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/usbvision/usbvision.h
drivers/media/video/vino.c
drivers/media/video/vivi.c
drivers/media/video/zc0301/Kconfig
drivers/media/video/zc0301/zc0301.h
drivers/media/video/zc0301/zc0301_core.c
drivers/media/video/zc0301/zc0301_pas202bcb.c
drivers/media/video/zc0301/zc0301_pb0330.c
drivers/media/video/zc0301/zc0301_sensor.h
drivers/media/video/zoran_driver.c
drivers/media/video/zr364xx.c
drivers/mtd/ubi/build.c
drivers/mtd/ubi/cdev.c
drivers/mtd/ubi/debug.c
drivers/mtd/ubi/debug.h
drivers/mtd/ubi/eba.c
drivers/mtd/ubi/gluebi.c
drivers/mtd/ubi/io.c
drivers/mtd/ubi/kapi.c
drivers/mtd/ubi/misc.c
drivers/mtd/ubi/scan.c
drivers/mtd/ubi/scan.h
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/upd.c
drivers/mtd/ubi/vmt.c
drivers/mtd/ubi/vtbl.c
drivers/mtd/ubi/wl.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/atl1/atl1_main.c
drivers/net/bnx2.c
drivers/net/bnx2.h
drivers/net/eepro100.c
drivers/net/hamradio/baycom_epp.c
drivers/net/natsemi.c
drivers/net/ne2k-pci.c
drivers/net/pppol2tp.c
drivers/net/r8169.c
drivers/net/sunvnet.c
drivers/net/sunvnet.h
drivers/net/tokenring/smctr.c
drivers/net/wan/pc300_drv.c
drivers/net/wan/sbni.c
drivers/net/xen-netfront.c [new file with mode: 0644]
drivers/parisc/hppb.c
drivers/parisc/superio.c
drivers/pnp/pnpbios/core.c
drivers/s390/char/Kconfig
drivers/s390/char/Makefile
drivers/s390/char/vmcp.c
drivers/s390/char/vmcp.h
drivers/s390/char/vmur.c [new file with mode: 0644]
drivers/s390/char/vmur.h [new file with mode: 0644]
drivers/s390/cio/device.c
drivers/s390/cio/qdio.c
drivers/sbus/char/bbc_envctrl.c
drivers/sbus/char/envctrl.c
drivers/serial/8250_hp300.c
drivers/serial/Kconfig
drivers/serial/Makefile
drivers/serial/zs.c [new file with mode: 0644]
drivers/serial/zs.h [new file with mode: 0644]
drivers/tc/Makefile
drivers/tc/zs.c [deleted file]
drivers/tc/zs.h [deleted file]
drivers/telephony/Kconfig
drivers/telephony/ixj.c
drivers/usb/Kconfig
drivers/usb/misc/auerswald.c
drivers/video/logo/Kconfig
drivers/video/matrox/matroxfb_maven.c
drivers/video/riva/riva_hw.c
drivers/xen/Makefile [new file with mode: 0644]
drivers/xen/grant-table.c [new file with mode: 0644]
drivers/xen/xenbus/Makefile [new file with mode: 0644]
drivers/xen/xenbus/xenbus_client.c [new file with mode: 0644]
drivers/xen/xenbus/xenbus_comms.c [new file with mode: 0644]
drivers/xen/xenbus/xenbus_comms.h [new file with mode: 0644]
drivers/xen/xenbus/xenbus_probe.c [new file with mode: 0644]
drivers/xen/xenbus/xenbus_probe.h [new file with mode: 0644]
drivers/xen/xenbus/xenbus_xs.c [new file with mode: 0644]
fs/9p/v9fs.c
fs/Kconfig
fs/anon_inodes.c
fs/attr.c
fs/ext2/acl.c
fs/ext2/ioctl.c
fs/ext3/acl.c
fs/ext3/ioctl.c
fs/ext4/acl.c
fs/ext4/balloc.c
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/namei.c
fs/ext4/super.c
fs/ext4/xattr.c
fs/ext4/xattr.h
fs/fcntl.c
fs/generic_acl.c
fs/gfs2/acl.c
fs/hfsplus/ioctl.c
fs/jbd2/journal.c
fs/jbd2/recovery.c
fs/jffs2/acl.c
fs/jfs/ioctl.c
fs/jfs/xattr.c
fs/namei.c
fs/ocfs2/file.c
fs/ocfs2/heartbeat.c
fs/ocfs2/ioctl.c
fs/open.c
fs/reiserfs/ioctl.c
fs/reiserfs/xattr_acl.c
fs/udf/super.c
fs/utimes.c
fs/xattr.c
include/asm-alpha/termios.h
include/asm-avr32/arch-at32ap/board.h
include/asm-avr32/arch-at32ap/sm.h [deleted file]
include/asm-avr32/atomic.h
include/asm-avr32/unaligned.h
include/asm-generic/unaligned.h
include/asm-i386/irq.h
include/asm-i386/mach-default/irq_vectors_limits.h
include/asm-i386/mmu_context.h
include/asm-i386/paravirt.h
include/asm-i386/pgalloc.h
include/asm-i386/setup.h
include/asm-i386/smp.h
include/asm-i386/timer.h
include/asm-i386/unistd.h
include/asm-i386/vmi_time.h
include/asm-i386/xen/hypercall.h [new file with mode: 0644]
include/asm-i386/xen/hypervisor.h [new file with mode: 0644]
include/asm-i386/xen/interface.h [new file with mode: 0644]
include/asm-ia64/ioctls.h
include/asm-ia64/termbits.h
include/asm-ia64/termios.h
include/asm-mips/dec/serial.h [deleted file]
include/asm-powerpc/systbl.h
include/asm-powerpc/unistd.h
include/asm-sparc64/io.h
include/asm-sparc64/mdesc.h
include/asm-sparc64/vio.h
include/asm-x86_64/unistd.h
include/linux/bsg.h
include/linux/elfnote.h
include/linux/ext4_fs.h
include/linux/ext4_fs_extents.h
include/linux/ext4_fs_i.h
include/linux/ext4_fs_sb.h
include/linux/falloc.h [new file with mode: 0644]
include/linux/fs.h
include/linux/genetlink.h
include/linux/jbd2.h
include/linux/kmod.h
include/linux/magic.h
include/linux/major.h
include/linux/netdevice.h
include/linux/netfilter_ipv4/ipt_iprange.h
include/linux/netlink.h
include/linux/notifier.h
include/linux/page-flags.h
include/linux/reboot.h
include/linux/serial_8250.h
include/linux/serial_core.h
include/linux/slob_def.h
include/linux/smp.h
include/linux/string.h
include/linux/syscalls.h
include/linux/vmalloc.h
include/media/saa7146.h
include/media/tuner.h
include/mtd/ubi-header.h
include/net/genetlink.h
include/net/tcp.h
include/net/xfrm.h
include/xen/events.h [new file with mode: 0644]
include/xen/features.h [new file with mode: 0644]
include/xen/grant_table.h [new file with mode: 0644]
include/xen/hvc-console.h [new file with mode: 0644]
include/xen/interface/elfnote.h [new file with mode: 0644]
include/xen/interface/event_channel.h [new file with mode: 0644]
include/xen/interface/features.h [new file with mode: 0644]
include/xen/interface/grant_table.h [new file with mode: 0644]
include/xen/interface/io/blkif.h [new file with mode: 0644]
include/xen/interface/io/console.h [new file with mode: 0644]
include/xen/interface/io/netif.h [new file with mode: 0644]
include/xen/interface/io/ring.h [new file with mode: 0644]
include/xen/interface/io/xenbus.h [new file with mode: 0644]
include/xen/interface/io/xs_wire.h [new file with mode: 0644]
include/xen/interface/memory.h [new file with mode: 0644]
include/xen/interface/physdev.h [new file with mode: 0644]
include/xen/interface/sched.h [new file with mode: 0644]
include/xen/interface/vcpu.h [new file with mode: 0644]
include/xen/interface/version.h [new file with mode: 0644]
include/xen/interface/xen.h [new file with mode: 0644]
include/xen/page.h [new file with mode: 0644]
include/xen/xenbus.h [new file with mode: 0644]
ipc/msg.c
ipc/sem.c
kernel/auditfilter.c
kernel/cpu.c
kernel/cpuset.c
kernel/kmod.c
kernel/sys.c
kernel/sysctl.c
lib/Makefile
lib/argv_split.c [new file with mode: 0644]
lib/kobject_uevent.c
mm/util.c
mm/vmalloc.c
net/atm/br2684.c
net/bridge/br_stp_if.c
net/core/dev.c
net/core/dev_mcast.c
net/core/gen_estimator.c
net/ipv4/tcp_bic.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_cubic.c
net/ipv4/tcp_highspeed.c
net/ipv4/tcp_htcp.c
net/ipv4/tcp_hybla.c
net/ipv4/tcp_illinois.c
net/ipv4/tcp_input.c
net/ipv4/tcp_lp.c
net/ipv4/tcp_scalable.c
net/ipv4/tcp_vegas.c
net/ipv4/tcp_veno.c
net/ipv4/tcp_yeah.c
net/irda/af_irda.c
net/irda/irda_device.c
net/irda/iriap.c
net/irda/irias_object.c
net/irda/irlap.c
net/irda/irlmp.c
net/irda/irproc.c
net/irda/irsysctl.c
net/irda/irttp.c
net/netfilter/Kconfig
net/netlink/af_netlink.c
net/netlink/genetlink.c
net/rfkill/rfkill.c
net/sched/Kconfig
net/sched/sch_atm.c
net/xfrm/xfrm_policy.c
security/keys/request_key.c
security/selinux/hooks.c
sound/pci/mixart/mixart_hwdep.c

index 4e7614e606c5675e241bae76e9523534072ae133..ecb47adda0638b9ac4a79ddc7ae7537801edf24a 100644 (file)
@@ -9,19 +9,29 @@ for accessing the i2c bus and the gpio pins of the bt8xx chipset.
 Please see Documentation/dvb/cards.txt => o Cards based on the Conexant Bt8xx PCI bridge:
 
 Compiling kernel please enable:
-a.)"Device drivers" => "Multimedia devices" => "Video For Linux" => "BT848 Video For Linux"
-b.)"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
- => "DVB for Linux" "DVB Core Support" "Bt8xx based PCI Cards"
+a.)"Device drivers" => "Multimedia devices" => "Video For Linux" => "Enable Video for Linux API 1 (DEPRECATED)"
+b.)"Device drivers" => "Multimedia devices" => "Video For Linux" => "Video Capture Adapters" => "BT848 Video For Linux"
+c.)"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices" => "DVB for Linux" "DVB Core Support" "Bt8xx based PCI Cards"
 
-2) Loading Modules
-==================
+Please use the following options with care as deselection of drivers which are in fact necessary
+may result in DVB devices that cannot be tuned due to lack of driver support:
+You can save RAM by deselecting every frontend module that your DVB card does not need.
+
+First please remove the static dependency of DVB card drivers on all frontend modules for all possible card variants by enabling:
+d.) "Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
+ => "DVB for Linux" "DVB Core Support" "Load and attach frontend modules as needed"
 
-In default cases bttv is loaded automatically.
-To load the backend either place dvb-bt8xx in etc/modules, or apply manually:
+If you know the frontend driver that your card needs please enable:
+e.)"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
+ => "DVB for Linux" "DVB Core Support" "Customise DVB Frontends" => "Customise the frontend modules to build"
+ Then please select your card-specific frontend module.
 
-       $ modprobe dvb-bt8xx
+2) Loading Modules
+==================
 
-All frontends will be loaded automatically.
+Regular case: If the bttv driver detects a bt8xx-based DVB card, all frontend and backend modules will be loaded automatically.
+Exceptions are:
+- Old TwinHan DST cards or clones with or without CA slot and not containing an Eeprom.
 People running udev please see Documentation/dvb/udev.txt.
 
 In the following cases overriding the PCI type detection for dvb-bt8xx might be necessary:
@@ -30,7 +40,6 @@ In the following cases overriding the PCI type detection for dvb-bt8xx might be
 ------------------------------
 
        $ modprobe bttv card=113
-       $ modprobe dvb-bt8xx
        $ modprobe dst
 
 Useful parameters for verbosity level and debugging the dst module:
@@ -65,10 +74,9 @@ DViCO FusionHDTV 5 Lite:     135
 Notice: The order of the card ID should be uprising:
 Example:
        $ modprobe bttv card=113 card=135
-       $ modprobe dvb-bt8xx
 
 For a full list of card ID's please see Documentation/video4linux/CARDLIST.bttv.
-In case of further problems send questions to the mailing list: www.linuxdvb.org.
+In case of further problems please subscribe and send questions to the mailing list: linux-dvb@linuxtv.org.
 
 Authors: Richard Walker,
         Jamie Honan,
index 4820366b6ae899667cf0589b789661d990eda7cc..b4d306ae923431d4844f42360f8cfdeb7e0753e4 100644 (file)
@@ -24,7 +24,8 @@ use IO::Handle;
 @components = ( "sp8870", "sp887x", "tda10045", "tda10046",
                "tda10046lifeview", "av7110", "dec2000t", "dec2540t",
                "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
-               "or51211", "or51132_qam", "or51132_vsb", "bluebird");
+               "or51211", "or51132_qam", "or51132_vsb", "bluebird",
+               "opera1");
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -56,7 +57,7 @@ syntax();
 
 sub sp8870 {
     my $sourcefile = "tt_Premium_217g.zip";
-    my $url = "http://www.technotrend.de/new/217g/$sourcefile";
+    my $url = "http://www.softwarepatch.pl/9999ccd06a4813cb827dbb0005071c71/$sourcefile";
     my $hash = "53970ec17a538945a6d8cb608a7b3899";
     my $outfile = "dvb-fe-sp8870.fw";
     my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
@@ -210,6 +211,45 @@ sub dec3000s {
 
     $outfile;
 }
+sub opera1{
+       my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0);
+
+       checkstandard();
+       my $fwfile1="dvb-usb-opera1-fpga-01.fw";
+       my $fwfile2="dvb-usb-opera-01.fw";
+       extract("2830SCap2.sys", 0x62e8, 55024, "$tmpdir/opera1-fpga.fw");
+       extract("2830SLoad2.sys",0x3178,0x3685-0x3178,"$tmpdir/fw1part1");
+       extract("2830SLoad2.sys",0x0980,0x3150-0x0980,"$tmpdir/fw1part2");
+       delzero("$tmpdir/fw1part1","$tmpdir/fw1part1-1");
+       delzero("$tmpdir/fw1part2","$tmpdir/fw1part2-1");
+       verify("$tmpdir/fw1part1-1","5e0909858fdf0b5b09ad48b9fe622e70");
+       verify("$tmpdir/fw1part2-1","d6e146f321427e931df2c6fcadac37a1");
+       verify("$tmpdir/opera1-fpga.fw","0f8133f5e9051f5f3c1928f7e5a1b07d");
+
+       my $RES1="\x01\x92\x7f\x00\x01\x00";
+       my $RES0="\x01\x92\x7f\x00\x00\x00";
+       my $DAT1="\x01\x00\xe6\x00\x01\x00";
+       my $DAT0="\x01\x00\xe6\x00\x00\x00";
+       open FW,">$tmpdir/opera.fw";
+       print FW "$RES1";
+       print FW "$DAT1";
+       print FW "$RES1";
+       print FW "$DAT1";
+       appendfile(FW,"$tmpdir/fw1part1-1");
+       print FW "$RES0";
+       print FW "$DAT0";
+       print FW "$RES1";
+       print FW "$DAT1";
+       appendfile(FW,"$tmpdir/fw1part2-1");
+       print FW "$RES1";
+       print FW "$DAT1";
+       print FW "$RES0";
+       print FW "$DAT0";
+       copy ("$tmpdir/opera1-fpga.fw",$fwfile1);
+       copy ("$tmpdir/opera.fw",$fwfile2);
+
+       $fwfile1.",".$fwfile2;
+}
 
 sub vp7041 {
     my $sourcefile = "2.422.zip";
@@ -440,6 +480,25 @@ sub appendfile {
     close(INFILE);
 }
 
+sub delzero{
+       my ($infile,$outfile) =@_;
+
+       open INFILE,"<$infile";
+       open OUTFILE,">$outfile";
+       while (1){
+               $rcount=sysread(INFILE,$buf,22);
+               $len=ord(substr($buf,0,1));
+               print OUTFILE substr($buf,0,1);
+               print OUTFILE substr($buf,2,$len+3);
+       last if ($rcount<1);
+       printf OUTFILE "%c",0;
+#print $len." ".length($buf)."\n";
+
+       }
+       close(INFILE);
+       close(OUTFILE);
+}
+
 sub syntax() {
     print STDERR "syntax: get_dvb_firmware <component>\n";
     print STDERR "Supported components:\n";
diff --git a/Documentation/dvb/opera-firmware.txt b/Documentation/dvb/opera-firmware.txt
new file mode 100644 (file)
index 0000000..93e784c
--- /dev/null
@@ -0,0 +1,27 @@
+To extract the firmware for the Opera DVB-S1 USB-Box
+you need to copy the files:
+
+2830SCap2.sys
+2830SLoad2.sys
+
+from the windriver disk into this directory.
+
+Then run
+
+./get_dvb_firware opera1
+
+and after that you have 2 files:
+
+dvb-usb-opera-01.fw
+dvb-usb-opera1-fpga-01.fw
+
+in here.
+
+Copy them into /lib/firmware/ .
+
+After that the driver can load the firmware
+(if you have enabled firmware loading
+in kernel config and have hotplug running).
+
+
+Marco Gittler <g.marco@freenet.de>
\ No newline at end of file
index b60639130a510df58f5580fb371b8dc51834cc03..177159c5f4c420fcb25b651698525d77544e2b7c 100644 (file)
@@ -66,7 +66,7 @@
  65 -> Lifeview FlyVideo 2000S LR90
  66 -> Terratec TValueRadio                                [153b:1135,153b:ff3b]
  67 -> IODATA GV-BCTV4/PCI                                 [10fc:4050]
- 68 -> 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)         [121a:3000,10b4:2637]
+ 68 -> 3Dfx VoodooTV FM (Euro)                             [10b4:2637]
  69 -> Active Imaging AIMMS
  70 -> Prolink Pixelview PV-BT878P+ (Rev.4C,8E)
  71 -> Lifeview FlyVideo 98EZ (capture only) LR51          [1851:1851]
 144 -> MagicTV
 145 -> SSAI Security Video Interface                       [4149:5353]
 146 -> SSAI Ultrasound Video Interface                     [414a:5353]
+147 -> VoodooTV 200 (USA)                                  [121a:3000]
+148 -> DViCO FusionHDTV 2                                  [dbc0:d200]
index 60f838beb9c890264e744f1b2b4743a74985a977..82ac8250e978b8e784d42888b445201726493389 100644 (file)
@@ -55,3 +55,4 @@
  54 -> Norwood Micro TV Tuner
  55 -> Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM  [c180:c980]
  56 -> Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder   [0070:9600,0070:9601,0070:9602]
+ 57 -> ADS Tech Instant Video PCI                          [1421:0390]
index 712e8c8333cc90153f37be879adee04ec89b73ea..3f8aeab50a103b406a5075645aefa4cc740f499a 100644 (file)
 113 -> Elitegroup ECS TVP3XP FM1246 Tuner Card (PAL,FM) [1019:4cb6]
 114 -> KWorld DVB-T 210                         [17de:7250]
 115 -> Sabrent PCMCIA TV-PCB05                  [0919:2003]
+116 -> 10MOONS TM300 TV Card                    [1131:2304]
index 44134f04b82afc0999dd51e97c4c073a62c4a3f8..a88c02d238059b0fa277409f66860704f0b56509 100644 (file)
@@ -40,7 +40,7 @@ tuner=38 - Philips PAL/SECAM multi (FM1216ME MK3)
 tuner=39 - LG NTSC (newer TAPC series)
 tuner=40 - HITACHI V7-J180AT
 tuner=41 - Philips PAL_MK (FI1216 MK)
-tuner=42 - Philips 1236D ATSC/NTSC dual in
+tuner=42 - Philips FCV1236D ATSC/NTSC dual in
 tuner=43 - Philips NTSC MK3 (FM1236MK3 or FM1236/F)
 tuner=44 - Philips 4 in 1 (ATI TV Wonder Pro/Conexant)
 tuner=45 - Microtune 4049 FM5
@@ -72,3 +72,4 @@ tuner=70 - Samsung TCPN 2121P30A
 tuner=71 - Xceive xc3028
 tuner=72 - Thomson FE6600
 tuner=73 - Samsung TCPG 6121P30A
+tuner=75 - Philips TEA5761 FM Radio
index 279717c96f63c6a0a951d395307d7aa7ebf94c32..1ffad19ce8910b375fa46b192a66918e28ac33f3 100644 (file)
@@ -436,7 +436,7 @@ HV7131D    Hynix Semiconductor     | Yes         No       No       No
 HV7131R    Hynix Semiconductor     | No          Yes      Yes      Yes
 MI-0343    Micron Technology       | Yes         No       No       No
 MI-0360    Micron Technology       | No          Yes      Yes      Yes
-OV7630     OmniVision Technologies | Yes         Yes      No       No
+OV7630     OmniVision Technologies | Yes         Yes      Yes      Yes
 OV7660     OmniVision Technologies | No          No       Yes      Yes
 PAS106B    PixArt Imaging          | Yes         No       No       No
 PAS202B    PixArt Imaging          | Yes         Yes      No       No
@@ -583,6 +583,7 @@ order):
 - Bertrik Sikken, who reverse-engineered and documented the Huffman compression
   algorithm used in the SN9C101, SN9C102 and SN9C103 controllers and
   implemented the first decoder;
+- Ronny Standke for the donation of a webcam;
 - Mizuno Takafumi for the donation of a webcam;
 - an "anonymous" donator (who didn't want his name to be revealed) for the
   donation of a webcam.
index c76992d0ff4d577783ea6bb6f9fb334562c8e6b7..4d9a0c33f2fdfa40a1b28ded41168c55a5bb2690 100644 (file)
@@ -62,4 +62,4 @@ Vendor  Product  Distributor     Model
 0x0784  0x0040   Traveler        Slimline X5
 0x06d6  0x0034   Trust           Powerc@m 750
 0x0a17  0x0062   Pentax          Optio 50L
-
+0x06d6  0x003b   Trust           Powerc@m 970Z
index 5abec1435ad8c94c5a25979d86c016d7b3452654..e78f62f13bacc60340e2fecbd2dd03691d290bc2 100644 (file)
@@ -913,6 +913,12 @@ M: mchan@broadcom.com
 L:     netdev@vger.kernel.org
 S:     Supported
 
+BSG (block layer generic sg v4 driver)
+P:     FUJITA Tomonori
+M:     fujita.tomonori@lab.ntt.co.jp
+L:     linux-scsi@vger.kernel.org
+S:     Supported
+
 BTTV VIDEO4LINUX DRIVER
 P:     Mauro Carvalho Chehab
 M:     mchehab@infradead.org
@@ -1734,6 +1740,7 @@ S:        Maintained
 i386 SETUP CODE / CPU ERRATA WORKAROUNDS
 P:     H. Peter Anvin
 M:     hpa@zytor.com
+T:     git.kernel.org:/pub/scm/linux/kernel/git/hpa/linux-2.6-x86setup.git
 S:     Maintained
 
 IA64 (Itanium) PLATFORM
@@ -2387,7 +2394,7 @@ P:        Artem Bityutskiy
 M:     dedekind@infradead.org
 W:     http://www.linux-mtd.infradead.org/
 L:     linux-mtd@lists.infradead.org
-T:     git git://git.infradead.org/ubi-2.6.git
+T:     git git://git.infradead.org/~dedekind/ubi-2.6.git
 S:     Maintained
 
 MICROTEK X6 SCANNER
@@ -4104,6 +4111,11 @@ W:       http://www.polyware.nl/~middelin/En/hobbies.html
 W:     http://www.polyware.nl/~middelin/hobbies.html
 S:     Maintained
 
+ZS DECSTATION Z85C30 SERIAL DRIVER
+P:     Maciej W. Rozycki
+M:     macro@linux-mips.org
+S:     Maintained
+
 THE REST
 P:     Linus Torvalds
 S:     Buried alive in reporters
index 80cfb758ee2be787da0b506db3b4353d22b91e08..b28731437c31c8e7f66549da67bfd79f54b8060f 100644 (file)
@@ -65,7 +65,7 @@ enum ipi_message_type {
 };
 
 /* Set to a secondary's cpuid when it comes online.  */
-static int smp_secondary_alive __initdata = 0;
+static int smp_secondary_alive __devinitdata = 0;
 
 /* Which cpus ids came online.  */
 cpumask_t cpu_online_map;
@@ -173,7 +173,7 @@ smp_callin(void)
 }
 
 /* Wait until hwrpb->txrdy is clear for cpu.  Return -1 on timeout.  */
-static int __init
+static int __devinit
 wait_for_txrdy (unsigned long cpumask)
 {
        unsigned long timeout;
@@ -358,7 +358,7 @@ secondary_cpu_start(int cpuid, struct task_struct *idle)
 /*
  * Bring one cpu online.
  */
-static int __init
+static int __devinit
 smp_boot_one_cpu(int cpuid)
 {
        struct task_struct *idle;
index ab3761c437a848f7ca965d62f5945a93ade945d0..8698e0746f9fd594e4647aed11f6c772dd9885da 100644 (file)
@@ -69,6 +69,7 @@ __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
        result = (result & 0xffffffff) + (result >> 32);
        return (__force __wsum)result;
 }
+EXPORT_SYMBOL(csum_tcpudp_nofold);
 
 /*
  * Do a 64-bit checksum on an arbitrary memory area..
index 3ec76586877ef0f462afbd54296d1db0c29ab320..d12346aaa88bdb19a76c54f1bd876657571271fa 100644 (file)
@@ -113,6 +113,10 @@ config BOARD_ATNGW100
        bool "ATNGW100 Network Gateway"
 endchoice
 
+if BOARD_ATSTK1000
+source "arch/avr32/boards/atstk1000/Kconfig"
+endif
+
 choice
        prompt "Boot loader type"
        default LOADER_U_BOOT
@@ -185,6 +189,27 @@ config CMDLINE
 
 endmenu
 
+menu "Power managment options"
+
+menu "CPU Frequency scaling"
+
+source "drivers/cpufreq/Kconfig"
+
+config CPU_FREQ_AT32AP
+       bool "CPU frequency driver for AT32AP"
+       depends on CPU_FREQ && PLATFORM_AT32AP
+       default n
+       help
+         This enables the CPU frequency driver for AT32AP processors.
+
+         For details, take a look in <file:Documentation/cpu-freq>.
+
+         If in doubt, say N.
+
+endmenu
+
+endmenu
+
 menu "Bus options"
 
 config PCI
diff --git a/arch/avr32/boards/atstk1000/Kconfig b/arch/avr32/boards/atstk1000/Kconfig
new file mode 100644 (file)
index 0000000..71bc7d3
--- /dev/null
@@ -0,0 +1,53 @@
+# STK1000 customization
+
+if BOARD_ATSTK1002
+
+config BOARD_ATSTK1002_CUSTOM
+       bool "Non-default STK-1002 jumper settings"
+       help
+         You will normally leave the jumpers on the CPU card at their
+         default settings.  If you need to use certain peripherals,
+         you will need to change some of those jumpers.
+
+if BOARD_ATSTK1002_CUSTOM
+
+config BOARD_ATSTK1002_SW1_CUSTOM
+       bool "SW1: use SSC1 (not SPI0)"
+       help
+         This also prevents using the external DAC as an audio interface,
+         and means you can't initialize the on-board QVGA display.
+
+config BOARD_ATSTK1002_SW2_CUSTOM
+       bool "SW2: use IRDA or TIMER0 (not UART-A, MMC/SD, and PS2-A)"
+       help
+         If you change this you'll want an updated boot loader putting
+         the console on UART-C not UART-A.
+
+config BOARD_ATSTK1002_SW3_CUSTOM
+       bool "SW3: use TIMER1 (not SSC0 and GCLK)"
+       help
+         This also prevents using the external DAC as an audio interface.
+
+config BOARD_ATSTK1002_SW4_CUSTOM
+       bool "SW4: use ISI/Camera (not GPIOs, SPI1, and PS2-B)"
+       help
+         To use the camera interface you'll need a custom card (on the
+         PCI-format connector) connect a video sensor.
+
+config BOARD_ATSTK1002_SW5_CUSTOM
+       bool "SW5: use MACB1 (not LCDC)"
+
+config BOARD_ATSTK1002_SW6_CUSTOM
+       bool "SW6: more GPIOs (not MACB0)"
+
+endif  # custom
+
+config BOARD_ATSTK1002_SPI1
+       bool "Configure SPI1 controller"
+       depends on !BOARD_ATSTK1002_SW4_CUSTOM
+       help
+         All the signals for the second SPI controller are available on
+         GPIO lines and accessed through the J1 jumper block.  Say "y"
+         here to configure that SPI controller.
+
+endif  # stk 1002
index e253e86a1a39205b478a047b33d87fbad974c70d..cb93eabb9c6c4145947df0bda8afaefd0d734340 100644 (file)
 
 #include "atstk1000.h"
 
-#define        SW2_DEFAULT             /* MMCI and UART_A available */
 
 struct eth_addr {
        u8 addr[6];
 };
 
 static struct eth_addr __initdata hw_addr[2];
-static struct eth_platform_data __initdata eth_data[2];
+static struct eth_platform_data __initdata eth_data[2] = {
+       {
+               /*
+                * The MDIO pullups on STK1000 are a bit too weak for
+                * the autodetection to work properly, so we have to
+                * mask out everything but the correct address.
+                */
+               .phy_mask       = ~(1U << 16),
+       },
+       {
+               .phy_mask       = ~(1U << 17),
+       },
+};
 
+#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
 static struct spi_board_info spi0_board_info[] __initdata = {
        {
                /* QVGA display */
@@ -45,6 +57,13 @@ static struct spi_board_info spi0_board_info[] __initdata = {
                .mode           = SPI_MODE_3,
        },
 };
+#endif
+
+#ifdef CONFIG_BOARD_ATSTK1002_SPI1
+static struct spi_board_info spi1_board_info[] __initdata = { {
+       /* patch in custom entries here */
+} };
+#endif
 
 /*
  * The next two functions should go away as the boot loader is
@@ -103,10 +122,10 @@ static void __init set_hw_addr(struct platform_device *pdev)
 
 void __init setup_board(void)
 {
-#ifdef SW2_DEFAULT
-       at32_map_usart(1, 0);   /* USART 1/A: /dev/ttyS0, DB9 */
-#else
+#ifdef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
        at32_map_usart(0, 1);   /* USART 0/B: /dev/ttyS1, IRDA */
+#else
+       at32_map_usart(1, 0);   /* USART 1/A: /dev/ttyS0, DB9 */
 #endif
        /* USART 2/unused: expansion connector */
        at32_map_usart(3, 2);   /* USART 3/C: /dev/ttyS2, DB9 */
@@ -140,18 +159,31 @@ static int __init atstk1002_init(void)
 
        at32_add_system_devices();
 
-#ifdef SW2_DEFAULT
-       at32_add_device_usart(0);
-#else
+#ifdef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
        at32_add_device_usart(1);
+#else
+       at32_add_device_usart(0);
 #endif
        at32_add_device_usart(2);
 
+#ifndef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM
        set_hw_addr(at32_add_device_eth(0, &eth_data[0]));
-
+#endif
+#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
        at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
+#endif
+#ifdef CONFIG_BOARD_ATSTK1002_SPI1
+       at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
+#endif
+#ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
+       set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
+#else
        at32_add_device_lcdc(0, &atstk1000_lcdc_data,
                             fbmem_start, fbmem_size);
+#endif
+#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
+       at32_add_device_ssc(0, ATMEL_SSC_TX);
+#endif
 
        return 0;
 }
index b279d66acf5fa09600a3901fa83cfda18d2706a3..d08b0bc6b2bbc31338f9f0cbc2f0e2b1da282ee9 100644 (file)
@@ -313,7 +313,7 @@ __tagtable(ATAG_MEM, parse_tag_mem);
 
 static int __init parse_tag_rdimg(struct tag *tag)
 {
-#ifdef CONFIG_INITRD
+#ifdef CONFIG_BLK_DEV_INITRD
        struct tag_mem_range *mem = &tag->u.mem_range;
        int ret;
 
@@ -323,7 +323,7 @@ static int __init parse_tag_rdimg(struct tag *tag)
                return 0;
        }
 
-       ret = add_reserved_region(mem->start, mem->start + mem->size - 1,
+       ret = add_reserved_region(mem->addr, mem->addr + mem->size - 1,
                                  "initrd");
        if (ret) {
                printk(KERN_WARNING
index f1d395724ac63aed5ba6c6731c07e3aa8ea31e0f..a8b445046e3e3843135f2a1e4c21b93239b79d8b 100644 (file)
@@ -1,3 +1,4 @@
 obj-y                          += at32ap.o clock.o intc.o extint.o pio.o hsmc.o
 obj-$(CONFIG_CPU_AT32AP7000)   += at32ap7000.o
 obj-$(CONFIG_CPU_AT32AP7000)   += time-tc.o
+obj-$(CONFIG_CPU_FREQ_AT32AP)  += cpufreq.o
index 90f207e8e96d809c1e14ac3348e90772e1d87826..7c4987f3287a7ca52d944ee30bc435225bdaac56 100644 (file)
 #include <linux/init.h>
 #include <linux/platform_device.h>
 
-#include <asm/io.h>
-
 #include <asm/arch/init.h>
-#include <asm/arch/sm.h>
-
-struct at32_sm system_manager;
-
-static int __init at32_sm_init(void)
-{
-       struct resource *regs;
-       struct at32_sm *sm = &system_manager;
-       int ret = -ENXIO;
-
-       regs = platform_get_resource(&at32_sm_device, IORESOURCE_MEM, 0);
-       if (!regs)
-               goto fail;
-
-       spin_lock_init(&sm->lock);
-       sm->pdev = &at32_sm_device;
-
-       ret = -ENOMEM;
-       sm->regs = ioremap(regs->start, regs->end - regs->start + 1);
-       if (!sm->regs)
-               goto fail;
-
-       return 0;
-
-fail:
-       printk(KERN_ERR "Failed to initialize System Manager: %d\n", ret);
-       return ret;
-}
 
 void __init setup_platform(void)
 {
-       at32_sm_init();
        at32_clock_init();
        at32_portmux_init();
 }
index 4dda42d3f6d5fdd8c070cbc6d6d2a215d70395b0..64cc5583ddfb0a5feb89669d00ce853055421a68 100644 (file)
 #include <asm/arch/at32ap7000.h>
 #include <asm/arch/board.h>
 #include <asm/arch/portmux.h>
-#include <asm/arch/sm.h>
 
 #include <video/atmel_lcdc.h>
 
 #include "clock.h"
 #include "hmatrix.h"
 #include "pio.h"
-#include "sm.h"
+#include "pm.h"
+
+/*
+ * We can reduce the code size a bit by using a constant here. Since
+ * this file is completely chip-specific, it's safe to not use
+ * ioremap. Generic drivers should of course never do this.
+ */
+#define AT32_PM_BASE   0xfff00000
 
 #define PBMEM(base)                                    \
        {                                               \
@@ -88,6 +94,8 @@ static struct clk devname##_##_name = {                               \
        .index          = _index,                               \
 }
 
+static DEFINE_SPINLOCK(pm_lock);
+
 unsigned long at32ap7000_osc_rates[3] = {
        [0] = 32768,
        /* FIXME: these are ATSTK1002-specific */
@@ -104,11 +112,11 @@ static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
 {
        unsigned long div, mul, rate;
 
-       if (!(control & SM_BIT(PLLEN)))
+       if (!(control & PM_BIT(PLLEN)))
                return 0;
 
-       div = SM_BFEXT(PLLDIV, control) + 1;
-       mul = SM_BFEXT(PLLMUL, control) + 1;
+       div = PM_BFEXT(PLLDIV, control) + 1;
+       mul = PM_BFEXT(PLLMUL, control) + 1;
 
        rate = clk->parent->get_rate(clk->parent);
        rate = (rate + div / 2) / div;
@@ -121,7 +129,7 @@ static unsigned long pll0_get_rate(struct clk *clk)
 {
        u32 control;
 
-       control = sm_readl(&system_manager, PM_PLL0);
+       control = pm_readl(PLL0);
 
        return pll_get_rate(clk, control);
 }
@@ -130,7 +138,7 @@ static unsigned long pll1_get_rate(struct clk *clk)
 {
        u32 control;
 
-       control = sm_readl(&system_manager, PM_PLL1);
+       control = pm_readl(PLL1);
 
        return pll_get_rate(clk, control);
 }
@@ -187,108 +195,139 @@ static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)
 
 static void cpu_clk_mode(struct clk *clk, int enabled)
 {
-       struct at32_sm *sm = &system_manager;
        unsigned long flags;
        u32 mask;
 
-       spin_lock_irqsave(&sm->lock, flags);
-       mask = sm_readl(sm, PM_CPU_MASK);
+       spin_lock_irqsave(&pm_lock, flags);
+       mask = pm_readl(CPU_MASK);
        if (enabled)
                mask |= 1 << clk->index;
        else
                mask &= ~(1 << clk->index);
-       sm_writel(sm, PM_CPU_MASK, mask);
-       spin_unlock_irqrestore(&sm->lock, flags);
+       pm_writel(CPU_MASK, mask);
+       spin_unlock_irqrestore(&pm_lock, flags);
 }
 
 static unsigned long cpu_clk_get_rate(struct clk *clk)
 {
        unsigned long cksel, shift = 0;
 
-       cksel = sm_readl(&system_manager, PM_CKSEL);
-       if (cksel & SM_BIT(CPUDIV))
-               shift = SM_BFEXT(CPUSEL, cksel) + 1;
+       cksel = pm_readl(CKSEL);
+       if (cksel & PM_BIT(CPUDIV))
+               shift = PM_BFEXT(CPUSEL, cksel) + 1;
 
        return bus_clk_get_rate(clk, shift);
 }
 
+static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply)
+{
+       u32 control;
+       unsigned long parent_rate, child_div, actual_rate, div;
+
+       parent_rate = clk->parent->get_rate(clk->parent);
+       control = pm_readl(CKSEL);
+
+       if (control & PM_BIT(HSBDIV))
+               child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1);
+       else
+               child_div = 1;
+
+       if (rate > 3 * (parent_rate / 4) || child_div == 1) {
+               actual_rate = parent_rate;
+               control &= ~PM_BIT(CPUDIV);
+       } else {
+               unsigned int cpusel;
+               div = (parent_rate + rate / 2) / rate;
+               if (div > child_div)
+                       div = child_div;
+               cpusel = (div > 1) ? (fls(div) - 2) : 0;
+               control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control);
+               actual_rate = parent_rate / (1 << (cpusel + 1));
+       }
+
+       pr_debug("clk %s: new rate %lu (actual rate %lu)\n",
+                       clk->name, rate, actual_rate);
+
+       if (apply)
+               pm_writel(CKSEL, control);
+
+       return actual_rate;
+}
+
 static void hsb_clk_mode(struct clk *clk, int enabled)
 {
-       struct at32_sm *sm = &system_manager;
        unsigned long flags;
        u32 mask;
 
-       spin_lock_irqsave(&sm->lock, flags);
-       mask = sm_readl(sm, PM_HSB_MASK);
+       spin_lock_irqsave(&pm_lock, flags);
+       mask = pm_readl(HSB_MASK);
        if (enabled)
                mask |= 1 << clk->index;
        else
                mask &= ~(1 << clk->index);
-       sm_writel(sm, PM_HSB_MASK, mask);
-       spin_unlock_irqrestore(&sm->lock, flags);
+       pm_writel(HSB_MASK, mask);
+       spin_unlock_irqrestore(&pm_lock, flags);
 }
 
 static unsigned long hsb_clk_get_rate(struct clk *clk)
 {
        unsigned long cksel, shift = 0;
 
-       cksel = sm_readl(&system_manager, PM_CKSEL);
-       if (cksel & SM_BIT(HSBDIV))
-               shift = SM_BFEXT(HSBSEL, cksel) + 1;
+       cksel = pm_readl(CKSEL);
+       if (cksel & PM_BIT(HSBDIV))
+               shift = PM_BFEXT(HSBSEL, cksel) + 1;
 
        return bus_clk_get_rate(clk, shift);
 }
 
 static void pba_clk_mode(struct clk *clk, int enabled)
 {
-       struct at32_sm *sm = &system_manager;
        unsigned long flags;
        u32 mask;
 
-       spin_lock_irqsave(&sm->lock, flags);
-       mask = sm_readl(sm, PM_PBA_MASK);
+       spin_lock_irqsave(&pm_lock, flags);
+       mask = pm_readl(PBA_MASK);
        if (enabled)
                mask |= 1 << clk->index;
        else
                mask &= ~(1 << clk->index);
-       sm_writel(sm, PM_PBA_MASK, mask);
-       spin_unlock_irqrestore(&sm->lock, flags);
+       pm_writel(PBA_MASK, mask);
+       spin_unlock_irqrestore(&pm_lock, flags);
 }
 
 static unsigned long pba_clk_get_rate(struct clk *clk)
 {
        unsigned long cksel, shift = 0;
 
-       cksel = sm_readl(&system_manager, PM_CKSEL);
-       if (cksel & SM_BIT(PBADIV))
-               shift = SM_BFEXT(PBASEL, cksel) + 1;
+       cksel = pm_readl(CKSEL);
+       if (cksel & PM_BIT(PBADIV))
+               shift = PM_BFEXT(PBASEL, cksel) + 1;
 
        return bus_clk_get_rate(clk, shift);
 }
 
 static void pbb_clk_mode(struct clk *clk, int enabled)
 {
-       struct at32_sm *sm = &system_manager;
        unsigned long flags;
        u32 mask;
 
-       spin_lock_irqsave(&sm->lock, flags);
-       mask = sm_readl(sm, PM_PBB_MASK);
+       spin_lock_irqsave(&pm_lock, flags);
+       mask = pm_readl(PBB_MASK);
        if (enabled)
                mask |= 1 << clk->index;
        else
                mask &= ~(1 << clk->index);
-       sm_writel(sm, PM_PBB_MASK, mask);
-       spin_unlock_irqrestore(&sm->lock, flags);
+       pm_writel(PBB_MASK, mask);
+       spin_unlock_irqrestore(&pm_lock, flags);
 }
 
 static unsigned long pbb_clk_get_rate(struct clk *clk)
 {
        unsigned long cksel, shift = 0;
 
-       cksel = sm_readl(&system_manager, PM_CKSEL);
-       if (cksel & SM_BIT(PBBDIV))
-               shift = SM_BFEXT(PBBSEL, cksel) + 1;
+       cksel = pm_readl(CKSEL);
+       if (cksel & PM_BIT(PBBDIV))
+               shift = PM_BFEXT(PBBSEL, cksel) + 1;
 
        return bus_clk_get_rate(clk, shift);
 }
@@ -296,6 +335,7 @@ static unsigned long pbb_clk_get_rate(struct clk *clk)
 static struct clk cpu_clk = {
        .name           = "cpu",
        .get_rate       = cpu_clk_get_rate,
+       .set_rate       = cpu_clk_set_rate,
        .users          = 1,
 };
 static struct clk hsb_clk = {
@@ -327,12 +367,12 @@ static void genclk_mode(struct clk *clk, int enabled)
 {
        u32 control;
 
-       control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
+       control = pm_readl(GCCTRL(clk->index));
        if (enabled)
-               control |= SM_BIT(CEN);
+               control |= PM_BIT(CEN);
        else
-               control &= ~SM_BIT(CEN);
-       sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control);
+               control &= ~PM_BIT(CEN);
+       pm_writel(GCCTRL(clk->index), control);
 }
 
 static unsigned long genclk_get_rate(struct clk *clk)
@@ -340,9 +380,9 @@ static unsigned long genclk_get_rate(struct clk *clk)
        u32 control;
        unsigned long div = 1;
 
-       control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
-       if (control & SM_BIT(DIVEN))
-               div = 2 * (SM_BFEXT(DIV, control) + 1);
+       control = pm_readl(GCCTRL(clk->index));
+       if (control & PM_BIT(DIVEN))
+               div = 2 * (PM_BFEXT(DIV, control) + 1);
 
        return clk->parent->get_rate(clk->parent) / div;
 }
@@ -353,23 +393,22 @@ static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
        unsigned long parent_rate, actual_rate, div;
 
        parent_rate = clk->parent->get_rate(clk->parent);
-       control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
+       control = pm_readl(GCCTRL(clk->index));
 
        if (rate > 3 * parent_rate / 4) {
                actual_rate = parent_rate;
-               control &= ~SM_BIT(DIVEN);
+               control &= ~PM_BIT(DIVEN);
        } else {
                div = (parent_rate + rate) / (2 * rate) - 1;
-               control = SM_BFINS(DIV, div, control) | SM_BIT(DIVEN);
+               control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN);
                actual_rate = parent_rate / (2 * (div + 1));
        }
 
-       printk("clk %s: new rate %lu (actual rate %lu)\n",
-              clk->name, rate, actual_rate);
+       dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n",
+               clk->name, rate, actual_rate);
 
        if (apply)
-               sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index,
-                         control);
+               pm_writel(GCCTRL(clk->index), control);
 
        return actual_rate;
 }
@@ -378,24 +417,24 @@ int genclk_set_parent(struct clk *clk, struct clk *parent)
 {
        u32 control;
 
-       printk("clk %s: new parent %s (was %s)\n",
-              clk->name, parent->name, clk->parent->name);
+       dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n",
+               clk->name, parent->name, clk->parent->name);
 
-       control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
+       control = pm_readl(GCCTRL(clk->index));
 
        if (parent == &osc1 || parent == &pll1)
-               control |= SM_BIT(OSCSEL);
+               control |= PM_BIT(OSCSEL);
        else if (parent == &osc0 || parent == &pll0)
-               control &= ~SM_BIT(OSCSEL);
+               control &= ~PM_BIT(OSCSEL);
        else
                return -EINVAL;
 
        if (parent == &pll0 || parent == &pll1)
-               control |= SM_BIT(PLLSEL);
+               control |= PM_BIT(PLLSEL);
        else
-               control &= ~SM_BIT(PLLSEL);
+               control &= ~PM_BIT(PLLSEL);
 
-       sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control);
+       pm_writel(GCCTRL(clk->index), control);
        clk->parent = parent;
 
        return 0;
@@ -408,11 +447,11 @@ static void __init genclk_init_parent(struct clk *clk)
 
        BUG_ON(clk->index > 7);
 
-       control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
-       if (control & SM_BIT(OSCSEL))
-               parent = (control & SM_BIT(PLLSEL)) ? &pll1 : &osc1;
+       control = pm_readl(GCCTRL(clk->index));
+       if (control & PM_BIT(OSCSEL))
+               parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1;
        else
-               parent = (control & SM_BIT(PLLSEL)) ? &pll0 : &osc0;
+               parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;
 
        clk->parent = parent;
 }
@@ -420,21 +459,53 @@ static void __init genclk_init_parent(struct clk *clk)
 /* --------------------------------------------------------------------
  *  System peripherals
  * -------------------------------------------------------------------- */
-static struct resource sm_resource[] = {
-       PBMEM(0xfff00000),
-       NAMED_IRQ(19, "eim"),
-       NAMED_IRQ(20, "pm"),
-       NAMED_IRQ(21, "rtc"),
+static struct resource at32_pm0_resource[] = {
+       {
+               .start  = 0xfff00000,
+               .end    = 0xfff0007f,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(20),
 };
-struct platform_device at32_sm_device = {
-       .name           = "sm",
-       .id             = 0,
-       .resource       = sm_resource,
-       .num_resources  = ARRAY_SIZE(sm_resource),
+
+static struct resource at32ap700x_rtc0_resource[] = {
+       {
+               .start  = 0xfff00080,
+               .end    = 0xfff000af,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(21),
+};
+
+static struct resource at32_wdt0_resource[] = {
+       {
+               .start  = 0xfff000b0,
+               .end    = 0xfff000bf,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct resource at32_eic0_resource[] = {
+       {
+               .start  = 0xfff00100,
+               .end    = 0xfff0013f,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(19),
 };
-static struct clk at32_sm_pclk = {
+
+DEFINE_DEV(at32_pm, 0);
+DEFINE_DEV(at32ap700x_rtc, 0);
+DEFINE_DEV(at32_wdt, 0);
+DEFINE_DEV(at32_eic, 0);
+
+/*
+ * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this
+ * is always running.
+ */
+static struct clk at32_pm_pclk = {
        .name           = "pclk",
-       .dev            = &at32_sm_device.dev,
+       .dev            = &at32_pm0_device.dev,
        .parent         = &pbb_clk,
        .mode           = pbb_clk_mode,
        .get_rate       = pbb_clk_get_rate,
@@ -583,10 +654,11 @@ DEV_CLK(mck, pio4, pba, 14);
 
 void __init at32_add_system_devices(void)
 {
-       system_manager.eim_first_irq = EIM_IRQ_BASE;
-
-       platform_device_register(&at32_sm_device);
+       platform_device_register(&at32_pm0_device);
        platform_device_register(&at32_intc0_device);
+       platform_device_register(&at32ap700x_rtc0_device);
+       platform_device_register(&at32_wdt0_device);
+       platform_device_register(&at32_eic0_device);
        platform_device_register(&smc0_device);
        platform_device_register(&pdc_device);
 
@@ -1012,6 +1084,89 @@ err_dup_modedb:
        return NULL;
 }
 
+/* --------------------------------------------------------------------
+ *  SSC
+ * -------------------------------------------------------------------- */
+static struct resource ssc0_resource[] = {
+       PBMEM(0xffe01c00),
+       IRQ(10),
+};
+DEFINE_DEV(ssc, 0);
+DEV_CLK(pclk, ssc0, pba, 7);
+
+static struct resource ssc1_resource[] = {
+       PBMEM(0xffe02000),
+       IRQ(11),
+};
+DEFINE_DEV(ssc, 1);
+DEV_CLK(pclk, ssc1, pba, 8);
+
+static struct resource ssc2_resource[] = {
+       PBMEM(0xffe02400),
+       IRQ(12),
+};
+DEFINE_DEV(ssc, 2);
+DEV_CLK(pclk, ssc2, pba, 9);
+
+struct platform_device *__init
+at32_add_device_ssc(unsigned int id, unsigned int flags)
+{
+       struct platform_device *pdev;
+
+       switch (id) {
+       case 0:
+               pdev = &ssc0_device;
+               if (flags & ATMEL_SSC_RF)
+                       select_peripheral(PA(21), PERIPH_A, 0); /* RF */
+               if (flags & ATMEL_SSC_RK)
+                       select_peripheral(PA(22), PERIPH_A, 0); /* RK */
+               if (flags & ATMEL_SSC_TK)
+                       select_peripheral(PA(23), PERIPH_A, 0); /* TK */
+               if (flags & ATMEL_SSC_TF)
+                       select_peripheral(PA(24), PERIPH_A, 0); /* TF */
+               if (flags & ATMEL_SSC_TD)
+                       select_peripheral(PA(25), PERIPH_A, 0); /* TD */
+               if (flags & ATMEL_SSC_RD)
+                       select_peripheral(PA(26), PERIPH_A, 0); /* RD */
+               break;
+       case 1:
+               pdev = &ssc1_device;
+               if (flags & ATMEL_SSC_RF)
+                       select_peripheral(PA(0), PERIPH_B, 0);  /* RF */
+               if (flags & ATMEL_SSC_RK)
+                       select_peripheral(PA(1), PERIPH_B, 0);  /* RK */
+               if (flags & ATMEL_SSC_TK)
+                       select_peripheral(PA(2), PERIPH_B, 0);  /* TK */
+               if (flags & ATMEL_SSC_TF)
+                       select_peripheral(PA(3), PERIPH_B, 0);  /* TF */
+               if (flags & ATMEL_SSC_TD)
+                       select_peripheral(PA(4), PERIPH_B, 0);  /* TD */
+               if (flags & ATMEL_SSC_RD)
+                       select_peripheral(PA(5), PERIPH_B, 0);  /* RD */
+               break;
+       case 2:
+               pdev = &ssc2_device;
+               if (flags & ATMEL_SSC_TD)
+                       select_peripheral(PB(13), PERIPH_A, 0); /* TD */
+               if (flags & ATMEL_SSC_RD)
+                       select_peripheral(PB(14), PERIPH_A, 0); /* RD */
+               if (flags & ATMEL_SSC_TK)
+                       select_peripheral(PB(15), PERIPH_A, 0); /* TK */
+               if (flags & ATMEL_SSC_TF)
+                       select_peripheral(PB(16), PERIPH_A, 0); /* TF */
+               if (flags & ATMEL_SSC_RF)
+                       select_peripheral(PB(17), PERIPH_A, 0); /* RF */
+               if (flags & ATMEL_SSC_RK)
+                       select_peripheral(PB(18), PERIPH_A, 0); /* RK */
+               break;
+       default:
+               return NULL;
+       }
+
+       platform_device_register(pdev);
+       return pdev;
+}
+
 /* --------------------------------------------------------------------
  *  GCLK
  * -------------------------------------------------------------------- */
@@ -1066,7 +1221,7 @@ struct clk *at32_clock_list[] = {
        &hsb_clk,
        &pba_clk,
        &pbb_clk,
-       &at32_sm_pclk,
+       &at32_pm_pclk,
        &at32_intc0_pclk,
        &hmatrix_clk,
        &ebi_clk,
@@ -1094,6 +1249,9 @@ struct clk *at32_clock_list[] = {
        &atmel_spi1_spi_clk,
        &atmel_lcdfb0_hck1,
        &atmel_lcdfb0_pixclk,
+       &ssc0_pclk,
+       &ssc1_pclk,
+       &ssc2_pclk,
        &gclk0,
        &gclk1,
        &gclk2,
@@ -1113,18 +1271,20 @@ void __init at32_portmux_init(void)
 
 void __init at32_clock_init(void)
 {
-       struct at32_sm *sm = &system_manager;
        u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
        int i;
 
-       if (sm_readl(sm, PM_MCCTRL) & SM_BIT(PLLSEL))
+       if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) {
                main_clock = &pll0;
-       else
+               cpu_clk.parent = &pll0;
+       } else {
                main_clock = &osc0;
+               cpu_clk.parent = &osc0;
+       }
 
-       if (sm_readl(sm, PM_PLL0) & SM_BIT(PLLOSC))
+       if (pm_readl(PLL0) & PM_BIT(PLLOSC))
                pll0.parent = &osc1;
-       if (sm_readl(sm, PM_PLL1) & SM_BIT(PLLOSC))
+       if (pm_readl(PLL1) & PM_BIT(PLLOSC))
                pll1.parent = &osc1;
 
        genclk_init_parent(&gclk0);
@@ -1157,8 +1317,8 @@ void __init at32_clock_init(void)
                        pbb_mask |= 1 << clk->index;
        }
 
-       sm_writel(sm, PM_CPU_MASK, cpu_mask);
-       sm_writel(sm, PM_HSB_MASK, hsb_mask);
-       sm_writel(sm, PM_PBA_MASK, pba_mask);
-       sm_writel(sm, PM_PBB_MASK, pbb_mask);
+       pm_writel(CPU_MASK, cpu_mask);
+       pm_writel(HSB_MASK, hsb_mask);
+       pm_writel(PBA_MASK, pba_mask);
+       pm_writel(PBB_MASK, pbb_mask);
 }
diff --git a/arch/avr32/mach-at32ap/cpufreq.c b/arch/avr32/mach-at32ap/cpufreq.c
new file mode 100644 (file)
index 0000000..235524b
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2004-2007 Atmel Corporation
+ *
+ * Based on MIPS implementation arch/mips/kernel/time.c
+ *   Copyright 2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*#define DEBUG*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <asm/system.h>
+
+static struct clk *cpuclk;
+
+static int at32_verify_speed(struct cpufreq_policy *policy)
+{
+       if (policy->cpu != 0)
+               return -EINVAL;
+
+       cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+                       policy->cpuinfo.max_freq);
+       return 0;
+}
+
+static unsigned int at32_get_speed(unsigned int cpu)
+{
+       /* No SMP support */
+       if (cpu)
+               return 0;
+       return (unsigned int)((clk_get_rate(cpuclk) + 500) / 1000);
+}
+
+static int at32_set_target(struct cpufreq_policy *policy,
+                         unsigned int target_freq,
+                         unsigned int relation)
+{
+       struct cpufreq_freqs freqs;
+       long freq;
+
+       /* Convert target_freq from kHz to Hz */
+       freq = clk_round_rate(cpuclk, target_freq * 1000);
+
+       /* Check if policy->min <= new_freq <= policy->max */
+       if(freq < (policy->min * 1000) || freq > (policy->max * 1000))
+               return -EINVAL;
+
+       pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000);
+
+       freqs.old = at32_get_speed(0);
+       freqs.new = (freq + 500) / 1000;
+       freqs.cpu = 0;
+       freqs.flags = 0;
+
+       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+       clk_set_rate(cpuclk, freq);
+       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+       pr_debug("cpufreq: set frequency %lu Hz\n", freq);
+
+       return 0;
+}
+
+static int __init at32_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+       if (policy->cpu != 0)
+               return -EINVAL;
+
+       cpuclk = clk_get(NULL, "cpu");
+       if (IS_ERR(cpuclk)) {
+               pr_debug("cpufreq: could not get CPU clk\n");
+               return PTR_ERR(cpuclk);
+       }
+
+       policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000;
+       policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
+       policy->cpuinfo.transition_latency = 0;
+       policy->cur = at32_get_speed(0);
+       policy->min = policy->cpuinfo.min_freq;
+       policy->max = policy->cpuinfo.max_freq;
+       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+       printk("cpufreq: AT32AP CPU frequency driver\n");
+
+       return 0;
+}
+
+static struct cpufreq_driver at32_driver = {
+       .name           = "at32ap",
+       .owner          = THIS_MODULE,
+       .init           = at32_cpufreq_driver_init,
+       .verify         = at32_verify_speed,
+       .target         = at32_set_target,
+       .get            = at32_get_speed,
+       .flags          = CPUFREQ_STICKY,
+};
+
+static int __init at32_cpufreq_init(void)
+{
+       return cpufreq_register_driver(&at32_driver);
+}
+
+arch_initcall(at32_cpufreq_init);
index 4a60eccfebd240762e751a3c43bd4191cb5fe714..8acd010900313af2194ea5652be7c5abde1b83bd 100644 (file)
 
 #include <asm/io.h>
 
-#include <asm/arch/sm.h>
-
-#include "sm.h"
+/* EIC register offsets */
+#define EIC_IER                                        0x0000
+#define EIC_IDR                                        0x0004
+#define EIC_IMR                                        0x0008
+#define EIC_ISR                                        0x000c
+#define EIC_ICR                                        0x0010
+#define EIC_MODE                               0x0014
+#define EIC_EDGE                               0x0018
+#define EIC_LEVEL                              0x001c
+#define EIC_TEST                               0x0020
+#define EIC_NMIC                               0x0024
+
+/* Bitfields in TEST */
+#define EIC_TESTEN_OFFSET                      31
+#define EIC_TESTEN_SIZE                                1
+
+/* Bitfields in NMIC */
+#define EIC_EN_OFFSET                          0
+#define EIC_EN_SIZE                            1
+
+/* Bit manipulation macros */
+#define EIC_BIT(name)                                  \
+       (1 << EIC_##name##_OFFSET)
+#define EIC_BF(name,value)                             \
+       (((value) & ((1 << EIC_##name##_SIZE) - 1))     \
+        << EIC_##name##_OFFSET)
+#define EIC_BFEXT(name,value)                          \
+       (((value) >> EIC_##name##_OFFSET)               \
+        & ((1 << EIC_##name##_SIZE) - 1))
+#define EIC_BFINS(name,value,old)                      \
+       (((old) & ~(((1 << EIC_##name##_SIZE) - 1)      \
+                   << EIC_##name##_OFFSET))            \
+        | EIC_BF(name,value))
+
+/* Register access macros */
+#define eic_readl(port,reg)                            \
+       __raw_readl((port)->regs + EIC_##reg)
+#define eic_writel(port,reg,value)                     \
+       __raw_writel((value), (port)->regs + EIC_##reg)
+
+struct eic {
+       void __iomem *regs;
+       struct irq_chip *chip;
+       unsigned int first_irq;
+};
 
-static void eim_ack_irq(unsigned int irq)
+static void eic_ack_irq(unsigned int irq)
 {
-       struct at32_sm *sm = get_irq_chip_data(irq);
-       sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq));
+       struct eic *eic = get_irq_chip_data(irq);
+       eic_writel(eic, ICR, 1 << (irq - eic->first_irq));
 }
 
-static void eim_mask_irq(unsigned int irq)
+static void eic_mask_irq(unsigned int irq)
 {
-       struct at32_sm *sm = get_irq_chip_data(irq);
-       sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq));
+       struct eic *eic = get_irq_chip_data(irq);
+       eic_writel(eic, IDR, 1 << (irq - eic->first_irq));
 }
 
-static void eim_mask_ack_irq(unsigned int irq)
+static void eic_mask_ack_irq(unsigned int irq)
 {
-       struct at32_sm *sm = get_irq_chip_data(irq);
-       sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq));
-       sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq));
+       struct eic *eic = get_irq_chip_data(irq);
+       eic_writel(eic, ICR, 1 << (irq - eic->first_irq));
+       eic_writel(eic, IDR, 1 << (irq - eic->first_irq));
 }
 
-static void eim_unmask_irq(unsigned int irq)
+static void eic_unmask_irq(unsigned int irq)
 {
-       struct at32_sm *sm = get_irq_chip_data(irq);
-       sm_writel(sm, EIM_IER, 1 << (irq - sm->eim_first_irq));
+       struct eic *eic = get_irq_chip_data(irq);
+       eic_writel(eic, IER, 1 << (irq - eic->first_irq));
 }
 
-static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
+static int eic_set_irq_type(unsigned int irq, unsigned int flow_type)
 {
-       struct at32_sm *sm = get_irq_chip_data(irq);
+       struct eic *eic = get_irq_chip_data(irq);
        struct irq_desc *desc;
-       unsigned int i = irq - sm->eim_first_irq;
+       unsigned int i = irq - eic->first_irq;
        u32 mode, edge, level;
-       unsigned long flags;
        int ret = 0;
 
        flow_type &= IRQ_TYPE_SENSE_MASK;
@@ -60,11 +101,10 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
                flow_type = IRQ_TYPE_LEVEL_LOW;
 
        desc = &irq_desc[irq];
-       spin_lock_irqsave(&sm->lock, flags);
 
-       mode = sm_readl(sm, EIM_MODE);
-       edge = sm_readl(sm, EIM_EDGE);
-       level = sm_readl(sm, EIM_LEVEL);
+       mode = eic_readl(eic, MODE);
+       edge = eic_readl(eic, EDGE);
+       level = eic_readl(eic, LEVEL);
 
        switch (flow_type) {
        case IRQ_TYPE_LEVEL_LOW:
@@ -89,9 +129,9 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
        }
 
        if (ret == 0) {
-               sm_writel(sm, EIM_MODE, mode);
-               sm_writel(sm, EIM_EDGE, edge);
-               sm_writel(sm, EIM_LEVEL, level);
+               eic_writel(eic, MODE, mode);
+               eic_writel(eic, EDGE, edge);
+               eic_writel(eic, LEVEL, level);
 
                if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
                        flow_type |= IRQ_LEVEL;
@@ -99,35 +139,33 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
                desc->status |= flow_type;
        }
 
-       spin_unlock_irqrestore(&sm->lock, flags);
-
        return ret;
 }
 
-struct irq_chip eim_chip = {
-       .name           = "eim",
-       .ack            = eim_ack_irq,
-       .mask           = eim_mask_irq,
-       .mask_ack       = eim_mask_ack_irq,
-       .unmask         = eim_unmask_irq,
-       .set_type       = eim_set_irq_type,
+struct irq_chip eic_chip = {
+       .name           = "eic",
+       .ack            = eic_ack_irq,
+       .mask           = eic_mask_irq,
+       .mask_ack       = eic_mask_ack_irq,
+       .unmask         = eic_unmask_irq,
+       .set_type       = eic_set_irq_type,
 };
 
-static void demux_eim_irq(unsigned int irq, struct irq_desc *desc)
+static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
 {
-       struct at32_sm *sm = desc->handler_data;
+       struct eic *eic = desc->handler_data;
        struct irq_desc *ext_desc;
        unsigned long status, pending;
        unsigned int i, ext_irq;
 
-       status = sm_readl(sm, EIM_ISR);
-       pending = status & sm_readl(sm, EIM_IMR);
+       status = eic_readl(eic, ISR);
+       pending = status & eic_readl(eic, IMR);
 
        while (pending) {
                i = fls(pending) - 1;
                pending &= ~(1 << i);
 
-               ext_irq = i + sm->eim_first_irq;
+               ext_irq = i + eic->first_irq;
                ext_desc = irq_desc + ext_irq;
                if (ext_desc->status & IRQ_LEVEL)
                        handle_level_irq(ext_irq, ext_desc);
@@ -136,51 +174,85 @@ static void demux_eim_irq(unsigned int irq, struct irq_desc *desc)
        }
 }
 
-static int __init eim_init(void)
+static int __init eic_probe(struct platform_device *pdev)
 {
-       struct at32_sm *sm = &system_manager;
+       struct eic *eic;
+       struct resource *regs;
        unsigned int i;
        unsigned int nr_irqs;
        unsigned int int_irq;
+       int ret;
        u32 pattern;
 
-       /*
-        * The EIM is really the same module as SM, so register
-        * mapping, etc. has been taken care of already.
-        */
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       int_irq = platform_get_irq(pdev, 0);
+       if (!regs || !int_irq) {
+               dev_dbg(&pdev->dev, "missing regs and/or irq resource\n");
+               return -ENXIO;
+       }
+
+       ret = -ENOMEM;
+       eic = kzalloc(sizeof(struct eic), GFP_KERNEL);
+       if (!eic) {
+               dev_dbg(&pdev->dev, "no memory for eic structure\n");
+               goto err_kzalloc;
+       }
+
+       eic->first_irq = EIM_IRQ_BASE + 32 * pdev->id;
+       eic->regs = ioremap(regs->start, regs->end - regs->start + 1);
+       if (!eic->regs) {
+               dev_dbg(&pdev->dev, "failed to map regs\n");
+               goto err_ioremap;
+       }
 
        /*
         * Find out how many interrupt lines that are actually
         * implemented in hardware.
         */
-       sm_writel(sm, EIM_IDR, ~0UL);
-       sm_writel(sm, EIM_MODE, ~0UL);
-       pattern = sm_readl(sm, EIM_MODE);
+       eic_writel(eic, IDR, ~0UL);
+       eic_writel(eic, MODE, ~0UL);
+       pattern = eic_readl(eic, MODE);
        nr_irqs = fls(pattern);
 
        /* Trigger on falling edge unless overridden by driver */
-       sm_writel(sm, EIM_MODE, 0UL);
-       sm_writel(sm, EIM_EDGE, 0UL);
+       eic_writel(eic, MODE, 0UL);
+       eic_writel(eic, EDGE, 0UL);
 
-       sm->eim_chip = &eim_chip;
+       eic->chip = &eic_chip;
 
        for (i = 0; i < nr_irqs; i++) {
                /* NOTE the handler we set here is ignored by the demux */
-               set_irq_chip_and_handler(sm->eim_first_irq + i, &eim_chip,
+               set_irq_chip_and_handler(eic->first_irq + i, &eic_chip,
                                         handle_level_irq);
-               set_irq_chip_data(sm->eim_first_irq + i, sm);
+               set_irq_chip_data(eic->first_irq + i, eic);
        }
 
-       int_irq = platform_get_irq_byname(sm->pdev, "eim");
-
-       set_irq_chained_handler(int_irq, demux_eim_irq);
-       set_irq_data(int_irq, sm);
+       set_irq_chained_handler(int_irq, demux_eic_irq);
+       set_irq_data(int_irq, eic);
 
-       printk("EIM: External Interrupt Module at 0x%p, IRQ %u\n",
-              sm->regs, int_irq);
-       printk("EIM: Handling %u external IRQs, starting with IRQ %u\n",
-              nr_irqs, sm->eim_first_irq);
+       dev_info(&pdev->dev,
+                "External Interrupt Controller at 0x%p, IRQ %u\n",
+                eic->regs, int_irq);
+       dev_info(&pdev->dev,
+                "Handling %u external IRQs, starting with IRQ %u\n",
+                nr_irqs, eic->first_irq);
 
        return 0;
+
+err_ioremap:
+       kfree(eic);
+err_kzalloc:
+       return ret;
+}
+
+static struct platform_driver eic_driver = {
+       .driver = {
+               .name = "at32_eic",
+       },
+};
+
+static int __init eic_init(void)
+{
+       return platform_driver_probe(&eic_driver, eic_probe);
 }
-arch_initcall(eim_init);
+arch_initcall(eic_init);
diff --git a/arch/avr32/mach-at32ap/pm.h b/arch/avr32/mach-at32ap/pm.h
new file mode 100644 (file)
index 0000000..a1f8ace
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Register definitions for the Power Manager (PM)
+ */
+#ifndef __ARCH_AVR32_MACH_AT32AP_PM_H__
+#define __ARCH_AVR32_MACH_AT32AP_PM_H__
+
+/* PM register offsets */
+#define PM_MCCTRL                              0x0000
+#define PM_CKSEL                               0x0004
+#define PM_CPU_MASK                            0x0008
+#define PM_HSB_MASK                            0x000c
+#define PM_PBA_MASK                            0x0010
+#define PM_PBB_MASK                            0x0014
+#define PM_PLL0                                        0x0020
+#define PM_PLL1                                        0x0024
+#define PM_IER                                 0x0040
+#define PM_IDR                                 0x0044
+#define PM_IMR                                 0x0048
+#define PM_ISR                                 0x004c
+#define PM_ICR                                 0x0050
+#define PM_GCCTRL(x)                           (0x0060 + 4 * (x))
+#define PM_RCAUSE                              0x00c0
+
+/* Bitfields in CKSEL */
+#define PM_CPUSEL_OFFSET                       0
+#define PM_CPUSEL_SIZE                         3
+#define PM_CPUDIV_OFFSET                       7
+#define PM_CPUDIV_SIZE                         1
+#define PM_HSBSEL_OFFSET                       8
+#define PM_HSBSEL_SIZE                         3
+#define PM_HSBDIV_OFFSET                       15
+#define PM_HSBDIV_SIZE                         1
+#define PM_PBASEL_OFFSET                       16
+#define PM_PBASEL_SIZE                         3
+#define PM_PBADIV_OFFSET                       23
+#define PM_PBADIV_SIZE                         1
+#define PM_PBBSEL_OFFSET                       24
+#define PM_PBBSEL_SIZE                         3
+#define PM_PBBDIV_OFFSET                       31
+#define PM_PBBDIV_SIZE                         1
+
+/* Bitfields in PLL0 */
+#define PM_PLLEN_OFFSET                                0
+#define PM_PLLEN_SIZE                          1
+#define PM_PLLOSC_OFFSET                       1
+#define PM_PLLOSC_SIZE                         1
+#define PM_PLLOPT_OFFSET                       2
+#define PM_PLLOPT_SIZE                         3
+#define PM_PLLDIV_OFFSET                       8
+#define PM_PLLDIV_SIZE                         8
+#define PM_PLLMUL_OFFSET                       16
+#define PM_PLLMUL_SIZE                         8
+#define PM_PLLCOUNT_OFFSET                     24
+#define PM_PLLCOUNT_SIZE                       6
+#define PM_PLLTEST_OFFSET                      31
+#define PM_PLLTEST_SIZE                                1
+
+/* Bitfields in ICR */
+#define PM_LOCK0_OFFSET                                0
+#define PM_LOCK0_SIZE                          1
+#define PM_LOCK1_OFFSET                                1
+#define PM_LOCK1_SIZE                          1
+#define PM_WAKE_OFFSET                         2
+#define PM_WAKE_SIZE                           1
+#define PM_CKRDY_OFFSET                                5
+#define PM_CKRDY_SIZE                          1
+#define PM_MSKRDY_OFFSET                       6
+#define PM_MSKRDY_SIZE                         1
+
+/* Bitfields in GCCTRL0 */
+#define PM_OSCSEL_OFFSET                       0
+#define PM_OSCSEL_SIZE                         1
+#define PM_PLLSEL_OFFSET                       1
+#define PM_PLLSEL_SIZE                         1
+#define PM_CEN_OFFSET                          2
+#define PM_CEN_SIZE                            1
+#define PM_DIVEN_OFFSET                                4
+#define PM_DIVEN_SIZE                          1
+#define PM_DIV_OFFSET                          8
+#define PM_DIV_SIZE                            8
+
+/* Bitfields in RCAUSE */
+#define PM_POR_OFFSET                          0
+#define PM_POR_SIZE                            1
+#define PM_EXT_OFFSET                          2
+#define PM_EXT_SIZE                            1
+#define PM_WDT_OFFSET                          3
+#define PM_WDT_SIZE                            1
+#define PM_NTAE_OFFSET                         4
+#define PM_NTAE_SIZE                           1
+
+/* Bit manipulation macros */
+#define PM_BIT(name)                                   \
+       (1 << PM_##name##_OFFSET)
+#define PM_BF(name,value)                              \
+       (((value) & ((1 << PM_##name##_SIZE) - 1))      \
+        << PM_##name##_OFFSET)
+#define PM_BFEXT(name,value)                           \
+       (((value) >> PM_##name##_OFFSET)                \
+        & ((1 << PM_##name##_SIZE) - 1))
+#define PM_BFINS(name,value,old)\
+       (((old) & ~(((1 << PM_##name##_SIZE) - 1)       \
+                   << PM_##name##_OFFSET))             \
+        | PM_BF(name,value))
+
+/* Register access macros */
+#define pm_readl(reg)                                                  \
+       __raw_readl((void __iomem *)AT32_PM_BASE + PM_##reg)
+#define pm_writel(reg,value)                                           \
+       __raw_writel((value), (void __iomem *)AT32_PM_BASE + PM_##reg)
+
+#endif /* __ARCH_AVR32_MACH_AT32AP_PM_H__ */
diff --git a/arch/avr32/mach-at32ap/sm.h b/arch/avr32/mach-at32ap/sm.h
deleted file mode 100644 (file)
index cad02b5..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Register definitions for SM
- *
- * System Manager
- */
-#ifndef __ASM_AVR32_SM_H__
-#define __ASM_AVR32_SM_H__
-
-/* SM register offsets */
-#define SM_PM_MCCTRL                            0x0000
-#define SM_PM_CKSEL                             0x0004
-#define SM_PM_CPU_MASK                          0x0008
-#define SM_PM_HSB_MASK                          0x000c
-#define SM_PM_PBA_MASK                         0x0010
-#define SM_PM_PBB_MASK                         0x0014
-#define SM_PM_PLL0                              0x0020
-#define SM_PM_PLL1                              0x0024
-#define SM_PM_VCTRL                             0x0030
-#define SM_PM_VMREF                             0x0034
-#define SM_PM_VMV                               0x0038
-#define SM_PM_IER                               0x0040
-#define SM_PM_IDR                               0x0044
-#define SM_PM_IMR                               0x0048
-#define SM_PM_ISR                               0x004c
-#define SM_PM_ICR                               0x0050
-#define SM_PM_GCCTRL                            0x0060
-#define SM_RTC_CTRL                             0x0080
-#define SM_RTC_VAL                              0x0084
-#define SM_RTC_TOP                              0x0088
-#define SM_RTC_IER                              0x0090
-#define SM_RTC_IDR                              0x0094
-#define SM_RTC_IMR                              0x0098
-#define SM_RTC_ISR                              0x009c
-#define SM_RTC_ICR                              0x00a0
-#define SM_WDT_CTRL                             0x00b0
-#define SM_WDT_CLR                              0x00b4
-#define SM_WDT_EXT                              0x00b8
-#define SM_RC_RCAUSE                            0x00c0
-#define SM_EIM_IER                              0x0100
-#define SM_EIM_IDR                              0x0104
-#define SM_EIM_IMR                              0x0108
-#define SM_EIM_ISR                              0x010c
-#define SM_EIM_ICR                              0x0110
-#define SM_EIM_MODE                             0x0114
-#define SM_EIM_EDGE                             0x0118
-#define SM_EIM_LEVEL                            0x011c
-#define SM_EIM_TEST                             0x0120
-#define SM_EIM_NMIC                             0x0124
-
-/* Bitfields in PM_MCCTRL */
-
-/* Bitfields in PM_CKSEL */
-#define SM_CPUSEL_OFFSET                        0
-#define SM_CPUSEL_SIZE                          3
-#define SM_CPUDIV_OFFSET                        7
-#define SM_CPUDIV_SIZE                          1
-#define SM_HSBSEL_OFFSET                        8
-#define SM_HSBSEL_SIZE                          3
-#define SM_HSBDIV_OFFSET                        15
-#define SM_HSBDIV_SIZE                          1
-#define SM_PBASEL_OFFSET                       16
-#define SM_PBASEL_SIZE                         3
-#define SM_PBADIV_OFFSET                       23
-#define SM_PBADIV_SIZE                         1
-#define SM_PBBSEL_OFFSET                       24
-#define SM_PBBSEL_SIZE                         3
-#define SM_PBBDIV_OFFSET                       31
-#define SM_PBBDIV_SIZE                         1
-
-/* Bitfields in PM_CPU_MASK */
-
-/* Bitfields in PM_HSB_MASK */
-
-/* Bitfields in PM_PBA_MASK */
-
-/* Bitfields in PM_PBB_MASK */
-
-/* Bitfields in PM_PLL0 */
-#define SM_PLLEN_OFFSET                         0
-#define SM_PLLEN_SIZE                           1
-#define SM_PLLOSC_OFFSET                        1
-#define SM_PLLOSC_SIZE                          1
-#define SM_PLLOPT_OFFSET                        2
-#define SM_PLLOPT_SIZE                          3
-#define SM_PLLDIV_OFFSET                        8
-#define SM_PLLDIV_SIZE                          8
-#define SM_PLLMUL_OFFSET                        16
-#define SM_PLLMUL_SIZE                          8
-#define SM_PLLCOUNT_OFFSET                      24
-#define SM_PLLCOUNT_SIZE                        6
-#define SM_PLLTEST_OFFSET                       31
-#define SM_PLLTEST_SIZE                         1
-
-/* Bitfields in PM_PLL1 */
-
-/* Bitfields in PM_VCTRL */
-#define SM_VAUTO_OFFSET                         0
-#define SM_VAUTO_SIZE                           1
-#define SM_PM_VCTRL_VAL_OFFSET                  8
-#define SM_PM_VCTRL_VAL_SIZE                    7
-
-/* Bitfields in PM_VMREF */
-#define SM_REFSEL_OFFSET                        0
-#define SM_REFSEL_SIZE                          4
-
-/* Bitfields in PM_VMV */
-#define SM_PM_VMV_VAL_OFFSET                    0
-#define SM_PM_VMV_VAL_SIZE                      8
-
-/* Bitfields in PM_IER */
-
-/* Bitfields in PM_IDR */
-
-/* Bitfields in PM_IMR */
-
-/* Bitfields in PM_ISR */
-
-/* Bitfields in PM_ICR */
-#define SM_LOCK0_OFFSET                         0
-#define SM_LOCK0_SIZE                           1
-#define SM_LOCK1_OFFSET                         1
-#define SM_LOCK1_SIZE                           1
-#define SM_WAKE_OFFSET                          2
-#define SM_WAKE_SIZE                            1
-#define SM_VOK_OFFSET                           3
-#define SM_VOK_SIZE                             1
-#define SM_VMRDY_OFFSET                         4
-#define SM_VMRDY_SIZE                           1
-#define SM_CKRDY_OFFSET                         5
-#define SM_CKRDY_SIZE                           1
-
-/* Bitfields in PM_GCCTRL */
-#define SM_OSCSEL_OFFSET                        0
-#define SM_OSCSEL_SIZE                          1
-#define SM_PLLSEL_OFFSET                        1
-#define SM_PLLSEL_SIZE                          1
-#define SM_CEN_OFFSET                           2
-#define SM_CEN_SIZE                             1
-#define SM_CPC_OFFSET                           3
-#define SM_CPC_SIZE                             1
-#define SM_DIVEN_OFFSET                         4
-#define SM_DIVEN_SIZE                           1
-#define SM_DIV_OFFSET                           8
-#define SM_DIV_SIZE                             8
-
-/* Bitfields in RTC_CTRL */
-#define SM_PCLR_OFFSET                          1
-#define SM_PCLR_SIZE                            1
-#define SM_TOPEN_OFFSET                         2
-#define SM_TOPEN_SIZE                           1
-#define SM_CLKEN_OFFSET                         3
-#define SM_CLKEN_SIZE                           1
-#define SM_PSEL_OFFSET                          8
-#define SM_PSEL_SIZE                            16
-
-/* Bitfields in RTC_VAL */
-#define SM_RTC_VAL_VAL_OFFSET                   0
-#define SM_RTC_VAL_VAL_SIZE                     31
-
-/* Bitfields in RTC_TOP */
-#define SM_RTC_TOP_VAL_OFFSET                   0
-#define SM_RTC_TOP_VAL_SIZE                     32
-
-/* Bitfields in RTC_IER */
-
-/* Bitfields in RTC_IDR */
-
-/* Bitfields in RTC_IMR */
-
-/* Bitfields in RTC_ISR */
-
-/* Bitfields in RTC_ICR */
-#define SM_TOPI_OFFSET                          0
-#define SM_TOPI_SIZE                            1
-
-/* Bitfields in WDT_CTRL */
-#define SM_KEY_OFFSET                           24
-#define SM_KEY_SIZE                             8
-
-/* Bitfields in WDT_CLR */
-
-/* Bitfields in WDT_EXT */
-
-/* Bitfields in RC_RCAUSE */
-#define SM_POR_OFFSET                           0
-#define SM_POR_SIZE                             1
-#define SM_BOD_OFFSET                           1
-#define SM_BOD_SIZE                             1
-#define SM_EXT_OFFSET                           2
-#define SM_EXT_SIZE                             1
-#define SM_WDT_OFFSET                           3
-#define SM_WDT_SIZE                             1
-#define SM_NTAE_OFFSET                          4
-#define SM_NTAE_SIZE                            1
-#define SM_SERP_OFFSET                          5
-#define SM_SERP_SIZE                            1
-
-/* Bitfields in EIM_IER */
-
-/* Bitfields in EIM_IDR */
-
-/* Bitfields in EIM_IMR */
-
-/* Bitfields in EIM_ISR */
-
-/* Bitfields in EIM_ICR */
-
-/* Bitfields in EIM_MODE */
-
-/* Bitfields in EIM_EDGE */
-#define SM_INT0_OFFSET                          0
-#define SM_INT0_SIZE                            1
-#define SM_INT1_OFFSET                          1
-#define SM_INT1_SIZE                            1
-#define SM_INT2_OFFSET                          2
-#define SM_INT2_SIZE                            1
-#define SM_INT3_OFFSET                          3
-#define SM_INT3_SIZE                            1
-
-/* Bitfields in EIM_LEVEL */
-
-/* Bitfields in EIM_TEST */
-#define SM_TESTEN_OFFSET                        31
-#define SM_TESTEN_SIZE                          1
-
-/* Bitfields in EIM_NMIC */
-#define SM_EN_OFFSET                            0
-#define SM_EN_SIZE                              1
-
-/* Bit manipulation macros */
-#define SM_BIT(name)                            (1 << SM_##name##_OFFSET)
-#define SM_BF(name,value)                       (((value) & ((1 << SM_##name##_SIZE) - 1)) << SM_##name##_OFFSET)
-#define SM_BFEXT(name,value)                    (((value) >> SM_##name##_OFFSET) & ((1 << SM_##name##_SIZE) - 1))
-#define SM_BFINS(name,value,old)                (((old) & ~(((1 << SM_##name##_SIZE) - 1) << SM_##name##_OFFSET)) | SM_BF(name,value))
-
-/* Register access macros */
-#define sm_readl(port,reg)                                     \
-       __raw_readl((port)->regs + SM_##reg)
-#define sm_writel(port,reg,value)                              \
-       __raw_writel((value), (port)->regs + SM_##reg)
-
-#endif /* __ASM_AVR32_SM_H__ */
index c1c32e4c863da0896e196af17f9c541e31b07089..a74c08786b21a8500067c2b442cb08b0b2c41daf 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/serial.h>
 #include <linux/serial_core.h>
 #include <linux/serial_reg.h>
+#include <linux/serial_8250.h>
 
 #include <asm/setup.h>
 #include <asm/irq.h>
index c7c9c2a15fab4dc87f7d16db27d14b82b04926dd..7a11b905ef49d0949c23d80a985fae3c400528c0 100644 (file)
@@ -222,6 +222,8 @@ config PARAVIRT
          However, when run without a hypervisor the kernel is
          theoretically slower.  If in doubt, say N.
 
+source "arch/i386/xen/Kconfig"
+
 config VMI
        bool "VMI Paravirt-ops support"
        depends on PARAVIRT
index 181cc29a7c4fcf9cf9472f4b21c2534c07ff4e11..01f0ff0daaf4203117a34a17c071fa2b110252ab 100644 (file)
@@ -93,6 +93,9 @@ mflags-$(CONFIG_X86_ES7000)   := -Iinclude/asm-i386/mach-es7000
 mcore-$(CONFIG_X86_ES7000)     := mach-default
 core-$(CONFIG_X86_ES7000)      := arch/i386/mach-es7000/
 
+# Xen paravirtualization support
+core-$(CONFIG_XEN)             += arch/i386/xen/
+
 # default subarch .h files
 mflags-y += -Iinclude/asm-i386/mach-default
 
index 08678a0a3d191a8a197763bc35202d0c79765b33..93386a4e40b49bfcb1b2b8c0be80251594fad283 100644 (file)
@@ -39,7 +39,7 @@ setup-y               += printf.o string.o tty.o video.o version.o voyager.o
 setup-y                += video-vga.o
 setup-y                += video-vesa.o
 setup-y                += video-bios.o
-
+targets                += $(setup-y)
 hostprogs-y    := tools/build
 
 HOSTCFLAGS_build.o := $(LINUXINCLUDE)
index 0329c4fe4f88956b4a423f41c61e7d96b5a5a649..dec70c9b6050073ebdfc50dd7be9f6ed08d08efb 100644 (file)
@@ -56,7 +56,7 @@ static inline u16 inw(u16 port)
 
 static inline void outl(u32 v, u16 port)
 {
-       asm volatile("outl %0,%1" : : "a" (v), "dn" (port));
+       asm volatile("outl %0,%1" : : "a" (v), "dN" (port));
 }
 static inline u32 inl(u32 port)
 {
index ce4fda261aaf35d4bb5edfc4d11799dd2cdd1cfd..b0e21c3cee5c91f01075116b495b676e8023028b 100644 (file)
@@ -31,6 +31,8 @@ static const char* safe_abs_relocs[] = {
                "__kernel_rt_sigreturn",
                "__kernel_sigreturn",
                "SYSENTER_RETURN",
+               "xen_irq_disable_direct_reloc",
+               "xen_save_fl_direct_reloc",
 };
 
 static int is_safe_abs_reloc(const char* sym_name)
index 8b0f4473b083efac607796179248a5bf98a35f52..991e8ceae1de3c296a0f456fe7aa86c08d763814 100644 (file)
@@ -115,8 +115,8 @@ static int has_eflag(u32 mask)
            "pushfl ; "
            "popl %1 ; "
            "popfl"
-           : "=r" (f0), "=r" (f1)
-           : "g" (mask));
+           : "=&r" (f0), "=&r" (f1)
+           : "ri" (mask));
 
        return !!((f0^f1) & mask);
 }
index 9b68bd1aef19d35c2ae5c75a790a2fd7dc93ba33..68222f2d4b670479fd7656f4036c848bfed7e5e8 100644 (file)
@@ -26,7 +26,7 @@ int query_mca(void)
            "setc %0 ; "
            "movw %%es, %1 ; "
            "popw %%es"
-           : "=acdSDm" (err), "=acdSDm" (es), "=b" (bx)
+           : "=acd" (err), "=acdSD" (es), "=b" (bx)
            : "a" (0xc000));
 
        if (err)
index 3fa53e15ed776e334921f7d54d7006ffff3faa90..1df025c732613fde1b8f79e20e740103e8433e1b 100644 (file)
@@ -65,7 +65,7 @@ static void move_kernel_around(void)
                             "popw %%ds ; "
                             "popw %%es"
                             : "+c" (dwords)
-                            : "rm" (dst_seg), "rm" (src_seg)
+                            : "r" (dst_seg), "r" (src_seg)
                             : "esi", "edi");
 
                syssize -= paras;
index 886f47d8a48883a4c3154ab8ffa3ea77f94f9ad9..b4248740ff0da355ee3ca44eb99b70d4532af773 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 /*
- * This file builds a disk-image from three different files:
+ * This file builds a disk-image from two different files:
  *
  * - setup: 8086 machine code, sets up system parm
  * - system: 80386 code for actual system
index a8db78736b02252d7dfca4f52a8550bbd73d94a7..9c668aad351501499610e14ee0c113f9f59a4e74 100644 (file)
@@ -31,7 +31,7 @@ void __attribute__((section(".inittext"))) putchar(int ch)
 
        /* int $0x10 is known to have bugs involving touching registers
           it shouldn't.  Be extra conservative... */
-       asm volatile("pushal; int $0x10; popal"
+       asm volatile("pushal; pushw %%ds; int $0x10; popw %%ds; popal"
                     : : "b" (0x0007), "c" (0x0001), "a" (0x0e00|ch));
 }
 
index 3bb3573cd6a15ad07b34a5324634f516bd726b71..958130ef004296c02f79614838152f0e1beae102 100644 (file)
@@ -195,7 +195,7 @@ static void vga_recalc_vertical(void)
 {
        unsigned int font_size, rows;
        u16 crtc;
-       u8 ov;
+       u8 pt, ov;
 
        set_fs(0);
        font_size = rdfs8(0x485); /* BIOS: font size (pixels) */
@@ -206,7 +206,12 @@ static void vga_recalc_vertical(void)
 
        crtc = vga_crtc();
 
+       pt = in_idx(crtc, 0x11);
+       pt &= ~0x80;            /* Unlock CR0-7 */
+       out_idx(pt, crtc, 0x11);
+
        out_idx((u8)rows, crtc, 0x12); /* Lower height register */
+
        ov = in_idx(crtc, 0x07); /* Overflow register */
        ov &= 0xbd;
        ov |= (rows >> (8-1)) & 0x02;
@@ -411,7 +416,7 @@ static void restore_screen(void)
                             "1: rep;stosl ; "
                             "popw %%es"
                             : "+D" (dst), "+c" (npad)
-                            : "bdSm" (video_segment),
+                            : "bdS" (video_segment),
                               "a" (0x07200720));
        }
 
index 29eca1710b2cdb06812defdd40d1961d5d43ec2e..b92447d51213be34075c0397fb62787d348d85e6 100644 (file)
@@ -117,8 +117,15 @@ extern int graphic_mode;   /* Graphics mode with linear frame buffer */
  * int $0x10 is notorious for touching registers it shouldn't.
  * gcc doesn't like %ebp being clobbered, so define it as a push/pop
  * sequence here.
+ *
+ * A number of systems, including the original PC can clobber %bp in
+ * certain circumstances, like when scrolling.  There exists at least
+ * one Trident video card which could clobber DS under a set of
+ * circumstances that we are unlikely to encounter (scrolling when
+ * using an extended graphics mode of more than 800x600 pixels), but
+ * it's cheap insurance to deal with that here.
  */
-#define INT10 "pushl %%ebp; int $0x10; popl %%ebp"
+#define INT10 "pushl %%ebp; pushw %%ds; int $0x10; popw %%ds; popl %%ebp"
 
 /* Accessing VGA indexed registers */
 static inline u8 in_idx(u16 port, u8 index)
index 9221614d0db8cd1c2c82cb1002cc7671f03729c4..61c8fe0453be5e08773e6334d7361edddcb5c78c 100644 (file)
@@ -32,7 +32,7 @@ int query_voyager(void)
            "setc %0 ; "
            "movw %%es, %1 ; "
            "popw %%es"
-           : "=qm" (err), "=rm" (es), "=D" (di)
+           : "=q" (err), "=r" (es), "=D" (di)
            : "a" (0xffc0));
 
        if (err)
index 27a776c9044dfd5c92bc85aa883ef601ab87cd7c..25f7eb513928d7727ce07fb8a5ceb45f97cb6260 100644 (file)
@@ -17,6 +17,8 @@
 #include <asm/thread_info.h>
 #include <asm/elf.h>
 
+#include <xen/interface/xen.h>
+
 #define DEFINE(sym, val) \
         asm volatile("\n->" #sym " %0 " #val : : "i" (val))
 
@@ -59,6 +61,7 @@ void foo(void)
        OFFSET(TI_addr_limit, thread_info, addr_limit);
        OFFSET(TI_restart_block, thread_info, restart_block);
        OFFSET(TI_sysenter_return, thread_info, sysenter_return);
+       OFFSET(TI_cpu, thread_info, cpu);
        BLANK();
 
        OFFSET(GDS_size, Xgt_desc_struct, size);
@@ -115,4 +118,10 @@ void foo(void)
        OFFSET(PARAVIRT_iret, paravirt_ops, iret);
        OFFSET(PARAVIRT_read_cr0, paravirt_ops, read_cr0);
 #endif
+
+#ifdef CONFIG_XEN
+       BLANK();
+       OFFSET(XEN_vcpu_info_mask, vcpu_info, evtchn_upcall_mask);
+       OFFSET(XEN_vcpu_info_pending, vcpu_info, evtchn_upcall_pending);
+#endif
 }
index 7ba7c3abd3a4a74866899b7d6d6cae38f3113b93..1203dc5ab87aa36ec2042ed8249c76892be1b20c 100644 (file)
@@ -134,19 +134,21 @@ static __cpuinit int thermal_throttle_cpu_callback(struct notifier_block *nfb,
        int err;
 
        sys_dev = get_cpu_sysdev(cpu);
-       mutex_lock(&therm_cpu_lock);
        switch (action) {
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
+               mutex_lock(&therm_cpu_lock);
                err = thermal_throttle_add_dev(sys_dev);
+               mutex_unlock(&therm_cpu_lock);
                WARN_ON(err);
                break;
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
+               mutex_lock(&therm_cpu_lock);
                thermal_throttle_remove_dev(sys_dev);
+               mutex_unlock(&therm_cpu_lock);
                break;
        }
-       mutex_unlock(&therm_cpu_lock);
        return NOTIFY_OK;
 }
 
index a1808022ea19bf6a5fab059c6cff765bdde3acfb..2452c6fbe9927bf34e804ade8e65b2a48b1927b8 100644 (file)
@@ -278,7 +278,7 @@ void efi_memmap_walk(efi_freemem_callback_t callback, void *arg)
        struct range {
                unsigned long start;
                unsigned long end;
-       } prev, curr;
+       } uninitialized_var(prev), curr;
        efi_memory_desc_t *md;
        unsigned long start, end;
        void *p;
index 3c3c220488c93fe20bd0a26d0553cc941ac7d81f..a714d6b43506c957c9527aba9b0525b24ad6f925 100644 (file)
@@ -409,8 +409,6 @@ restore_nocheck_notrace:
 1:     INTERRUPT_RETURN
 .section .fixup,"ax"
 iret_exc:
-       TRACE_IRQS_ON
-       ENABLE_INTERRUPTS(CLBR_NONE)
        pushl $0                        # no error code
        pushl $do_iret_error
        jmp error_code
@@ -1023,6 +1021,91 @@ ENTRY(kernel_thread_helper)
        CFI_ENDPROC
 ENDPROC(kernel_thread_helper)
 
+#ifdef CONFIG_XEN
+ENTRY(xen_hypervisor_callback)
+       CFI_STARTPROC
+       pushl $0
+       CFI_ADJUST_CFA_OFFSET 4
+       SAVE_ALL
+       TRACE_IRQS_OFF
+
+       /* Check to see if we got the event in the critical
+          region in xen_iret_direct, after we've reenabled
+          events and checked for pending events.  This simulates
+          iret instruction's behaviour where it delivers a
+          pending interrupt when enabling interrupts. */
+       movl PT_EIP(%esp),%eax
+       cmpl $xen_iret_start_crit,%eax
+       jb   1f
+       cmpl $xen_iret_end_crit,%eax
+       jae  1f
+
+       call xen_iret_crit_fixup
+
+1:     mov %esp, %eax
+       call xen_evtchn_do_upcall
+       jmp  ret_from_intr
+       CFI_ENDPROC
+ENDPROC(xen_hypervisor_callback)
+
+# Hypervisor uses this for application faults while it executes.
+# We get here for two reasons:
+#  1. Fault while reloading DS, ES, FS or GS
+#  2. Fault while executing IRET
+# Category 1 we fix up by reattempting the load, and zeroing the segment
+# register if the load fails.
+# Category 2 we fix up by jumping to do_iret_error. We cannot use the
+# normal Linux return path in this case because if we use the IRET hypercall
+# to pop the stack frame we end up in an infinite loop of failsafe callbacks.
+# We distinguish between categories by maintaining a status value in EAX.
+ENTRY(xen_failsafe_callback)
+       CFI_STARTPROC
+       pushl %eax
+       CFI_ADJUST_CFA_OFFSET 4
+       movl $1,%eax
+1:     mov 4(%esp),%ds
+2:     mov 8(%esp),%es
+3:     mov 12(%esp),%fs
+4:     mov 16(%esp),%gs
+       testl %eax,%eax
+       popl %eax
+       CFI_ADJUST_CFA_OFFSET -4
+       lea 16(%esp),%esp
+       CFI_ADJUST_CFA_OFFSET -16
+       jz 5f
+       addl $16,%esp
+       jmp iret_exc            # EAX != 0 => Category 2 (Bad IRET)
+5:     pushl $0                # EAX == 0 => Category 1 (Bad segment)
+       CFI_ADJUST_CFA_OFFSET 4
+       SAVE_ALL
+       jmp ret_from_exception
+       CFI_ENDPROC
+
+.section .fixup,"ax"
+6:     xorl %eax,%eax
+       movl %eax,4(%esp)
+       jmp 1b
+7:     xorl %eax,%eax
+       movl %eax,8(%esp)
+       jmp 2b
+8:     xorl %eax,%eax
+       movl %eax,12(%esp)
+       jmp 3b
+9:     xorl %eax,%eax
+       movl %eax,16(%esp)
+       jmp 4b
+.previous
+.section __ex_table,"a"
+       .align 4
+       .long 1b,6b
+       .long 2b,7b
+       .long 3b,8b
+       .long 4b,9b
+.previous
+ENDPROC(xen_failsafe_callback)
+
+#endif /* CONFIG_XEN */
+
 .section .rodata,"a"
 #include "syscall_table.S"
 
index 82714668d43bb566ffbc56148bfa9e166d6081db..7c52b222207ed80ffbaa06cbf6f9c06dd73d7229 100644 (file)
@@ -510,7 +510,8 @@ ENTRY(_stext)
 /*
  * BSS section
  */
-.section ".bss.page_aligned","w"
+.section ".bss.page_aligned","wa"
+       .align PAGE_SIZE_asm
 ENTRY(swapper_pg_dir)
        .fill 1024,4,0
 ENTRY(swapper_pg_pmd)
@@ -538,6 +539,8 @@ fault_msg:
        .ascii "Int %d: CR2 %p  err %p  EIP %p  CS %p  flags %p\n"
        .asciz "Stack: %p %p %p %p %p %p %p %p\n"
 
+#include "../xen/xen-head.S"
+
 /*
  * The IDT and GDT 'descriptors' are a strange 48-bit object
  * only used by the lidt and lgdt instructions. They are not
index faab09abca5e33a3bb1cff6b50848a788bc20349..53f07a8275e3a9b39ba4581e8f8a03bb75e336ce 100644 (file)
@@ -228,6 +228,41 @@ static int __init print_banner(void)
 }
 core_initcall(print_banner);
 
+static struct resource reserve_ioports = {
+       .start = 0,
+       .end = IO_SPACE_LIMIT,
+       .name = "paravirt-ioport",
+       .flags = IORESOURCE_IO | IORESOURCE_BUSY,
+};
+
+static struct resource reserve_iomem = {
+       .start = 0,
+       .end = -1,
+       .name = "paravirt-iomem",
+       .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
+};
+
+/*
+ * Reserve the whole legacy IO space to prevent any legacy drivers
+ * from wasting time probing for their hardware.  This is a fairly
+ * brute-force approach to disabling all non-virtual drivers.
+ *
+ * Note that this must be called very early to have any effect.
+ */
+int paravirt_disable_iospace(void)
+{
+       int ret;
+
+       ret = request_resource(&ioport_resource, &reserve_ioports);
+       if (ret == 0) {
+               ret = request_resource(&iomem_resource, &reserve_iomem);
+               if (ret)
+                       release_resource(&reserve_ioports);
+       }
+
+       return ret;
+}
+
 struct paravirt_ops paravirt_ops = {
        .name = "bare hardware",
        .paravirt_enabled = 0,
@@ -267,7 +302,7 @@ struct paravirt_ops paravirt_ops = {
        .write_msr = native_write_msr_safe,
        .read_tsc = native_read_tsc,
        .read_pmc = native_read_pmc,
-       .get_scheduled_cycles = native_read_tsc,
+       .sched_clock = native_sched_clock,
        .get_cpu_khz = native_calculate_cpu_khz,
        .load_tr_desc = native_load_tr_desc,
        .set_ldt = native_set_ldt,
index 1c075f58d1f9e2a8d33353513d63fcb3504d6e15..0c8f00e69c4d92630256a6530b03e4b4cf4d6190 100644 (file)
@@ -164,14 +164,22 @@ static unsigned long convert_eip_to_linear(struct task_struct *child, struct pt_
                u32 *desc;
                unsigned long base;
 
-               down(&child->mm->context.sem);
-               desc = child->mm->context.ldt + (seg & ~7);
-               base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000);
+               seg &= ~7UL;
 
-               /* 16-bit code segment? */
-               if (!((desc[1] >> 22) & 1))
-                       addr &= 0xffff;
-               addr += base;
+               down(&child->mm->context.sem);
+               if (unlikely((seg >> 3) >= child->mm->context.size))
+                       addr = -1L; /* bogus selector, access would fault */
+               else {
+                       desc = child->mm->context.ldt + seg;
+                       base = ((desc[0] >> 16) |
+                               ((desc[1] & 0xff) << 16) |
+                               (desc[1] & 0xff000000));
+
+                       /* 16-bit code segment? */
+                       if (!((desc[1] >> 22) & 1))
+                               addr &= 0xffff;
+                       addr += base;
+               }
                up(&child->mm->context.sem);
        }
        return addr;
index 2d61e65eeb504164318c0c9e0b839b2a52808e2b..74871d066c2b0ce85351d36748865f293f620759 100644 (file)
@@ -601,6 +601,8 @@ void __init setup_arch(char **cmdline_p)
         * NOTE: at this point the bootmem allocator is fully available.
         */
 
+       paravirt_post_allocator_init();
+
        dmi_scan_machine();
 
 #ifdef CONFIG_X86_GENERICARCH
index 6299c080f6e2e3ce9e003a28314278f0eaa5a974..2d35d8502029c3d50e08e57fbf140844593af091 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <asm/mtrr.h>
 #include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
 #include <mach_apic.h>
 
 /*
@@ -249,13 +250,13 @@ static unsigned long flush_va;
 static DEFINE_SPINLOCK(tlbstate_lock);
 
 /*
- * We cannot call mmdrop() because we are in interrupt context, 
+ * We cannot call mmdrop() because we are in interrupt context,
  * instead update mm->cpu_vm_mask.
  *
  * We need to reload %cr3 since the page tables may be going
  * away from under us..
  */
-static inline void leave_mm (unsigned long cpu)
+void leave_mm(unsigned long cpu)
 {
        if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK)
                BUG();
index 0b2954534b8e71f3216f23a7ae8c933e0bc48d7c..5910d3fac561d5f33d26df53f63fad2ac0c8d2fe 100644 (file)
@@ -148,7 +148,7 @@ void __init smp_alloc_memory(void)
  * a given CPU
  */
 
-static void __cpuinit smp_store_cpu_info(int id)
+void __cpuinit smp_store_cpu_info(int id)
 {
        struct cpuinfo_x86 *c = cpu_data + id;
 
@@ -308,8 +308,7 @@ cpumask_t cpu_coregroup_map(int cpu)
 /* representing cpus for which sibling maps can be computed */
 static cpumask_t cpu_sibling_setup_map;
 
-static inline void
-set_cpu_sibling_map(int cpu)
+void set_cpu_sibling_map(int cpu)
 {
        int i;
        struct cpuinfo_x86 *c = cpu_data;
@@ -1144,8 +1143,7 @@ void __init native_smp_prepare_boot_cpu(void)
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-static void
-remove_siblinginfo(int cpu)
+void remove_siblinginfo(int cpu)
 {
        int sibling;
        struct cpuinfo_x86 *c = cpu_data;
index 1868ae18eb4d7aa3287746b40242865d47dfa551..bbfe85a0f699b198008445182430f2848843699c 100644 (file)
@@ -47,7 +47,7 @@ int smp_call_function(void (*func) (void *info), void *info, int nonatomic,
 EXPORT_SYMBOL(smp_call_function);
 
 /**
- * smp_call_function_single - Run a function on another CPU
+ * smp_call_function_single - Run a function on a specific CPU
  * @cpu: The target CPU.  Cannot be the calling CPU.
  * @func: The function to run. This must be fast and non-blocking.
  * @info: An arbitrary pointer to pass to the function.
@@ -66,9 +66,11 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
        int ret;
        int me = get_cpu();
        if (cpu == me) {
-               WARN_ON(1);
+               local_irq_disable();
+               func(info);
+               local_irq_enable();
                put_cpu();
-               return -EBUSY;
+               return 0;
        }
 
        ret = smp_call_function_mask(cpumask_of_cpu(cpu), func, info, wait);
index bf6adce52267c2b94d2c4dac064f508a43c6492b..8344c70adf615264bc509a9d6e6f959a72b771d4 100644 (file)
@@ -323,3 +323,4 @@ ENTRY(sys_call_table)
        .long sys_signalfd
        .long sys_timerfd
        .long sys_eventfd
+       .long sys_fallocate
index 18c1c285836d3a65bd5a03314094d01851b64ef2..d32fd4b6f78e39536875f228f9a3b11fbbfa2728 100644 (file)
@@ -518,10 +518,12 @@ fastcall void do_##name(struct pt_regs * regs, long error_code) \
        do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
 }
 
-#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
+#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr, irq) \
 fastcall void do_##name(struct pt_regs * regs, long error_code) \
 { \
        siginfo_t info; \
+       if (irq) \
+               local_irq_enable(); \
        info.si_signo = signr; \
        info.si_errno = 0; \
        info.si_code = sicode; \
@@ -561,13 +563,13 @@ DO_VM86_ERROR( 3, SIGTRAP, "int3", int3)
 #endif
 DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow)
 DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds)
-DO_ERROR_INFO( 6, SIGILL,  "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip)
+DO_ERROR_INFO( 6, SIGILL,  "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip, 0)
 DO_ERROR( 9, SIGFPE,  "coprocessor segment overrun", coprocessor_segment_overrun)
 DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
 DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present)
 DO_ERROR(12, SIGBUS,  "stack segment", stack_segment)
-DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
-DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0)
+DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0)
+DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0, 1)
 
 fastcall void __kprobes do_general_protection(struct pt_regs * regs,
                                              long error_code)
index ea63a30ca3e88daa1bca2975f3c9f98812d7dffc..252f9010f283a8acdfb4513fca5f052c1c6b3bb9 100644 (file)
@@ -84,7 +84,7 @@ static inline int check_tsc_unstable(void)
  *
  *                     -johnstul@us.ibm.com "math is hard, lets go shopping!"
  */
-static unsigned long cyc2ns_scale __read_mostly;
+unsigned long cyc2ns_scale __read_mostly;
 
 #define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
 
@@ -93,15 +93,10 @@ static inline void set_cyc2ns_scale(unsigned long cpu_khz)
        cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz;
 }
 
-static inline unsigned long long cycles_2_ns(unsigned long long cyc)
-{
-       return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
-}
-
 /*
  * Scheduler clock - returns current time in nanosec units.
  */
-unsigned long long sched_clock(void)
+unsigned long long native_sched_clock(void)
 {
        unsigned long long this_offset;
 
@@ -118,12 +113,24 @@ unsigned long long sched_clock(void)
                return (jiffies_64 - INITIAL_JIFFIES) * (1000000000 / HZ);
 
        /* read the Time Stamp Counter: */
-       get_scheduled_cycles(this_offset);
+       rdtscll(this_offset);
 
        /* return the value in ns */
        return cycles_2_ns(this_offset);
 }
 
+/* We need to define a real function for sched_clock, to override the
+   weak default version */
+#ifdef CONFIG_PARAVIRT
+unsigned long long sched_clock(void)
+{
+       return paravirt_sched_clock();
+}
+#else
+unsigned long long sched_clock(void)
+       __attribute__((alias("native_sched_clock")));
+#endif
+
 unsigned long native_calculate_cpu_khz(void)
 {
        unsigned long long start, end;
index c12720d7cbc50b8b0bc0804ba19df993128a574d..72042bb7ec941a0537670136e105954331caa5d5 100644 (file)
@@ -362,7 +362,7 @@ static void *vmi_kmap_atomic_pte(struct page *page, enum km_type type)
 }
 #endif
 
-static void vmi_allocate_pt(u32 pfn)
+static void vmi_allocate_pt(struct mm_struct *mm, u32 pfn)
 {
        vmi_set_page_type(pfn, VMI_PAGE_L1);
        vmi_ops.allocate_page(pfn, VMI_PAGE_L1, 0, 0, 0);
@@ -891,7 +891,7 @@ static inline int __init activate_vmi(void)
                paravirt_ops.setup_boot_clock = vmi_time_bsp_init;
                paravirt_ops.setup_secondary_clock = vmi_time_ap_init;
 #endif
-               paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles;
+               paravirt_ops.sched_clock = vmi_sched_clock;
                paravirt_ops.get_cpu_khz = vmi_cpu_khz;
 
                /* We have true wallclock functions; disable CMOS clock sync */
index 26a37f8a876259aa29ba794db48d0cb6988608e6..f9b845f4e6923818817dfc87f32c626a0ff6bbe4 100644 (file)
@@ -64,10 +64,10 @@ int vmi_set_wallclock(unsigned long now)
        return 0;
 }
 
-/* paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles */
-unsigned long long vmi_get_sched_cycles(void)
+/* paravirt_ops.sched_clock = vmi_sched_clock */
+unsigned long long vmi_sched_clock(void)
 {
-       return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE);
+       return cycles_2_ns(vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE));
 }
 
 /* paravirt_ops.get_cpu_khz = vmi_cpu_khz */
index aa87b06c7c8233930358bcc613f2c10dcd764f61..00f1bc47d3a248813f15519ac0175e43f4d904cd 100644 (file)
@@ -88,6 +88,7 @@ SECTIONS
 
   . = ALIGN(4096);
   .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
+       *(.data.page_aligned)
        *(.data.idt)
   }
 
index d4b5be4f3d5fc67a157d38b24388c5c069dfe106..271f16a8ca01044bbc8f58058286ba812e2a7dab 100644 (file)
@@ -3,23 +3,40 @@
  * Here we can supply some information useful to userland.
  */
 
-#include <linux/uts.h>
 #include <linux/version.h>
+#include <linux/elfnote.h>
 
-#define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type)                        \
-       .section name, flags;                                                 \
-       .balign 4;                                                            \
-       .long 1f - 0f;          /* name length */                             \
-       .long 3f - 2f;          /* data length */                             \
-       .long type;             /* note type */                               \
-0:     .asciz vendor;          /* vendor name */                             \
-1:     .balign 4;                                                            \
-2:
+/* Ideally this would use UTS_NAME, but using a quoted string here
+   doesn't work. Remember to change this when changing the
+   kernel's name. */
+ELFNOTE_START(Linux, 0, "a")
+       .long LINUX_VERSION_CODE
+ELFNOTE_END
 
-#define ASM_ELF_NOTE_END                                                     \
-3:     .balign 4;              /* pad out section */                         \
-       .previous
+#ifdef CONFIG_XEN
 
-       ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0)
-       .long LINUX_VERSION_CODE
-       ASM_ELF_NOTE_END
+/*
+ * Add a special note telling glibc's dynamic linker a fake hardware
+ * flavor that it will use to choose the search path for libraries in the
+ * same way it uses real hardware capabilities like "mmx".
+ * We supply "nosegneg" as the fake capability, to indicate that we
+ * do not like negative offsets in instructions using segment overrides,
+ * since we implement those inefficiently.  This makes it possible to
+ * install libraries optimized to avoid those access patterns in someplace
+ * like /lib/i686/tls/nosegneg.  Note that an /etc/ld.so.conf.d/file
+ * corresponding to the bits here is needed to make ldconfig work right.
+ * It should contain:
+ *     hwcap 1 nosegneg
+ * to match the mapping of bit to name that we give here.
+ */
+
+/* Bit used for the pseudo-hwcap for non-negative segments.  We use
+   bit 1 to avoid bugs in some versions of glibc when bit 0 is
+   used; the choice is otherwise arbitrary. */
+#define VDSO_NOTE_NONEGSEG_BIT 1
+
+ELFNOTE_START(GNU, 2, "a")
+       .long 1, 1<<VDSO_NOTE_NONEGSEG_BIT              /* ncaps, mask */
+       .byte VDSO_NOTE_NONEGSEG_BIT; .asciz "nosegneg" /* bit, name */
+ELFNOTE_END
+#endif
index b4b24e0e45e1548b12ad3be6c82cef3658723643..f9d5953381595bdef0df4671d1e8cd4cbdc05bbe 100644 (file)
@@ -52,7 +52,7 @@ execute(const char *string)
                NULL,
        };
 
-       if ((ret = call_usermodehelper(argv[0], argv, envp, 1)) != 0) {
+       if ((ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC)) != 0) {
                printk(KERN_ERR "Voyager failed to run \"%s\": %i\n",
                       string, ret);
        }
index 7135946d366322ade4cb529372f7389647a91d31..6a68b1ae061cf3a8626d9a8da3a91a4a61157459 100644 (file)
@@ -87,7 +87,7 @@ static pte_t * __init one_page_table_init(pmd_t *pmd)
        if (!(pmd_val(*pmd) & _PAGE_PRESENT)) {
                pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
 
-               paravirt_alloc_pt(__pa(page_table) >> PAGE_SHIFT);
+               paravirt_alloc_pt(&init_mm, __pa(page_table) >> PAGE_SHIFT);
                set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
                BUG_ON(page_table != pte_offset_kernel(pmd, 0));
        }
@@ -473,6 +473,7 @@ void zap_low_mappings (void)
 
 static int disable_nx __initdata = 0;
 u64 __supported_pte_mask __read_mostly = ~_PAGE_NX;
+EXPORT_SYMBOL_GPL(__supported_pte_mask);
 
 /*
  * noexec = on|off
index 2eb14a73be9c054956067981416e26fa4e64341f..37992ffb163318f78a64fb4899d3d26ea3142a7a 100644 (file)
@@ -60,7 +60,7 @@ static struct page *split_large_page(unsigned long address, pgprot_t prot,
        address = __pa(address);
        addr = address & LARGE_PAGE_MASK; 
        pbase = (pte_t *)page_address(base);
-       paravirt_alloc_pt(page_to_pfn(base));
+       paravirt_alloc_pt(&init_mm, page_to_pfn(base));
        for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) {
                set_pte(&pbase[i], pfn_pte(addr >> PAGE_SHIFT,
                                           addr == address ? prot : ref_prot));
diff --git a/arch/i386/xen/Kconfig b/arch/i386/xen/Kconfig
new file mode 100644 (file)
index 0000000..9df99e1
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# This Kconfig describes xen options
+#
+
+config XEN
+       bool "Enable support for Xen hypervisor"
+       depends on PARAVIRT && X86_CMPXCHG && X86_TSC && !NEED_MULTIPLE_NODES
+       help
+         This is the Linux Xen port.  Enabling this will allow the
+         kernel to boot in a paravirtualized environment under the
+         Xen hypervisor.
diff --git a/arch/i386/xen/Makefile b/arch/i386/xen/Makefile
new file mode 100644 (file)
index 0000000..343df24
--- /dev/null
@@ -0,0 +1,4 @@
+obj-y          := enlighten.o setup.o features.o multicalls.o mmu.o \
+                       events.o time.o manage.o xen-asm.o
+
+obj-$(CONFIG_SMP)      += smp.o
diff --git a/arch/i386/xen/enlighten.c b/arch/i386/xen/enlighten.c
new file mode 100644 (file)
index 0000000..9a8c118
--- /dev/null
@@ -0,0 +1,1144 @@
+/*
+ * Core of Xen paravirt_ops implementation.
+ *
+ * This file contains the xen_paravirt_ops structure itself, and the
+ * implementations for:
+ * - privileged instructions
+ * - interrupt flags
+ * - segment operations
+ * - booting and setup
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/preempt.h>
+#include <linux/hardirq.h>
+#include <linux/percpu.h>
+#include <linux/delay.h>
+#include <linux/start_kernel.h>
+#include <linux/sched.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/page-flags.h>
+#include <linux/highmem.h>
+#include <linux/smp.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/physdev.h>
+#include <xen/interface/vcpu.h>
+#include <xen/interface/sched.h>
+#include <xen/features.h>
+#include <xen/page.h>
+
+#include <asm/paravirt.h>
+#include <asm/page.h>
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/fixmap.h>
+#include <asm/processor.h>
+#include <asm/setup.h>
+#include <asm/desc.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/reboot.h>
+
+#include "xen-ops.h"
+#include "mmu.h"
+#include "multicalls.h"
+
+EXPORT_SYMBOL_GPL(hypercall_page);
+
+DEFINE_PER_CPU(enum paravirt_lazy_mode, xen_lazy_mode);
+
+DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu);
+DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info);
+DEFINE_PER_CPU(unsigned long, xen_cr3);
+
+struct start_info *xen_start_info;
+EXPORT_SYMBOL_GPL(xen_start_info);
+
+static /* __initdata */ struct shared_info dummy_shared_info;
+
+/*
+ * Point at some empty memory to start with. We map the real shared_info
+ * page as soon as fixmap is up and running.
+ */
+struct shared_info *HYPERVISOR_shared_info = (void *)&dummy_shared_info;
+
+/*
+ * Flag to determine whether vcpu info placement is available on all
+ * VCPUs.  We assume it is to start with, and then set it to zero on
+ * the first failure.  This is because it can succeed on some VCPUs
+ * and not others, since it can involve hypervisor memory allocation,
+ * or because the guest failed to guarantee all the appropriate
+ * constraints on all VCPUs (ie buffer can't cross a page boundary).
+ *
+ * Note that any particular CPU may be using a placed vcpu structure,
+ * but we can only optimise if the all are.
+ *
+ * 0: not available, 1: available
+ */
+static int have_vcpu_info_placement = 1;
+
+static void __init xen_vcpu_setup(int cpu)
+{
+       struct vcpu_register_vcpu_info info;
+       int err;
+       struct vcpu_info *vcpup;
+
+       per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
+
+       if (!have_vcpu_info_placement)
+               return;         /* already tested, not available */
+
+       vcpup = &per_cpu(xen_vcpu_info, cpu);
+
+       info.mfn = virt_to_mfn(vcpup);
+       info.offset = offset_in_page(vcpup);
+
+       printk(KERN_DEBUG "trying to map vcpu_info %d at %p, mfn %x, offset %d\n",
+              cpu, vcpup, info.mfn, info.offset);
+
+       /* Check to see if the hypervisor will put the vcpu_info
+          structure where we want it, which allows direct access via
+          a percpu-variable. */
+       err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, cpu, &info);
+
+       if (err) {
+               printk(KERN_DEBUG "register_vcpu_info failed: err=%d\n", err);
+               have_vcpu_info_placement = 0;
+       } else {
+               /* This cpu is using the registered vcpu info, even if
+                  later ones fail to. */
+               per_cpu(xen_vcpu, cpu) = vcpup;
+
+               printk(KERN_DEBUG "cpu %d using vcpu_info at %p\n",
+                      cpu, vcpup);
+       }
+}
+
+static void __init xen_banner(void)
+{
+       printk(KERN_INFO "Booting paravirtualized kernel on %s\n",
+              paravirt_ops.name);
+       printk(KERN_INFO "Hypervisor signature: %s\n", xen_start_info->magic);
+}
+
+static void xen_cpuid(unsigned int *eax, unsigned int *ebx,
+                     unsigned int *ecx, unsigned int *edx)
+{
+       unsigned maskedx = ~0;
+
+       /*
+        * Mask out inconvenient features, to try and disable as many
+        * unsupported kernel subsystems as possible.
+        */
+       if (*eax == 1)
+               maskedx = ~((1 << X86_FEATURE_APIC) |  /* disable APIC */
+                           (1 << X86_FEATURE_ACPI) |  /* disable ACPI */
+                           (1 << X86_FEATURE_ACC));   /* thermal monitoring */
+
+       asm(XEN_EMULATE_PREFIX "cpuid"
+               : "=a" (*eax),
+                 "=b" (*ebx),
+                 "=c" (*ecx),
+                 "=d" (*edx)
+               : "0" (*eax), "2" (*ecx));
+       *edx &= maskedx;
+}
+
+static void xen_set_debugreg(int reg, unsigned long val)
+{
+       HYPERVISOR_set_debugreg(reg, val);
+}
+
+static unsigned long xen_get_debugreg(int reg)
+{
+       return HYPERVISOR_get_debugreg(reg);
+}
+
+static unsigned long xen_save_fl(void)
+{
+       struct vcpu_info *vcpu;
+       unsigned long flags;
+
+       vcpu = x86_read_percpu(xen_vcpu);
+
+       /* flag has opposite sense of mask */
+       flags = !vcpu->evtchn_upcall_mask;
+
+       /* convert to IF type flag
+          -0 -> 0x00000000
+          -1 -> 0xffffffff
+       */
+       return (-flags) & X86_EFLAGS_IF;
+}
+
+static void xen_restore_fl(unsigned long flags)
+{
+       struct vcpu_info *vcpu;
+
+       /* convert from IF type flag */
+       flags = !(flags & X86_EFLAGS_IF);
+
+       /* There's a one instruction preempt window here.  We need to
+          make sure we're don't switch CPUs between getting the vcpu
+          pointer and updating the mask. */
+       preempt_disable();
+       vcpu = x86_read_percpu(xen_vcpu);
+       vcpu->evtchn_upcall_mask = flags;
+       preempt_enable_no_resched();
+
+       /* Doesn't matter if we get preempted here, because any
+          pending event will get dealt with anyway. */
+
+       if (flags == 0) {
+               preempt_check_resched();
+               barrier(); /* unmask then check (avoid races) */
+               if (unlikely(vcpu->evtchn_upcall_pending))
+                       force_evtchn_callback();
+       }
+}
+
+static void xen_irq_disable(void)
+{
+       /* There's a one instruction preempt window here.  We need to
+          make sure we're don't switch CPUs between getting the vcpu
+          pointer and updating the mask. */
+       preempt_disable();
+       x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1;
+       preempt_enable_no_resched();
+}
+
+static void xen_irq_enable(void)
+{
+       struct vcpu_info *vcpu;
+
+       /* There's a one instruction preempt window here.  We need to
+          make sure we're don't switch CPUs between getting the vcpu
+          pointer and updating the mask. */
+       preempt_disable();
+       vcpu = x86_read_percpu(xen_vcpu);
+       vcpu->evtchn_upcall_mask = 0;
+       preempt_enable_no_resched();
+
+       /* Doesn't matter if we get preempted here, because any
+          pending event will get dealt with anyway. */
+
+       barrier(); /* unmask then check (avoid races) */
+       if (unlikely(vcpu->evtchn_upcall_pending))
+               force_evtchn_callback();
+}
+
+static void xen_safe_halt(void)
+{
+       /* Blocking includes an implicit local_irq_enable(). */
+       if (HYPERVISOR_sched_op(SCHEDOP_block, 0) != 0)
+               BUG();
+}
+
+static void xen_halt(void)
+{
+       if (irqs_disabled())
+               HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
+       else
+               xen_safe_halt();
+}
+
+static void xen_set_lazy_mode(enum paravirt_lazy_mode mode)
+{
+       BUG_ON(preemptible());
+
+       switch (mode) {
+       case PARAVIRT_LAZY_NONE:
+               BUG_ON(x86_read_percpu(xen_lazy_mode) == PARAVIRT_LAZY_NONE);
+               break;
+
+       case PARAVIRT_LAZY_MMU:
+       case PARAVIRT_LAZY_CPU:
+               BUG_ON(x86_read_percpu(xen_lazy_mode) != PARAVIRT_LAZY_NONE);
+               break;
+
+       case PARAVIRT_LAZY_FLUSH:
+               /* flush if necessary, but don't change state */
+               if (x86_read_percpu(xen_lazy_mode) != PARAVIRT_LAZY_NONE)
+                       xen_mc_flush();
+               return;
+       }
+
+       xen_mc_flush();
+       x86_write_percpu(xen_lazy_mode, mode);
+}
+
+static unsigned long xen_store_tr(void)
+{
+       return 0;
+}
+
+static void xen_set_ldt(const void *addr, unsigned entries)
+{
+       unsigned long linear_addr = (unsigned long)addr;
+       struct mmuext_op *op;
+       struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+
+       op = mcs.args;
+       op->cmd = MMUEXT_SET_LDT;
+       if (linear_addr) {
+               /* ldt my be vmalloced, use arbitrary_virt_to_machine */
+               xmaddr_t maddr;
+               maddr = arbitrary_virt_to_machine((unsigned long)addr);
+               linear_addr = (unsigned long)maddr.maddr;
+       }
+       op->arg1.linear_addr = linear_addr;
+       op->arg2.nr_ents = entries;
+
+       MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+       xen_mc_issue(PARAVIRT_LAZY_CPU);
+}
+
+static void xen_load_gdt(const struct Xgt_desc_struct *dtr)
+{
+       unsigned long *frames;
+       unsigned long va = dtr->address;
+       unsigned int size = dtr->size + 1;
+       unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+       int f;
+       struct multicall_space mcs;
+
+       /* A GDT can be up to 64k in size, which corresponds to 8192
+          8-byte entries, or 16 4k pages.. */
+
+       BUG_ON(size > 65536);
+       BUG_ON(va & ~PAGE_MASK);
+
+       mcs = xen_mc_entry(sizeof(*frames) * pages);
+       frames = mcs.args;
+
+       for (f = 0; va < dtr->address + size; va += PAGE_SIZE, f++) {
+               frames[f] = virt_to_mfn(va);
+               make_lowmem_page_readonly((void *)va);
+       }
+
+       MULTI_set_gdt(mcs.mc, frames, size / sizeof(struct desc_struct));
+
+       xen_mc_issue(PARAVIRT_LAZY_CPU);
+}
+
+static void load_TLS_descriptor(struct thread_struct *t,
+                               unsigned int cpu, unsigned int i)
+{
+       struct desc_struct *gdt = get_cpu_gdt_table(cpu);
+       xmaddr_t maddr = virt_to_machine(&gdt[GDT_ENTRY_TLS_MIN+i]);
+       struct multicall_space mc = __xen_mc_entry(0);
+
+       MULTI_update_descriptor(mc.mc, maddr.maddr, t->tls_array[i]);
+}
+
+static void xen_load_tls(struct thread_struct *t, unsigned int cpu)
+{
+       xen_mc_batch();
+
+       load_TLS_descriptor(t, cpu, 0);
+       load_TLS_descriptor(t, cpu, 1);
+       load_TLS_descriptor(t, cpu, 2);
+
+       xen_mc_issue(PARAVIRT_LAZY_CPU);
+
+       /*
+        * XXX sleazy hack: If we're being called in a lazy-cpu zone,
+        * it means we're in a context switch, and %gs has just been
+        * saved.  This means we can zero it out to prevent faults on
+        * exit from the hypervisor if the next process has no %gs.
+        * Either way, it has been saved, and the new value will get
+        * loaded properly.  This will go away as soon as Xen has been
+        * modified to not save/restore %gs for normal hypercalls.
+        */
+       if (xen_get_lazy_mode() == PARAVIRT_LAZY_CPU)
+               loadsegment(gs, 0);
+}
+
+static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum,
+                               u32 low, u32 high)
+{
+       unsigned long lp = (unsigned long)&dt[entrynum];
+       xmaddr_t mach_lp = virt_to_machine(lp);
+       u64 entry = (u64)high << 32 | low;
+
+       preempt_disable();
+
+       xen_mc_flush();
+       if (HYPERVISOR_update_descriptor(mach_lp.maddr, entry))
+               BUG();
+
+       preempt_enable();
+}
+
+static int cvt_gate_to_trap(int vector, u32 low, u32 high,
+                           struct trap_info *info)
+{
+       u8 type, dpl;
+
+       type = (high >> 8) & 0x1f;
+       dpl = (high >> 13) & 3;
+
+       if (type != 0xf && type != 0xe)
+               return 0;
+
+       info->vector = vector;
+       info->address = (high & 0xffff0000) | (low & 0x0000ffff);
+       info->cs = low >> 16;
+       info->flags = dpl;
+       /* interrupt gates clear IF */
+       if (type == 0xe)
+               info->flags |= 4;
+
+       return 1;
+}
+
+/* Locations of each CPU's IDT */
+static DEFINE_PER_CPU(struct Xgt_desc_struct, idt_desc);
+
+/* Set an IDT entry.  If the entry is part of the current IDT, then
+   also update Xen. */
+static void xen_write_idt_entry(struct desc_struct *dt, int entrynum,
+                               u32 low, u32 high)
+{
+       unsigned long p = (unsigned long)&dt[entrynum];
+       unsigned long start, end;
+
+       preempt_disable();
+
+       start = __get_cpu_var(idt_desc).address;
+       end = start + __get_cpu_var(idt_desc).size + 1;
+
+       xen_mc_flush();
+
+       write_dt_entry(dt, entrynum, low, high);
+
+       if (p >= start && (p + 8) <= end) {
+               struct trap_info info[2];
+
+               info[1].address = 0;
+
+               if (cvt_gate_to_trap(entrynum, low, high, &info[0]))
+                       if (HYPERVISOR_set_trap_table(info))
+                               BUG();
+       }
+
+       preempt_enable();
+}
+
+static void xen_convert_trap_info(const struct Xgt_desc_struct *desc,
+                                 struct trap_info *traps)
+{
+       unsigned in, out, count;
+
+       count = (desc->size+1) / 8;
+       BUG_ON(count > 256);
+
+       for (in = out = 0; in < count; in++) {
+               const u32 *entry = (u32 *)(desc->address + in * 8);
+
+               if (cvt_gate_to_trap(in, entry[0], entry[1], &traps[out]))
+                       out++;
+       }
+       traps[out].address = 0;
+}
+
+void xen_copy_trap_info(struct trap_info *traps)
+{
+       const struct Xgt_desc_struct *desc = &__get_cpu_var(idt_desc);
+
+       xen_convert_trap_info(desc, traps);
+}
+
+/* Load a new IDT into Xen.  In principle this can be per-CPU, so we
+   hold a spinlock to protect the static traps[] array (static because
+   it avoids allocation, and saves stack space). */
+static void xen_load_idt(const struct Xgt_desc_struct *desc)
+{
+       static DEFINE_SPINLOCK(lock);
+       static struct trap_info traps[257];
+
+       spin_lock(&lock);
+
+       __get_cpu_var(idt_desc) = *desc;
+
+       xen_convert_trap_info(desc, traps);
+
+       xen_mc_flush();
+       if (HYPERVISOR_set_trap_table(traps))
+               BUG();
+
+       spin_unlock(&lock);
+}
+
+/* Write a GDT descriptor entry.  Ignore LDT descriptors, since
+   they're handled differently. */
+static void xen_write_gdt_entry(struct desc_struct *dt, int entry,
+                               u32 low, u32 high)
+{
+       preempt_disable();
+
+       switch ((high >> 8) & 0xff) {
+       case DESCTYPE_LDT:
+       case DESCTYPE_TSS:
+               /* ignore */
+               break;
+
+       default: {
+               xmaddr_t maddr = virt_to_machine(&dt[entry]);
+               u64 desc = (u64)high << 32 | low;
+
+               xen_mc_flush();
+               if (HYPERVISOR_update_descriptor(maddr.maddr, desc))
+                       BUG();
+       }
+
+       }
+
+       preempt_enable();
+}
+
+static void xen_load_esp0(struct tss_struct *tss,
+                         struct thread_struct *thread)
+{
+       struct multicall_space mcs = xen_mc_entry(0);
+       MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->esp0);
+       xen_mc_issue(PARAVIRT_LAZY_CPU);
+}
+
+static void xen_set_iopl_mask(unsigned mask)
+{
+       struct physdev_set_iopl set_iopl;
+
+       /* Force the change at ring 0. */
+       set_iopl.iopl = (mask == 0) ? 1 : (mask >> 12) & 3;
+       HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
+}
+
+static void xen_io_delay(void)
+{
+}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+static unsigned long xen_apic_read(unsigned long reg)
+{
+       return 0;
+}
+
+static void xen_apic_write(unsigned long reg, unsigned long val)
+{
+       /* Warn to see if there's any stray references */
+       WARN_ON(1);
+}
+#endif
+
+static void xen_flush_tlb(void)
+{
+       struct mmuext_op *op;
+       struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+
+       op = mcs.args;
+       op->cmd = MMUEXT_TLB_FLUSH_LOCAL;
+       MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+       xen_mc_issue(PARAVIRT_LAZY_MMU);
+}
+
+static void xen_flush_tlb_single(unsigned long addr)
+{
+       struct mmuext_op *op;
+       struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+
+       op = mcs.args;
+       op->cmd = MMUEXT_INVLPG_LOCAL;
+       op->arg1.linear_addr = addr & PAGE_MASK;
+       MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+       xen_mc_issue(PARAVIRT_LAZY_MMU);
+}
+
+static void xen_flush_tlb_others(const cpumask_t *cpus, struct mm_struct *mm,
+                                unsigned long va)
+{
+       struct {
+               struct mmuext_op op;
+               cpumask_t mask;
+       } *args;
+       cpumask_t cpumask = *cpus;
+       struct multicall_space mcs;
+
+       /*
+        * A couple of (to be removed) sanity checks:
+        *
+        * - current CPU must not be in mask
+        * - mask must exist :)
+        */
+       BUG_ON(cpus_empty(cpumask));
+       BUG_ON(cpu_isset(smp_processor_id(), cpumask));
+       BUG_ON(!mm);
+
+       /* If a CPU which we ran on has gone down, OK. */
+       cpus_and(cpumask, cpumask, cpu_online_map);
+       if (cpus_empty(cpumask))
+               return;
+
+       mcs = xen_mc_entry(sizeof(*args));
+       args = mcs.args;
+       args->mask = cpumask;
+       args->op.arg2.vcpumask = &args->mask;
+
+       if (va == TLB_FLUSH_ALL) {
+               args->op.cmd = MMUEXT_TLB_FLUSH_MULTI;
+       } else {
+               args->op.cmd = MMUEXT_INVLPG_MULTI;
+               args->op.arg1.linear_addr = va;
+       }
+
+       MULTI_mmuext_op(mcs.mc, &args->op, 1, NULL, DOMID_SELF);
+
+       xen_mc_issue(PARAVIRT_LAZY_MMU);
+}
+
+static void xen_write_cr2(unsigned long cr2)
+{
+       x86_read_percpu(xen_vcpu)->arch.cr2 = cr2;
+}
+
+static unsigned long xen_read_cr2(void)
+{
+       return x86_read_percpu(xen_vcpu)->arch.cr2;
+}
+
+static unsigned long xen_read_cr2_direct(void)
+{
+       return x86_read_percpu(xen_vcpu_info.arch.cr2);
+}
+
+static void xen_write_cr4(unsigned long cr4)
+{
+       /* never allow TSC to be disabled */
+       native_write_cr4(cr4 & ~X86_CR4_TSD);
+}
+
+static unsigned long xen_read_cr3(void)
+{
+       return x86_read_percpu(xen_cr3);
+}
+
+static void xen_write_cr3(unsigned long cr3)
+{
+       BUG_ON(preemptible());
+
+       if (cr3 == x86_read_percpu(xen_cr3)) {
+               /* just a simple tlb flush */
+               xen_flush_tlb();
+               return;
+       }
+
+       x86_write_percpu(xen_cr3, cr3);
+
+
+       {
+               struct mmuext_op *op;
+               struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+               unsigned long mfn = pfn_to_mfn(PFN_DOWN(cr3));
+
+               op = mcs.args;
+               op->cmd = MMUEXT_NEW_BASEPTR;
+               op->arg1.mfn = mfn;
+
+               MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+               xen_mc_issue(PARAVIRT_LAZY_CPU);
+       }
+}
+
+/* Early in boot, while setting up the initial pagetable, assume
+   everything is pinned. */
+static __init void xen_alloc_pt_init(struct mm_struct *mm, u32 pfn)
+{
+       BUG_ON(mem_map);        /* should only be used early */
+       make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
+}
+
+/* This needs to make sure the new pte page is pinned iff its being
+   attached to a pinned pagetable. */
+static void xen_alloc_pt(struct mm_struct *mm, u32 pfn)
+{
+       struct page *page = pfn_to_page(pfn);
+
+       if (PagePinned(virt_to_page(mm->pgd))) {
+               SetPagePinned(page);
+
+               if (!PageHighMem(page))
+                       make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
+               else
+                       /* make sure there are no stray mappings of
+                          this page */
+                       kmap_flush_unused();
+       }
+}
+
+/* This should never happen until we're OK to use struct page */
+static void xen_release_pt(u32 pfn)
+{
+       struct page *page = pfn_to_page(pfn);
+
+       if (PagePinned(page)) {
+               if (!PageHighMem(page))
+                       make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
+       }
+}
+
+#ifdef CONFIG_HIGHPTE
+static void *xen_kmap_atomic_pte(struct page *page, enum km_type type)
+{
+       pgprot_t prot = PAGE_KERNEL;
+
+       if (PagePinned(page))
+               prot = PAGE_KERNEL_RO;
+
+       if (0 && PageHighMem(page))
+               printk("mapping highpte %lx type %d prot %s\n",
+                      page_to_pfn(page), type,
+                      (unsigned long)pgprot_val(prot) & _PAGE_RW ? "WRITE" : "READ");
+
+       return kmap_atomic_prot(page, type, prot);
+}
+#endif
+
+static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
+{
+       /* If there's an existing pte, then don't allow _PAGE_RW to be set */
+       if (pte_val_ma(*ptep) & _PAGE_PRESENT)
+               pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) &
+                              pte_val_ma(pte));
+
+       return pte;
+}
+
+/* Init-time set_pte while constructing initial pagetables, which
+   doesn't allow RO pagetable pages to be remapped RW */
+static __init void xen_set_pte_init(pte_t *ptep, pte_t pte)
+{
+       pte = mask_rw_pte(ptep, pte);
+
+       xen_set_pte(ptep, pte);
+}
+
+static __init void xen_pagetable_setup_start(pgd_t *base)
+{
+       pgd_t *xen_pgd = (pgd_t *)xen_start_info->pt_base;
+
+       /* special set_pte for pagetable initialization */
+       paravirt_ops.set_pte = xen_set_pte_init;
+
+       init_mm.pgd = base;
+       /*
+        * copy top-level of Xen-supplied pagetable into place.  For
+        * !PAE we can use this as-is, but for PAE it is a stand-in
+        * while we copy the pmd pages.
+        */
+       memcpy(base, xen_pgd, PTRS_PER_PGD * sizeof(pgd_t));
+
+       if (PTRS_PER_PMD > 1) {
+               int i;
+               /*
+                * For PAE, need to allocate new pmds, rather than
+                * share Xen's, since Xen doesn't like pmd's being
+                * shared between address spaces.
+                */
+               for (i = 0; i < PTRS_PER_PGD; i++) {
+                       if (pgd_val_ma(xen_pgd[i]) & _PAGE_PRESENT) {
+                               pmd_t *pmd = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
+
+                               memcpy(pmd, (void *)pgd_page_vaddr(xen_pgd[i]),
+                                      PAGE_SIZE);
+
+                               make_lowmem_page_readonly(pmd);
+
+                               set_pgd(&base[i], __pgd(1 + __pa(pmd)));
+                       } else
+                               pgd_clear(&base[i]);
+               }
+       }
+
+       /* make sure zero_page is mapped RO so we can use it in pagetables */
+       make_lowmem_page_readonly(empty_zero_page);
+       make_lowmem_page_readonly(base);
+       /*
+        * Switch to new pagetable.  This is done before
+        * pagetable_init has done anything so that the new pages
+        * added to the table can be prepared properly for Xen.
+        */
+       xen_write_cr3(__pa(base));
+}
+
+static __init void xen_pagetable_setup_done(pgd_t *base)
+{
+       /* This will work as long as patching hasn't happened yet
+          (which it hasn't) */
+       paravirt_ops.alloc_pt = xen_alloc_pt;
+       paravirt_ops.set_pte = xen_set_pte;
+
+       if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+               /*
+                * Create a mapping for the shared info page.
+                * Should be set_fixmap(), but shared_info is a machine
+                * address with no corresponding pseudo-phys address.
+                */
+               set_pte_mfn(fix_to_virt(FIX_PARAVIRT_BOOTMAP),
+                           PFN_DOWN(xen_start_info->shared_info),
+                           PAGE_KERNEL);
+
+               HYPERVISOR_shared_info =
+                       (struct shared_info *)fix_to_virt(FIX_PARAVIRT_BOOTMAP);
+
+       } else
+               HYPERVISOR_shared_info =
+                       (struct shared_info *)__va(xen_start_info->shared_info);
+
+       /* Actually pin the pagetable down, but we can't set PG_pinned
+          yet because the page structures don't exist yet. */
+       {
+               struct mmuext_op op;
+#ifdef CONFIG_X86_PAE
+               op.cmd = MMUEXT_PIN_L3_TABLE;
+#else
+               op.cmd = MMUEXT_PIN_L3_TABLE;
+#endif
+               op.arg1.mfn = pfn_to_mfn(PFN_DOWN(__pa(base)));
+               if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
+                       BUG();
+       }
+}
+
+/* This is called once we have the cpu_possible_map */
+void __init xen_setup_vcpu_info_placement(void)
+{
+       int cpu;
+
+       for_each_possible_cpu(cpu)
+               xen_vcpu_setup(cpu);
+
+       /* xen_vcpu_setup managed to place the vcpu_info within the
+          percpu area for all cpus, so make use of it */
+       if (have_vcpu_info_placement) {
+               printk(KERN_INFO "Xen: using vcpu_info placement\n");
+
+               paravirt_ops.save_fl = xen_save_fl_direct;
+               paravirt_ops.restore_fl = xen_restore_fl_direct;
+               paravirt_ops.irq_disable = xen_irq_disable_direct;
+               paravirt_ops.irq_enable = xen_irq_enable_direct;
+               paravirt_ops.read_cr2 = xen_read_cr2_direct;
+               paravirt_ops.iret = xen_iret_direct;
+       }
+}
+
+static unsigned xen_patch(u8 type, u16 clobbers, void *insns, unsigned len)
+{
+       char *start, *end, *reloc;
+       unsigned ret;
+
+       start = end = reloc = NULL;
+
+#define SITE(x)                                                                \
+       case PARAVIRT_PATCH(x):                                         \
+       if (have_vcpu_info_placement) {                                 \
+               start = (char *)xen_##x##_direct;                       \
+               end = xen_##x##_direct_end;                             \
+               reloc = xen_##x##_direct_reloc;                         \
+       }                                                               \
+       goto patch_site
+
+       switch (type) {
+               SITE(irq_enable);
+               SITE(irq_disable);
+               SITE(save_fl);
+               SITE(restore_fl);
+#undef SITE
+
+       patch_site:
+               if (start == NULL || (end-start) > len)
+                       goto default_patch;
+
+               ret = paravirt_patch_insns(insns, len, start, end);
+
+               /* Note: because reloc is assigned from something that
+                  appears to be an array, gcc assumes it's non-null,
+                  but doesn't know its relationship with start and
+                  end. */
+               if (reloc > start && reloc < end) {
+                       int reloc_off = reloc - start;
+                       long *relocp = (long *)(insns + reloc_off);
+                       long delta = start - (char *)insns;
+
+                       *relocp += delta;
+               }
+               break;
+
+       default_patch:
+       default:
+               ret = paravirt_patch_default(type, clobbers, insns, len);
+               break;
+       }
+
+       return ret;
+}
+
+static const struct paravirt_ops xen_paravirt_ops __initdata = {
+       .paravirt_enabled = 1,
+       .shared_kernel_pmd = 0,
+
+       .name = "Xen",
+       .banner = xen_banner,
+
+       .patch = xen_patch,
+
+       .memory_setup = xen_memory_setup,
+       .arch_setup = xen_arch_setup,
+       .init_IRQ = xen_init_IRQ,
+       .post_allocator_init = xen_mark_init_mm_pinned,
+
+       .time_init = xen_time_init,
+       .set_wallclock = xen_set_wallclock,
+       .get_wallclock = xen_get_wallclock,
+       .get_cpu_khz = xen_cpu_khz,
+       .sched_clock = xen_sched_clock,
+
+       .cpuid = xen_cpuid,
+
+       .set_debugreg = xen_set_debugreg,
+       .get_debugreg = xen_get_debugreg,
+
+       .clts = native_clts,
+
+       .read_cr0 = native_read_cr0,
+       .write_cr0 = native_write_cr0,
+
+       .read_cr2 = xen_read_cr2,
+       .write_cr2 = xen_write_cr2,
+
+       .read_cr3 = xen_read_cr3,
+       .write_cr3 = xen_write_cr3,
+
+       .read_cr4 = native_read_cr4,
+       .read_cr4_safe = native_read_cr4_safe,
+       .write_cr4 = xen_write_cr4,
+
+       .save_fl = xen_save_fl,
+       .restore_fl = xen_restore_fl,
+       .irq_disable = xen_irq_disable,
+       .irq_enable = xen_irq_enable,
+       .safe_halt = xen_safe_halt,
+       .halt = xen_halt,
+       .wbinvd = native_wbinvd,
+
+       .read_msr = native_read_msr_safe,
+       .write_msr = native_write_msr_safe,
+       .read_tsc = native_read_tsc,
+       .read_pmc = native_read_pmc,
+
+       .iret = (void *)&hypercall_page[__HYPERVISOR_iret],
+       .irq_enable_sysexit = NULL,  /* never called */
+
+       .load_tr_desc = paravirt_nop,
+       .set_ldt = xen_set_ldt,
+       .load_gdt = xen_load_gdt,
+       .load_idt = xen_load_idt,
+       .load_tls = xen_load_tls,
+
+       .store_gdt = native_store_gdt,
+       .store_idt = native_store_idt,
+       .store_tr = xen_store_tr,
+
+       .write_ldt_entry = xen_write_ldt_entry,
+       .write_gdt_entry = xen_write_gdt_entry,
+       .write_idt_entry = xen_write_idt_entry,
+       .load_esp0 = xen_load_esp0,
+
+       .set_iopl_mask = xen_set_iopl_mask,
+       .io_delay = xen_io_delay,
+
+#ifdef CONFIG_X86_LOCAL_APIC
+       .apic_write = xen_apic_write,
+       .apic_write_atomic = xen_apic_write,
+       .apic_read = xen_apic_read,
+       .setup_boot_clock = paravirt_nop,
+       .setup_secondary_clock = paravirt_nop,
+       .startup_ipi_hook = paravirt_nop,
+#endif
+
+       .flush_tlb_user = xen_flush_tlb,
+       .flush_tlb_kernel = xen_flush_tlb,
+       .flush_tlb_single = xen_flush_tlb_single,
+       .flush_tlb_others = xen_flush_tlb_others,
+
+       .pte_update = paravirt_nop,
+       .pte_update_defer = paravirt_nop,
+
+       .pagetable_setup_start = xen_pagetable_setup_start,
+       .pagetable_setup_done = xen_pagetable_setup_done,
+
+       .alloc_pt = xen_alloc_pt_init,
+       .release_pt = xen_release_pt,
+       .alloc_pd = paravirt_nop,
+       .alloc_pd_clone = paravirt_nop,
+       .release_pd = paravirt_nop,
+
+#ifdef CONFIG_HIGHPTE
+       .kmap_atomic_pte = xen_kmap_atomic_pte,
+#endif
+
+       .set_pte = NULL,        /* see xen_pagetable_setup_* */
+       .set_pte_at = xen_set_pte_at,
+       .set_pmd = xen_set_pmd,
+
+       .pte_val = xen_pte_val,
+       .pgd_val = xen_pgd_val,
+
+       .make_pte = xen_make_pte,
+       .make_pgd = xen_make_pgd,
+
+#ifdef CONFIG_X86_PAE
+       .set_pte_atomic = xen_set_pte_atomic,
+       .set_pte_present = xen_set_pte_at,
+       .set_pud = xen_set_pud,
+       .pte_clear = xen_pte_clear,
+       .pmd_clear = xen_pmd_clear,
+
+       .make_pmd = xen_make_pmd,
+       .pmd_val = xen_pmd_val,
+#endif /* PAE */
+
+       .activate_mm = xen_activate_mm,
+       .dup_mmap = xen_dup_mmap,
+       .exit_mmap = xen_exit_mmap,
+
+       .set_lazy_mode = xen_set_lazy_mode,
+};
+
+#ifdef CONFIG_SMP
+static const struct smp_ops xen_smp_ops __initdata = {
+       .smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu,
+       .smp_prepare_cpus = xen_smp_prepare_cpus,
+       .cpu_up = xen_cpu_up,
+       .smp_cpus_done = xen_smp_cpus_done,
+
+       .smp_send_stop = xen_smp_send_stop,
+       .smp_send_reschedule = xen_smp_send_reschedule,
+       .smp_call_function_mask = xen_smp_call_function_mask,
+};
+#endif /* CONFIG_SMP */
+
+static void xen_reboot(int reason)
+{
+#ifdef CONFIG_SMP
+       smp_send_stop();
+#endif
+
+       if (HYPERVISOR_sched_op(SCHEDOP_shutdown, reason))
+               BUG();
+}
+
+static void xen_restart(char *msg)
+{
+       xen_reboot(SHUTDOWN_reboot);
+}
+
+static void xen_emergency_restart(void)
+{
+       xen_reboot(SHUTDOWN_reboot);
+}
+
+static void xen_machine_halt(void)
+{
+       xen_reboot(SHUTDOWN_poweroff);
+}
+
+static void xen_crash_shutdown(struct pt_regs *regs)
+{
+       xen_reboot(SHUTDOWN_crash);
+}
+
+static const struct machine_ops __initdata xen_machine_ops = {
+       .restart = xen_restart,
+       .halt = xen_machine_halt,
+       .power_off = xen_machine_halt,
+       .shutdown = xen_machine_halt,
+       .crash_shutdown = xen_crash_shutdown,
+       .emergency_restart = xen_emergency_restart,
+};
+
+
+/* First C function to be called on Xen boot */
+asmlinkage void __init xen_start_kernel(void)
+{
+       pgd_t *pgd;
+
+       if (!xen_start_info)
+               return;
+
+       BUG_ON(memcmp(xen_start_info->magic, "xen-3.0", 7) != 0);
+
+       /* Install Xen paravirt ops */
+       paravirt_ops = xen_paravirt_ops;
+       machine_ops = xen_machine_ops;
+
+#ifdef CONFIG_SMP
+       smp_ops = xen_smp_ops;
+#endif
+
+       xen_setup_features();
+
+       /* Get mfn list */
+       if (!xen_feature(XENFEAT_auto_translated_physmap))
+               phys_to_machine_mapping = (unsigned long *)xen_start_info->mfn_list;
+
+       pgd = (pgd_t *)xen_start_info->pt_base;
+
+       init_pg_tables_end = __pa(pgd) + xen_start_info->nr_pt_frames*PAGE_SIZE;
+
+       init_mm.pgd = pgd; /* use the Xen pagetables to start */
+
+       /* keep using Xen gdt for now; no urgent need to change it */
+
+       x86_write_percpu(xen_cr3, __pa(pgd));
+
+#ifdef CONFIG_SMP
+       /* Don't do the full vcpu_info placement stuff until we have a
+          possible map. */
+       per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
+#else
+       /* May as well do it now, since there's no good time to call
+          it later on UP. */
+       xen_setup_vcpu_info_placement();
+#endif
+
+       paravirt_ops.kernel_rpl = 1;
+       if (xen_feature(XENFEAT_supervisor_mode_kernel))
+               paravirt_ops.kernel_rpl = 0;
+
+       /* set the limit of our address space */
+       reserve_top_address(-HYPERVISOR_VIRT_START + 2 * PAGE_SIZE);
+
+       /* set up basic CPUID stuff */
+       cpu_detect(&new_cpu_data);
+       new_cpu_data.hard_math = 1;
+       new_cpu_data.x86_capability[0] = cpuid_edx(1);
+
+       /* Poke various useful things into boot_params */
+       LOADER_TYPE = (9 << 4) | 0;
+       INITRD_START = xen_start_info->mod_start ? __pa(xen_start_info->mod_start) : 0;
+       INITRD_SIZE = xen_start_info->mod_len;
+
+       /* Start the world */
+       start_kernel();
+}
diff --git a/arch/i386/xen/events.c b/arch/i386/xen/events.c
new file mode 100644 (file)
index 0000000..8904acc
--- /dev/null
@@ -0,0 +1,590 @@
+/*
+ * Xen event channels
+ *
+ * Xen models interrupts with abstract event channels.  Because each
+ * domain gets 1024 event channels, but NR_IRQ is not that large, we
+ * must dynamically map irqs<->event channels.  The event channels
+ * interface with the rest of the kernel by defining a xen interrupt
+ * chip.  When an event is recieved, it is mapped to an irq and sent
+ * through the normal interrupt processing path.
+ *
+ * There are four kinds of events which can be mapped to an event
+ * channel:
+ *
+ * 1. Inter-domain notifications.  This includes all the virtual
+ *    device events, since they're driven by front-ends in another domain
+ *    (typically dom0).
+ * 2. VIRQs, typically used for timers.  These are per-cpu events.
+ * 3. IPIs.
+ * 4. Hardware interrupts. Not supported at present.
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+
+#include <linux/linkage.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+#include <asm/sync_bitops.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/events.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/event_channel.h>
+
+#include "xen-ops.h"
+
+/*
+ * This lock protects updates to the following mapping and reference-count
+ * arrays. The lock does not need to be acquired to read the mapping tables.
+ */
+static DEFINE_SPINLOCK(irq_mapping_update_lock);
+
+/* IRQ <-> VIRQ mapping. */
+static DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1] = -1};
+
+/* IRQ <-> IPI mapping */
+static DEFINE_PER_CPU(int, ipi_to_irq[XEN_NR_IPIS]) = {[0 ... XEN_NR_IPIS-1] = -1};
+
+/* Packed IRQ information: binding type, sub-type index, and event channel. */
+struct packed_irq
+{
+       unsigned short evtchn;
+       unsigned char index;
+       unsigned char type;
+};
+
+static struct packed_irq irq_info[NR_IRQS];
+
+/* Binding types. */
+enum {
+       IRQT_UNBOUND,
+       IRQT_PIRQ,
+       IRQT_VIRQ,
+       IRQT_IPI,
+       IRQT_EVTCHN
+};
+
+/* Convenient shorthand for packed representation of an unbound IRQ. */
+#define IRQ_UNBOUND    mk_irq_info(IRQT_UNBOUND, 0, 0)
+
+static int evtchn_to_irq[NR_EVENT_CHANNELS] = {
+       [0 ... NR_EVENT_CHANNELS-1] = -1
+};
+static unsigned long cpu_evtchn_mask[NR_CPUS][NR_EVENT_CHANNELS/BITS_PER_LONG];
+static u8 cpu_evtchn[NR_EVENT_CHANNELS];
+
+/* Reference counts for bindings to IRQs. */
+static int irq_bindcount[NR_IRQS];
+
+/* Xen will never allocate port zero for any purpose. */
+#define VALID_EVTCHN(chn)      ((chn) != 0)
+
+/*
+ * Force a proper event-channel callback from Xen after clearing the
+ * callback mask. We do this in a very simple manner, by making a call
+ * down into Xen. The pending flag will be checked by Xen on return.
+ */
+void force_evtchn_callback(void)
+{
+       (void)HYPERVISOR_xen_version(0, NULL);
+}
+EXPORT_SYMBOL_GPL(force_evtchn_callback);
+
+static struct irq_chip xen_dynamic_chip;
+
+/* Constructor for packed IRQ information. */
+static inline struct packed_irq mk_irq_info(u32 type, u32 index, u32 evtchn)
+{
+       return (struct packed_irq) { evtchn, index, type };
+}
+
+/*
+ * Accessors for packed IRQ information.
+ */
+static inline unsigned int evtchn_from_irq(int irq)
+{
+       return irq_info[irq].evtchn;
+}
+
+static inline unsigned int index_from_irq(int irq)
+{
+       return irq_info[irq].index;
+}
+
+static inline unsigned int type_from_irq(int irq)
+{
+       return irq_info[irq].type;
+}
+
+static inline unsigned long active_evtchns(unsigned int cpu,
+                                          struct shared_info *sh,
+                                          unsigned int idx)
+{
+       return (sh->evtchn_pending[idx] &
+               cpu_evtchn_mask[cpu][idx] &
+               ~sh->evtchn_mask[idx]);
+}
+
+static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
+{
+       int irq = evtchn_to_irq[chn];
+
+       BUG_ON(irq == -1);
+#ifdef CONFIG_SMP
+       irq_desc[irq].affinity = cpumask_of_cpu(cpu);
+#endif
+
+       __clear_bit(chn, cpu_evtchn_mask[cpu_evtchn[chn]]);
+       __set_bit(chn, cpu_evtchn_mask[cpu]);
+
+       cpu_evtchn[chn] = cpu;
+}
+
+static void init_evtchn_cpu_bindings(void)
+{
+#ifdef CONFIG_SMP
+       int i;
+       /* By default all event channels notify CPU#0. */
+       for (i = 0; i < NR_IRQS; i++)
+               irq_desc[i].affinity = cpumask_of_cpu(0);
+#endif
+
+       memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
+       memset(cpu_evtchn_mask[0], ~0, sizeof(cpu_evtchn_mask[0]));
+}
+
+static inline unsigned int cpu_from_evtchn(unsigned int evtchn)
+{
+       return cpu_evtchn[evtchn];
+}
+
+static inline void clear_evtchn(int port)
+{
+       struct shared_info *s = HYPERVISOR_shared_info;
+       sync_clear_bit(port, &s->evtchn_pending[0]);
+}
+
+static inline void set_evtchn(int port)
+{
+       struct shared_info *s = HYPERVISOR_shared_info;
+       sync_set_bit(port, &s->evtchn_pending[0]);
+}
+
+
+/**
+ * notify_remote_via_irq - send event to remote end of event channel via irq
+ * @irq: irq of event channel to send event to
+ *
+ * Unlike notify_remote_via_evtchn(), this is safe to use across
+ * save/restore. Notifications on a broken connection are silently
+ * dropped.
+ */
+void notify_remote_via_irq(int irq)
+{
+       int evtchn = evtchn_from_irq(irq);
+
+       if (VALID_EVTCHN(evtchn))
+               notify_remote_via_evtchn(evtchn);
+}
+EXPORT_SYMBOL_GPL(notify_remote_via_irq);
+
+static void mask_evtchn(int port)
+{
+       struct shared_info *s = HYPERVISOR_shared_info;
+       sync_set_bit(port, &s->evtchn_mask[0]);
+}
+
+static void unmask_evtchn(int port)
+{
+       struct shared_info *s = HYPERVISOR_shared_info;
+       unsigned int cpu = get_cpu();
+
+       BUG_ON(!irqs_disabled());
+
+       /* Slow path (hypercall) if this is a non-local port. */
+       if (unlikely(cpu != cpu_from_evtchn(port))) {
+               struct evtchn_unmask unmask = { .port = port };
+               (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask);
+       } else {
+               struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
+
+               sync_clear_bit(port, &s->evtchn_mask[0]);
+
+               /*
+                * The following is basically the equivalent of
+                * 'hw_resend_irq'. Just like a real IO-APIC we 'lose
+                * the interrupt edge' if the channel is masked.
+                */
+               if (sync_test_bit(port, &s->evtchn_pending[0]) &&
+                   !sync_test_and_set_bit(port / BITS_PER_LONG,
+                                          &vcpu_info->evtchn_pending_sel))
+                       vcpu_info->evtchn_upcall_pending = 1;
+       }
+
+       put_cpu();
+}
+
+static int find_unbound_irq(void)
+{
+       int irq;
+
+       /* Only allocate from dynirq range */
+       for (irq = 0; irq < NR_IRQS; irq++)
+               if (irq_bindcount[irq] == 0)
+                       break;
+
+       if (irq == NR_IRQS)
+               panic("No available IRQ to bind to: increase NR_IRQS!\n");
+
+       return irq;
+}
+
+int bind_evtchn_to_irq(unsigned int evtchn)
+{
+       int irq;
+
+       spin_lock(&irq_mapping_update_lock);
+
+       irq = evtchn_to_irq[evtchn];
+
+       if (irq == -1) {
+               irq = find_unbound_irq();
+
+               dynamic_irq_init(irq);
+               set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
+                                             handle_level_irq, "event");
+
+               evtchn_to_irq[evtchn] = irq;
+               irq_info[irq] = mk_irq_info(IRQT_EVTCHN, 0, evtchn);
+       }
+
+       irq_bindcount[irq]++;
+
+       spin_unlock(&irq_mapping_update_lock);
+
+       return irq;
+}
+EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
+
+static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
+{
+       struct evtchn_bind_ipi bind_ipi;
+       int evtchn, irq;
+
+       spin_lock(&irq_mapping_update_lock);
+
+       irq = per_cpu(ipi_to_irq, cpu)[ipi];
+       if (irq == -1) {
+               irq = find_unbound_irq();
+               if (irq < 0)
+                       goto out;
+
+               dynamic_irq_init(irq);
+               set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
+                                             handle_level_irq, "ipi");
+
+               bind_ipi.vcpu = cpu;
+               if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
+                                               &bind_ipi) != 0)
+                       BUG();
+               evtchn = bind_ipi.port;
+
+               evtchn_to_irq[evtchn] = irq;
+               irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn);
+
+               per_cpu(ipi_to_irq, cpu)[ipi] = irq;
+
+               bind_evtchn_to_cpu(evtchn, cpu);
+       }
+
+       irq_bindcount[irq]++;
+
+ out:
+       spin_unlock(&irq_mapping_update_lock);
+       return irq;
+}
+
+
+static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
+{
+       struct evtchn_bind_virq bind_virq;
+       int evtchn, irq;
+
+       spin_lock(&irq_mapping_update_lock);
+
+       irq = per_cpu(virq_to_irq, cpu)[virq];
+
+       if (irq == -1) {
+               bind_virq.virq = virq;
+               bind_virq.vcpu = cpu;
+               if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
+                                               &bind_virq) != 0)
+                       BUG();
+               evtchn = bind_virq.port;
+
+               irq = find_unbound_irq();
+
+               dynamic_irq_init(irq);
+               set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
+                                             handle_level_irq, "virq");
+
+               evtchn_to_irq[evtchn] = irq;
+               irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn);
+
+               per_cpu(virq_to_irq, cpu)[virq] = irq;
+
+               bind_evtchn_to_cpu(evtchn, cpu);
+       }
+
+       irq_bindcount[irq]++;
+
+       spin_unlock(&irq_mapping_update_lock);
+
+       return irq;
+}
+
+static void unbind_from_irq(unsigned int irq)
+{
+       struct evtchn_close close;
+       int evtchn = evtchn_from_irq(irq);
+
+       spin_lock(&irq_mapping_update_lock);
+
+       if (VALID_EVTCHN(evtchn) && (--irq_bindcount[irq] == 0)) {
+               close.port = evtchn;
+               if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
+                       BUG();
+
+               switch (type_from_irq(irq)) {
+               case IRQT_VIRQ:
+                       per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
+                               [index_from_irq(irq)] = -1;
+                       break;
+               default:
+                       break;
+               }
+
+               /* Closed ports are implicitly re-bound to VCPU0. */
+               bind_evtchn_to_cpu(evtchn, 0);
+
+               evtchn_to_irq[evtchn] = -1;
+               irq_info[irq] = IRQ_UNBOUND;
+
+               dynamic_irq_init(irq);
+       }
+
+       spin_unlock(&irq_mapping_update_lock);
+}
+
+int bind_evtchn_to_irqhandler(unsigned int evtchn,
+                             irqreturn_t (*handler)(int, void *),
+                             unsigned long irqflags,
+                             const char *devname, void *dev_id)
+{
+       unsigned int irq;
+       int retval;
+
+       irq = bind_evtchn_to_irq(evtchn);
+       retval = request_irq(irq, handler, irqflags, devname, dev_id);
+       if (retval != 0) {
+               unbind_from_irq(irq);
+               return retval;
+       }
+
+       return irq;
+}
+EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler);
+
+int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
+                           irqreturn_t (*handler)(int, void *),
+                           unsigned long irqflags, const char *devname, void *dev_id)
+{
+       unsigned int irq;
+       int retval;
+
+       irq = bind_virq_to_irq(virq, cpu);
+       retval = request_irq(irq, handler, irqflags, devname, dev_id);
+       if (retval != 0) {
+               unbind_from_irq(irq);
+               return retval;
+       }
+
+       return irq;
+}
+EXPORT_SYMBOL_GPL(bind_virq_to_irqhandler);
+
+int bind_ipi_to_irqhandler(enum ipi_vector ipi,
+                          unsigned int cpu,
+                          irq_handler_t handler,
+                          unsigned long irqflags,
+                          const char *devname,
+                          void *dev_id)
+{
+       int irq, retval;
+
+       irq = bind_ipi_to_irq(ipi, cpu);
+       if (irq < 0)
+               return irq;
+
+       retval = request_irq(irq, handler, irqflags, devname, dev_id);
+       if (retval != 0) {
+               unbind_from_irq(irq);
+               return retval;
+       }
+
+       return irq;
+}
+
+void unbind_from_irqhandler(unsigned int irq, void *dev_id)
+{
+       free_irq(irq, dev_id);
+       unbind_from_irq(irq);
+}
+EXPORT_SYMBOL_GPL(unbind_from_irqhandler);
+
+void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector)
+{
+       int irq = per_cpu(ipi_to_irq, cpu)[vector];
+       BUG_ON(irq < 0);
+       notify_remote_via_irq(irq);
+}
+
+
+/*
+ * Search the CPUs pending events bitmasks.  For each one found, map
+ * the event number to an irq, and feed it into do_IRQ() for
+ * handling.
+ *
+ * Xen uses a two-level bitmap to speed searching.  The first level is
+ * a bitset of words which contain pending event bits.  The second
+ * level is a bitset of pending events themselves.
+ */
+fastcall void xen_evtchn_do_upcall(struct pt_regs *regs)
+{
+       int cpu = get_cpu();
+       struct shared_info *s = HYPERVISOR_shared_info;
+       struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
+       unsigned long pending_words;
+
+       vcpu_info->evtchn_upcall_pending = 0;
+
+       /* NB. No need for a barrier here -- XCHG is a barrier on x86. */
+       pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0);
+       while (pending_words != 0) {
+               unsigned long pending_bits;
+               int word_idx = __ffs(pending_words);
+               pending_words &= ~(1UL << word_idx);
+
+               while ((pending_bits = active_evtchns(cpu, s, word_idx)) != 0) {
+                       int bit_idx = __ffs(pending_bits);
+                       int port = (word_idx * BITS_PER_LONG) + bit_idx;
+                       int irq = evtchn_to_irq[port];
+
+                       if (irq != -1) {
+                               regs->orig_eax = ~irq;
+                               do_IRQ(regs);
+                       }
+               }
+       }
+
+       put_cpu();
+}
+
+/* Rebind an evtchn so that it gets delivered to a specific cpu */
+static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
+{
+       struct evtchn_bind_vcpu bind_vcpu;
+       int evtchn = evtchn_from_irq(irq);
+
+       if (!VALID_EVTCHN(evtchn))
+               return;
+
+       /* Send future instances of this interrupt to other vcpu. */
+       bind_vcpu.port = evtchn;
+       bind_vcpu.vcpu = tcpu;
+
+       /*
+        * If this fails, it usually just indicates that we're dealing with a
+        * virq or IPI channel, which don't actually need to be rebound. Ignore
+        * it, but don't do the xenlinux-level rebind in that case.
+        */
+       if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0)
+               bind_evtchn_to_cpu(evtchn, tcpu);
+}
+
+
+static void set_affinity_irq(unsigned irq, cpumask_t dest)
+{
+       unsigned tcpu = first_cpu(dest);
+       rebind_irq_to_cpu(irq, tcpu);
+}
+
+static void enable_dynirq(unsigned int irq)
+{
+       int evtchn = evtchn_from_irq(irq);
+
+       if (VALID_EVTCHN(evtchn))
+               unmask_evtchn(evtchn);
+}
+
+static void disable_dynirq(unsigned int irq)
+{
+       int evtchn = evtchn_from_irq(irq);
+
+       if (VALID_EVTCHN(evtchn))
+               mask_evtchn(evtchn);
+}
+
+static void ack_dynirq(unsigned int irq)
+{
+       int evtchn = evtchn_from_irq(irq);
+
+       move_native_irq(irq);
+
+       if (VALID_EVTCHN(evtchn))
+               clear_evtchn(evtchn);
+}
+
+static int retrigger_dynirq(unsigned int irq)
+{
+       int evtchn = evtchn_from_irq(irq);
+       int ret = 0;
+
+       if (VALID_EVTCHN(evtchn)) {
+               set_evtchn(evtchn);
+               ret = 1;
+       }
+
+       return ret;
+}
+
+static struct irq_chip xen_dynamic_chip __read_mostly = {
+       .name           = "xen-dyn",
+       .mask           = disable_dynirq,
+       .unmask         = enable_dynirq,
+       .ack            = ack_dynirq,
+       .set_affinity   = set_affinity_irq,
+       .retrigger      = retrigger_dynirq,
+};
+
+void __init xen_init_IRQ(void)
+{
+       int i;
+
+       init_evtchn_cpu_bindings();
+
+       /* No event channels are 'live' right now. */
+       for (i = 0; i < NR_EVENT_CHANNELS; i++)
+               mask_evtchn(i);
+
+       /* Dynamic IRQ space is currently unbound. Zero the refcnts. */
+       for (i = 0; i < NR_IRQS; i++)
+               irq_bindcount[i] = 0;
+
+       irq_ctx_init(smp_processor_id());
+}
diff --git a/arch/i386/xen/features.c b/arch/i386/xen/features.c
new file mode 100644 (file)
index 0000000..0707714
--- /dev/null
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * features.c
+ *
+ * Xen feature flags.
+ *
+ * Copyright (c) 2006, Ian Campbell, XenSource Inc.
+ */
+#include <linux/types.h>
+#include <linux/cache.h>
+#include <linux/module.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/features.h>
+
+u8 xen_features[XENFEAT_NR_SUBMAPS * 32] __read_mostly;
+EXPORT_SYMBOL_GPL(xen_features);
+
+void xen_setup_features(void)
+{
+       struct xen_feature_info fi;
+       int i, j;
+
+       for (i = 0; i < XENFEAT_NR_SUBMAPS; i++) {
+               fi.submap_idx = i;
+               if (HYPERVISOR_xen_version(XENVER_get_features, &fi) < 0)
+                       break;
+               for (j = 0; j < 32; j++)
+                       xen_features[i * 32 + j] = !!(fi.submap & 1<<j);
+       }
+}
diff --git a/arch/i386/xen/manage.c b/arch/i386/xen/manage.c
new file mode 100644 (file)
index 0000000..aa7af9e
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Handle extern requests for shutdown, reboot and sysrq
+ */
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/reboot.h>
+#include <linux/sysrq.h>
+
+#include <xen/xenbus.h>
+
+#define SHUTDOWN_INVALID  -1
+#define SHUTDOWN_POWEROFF  0
+#define SHUTDOWN_SUSPEND   2
+/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
+ * report a crash, not be instructed to crash!
+ * HALT is the same as POWEROFF, as far as we're concerned.  The tools use
+ * the distinction when we return the reason code to them.
+ */
+#define SHUTDOWN_HALT      4
+
+/* Ignore multiple shutdown requests. */
+static int shutting_down = SHUTDOWN_INVALID;
+
+static void shutdown_handler(struct xenbus_watch *watch,
+                            const char **vec, unsigned int len)
+{
+       char *str;
+       struct xenbus_transaction xbt;
+       int err;
+
+       if (shutting_down != SHUTDOWN_INVALID)
+               return;
+
+ again:
+       err = xenbus_transaction_start(&xbt);
+       if (err)
+               return;
+
+       str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
+       /* Ignore read errors and empty reads. */
+       if (XENBUS_IS_ERR_READ(str)) {
+               xenbus_transaction_end(xbt, 1);
+               return;
+       }
+
+       xenbus_write(xbt, "control", "shutdown", "");
+
+       err = xenbus_transaction_end(xbt, 0);
+       if (err == -EAGAIN) {
+               kfree(str);
+               goto again;
+       }
+
+       if (strcmp(str, "poweroff") == 0 ||
+           strcmp(str, "halt") == 0)
+               orderly_poweroff(false);
+       else if (strcmp(str, "reboot") == 0)
+               ctrl_alt_del();
+       else {
+               printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
+               shutting_down = SHUTDOWN_INVALID;
+       }
+
+       kfree(str);
+}
+
+static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
+                         unsigned int len)
+{
+       char sysrq_key = '\0';
+       struct xenbus_transaction xbt;
+       int err;
+
+ again:
+       err = xenbus_transaction_start(&xbt);
+       if (err)
+               return;
+       if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
+               printk(KERN_ERR "Unable to read sysrq code in "
+                      "control/sysrq\n");
+               xenbus_transaction_end(xbt, 1);
+               return;
+       }
+
+       if (sysrq_key != '\0')
+               xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
+
+       err = xenbus_transaction_end(xbt, 0);
+       if (err == -EAGAIN)
+               goto again;
+
+       if (sysrq_key != '\0')
+               handle_sysrq(sysrq_key, NULL);
+}
+
+static struct xenbus_watch shutdown_watch = {
+       .node = "control/shutdown",
+       .callback = shutdown_handler
+};
+
+static struct xenbus_watch sysrq_watch = {
+       .node = "control/sysrq",
+       .callback = sysrq_handler
+};
+
+static int setup_shutdown_watcher(void)
+{
+       int err;
+
+       err = register_xenbus_watch(&shutdown_watch);
+       if (err) {
+               printk(KERN_ERR "Failed to set shutdown watcher\n");
+               return err;
+       }
+
+       err = register_xenbus_watch(&sysrq_watch);
+       if (err) {
+               printk(KERN_ERR "Failed to set sysrq watcher\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static int shutdown_event(struct notifier_block *notifier,
+                         unsigned long event,
+                         void *data)
+{
+       setup_shutdown_watcher();
+       return NOTIFY_DONE;
+}
+
+static int __init setup_shutdown_event(void)
+{
+       static struct notifier_block xenstore_notifier = {
+               .notifier_call = shutdown_event
+       };
+       register_xenstore_notifier(&xenstore_notifier);
+
+       return 0;
+}
+
+subsys_initcall(setup_shutdown_event);
diff --git a/arch/i386/xen/mmu.c b/arch/i386/xen/mmu.c
new file mode 100644 (file)
index 0000000..4ae038a
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ * Xen mmu operations
+ *
+ * This file contains the various mmu fetch and update operations.
+ * The most important job they must perform is the mapping between the
+ * domain's pfn and the overall machine mfns.
+ *
+ * Xen allows guests to directly update the pagetable, in a controlled
+ * fashion.  In other words, the guest modifies the same pagetable
+ * that the CPU actually uses, which eliminates the overhead of having
+ * a separate shadow pagetable.
+ *
+ * In order to allow this, it falls on the guest domain to map its
+ * notion of a "physical" pfn - which is just a domain-local linear
+ * address - into a real "machine address" which the CPU's MMU can
+ * use.
+ *
+ * A pgd_t/pmd_t/pte_t will typically contain an mfn, and so can be
+ * inserted directly into the pagetable.  When creating a new
+ * pte/pmd/pgd, it converts the passed pfn into an mfn.  Conversely,
+ * when reading the content back with __(pgd|pmd|pte)_val, it converts
+ * the mfn back into a pfn.
+ *
+ * The other constraint is that all pages which make up a pagetable
+ * must be mapped read-only in the guest.  This prevents uncontrolled
+ * guest updates to the pagetable.  Xen strictly enforces this, and
+ * will disallow any pagetable update which will end up mapping a
+ * pagetable page RW, and will disallow using any writable page as a
+ * pagetable.
+ *
+ * Naively, when loading %cr3 with the base of a new pagetable, Xen
+ * would need to validate the whole pagetable before going on.
+ * Naturally, this is quite slow.  The solution is to "pin" a
+ * pagetable, which enforces all the constraints on the pagetable even
+ * when it is not actively in use.  This menas that Xen can be assured
+ * that it is still valid when you do load it into %cr3, and doesn't
+ * need to revalidate it.
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+#include <linux/sched.h>
+#include <linux/highmem.h>
+#include <linux/bug.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
+#include <asm/paravirt.h>
+
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+
+#include <xen/page.h>
+#include <xen/interface/xen.h>
+
+#include "multicalls.h"
+#include "mmu.h"
+
+xmaddr_t arbitrary_virt_to_machine(unsigned long address)
+{
+       pte_t *pte = lookup_address(address);
+       unsigned offset = address & PAGE_MASK;
+
+       BUG_ON(pte == NULL);
+
+       return XMADDR((pte_mfn(*pte) << PAGE_SHIFT) + offset);
+}
+
+void make_lowmem_page_readonly(void *vaddr)
+{
+       pte_t *pte, ptev;
+       unsigned long address = (unsigned long)vaddr;
+
+       pte = lookup_address(address);
+       BUG_ON(pte == NULL);
+
+       ptev = pte_wrprotect(*pte);
+
+       if (HYPERVISOR_update_va_mapping(address, ptev, 0))
+               BUG();
+}
+
+void make_lowmem_page_readwrite(void *vaddr)
+{
+       pte_t *pte, ptev;
+       unsigned long address = (unsigned long)vaddr;
+
+       pte = lookup_address(address);
+       BUG_ON(pte == NULL);
+
+       ptev = pte_mkwrite(*pte);
+
+       if (HYPERVISOR_update_va_mapping(address, ptev, 0))
+               BUG();
+}
+
+
+void xen_set_pmd(pmd_t *ptr, pmd_t val)
+{
+       struct multicall_space mcs;
+       struct mmu_update *u;
+
+       preempt_disable();
+
+       mcs = xen_mc_entry(sizeof(*u));
+       u = mcs.args;
+       u->ptr = virt_to_machine(ptr).maddr;
+       u->val = pmd_val_ma(val);
+       MULTI_mmu_update(mcs.mc, u, 1, NULL, DOMID_SELF);
+
+       xen_mc_issue(PARAVIRT_LAZY_MMU);
+
+       preempt_enable();
+}
+
+/*
+ * Associate a virtual page frame with a given physical page frame
+ * and protection flags for that frame.
+ */
+void set_pte_mfn(unsigned long vaddr, unsigned long mfn, pgprot_t flags)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+
+       pgd = swapper_pg_dir + pgd_index(vaddr);
+       if (pgd_none(*pgd)) {
+               BUG();
+               return;
+       }
+       pud = pud_offset(pgd, vaddr);
+       if (pud_none(*pud)) {
+               BUG();
+               return;
+       }
+       pmd = pmd_offset(pud, vaddr);
+       if (pmd_none(*pmd)) {
+               BUG();
+               return;
+       }
+       pte = pte_offset_kernel(pmd, vaddr);
+       /* <mfn,flags> stored as-is, to permit clearing entries */
+       xen_set_pte(pte, mfn_pte(mfn, flags));
+
+       /*
+        * It's enough to flush this one mapping.
+        * (PGE mappings get flushed as well)
+        */
+       __flush_tlb_one(vaddr);
+}
+
+void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
+                   pte_t *ptep, pte_t pteval)
+{
+       if (mm == current->mm || mm == &init_mm) {
+               if (xen_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
+                       struct multicall_space mcs;
+                       mcs = xen_mc_entry(0);
+
+                       MULTI_update_va_mapping(mcs.mc, addr, pteval, 0);
+                       xen_mc_issue(PARAVIRT_LAZY_MMU);
+                       return;
+               } else
+                       if (HYPERVISOR_update_va_mapping(addr, pteval, 0) == 0)
+                               return;
+       }
+       xen_set_pte(ptep, pteval);
+}
+
+#ifdef CONFIG_X86_PAE
+void xen_set_pud(pud_t *ptr, pud_t val)
+{
+       struct multicall_space mcs;
+       struct mmu_update *u;
+
+       preempt_disable();
+
+       mcs = xen_mc_entry(sizeof(*u));
+       u = mcs.args;
+       u->ptr = virt_to_machine(ptr).maddr;
+       u->val = pud_val_ma(val);
+       MULTI_mmu_update(mcs.mc, u, 1, NULL, DOMID_SELF);
+
+       xen_mc_issue(PARAVIRT_LAZY_MMU);
+
+       preempt_enable();
+}
+
+void xen_set_pte(pte_t *ptep, pte_t pte)
+{
+       ptep->pte_high = pte.pte_high;
+       smp_wmb();
+       ptep->pte_low = pte.pte_low;
+}
+
+void xen_set_pte_atomic(pte_t *ptep, pte_t pte)
+{
+       set_64bit((u64 *)ptep, pte_val_ma(pte));
+}
+
+void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+       ptep->pte_low = 0;
+       smp_wmb();              /* make sure low gets written first */
+       ptep->pte_high = 0;
+}
+
+void xen_pmd_clear(pmd_t *pmdp)
+{
+       xen_set_pmd(pmdp, __pmd(0));
+}
+
+unsigned long long xen_pte_val(pte_t pte)
+{
+       unsigned long long ret = 0;
+
+       if (pte.pte_low) {
+               ret = ((unsigned long long)pte.pte_high << 32) | pte.pte_low;
+               ret = machine_to_phys(XMADDR(ret)).paddr | 1;
+       }
+
+       return ret;
+}
+
+unsigned long long xen_pmd_val(pmd_t pmd)
+{
+       unsigned long long ret = pmd.pmd;
+       if (ret)
+               ret = machine_to_phys(XMADDR(ret)).paddr | 1;
+       return ret;
+}
+
+unsigned long long xen_pgd_val(pgd_t pgd)
+{
+       unsigned long long ret = pgd.pgd;
+       if (ret)
+               ret = machine_to_phys(XMADDR(ret)).paddr | 1;
+       return ret;
+}
+
+pte_t xen_make_pte(unsigned long long pte)
+{
+       if (pte & 1)
+               pte = phys_to_machine(XPADDR(pte)).maddr;
+
+       return (pte_t){ pte, pte >> 32 };
+}
+
+pmd_t xen_make_pmd(unsigned long long pmd)
+{
+       if (pmd & 1)
+               pmd = phys_to_machine(XPADDR(pmd)).maddr;
+
+       return (pmd_t){ pmd };
+}
+
+pgd_t xen_make_pgd(unsigned long long pgd)
+{
+       if (pgd & _PAGE_PRESENT)
+               pgd = phys_to_machine(XPADDR(pgd)).maddr;
+
+       return (pgd_t){ pgd };
+}
+#else  /* !PAE */
+void xen_set_pte(pte_t *ptep, pte_t pte)
+{
+       *ptep = pte;
+}
+
+unsigned long xen_pte_val(pte_t pte)
+{
+       unsigned long ret = pte.pte_low;
+
+       if (ret & _PAGE_PRESENT)
+               ret = machine_to_phys(XMADDR(ret)).paddr;
+
+       return ret;
+}
+
+unsigned long xen_pgd_val(pgd_t pgd)
+{
+       unsigned long ret = pgd.pgd;
+       if (ret)
+               ret = machine_to_phys(XMADDR(ret)).paddr | 1;
+       return ret;
+}
+
+pte_t xen_make_pte(unsigned long pte)
+{
+       if (pte & _PAGE_PRESENT)
+               pte = phys_to_machine(XPADDR(pte)).maddr;
+
+       return (pte_t){ pte };
+}
+
+pgd_t xen_make_pgd(unsigned long pgd)
+{
+       if (pgd & _PAGE_PRESENT)
+               pgd = phys_to_machine(XPADDR(pgd)).maddr;
+
+       return (pgd_t){ pgd };
+}
+#endif /* CONFIG_X86_PAE */
+
+
+
+/*
+  (Yet another) pagetable walker.  This one is intended for pinning a
+  pagetable.  This means that it walks a pagetable and calls the
+  callback function on each page it finds making up the page table,
+  at every level.  It walks the entire pagetable, but it only bothers
+  pinning pte pages which are below pte_limit.  In the normal case
+  this will be TASK_SIZE, but at boot we need to pin up to
+  FIXADDR_TOP.  But the important bit is that we don't pin beyond
+  there, because then we start getting into Xen's ptes.
+*/
+static int pgd_walk(pgd_t *pgd_base, int (*func)(struct page *, unsigned),
+                   unsigned long limit)
+{
+       pgd_t *pgd = pgd_base;
+       int flush = 0;
+       unsigned long addr = 0;
+       unsigned long pgd_next;
+
+       BUG_ON(limit > FIXADDR_TOP);
+
+       if (xen_feature(XENFEAT_auto_translated_physmap))
+               return 0;
+
+       for (; addr != FIXADDR_TOP; pgd++, addr = pgd_next) {
+               pud_t *pud;
+               unsigned long pud_limit, pud_next;
+
+               pgd_next = pud_limit = pgd_addr_end(addr, FIXADDR_TOP);
+
+               if (!pgd_val(*pgd))
+                       continue;
+
+               pud = pud_offset(pgd, 0);
+
+               if (PTRS_PER_PUD > 1) /* not folded */
+                       flush |= (*func)(virt_to_page(pud), 0);
+
+               for (; addr != pud_limit; pud++, addr = pud_next) {
+                       pmd_t *pmd;
+                       unsigned long pmd_limit;
+
+                       pud_next = pud_addr_end(addr, pud_limit);
+
+                       if (pud_next < limit)
+                               pmd_limit = pud_next;
+                       else
+                               pmd_limit = limit;
+
+                       if (pud_none(*pud))
+                               continue;
+
+                       pmd = pmd_offset(pud, 0);
+
+                       if (PTRS_PER_PMD > 1) /* not folded */
+                               flush |= (*func)(virt_to_page(pmd), 0);
+
+                       for (; addr != pmd_limit; pmd++) {
+                               addr += (PAGE_SIZE * PTRS_PER_PTE);
+                               if ((pmd_limit-1) < (addr-1)) {
+                                       addr = pmd_limit;
+                                       break;
+                               }
+
+                               if (pmd_none(*pmd))
+                                       continue;
+
+                               flush |= (*func)(pmd_page(*pmd), 0);
+                       }
+               }
+       }
+
+       flush |= (*func)(virt_to_page(pgd_base), UVMF_TLB_FLUSH);
+
+       return flush;
+}
+
+static int pin_page(struct page *page, unsigned flags)
+{
+       unsigned pgfl = test_and_set_bit(PG_pinned, &page->flags);
+       int flush;
+
+       if (pgfl)
+               flush = 0;              /* already pinned */
+       else if (PageHighMem(page))
+               /* kmaps need flushing if we found an unpinned
+                  highpage */
+               flush = 1;
+       else {
+               void *pt = lowmem_page_address(page);
+               unsigned long pfn = page_to_pfn(page);
+               struct multicall_space mcs = __xen_mc_entry(0);
+
+               flush = 0;
+
+               MULTI_update_va_mapping(mcs.mc, (unsigned long)pt,
+                                       pfn_pte(pfn, PAGE_KERNEL_RO),
+                                       flags);
+       }
+
+       return flush;
+}
+
+/* This is called just after a mm has been created, but it has not
+   been used yet.  We need to make sure that its pagetable is all
+   read-only, and can be pinned. */
+void xen_pgd_pin(pgd_t *pgd)
+{
+       struct multicall_space mcs;
+       struct mmuext_op *op;
+
+       xen_mc_batch();
+
+       if (pgd_walk(pgd, pin_page, TASK_SIZE)) {
+               /* re-enable interrupts for kmap_flush_unused */
+               xen_mc_issue(0);
+               kmap_flush_unused();
+               xen_mc_batch();
+       }
+
+       mcs = __xen_mc_entry(sizeof(*op));
+       op = mcs.args;
+
+#ifdef CONFIG_X86_PAE
+       op->cmd = MMUEXT_PIN_L3_TABLE;
+#else
+       op->cmd = MMUEXT_PIN_L2_TABLE;
+#endif
+       op->arg1.mfn = pfn_to_mfn(PFN_DOWN(__pa(pgd)));
+       MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+       xen_mc_issue(0);
+}
+
+/* The init_mm pagetable is really pinned as soon as its created, but
+   that's before we have page structures to store the bits.  So do all
+   the book-keeping now. */
+static __init int mark_pinned(struct page *page, unsigned flags)
+{
+       SetPagePinned(page);
+       return 0;
+}
+
+void __init xen_mark_init_mm_pinned(void)
+{
+       pgd_walk(init_mm.pgd, mark_pinned, FIXADDR_TOP);
+}
+
+static int unpin_page(struct page *page, unsigned flags)
+{
+       unsigned pgfl = test_and_clear_bit(PG_pinned, &page->flags);
+
+       if (pgfl && !PageHighMem(page)) {
+               void *pt = lowmem_page_address(page);
+               unsigned long pfn = page_to_pfn(page);
+               struct multicall_space mcs = __xen_mc_entry(0);
+
+               MULTI_update_va_mapping(mcs.mc, (unsigned long)pt,
+                                       pfn_pte(pfn, PAGE_KERNEL),
+                                       flags);
+       }
+
+       return 0;               /* never need to flush on unpin */
+}
+
+/* Release a pagetables pages back as normal RW */
+static void xen_pgd_unpin(pgd_t *pgd)
+{
+       struct mmuext_op *op;
+       struct multicall_space mcs;
+
+       xen_mc_batch();
+
+       mcs = __xen_mc_entry(sizeof(*op));
+
+       op = mcs.args;
+       op->cmd = MMUEXT_UNPIN_TABLE;
+       op->arg1.mfn = pfn_to_mfn(PFN_DOWN(__pa(pgd)));
+
+       MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+       pgd_walk(pgd, unpin_page, TASK_SIZE);
+
+       xen_mc_issue(0);
+}
+
+void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
+{
+       spin_lock(&next->page_table_lock);
+       xen_pgd_pin(next->pgd);
+       spin_unlock(&next->page_table_lock);
+}
+
+void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
+{
+       spin_lock(&mm->page_table_lock);
+       xen_pgd_pin(mm->pgd);
+       spin_unlock(&mm->page_table_lock);
+}
+
+
+#ifdef CONFIG_SMP
+/* Another cpu may still have their %cr3 pointing at the pagetable, so
+   we need to repoint it somewhere else before we can unpin it. */
+static void drop_other_mm_ref(void *info)
+{
+       struct mm_struct *mm = info;
+
+       if (__get_cpu_var(cpu_tlbstate).active_mm == mm)
+               leave_mm(smp_processor_id());
+}
+
+static void drop_mm_ref(struct mm_struct *mm)
+{
+       if (current->active_mm == mm) {
+               if (current->mm == mm)
+                       load_cr3(swapper_pg_dir);
+               else
+                       leave_mm(smp_processor_id());
+       }
+
+       if (!cpus_empty(mm->cpu_vm_mask))
+               xen_smp_call_function_mask(mm->cpu_vm_mask, drop_other_mm_ref,
+                                          mm, 1);
+}
+#else
+static void drop_mm_ref(struct mm_struct *mm)
+{
+       if (current->active_mm == mm)
+               load_cr3(swapper_pg_dir);
+}
+#endif
+
+/*
+ * While a process runs, Xen pins its pagetables, which means that the
+ * hypervisor forces it to be read-only, and it controls all updates
+ * to it.  This means that all pagetable updates have to go via the
+ * hypervisor, which is moderately expensive.
+ *
+ * Since we're pulling the pagetable down, we switch to use init_mm,
+ * unpin old process pagetable and mark it all read-write, which
+ * allows further operations on it to be simple memory accesses.
+ *
+ * The only subtle point is that another CPU may be still using the
+ * pagetable because of lazy tlb flushing.  This means we need need to
+ * switch all CPUs off this pagetable before we can unpin it.
+ */
+void xen_exit_mmap(struct mm_struct *mm)
+{
+       get_cpu();              /* make sure we don't move around */
+       drop_mm_ref(mm);
+       put_cpu();
+
+       spin_lock(&mm->page_table_lock);
+       xen_pgd_unpin(mm->pgd);
+       spin_unlock(&mm->page_table_lock);
+}
diff --git a/arch/i386/xen/mmu.h b/arch/i386/xen/mmu.h
new file mode 100644 (file)
index 0000000..c9ff27f
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef _XEN_MMU_H
+
+#include <linux/linkage.h>
+#include <asm/page.h>
+
+/*
+ * Page-directory addresses above 4GB do not fit into architectural %cr3.
+ * When accessing %cr3, or equivalent field in vcpu_guest_context, guests
+ * must use the following accessor macros to pack/unpack valid MFNs.
+ *
+ * Note that Xen is using the fact that the pagetable base is always
+ * page-aligned, and putting the 12 MSB of the address into the 12 LSB
+ * of cr3.
+ */
+#define xen_pfn_to_cr3(pfn) (((unsigned)(pfn) << 12) | ((unsigned)(pfn) >> 20))
+#define xen_cr3_to_pfn(cr3) (((unsigned)(cr3) >> 12) | ((unsigned)(cr3) << 20))
+
+
+void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
+
+void xen_set_pte(pte_t *ptep, pte_t pteval);
+void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
+                   pte_t *ptep, pte_t pteval);
+void xen_set_pmd(pmd_t *pmdp, pmd_t pmdval);
+
+void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next);
+void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm);
+void xen_exit_mmap(struct mm_struct *mm);
+
+void xen_pgd_pin(pgd_t *pgd);
+//void xen_pgd_unpin(pgd_t *pgd);
+
+#ifdef CONFIG_X86_PAE
+unsigned long long xen_pte_val(pte_t);
+unsigned long long xen_pmd_val(pmd_t);
+unsigned long long xen_pgd_val(pgd_t);
+
+pte_t xen_make_pte(unsigned long long);
+pmd_t xen_make_pmd(unsigned long long);
+pgd_t xen_make_pgd(unsigned long long);
+
+void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
+                   pte_t *ptep, pte_t pteval);
+void xen_set_pte_atomic(pte_t *ptep, pte_t pte);
+void xen_set_pud(pud_t *ptr, pud_t val);
+void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
+void xen_pmd_clear(pmd_t *pmdp);
+
+
+#else
+unsigned long xen_pte_val(pte_t);
+unsigned long xen_pmd_val(pmd_t);
+unsigned long xen_pgd_val(pgd_t);
+
+pte_t xen_make_pte(unsigned long);
+pmd_t xen_make_pmd(unsigned long);
+pgd_t xen_make_pgd(unsigned long);
+#endif
+
+#endif /* _XEN_MMU_H */
diff --git a/arch/i386/xen/multicalls.c b/arch/i386/xen/multicalls.c
new file mode 100644 (file)
index 0000000..c837e8e
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Xen hypercall batching.
+ *
+ * Xen allows multiple hypercalls to be issued at once, using the
+ * multicall interface.  This allows the cost of trapping into the
+ * hypervisor to be amortized over several calls.
+ *
+ * This file implements a simple interface for multicalls.  There's a
+ * per-cpu buffer of outstanding multicalls.  When you want to queue a
+ * multicall for issuing, you can allocate a multicall slot for the
+ * call and its arguments, along with storage for space which is
+ * pointed to by the arguments (for passing pointers to structures,
+ * etc).  When the multicall is actually issued, all the space for the
+ * commands and allocated memory is freed for reuse.
+ *
+ * Multicalls are flushed whenever any of the buffers get full, or
+ * when explicitly requested.  There's no way to get per-multicall
+ * return results back.  It will BUG if any of the multicalls fail.
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+#include <linux/percpu.h>
+#include <linux/hardirq.h>
+
+#include <asm/xen/hypercall.h>
+
+#include "multicalls.h"
+
+#define MC_BATCH       32
+#define MC_ARGS                (MC_BATCH * 16 / sizeof(u64))
+
+struct mc_buffer {
+       struct multicall_entry entries[MC_BATCH];
+       u64 args[MC_ARGS];
+       unsigned mcidx, argidx;
+};
+
+static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
+DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
+
+void xen_mc_flush(void)
+{
+       struct mc_buffer *b = &__get_cpu_var(mc_buffer);
+       int ret = 0;
+       unsigned long flags;
+
+       BUG_ON(preemptible());
+
+       /* Disable interrupts in case someone comes in and queues
+          something in the middle */
+       local_irq_save(flags);
+
+       if (b->mcidx) {
+               int i;
+
+               if (HYPERVISOR_multicall(b->entries, b->mcidx) != 0)
+                       BUG();
+               for (i = 0; i < b->mcidx; i++)
+                       if (b->entries[i].result < 0)
+                               ret++;
+               b->mcidx = 0;
+               b->argidx = 0;
+       } else
+               BUG_ON(b->argidx != 0);
+
+       local_irq_restore(flags);
+
+       BUG_ON(ret);
+}
+
+struct multicall_space __xen_mc_entry(size_t args)
+{
+       struct mc_buffer *b = &__get_cpu_var(mc_buffer);
+       struct multicall_space ret;
+       unsigned argspace = (args + sizeof(u64) - 1) / sizeof(u64);
+
+       BUG_ON(preemptible());
+       BUG_ON(argspace > MC_ARGS);
+
+       if (b->mcidx == MC_BATCH ||
+           (b->argidx + argspace) > MC_ARGS)
+               xen_mc_flush();
+
+       ret.mc = &b->entries[b->mcidx];
+       b->mcidx++;
+       ret.args = &b->args[b->argidx];
+       b->argidx += argspace;
+
+       return ret;
+}
diff --git a/arch/i386/xen/multicalls.h b/arch/i386/xen/multicalls.h
new file mode 100644 (file)
index 0000000..e6f7530
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef _XEN_MULTICALLS_H
+#define _XEN_MULTICALLS_H
+
+#include "xen-ops.h"
+
+/* Multicalls */
+struct multicall_space
+{
+       struct multicall_entry *mc;
+       void *args;
+};
+
+/* Allocate room for a multicall and its args */
+struct multicall_space __xen_mc_entry(size_t args);
+
+DECLARE_PER_CPU(unsigned long, xen_mc_irq_flags);
+
+/* Call to start a batch of multiple __xen_mc_entry()s.  Must be
+   paired with xen_mc_issue() */
+static inline void xen_mc_batch(void)
+{
+       /* need to disable interrupts until this entry is complete */
+       local_irq_save(__get_cpu_var(xen_mc_irq_flags));
+}
+
+static inline struct multicall_space xen_mc_entry(size_t args)
+{
+       xen_mc_batch();
+       return __xen_mc_entry(args);
+}
+
+/* Flush all pending multicalls */
+void xen_mc_flush(void);
+
+/* Issue a multicall if we're not in a lazy mode */
+static inline void xen_mc_issue(unsigned mode)
+{
+       if ((xen_get_lazy_mode() & mode) == 0)
+               xen_mc_flush();
+
+       /* restore flags saved in xen_mc_batch */
+       local_irq_restore(x86_read_percpu(xen_mc_irq_flags));
+}
+
+#endif /* _XEN_MULTICALLS_H */
diff --git a/arch/i386/xen/setup.c b/arch/i386/xen/setup.c
new file mode 100644 (file)
index 0000000..2fe6eac
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Machine specific setup for xen
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/pm.h>
+
+#include <asm/elf.h>
+#include <asm/e820.h>
+#include <asm/setup.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/interface/physdev.h>
+#include <xen/features.h>
+
+#include "xen-ops.h"
+
+/* These are code, but not functions.  Defined in entry.S */
+extern const char xen_hypervisor_callback[];
+extern const char xen_failsafe_callback[];
+
+unsigned long *phys_to_machine_mapping;
+EXPORT_SYMBOL(phys_to_machine_mapping);
+
+/**
+ * machine_specific_memory_setup - Hook for machine specific memory setup.
+ **/
+
+char * __init xen_memory_setup(void)
+{
+       unsigned long max_pfn = xen_start_info->nr_pages;
+
+       e820.nr_map = 0;
+       add_memory_region(0, PFN_PHYS(max_pfn), E820_RAM);
+
+       return "Xen";
+}
+
+static void xen_idle(void)
+{
+       local_irq_disable();
+
+       if (need_resched())
+               local_irq_enable();
+       else {
+               current_thread_info()->status &= ~TS_POLLING;
+               smp_mb__after_clear_bit();
+               safe_halt();
+               current_thread_info()->status |= TS_POLLING;
+       }
+}
+
+void __init xen_arch_setup(void)
+{
+       struct physdev_set_iopl set_iopl;
+       int rc;
+
+       HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
+       HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables);
+
+       if (!xen_feature(XENFEAT_auto_translated_physmap))
+               HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_pae_extended_cr3);
+
+       HYPERVISOR_set_callbacks(__KERNEL_CS, (unsigned long)xen_hypervisor_callback,
+                                __KERNEL_CS, (unsigned long)xen_failsafe_callback);
+
+       set_iopl.iopl = 1;
+       rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
+       if (rc != 0)
+               printk(KERN_INFO "physdev_op failed %d\n", rc);
+
+#ifdef CONFIG_ACPI
+       if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
+               printk(KERN_INFO "ACPI in unprivileged domain disabled\n");
+               disable_acpi();
+       }
+#endif
+
+       memcpy(boot_command_line, xen_start_info->cmd_line,
+              MAX_GUEST_CMDLINE > COMMAND_LINE_SIZE ?
+              COMMAND_LINE_SIZE : MAX_GUEST_CMDLINE);
+
+       pm_idle = xen_idle;
+
+#ifdef CONFIG_SMP
+       /* fill cpus_possible with all available cpus */
+       xen_fill_possible_map();
+#endif
+
+       paravirt_disable_iospace();
+}
diff --git a/arch/i386/xen/smp.c b/arch/i386/xen/smp.c
new file mode 100644 (file)
index 0000000..557b8e2
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * Xen SMP support
+ *
+ * This file implements the Xen versions of smp_ops.  SMP under Xen is
+ * very straightforward.  Bringing a CPU up is simply a matter of
+ * loading its initial context and setting it running.
+ *
+ * IPIs are handled through the Xen event mechanism.
+ *
+ * Because virtual CPUs can be scheduled onto any real CPU, there's no
+ * useful topology information for the kernel to make use of.  As a
+ * result, all CPUs are treated as if they're single-core and
+ * single-threaded.
+ *
+ * This does not handle HOTPLUG_CPU yet.
+ */
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/smp.h>
+
+#include <asm/paravirt.h>
+#include <asm/desc.h>
+#include <asm/pgtable.h>
+#include <asm/cpu.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/vcpu.h>
+
+#include <asm/xen/interface.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/page.h>
+#include <xen/events.h>
+
+#include "xen-ops.h"
+#include "mmu.h"
+
+static cpumask_t cpu_initialized_map;
+static DEFINE_PER_CPU(int, resched_irq);
+static DEFINE_PER_CPU(int, callfunc_irq);
+
+/*
+ * Structure and data for smp_call_function(). This is designed to minimise
+ * static memory requirements. It also looks cleaner.
+ */
+static DEFINE_SPINLOCK(call_lock);
+
+struct call_data_struct {
+       void (*func) (void *info);
+       void *info;
+       atomic_t started;
+       atomic_t finished;
+       int wait;
+};
+
+static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id);
+
+static struct call_data_struct *call_data;
+
+/*
+ * Reschedule call back. Nothing to do,
+ * all the work is done automatically when
+ * we return from the interrupt.
+ */
+static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id)
+{
+       return IRQ_HANDLED;
+}
+
+static __cpuinit void cpu_bringup_and_idle(void)
+{
+       int cpu = smp_processor_id();
+
+       cpu_init();
+
+       preempt_disable();
+       per_cpu(cpu_state, cpu) = CPU_ONLINE;
+
+       xen_setup_cpu_clockevents();
+
+       /* We can take interrupts now: we're officially "up". */
+       local_irq_enable();
+
+       wmb();                  /* make sure everything is out */
+       cpu_idle();
+}
+
+static int xen_smp_intr_init(unsigned int cpu)
+{
+       int rc;
+       const char *resched_name, *callfunc_name;
+
+       per_cpu(resched_irq, cpu) = per_cpu(callfunc_irq, cpu) = -1;
+
+       resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu);
+       rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR,
+                                   cpu,
+                                   xen_reschedule_interrupt,
+                                   IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+                                   resched_name,
+                                   NULL);
+       if (rc < 0)
+               goto fail;
+       per_cpu(resched_irq, cpu) = rc;
+
+       callfunc_name = kasprintf(GFP_KERNEL, "callfunc%d", cpu);
+       rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_VECTOR,
+                                   cpu,
+                                   xen_call_function_interrupt,
+                                   IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+                                   callfunc_name,
+                                   NULL);
+       if (rc < 0)
+               goto fail;
+       per_cpu(callfunc_irq, cpu) = rc;
+
+       return 0;
+
+ fail:
+       if (per_cpu(resched_irq, cpu) >= 0)
+               unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
+       if (per_cpu(callfunc_irq, cpu) >= 0)
+               unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
+       return rc;
+}
+
+void __init xen_fill_possible_map(void)
+{
+       int i, rc;
+
+       for (i = 0; i < NR_CPUS; i++) {
+               rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
+               if (rc >= 0)
+                       cpu_set(i, cpu_possible_map);
+       }
+}
+
+void __init xen_smp_prepare_boot_cpu(void)
+{
+       int cpu;
+
+       BUG_ON(smp_processor_id() != 0);
+       native_smp_prepare_boot_cpu();
+
+       /* We've switched to the "real" per-cpu gdt, so make sure the
+          old memory can be recycled */
+       make_lowmem_page_readwrite(&per_cpu__gdt_page);
+
+       for (cpu = 0; cpu < NR_CPUS; cpu++) {
+               cpus_clear(cpu_sibling_map[cpu]);
+               cpus_clear(cpu_core_map[cpu]);
+       }
+
+       xen_setup_vcpu_info_placement();
+}
+
+void __init xen_smp_prepare_cpus(unsigned int max_cpus)
+{
+       unsigned cpu;
+
+       for (cpu = 0; cpu < NR_CPUS; cpu++) {
+               cpus_clear(cpu_sibling_map[cpu]);
+               cpus_clear(cpu_core_map[cpu]);
+       }
+
+       smp_store_cpu_info(0);
+       set_cpu_sibling_map(0);
+
+       if (xen_smp_intr_init(0))
+               BUG();
+
+       cpu_initialized_map = cpumask_of_cpu(0);
+
+       /* Restrict the possible_map according to max_cpus. */
+       while ((num_possible_cpus() > 1) && (num_possible_cpus() > max_cpus)) {
+               for (cpu = NR_CPUS-1; !cpu_isset(cpu, cpu_possible_map); cpu--)
+                       continue;
+               cpu_clear(cpu, cpu_possible_map);
+       }
+
+       for_each_possible_cpu (cpu) {
+               struct task_struct *idle;
+
+               if (cpu == 0)
+                       continue;
+
+               idle = fork_idle(cpu);
+               if (IS_ERR(idle))
+                       panic("failed fork for CPU %d", cpu);
+
+               cpu_set(cpu, cpu_present_map);
+       }
+
+       //init_xenbus_allowed_cpumask();
+}
+
+static __cpuinit int
+cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
+{
+       struct vcpu_guest_context *ctxt;
+       struct gdt_page *gdt = &per_cpu(gdt_page, cpu);
+
+       if (cpu_test_and_set(cpu, cpu_initialized_map))
+               return 0;
+
+       ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+       if (ctxt == NULL)
+               return -ENOMEM;
+
+       ctxt->flags = VGCF_IN_KERNEL;
+       ctxt->user_regs.ds = __USER_DS;
+       ctxt->user_regs.es = __USER_DS;
+       ctxt->user_regs.fs = __KERNEL_PERCPU;
+       ctxt->user_regs.gs = 0;
+       ctxt->user_regs.ss = __KERNEL_DS;
+       ctxt->user_regs.eip = (unsigned long)cpu_bringup_and_idle;
+       ctxt->user_regs.eflags = 0x1000; /* IOPL_RING1 */
+
+       memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
+
+       xen_copy_trap_info(ctxt->trap_ctxt);
+
+       ctxt->ldt_ents = 0;
+
+       BUG_ON((unsigned long)gdt->gdt & ~PAGE_MASK);
+       make_lowmem_page_readonly(gdt->gdt);
+
+       ctxt->gdt_frames[0] = virt_to_mfn(gdt->gdt);
+       ctxt->gdt_ents      = ARRAY_SIZE(gdt->gdt);
+
+       ctxt->user_regs.cs = __KERNEL_CS;
+       ctxt->user_regs.esp = idle->thread.esp0 - sizeof(struct pt_regs);
+
+       ctxt->kernel_ss = __KERNEL_DS;
+       ctxt->kernel_sp = idle->thread.esp0;
+
+       ctxt->event_callback_cs     = __KERNEL_CS;
+       ctxt->event_callback_eip    = (unsigned long)xen_hypervisor_callback;
+       ctxt->failsafe_callback_cs  = __KERNEL_CS;
+       ctxt->failsafe_callback_eip = (unsigned long)xen_failsafe_callback;
+
+       per_cpu(xen_cr3, cpu) = __pa(swapper_pg_dir);
+       ctxt->ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir));
+
+       if (HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, ctxt))
+               BUG();
+
+       kfree(ctxt);
+       return 0;
+}
+
+int __cpuinit xen_cpu_up(unsigned int cpu)
+{
+       struct task_struct *idle = idle_task(cpu);
+       int rc;
+
+#if 0
+       rc = cpu_up_check(cpu);
+       if (rc)
+               return rc;
+#endif
+
+       init_gdt(cpu);
+       per_cpu(current_task, cpu) = idle;
+       irq_ctx_init(cpu);
+       xen_setup_timer(cpu);
+
+       /* make sure interrupts start blocked */
+       per_cpu(xen_vcpu, cpu)->evtchn_upcall_mask = 1;
+
+       rc = cpu_initialize_context(cpu, idle);
+       if (rc)
+               return rc;
+
+       if (num_online_cpus() == 1)
+               alternatives_smp_switch(1);
+
+       rc = xen_smp_intr_init(cpu);
+       if (rc)
+               return rc;
+
+       smp_store_cpu_info(cpu);
+       set_cpu_sibling_map(cpu);
+       /* This must be done before setting cpu_online_map */
+       wmb();
+
+       cpu_set(cpu, cpu_online_map);
+
+       rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL);
+       BUG_ON(rc);
+
+       return 0;
+}
+
+void xen_smp_cpus_done(unsigned int max_cpus)
+{
+}
+
+static void stop_self(void *v)
+{
+       int cpu = smp_processor_id();
+
+       /* make sure we're not pinning something down */
+       load_cr3(swapper_pg_dir);
+       /* should set up a minimal gdt */
+
+       HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL);
+       BUG();
+}
+
+void xen_smp_send_stop(void)
+{
+       smp_call_function(stop_self, NULL, 0, 0);
+}
+
+void xen_smp_send_reschedule(int cpu)
+{
+       xen_send_IPI_one(cpu, XEN_RESCHEDULE_VECTOR);
+}
+
+
+static void xen_send_IPI_mask(cpumask_t mask, enum ipi_vector vector)
+{
+       unsigned cpu;
+
+       cpus_and(mask, mask, cpu_online_map);
+
+       for_each_cpu_mask(cpu, mask)
+               xen_send_IPI_one(cpu, vector);
+}
+
+static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id)
+{
+       void (*func) (void *info) = call_data->func;
+       void *info = call_data->info;
+       int wait = call_data->wait;
+
+       /*
+        * Notify initiating CPU that I've grabbed the data and am
+        * about to execute the function
+        */
+       mb();
+       atomic_inc(&call_data->started);
+       /*
+        * At this point the info structure may be out of scope unless wait==1
+        */
+       irq_enter();
+       (*func)(info);
+       irq_exit();
+
+       if (wait) {
+               mb();           /* commit everything before setting finished */
+               atomic_inc(&call_data->finished);
+       }
+
+       return IRQ_HANDLED;
+}
+
+int xen_smp_call_function_mask(cpumask_t mask, void (*func)(void *),
+                              void *info, int wait)
+{
+       struct call_data_struct data;
+       int cpus;
+
+       /* Holding any lock stops cpus from going down. */
+       spin_lock(&call_lock);
+
+       cpu_clear(smp_processor_id(), mask);
+
+       cpus = cpus_weight(mask);
+       if (!cpus) {
+               spin_unlock(&call_lock);
+               return 0;
+       }
+
+       /* Can deadlock when called with interrupts disabled */
+       WARN_ON(irqs_disabled());
+
+       data.func = func;
+       data.info = info;
+       atomic_set(&data.started, 0);
+       data.wait = wait;
+       if (wait)
+               atomic_set(&data.finished, 0);
+
+       call_data = &data;
+       mb();                   /* write everything before IPI */
+
+       /* Send a message to other CPUs and wait for them to respond */
+       xen_send_IPI_mask(mask, XEN_CALL_FUNCTION_VECTOR);
+
+       /* Make sure other vcpus get a chance to run.
+          XXX too severe?  Maybe we should check the other CPU's states? */
+       HYPERVISOR_sched_op(SCHEDOP_yield, 0);
+
+       /* Wait for response */
+       while (atomic_read(&data.started) != cpus ||
+              (wait && atomic_read(&data.finished) != cpus))
+               cpu_relax();
+
+       spin_unlock(&call_lock);
+
+       return 0;
+}
diff --git a/arch/i386/xen/time.c b/arch/i386/xen/time.c
new file mode 100644 (file)
index 0000000..51fdabf
--- /dev/null
@@ -0,0 +1,590 @@
+/*
+ * Xen time implementation.
+ *
+ * This is implemented in terms of a clocksource driver which uses
+ * the hypervisor clock as a nanosecond timebase, and a clockevent
+ * driver which uses the hypervisor's timer mechanism.
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/events.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/vcpu.h>
+
+#include "xen-ops.h"
+
+#define XEN_SHIFT 22
+
+/* Xen may fire a timer up to this many ns early */
+#define TIMER_SLOP     100000
+#define NS_PER_TICK    (1000000000LL / HZ)
+
+static cycle_t xen_clocksource_read(void);
+
+/* These are perodically updated in shared_info, and then copied here. */
+struct shadow_time_info {
+       u64 tsc_timestamp;     /* TSC at last update of time vals.  */
+       u64 system_timestamp;  /* Time, in nanosecs, since boot.    */
+       u32 tsc_to_nsec_mul;
+       int tsc_shift;
+       u32 version;
+};
+
+static DEFINE_PER_CPU(struct shadow_time_info, shadow_time);
+
+/* runstate info updated by Xen */
+static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
+
+/* snapshots of runstate info */
+static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate_snapshot);
+
+/* unused ns of stolen and blocked time */
+static DEFINE_PER_CPU(u64, residual_stolen);
+static DEFINE_PER_CPU(u64, residual_blocked);
+
+/* return an consistent snapshot of 64-bit time/counter value */
+static u64 get64(const u64 *p)
+{
+       u64 ret;
+
+       if (BITS_PER_LONG < 64) {
+               u32 *p32 = (u32 *)p;
+               u32 h, l;
+
+               /*
+                * Read high then low, and then make sure high is
+                * still the same; this will only loop if low wraps
+                * and carries into high.
+                * XXX some clean way to make this endian-proof?
+                */
+               do {
+                       h = p32[1];
+                       barrier();
+                       l = p32[0];
+                       barrier();
+               } while (p32[1] != h);
+
+               ret = (((u64)h) << 32) | l;
+       } else
+               ret = *p;
+
+       return ret;
+}
+
+/*
+ * Runstate accounting
+ */
+static void get_runstate_snapshot(struct vcpu_runstate_info *res)
+{
+       u64 state_time;
+       struct vcpu_runstate_info *state;
+
+       BUG_ON(preemptible());
+
+       state = &__get_cpu_var(runstate);
+
+       /*
+        * The runstate info is always updated by the hypervisor on
+        * the current CPU, so there's no need to use anything
+        * stronger than a compiler barrier when fetching it.
+        */
+       do {
+               state_time = get64(&state->state_entry_time);
+               barrier();
+               *res = *state;
+               barrier();
+       } while (get64(&state->state_entry_time) != state_time);
+}
+
+static void setup_runstate_info(int cpu)
+{
+       struct vcpu_register_runstate_memory_area area;
+
+       area.addr.v = &per_cpu(runstate, cpu);
+
+       if (HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area,
+                              cpu, &area))
+               BUG();
+}
+
+static void do_stolen_accounting(void)
+{
+       struct vcpu_runstate_info state;
+       struct vcpu_runstate_info *snap;
+       s64 blocked, runnable, offline, stolen;
+       cputime_t ticks;
+
+       get_runstate_snapshot(&state);
+
+       WARN_ON(state.state != RUNSTATE_running);
+
+       snap = &__get_cpu_var(runstate_snapshot);
+
+       /* work out how much time the VCPU has not been runn*ing*  */
+       blocked = state.time[RUNSTATE_blocked] - snap->time[RUNSTATE_blocked];
+       runnable = state.time[RUNSTATE_runnable] - snap->time[RUNSTATE_runnable];
+       offline = state.time[RUNSTATE_offline] - snap->time[RUNSTATE_offline];
+
+       *snap = state;
+
+       /* Add the appropriate number of ticks of stolen time,
+          including any left-overs from last time.  Passing NULL to
+          account_steal_time accounts the time as stolen. */
+       stolen = runnable + offline + __get_cpu_var(residual_stolen);
+
+       if (stolen < 0)
+               stolen = 0;
+
+       ticks = 0;
+       while (stolen >= NS_PER_TICK) {
+               ticks++;
+               stolen -= NS_PER_TICK;
+       }
+       __get_cpu_var(residual_stolen) = stolen;
+       account_steal_time(NULL, ticks);
+
+       /* Add the appropriate number of ticks of blocked time,
+          including any left-overs from last time.  Passing idle to
+          account_steal_time accounts the time as idle/wait. */
+       blocked += __get_cpu_var(residual_blocked);
+
+       if (blocked < 0)
+               blocked = 0;
+
+       ticks = 0;
+       while (blocked >= NS_PER_TICK) {
+               ticks++;
+               blocked -= NS_PER_TICK;
+       }
+       __get_cpu_var(residual_blocked) = blocked;
+       account_steal_time(idle_task(smp_processor_id()), ticks);
+}
+
+/*
+ * Xen sched_clock implementation.  Returns the number of unstolen
+ * nanoseconds, which is nanoseconds the VCPU spent in RUNNING+BLOCKED
+ * states.
+ */
+unsigned long long xen_sched_clock(void)
+{
+       struct vcpu_runstate_info state;
+       cycle_t now;
+       u64 ret;
+       s64 offset;
+
+       /*
+        * Ideally sched_clock should be called on a per-cpu basis
+        * anyway, so preempt should already be disabled, but that's
+        * not current practice at the moment.
+        */
+       preempt_disable();
+
+       now = xen_clocksource_read();
+
+       get_runstate_snapshot(&state);
+
+       WARN_ON(state.state != RUNSTATE_running);
+
+       offset = now - state.state_entry_time;
+       if (offset < 0)
+               offset = 0;
+
+       ret = state.time[RUNSTATE_blocked] +
+               state.time[RUNSTATE_running] +
+               offset;
+
+       preempt_enable();
+
+       return ret;
+}
+
+
+/* Get the CPU speed from Xen */
+unsigned long xen_cpu_khz(void)
+{
+       u64 cpu_khz = 1000000ULL << 32;
+       const struct vcpu_time_info *info =
+               &HYPERVISOR_shared_info->vcpu_info[0].time;
+
+       do_div(cpu_khz, info->tsc_to_system_mul);
+       if (info->tsc_shift < 0)
+               cpu_khz <<= -info->tsc_shift;
+       else
+               cpu_khz >>= info->tsc_shift;
+
+       return cpu_khz;
+}
+
+/*
+ * Reads a consistent set of time-base values from Xen, into a shadow data
+ * area.
+ */
+static unsigned get_time_values_from_xen(void)
+{
+       struct vcpu_time_info   *src;
+       struct shadow_time_info *dst;
+
+       /* src is shared memory with the hypervisor, so we need to
+          make sure we get a consistent snapshot, even in the face of
+          being preempted. */
+       src = &__get_cpu_var(xen_vcpu)->time;
+       dst = &__get_cpu_var(shadow_time);
+
+       do {
+               dst->version = src->version;
+               rmb();          /* fetch version before data */
+               dst->tsc_timestamp     = src->tsc_timestamp;
+               dst->system_timestamp  = src->system_time;
+               dst->tsc_to_nsec_mul   = src->tsc_to_system_mul;
+               dst->tsc_shift         = src->tsc_shift;
+               rmb();          /* test version after fetching data */
+       } while ((src->version & 1) | (dst->version ^ src->version));
+
+       return dst->version;
+}
+
+/*
+ * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
+ * yielding a 64-bit result.
+ */
+static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
+{
+       u64 product;
+#ifdef __i386__
+       u32 tmp1, tmp2;
+#endif
+
+       if (shift < 0)
+               delta >>= -shift;
+       else
+               delta <<= shift;
+
+#ifdef __i386__
+       __asm__ (
+               "mul  %5       ; "
+               "mov  %4,%%eax ; "
+               "mov  %%edx,%4 ; "
+               "mul  %5       ; "
+               "xor  %5,%5    ; "
+               "add  %4,%%eax ; "
+               "adc  %5,%%edx ; "
+               : "=A" (product), "=r" (tmp1), "=r" (tmp2)
+               : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
+#elif __x86_64__
+       __asm__ (
+               "mul %%rdx ; shrd $32,%%rdx,%%rax"
+               : "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
+#else
+#error implement me!
+#endif
+
+       return product;
+}
+
+static u64 get_nsec_offset(struct shadow_time_info *shadow)
+{
+       u64 now, delta;
+       now = native_read_tsc();
+       delta = now - shadow->tsc_timestamp;
+       return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
+}
+
+static cycle_t xen_clocksource_read(void)
+{
+       struct shadow_time_info *shadow = &get_cpu_var(shadow_time);
+       cycle_t ret;
+       unsigned version;
+
+       do {
+               version = get_time_values_from_xen();
+               barrier();
+               ret = shadow->system_timestamp + get_nsec_offset(shadow);
+               barrier();
+       } while (version != __get_cpu_var(xen_vcpu)->time.version);
+
+       put_cpu_var(shadow_time);
+
+       return ret;
+}
+
+static void xen_read_wallclock(struct timespec *ts)
+{
+       const struct shared_info *s = HYPERVISOR_shared_info;
+       u32 version;
+       u64 delta;
+       struct timespec now;
+
+       /* get wallclock at system boot */
+       do {
+               version = s->wc_version;
+               rmb();          /* fetch version before time */
+               now.tv_sec  = s->wc_sec;
+               now.tv_nsec = s->wc_nsec;
+               rmb();          /* fetch time before checking version */
+       } while ((s->wc_version & 1) | (version ^ s->wc_version));
+
+       delta = xen_clocksource_read(); /* time since system boot */
+       delta += now.tv_sec * (u64)NSEC_PER_SEC + now.tv_nsec;
+
+       now.tv_nsec = do_div(delta, NSEC_PER_SEC);
+       now.tv_sec = delta;
+
+       set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
+}
+
+unsigned long xen_get_wallclock(void)
+{
+       struct timespec ts;
+
+       xen_read_wallclock(&ts);
+
+       return ts.tv_sec;
+}
+
+int xen_set_wallclock(unsigned long now)
+{
+       /* do nothing for domU */
+       return -1;
+}
+
+static struct clocksource xen_clocksource __read_mostly = {
+       .name = "xen",
+       .rating = 400,
+       .read = xen_clocksource_read,
+       .mask = ~0,
+       .mult = 1<<XEN_SHIFT,           /* time directly in nanoseconds */
+       .shift = XEN_SHIFT,
+       .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/*
+   Xen clockevent implementation
+
+   Xen has two clockevent implementations:
+
+   The old timer_op one works with all released versions of Xen prior
+   to version 3.0.4.  This version of the hypervisor provides a
+   single-shot timer with nanosecond resolution.  However, sharing the
+   same event channel is a 100Hz tick which is delivered while the
+   vcpu is running.  We don't care about or use this tick, but it will
+   cause the core time code to think the timer fired too soon, and
+   will end up resetting it each time.  It could be filtered, but
+   doing so has complications when the ktime clocksource is not yet
+   the xen clocksource (ie, at boot time).
+
+   The new vcpu_op-based timer interface allows the tick timer period
+   to be changed or turned off.  The tick timer is not useful as a
+   periodic timer because events are only delivered to running vcpus.
+   The one-shot timer can report when a timeout is in the past, so
+   set_next_event is capable of returning -ETIME when appropriate.
+   This interface is used when available.
+*/
+
+
+/*
+  Get a hypervisor absolute time.  In theory we could maintain an
+  offset between the kernel's time and the hypervisor's time, and
+  apply that to a kernel's absolute timeout.  Unfortunately the
+  hypervisor and kernel times can drift even if the kernel is using
+  the Xen clocksource, because ntp can warp the kernel's clocksource.
+*/
+static s64 get_abs_timeout(unsigned long delta)
+{
+       return xen_clocksource_read() + delta;
+}
+
+static void xen_timerop_set_mode(enum clock_event_mode mode,
+                                struct clock_event_device *evt)
+{
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               /* unsupported */
+               WARN_ON(1);
+               break;
+
+       case CLOCK_EVT_MODE_ONESHOT:
+               break;
+
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               HYPERVISOR_set_timer_op(0);  /* cancel timeout */
+               break;
+       }
+}
+
+static int xen_timerop_set_next_event(unsigned long delta,
+                                     struct clock_event_device *evt)
+{
+       WARN_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
+
+       if (HYPERVISOR_set_timer_op(get_abs_timeout(delta)) < 0)
+               BUG();
+
+       /* We may have missed the deadline, but there's no real way of
+          knowing for sure.  If the event was in the past, then we'll
+          get an immediate interrupt. */
+
+       return 0;
+}
+
+static const struct clock_event_device xen_timerop_clockevent = {
+       .name = "xen",
+       .features = CLOCK_EVT_FEAT_ONESHOT,
+
+       .max_delta_ns = 0xffffffff,
+       .min_delta_ns = TIMER_SLOP,
+
+       .mult = 1,
+       .shift = 0,
+       .rating = 500,
+
+       .set_mode = xen_timerop_set_mode,
+       .set_next_event = xen_timerop_set_next_event,
+};
+
+
+
+static void xen_vcpuop_set_mode(enum clock_event_mode mode,
+                               struct clock_event_device *evt)
+{
+       int cpu = smp_processor_id();
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               WARN_ON(1);     /* unsupported */
+               break;
+
+       case CLOCK_EVT_MODE_ONESHOT:
+               if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
+                       BUG();
+               break;
+
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               if (HYPERVISOR_vcpu_op(VCPUOP_stop_singleshot_timer, cpu, NULL) ||
+                   HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
+                       BUG();
+               break;
+       }
+}
+
+static int xen_vcpuop_set_next_event(unsigned long delta,
+                                    struct clock_event_device *evt)
+{
+       int cpu = smp_processor_id();
+       struct vcpu_set_singleshot_timer single;
+       int ret;
+
+       WARN_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
+
+       single.timeout_abs_ns = get_abs_timeout(delta);
+       single.flags = VCPU_SSHOTTMR_future;
+
+       ret = HYPERVISOR_vcpu_op(VCPUOP_set_singleshot_timer, cpu, &single);
+
+       BUG_ON(ret != 0 && ret != -ETIME);
+
+       return ret;
+}
+
+static const struct clock_event_device xen_vcpuop_clockevent = {
+       .name = "xen",
+       .features = CLOCK_EVT_FEAT_ONESHOT,
+
+       .max_delta_ns = 0xffffffff,
+       .min_delta_ns = TIMER_SLOP,
+
+       .mult = 1,
+       .shift = 0,
+       .rating = 500,
+
+       .set_mode = xen_vcpuop_set_mode,
+       .set_next_event = xen_vcpuop_set_next_event,
+};
+
+static const struct clock_event_device *xen_clockevent =
+       &xen_timerop_clockevent;
+static DEFINE_PER_CPU(struct clock_event_device, xen_clock_events);
+
+static irqreturn_t xen_timer_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *evt = &__get_cpu_var(xen_clock_events);
+       irqreturn_t ret;
+
+       ret = IRQ_NONE;
+       if (evt->event_handler) {
+               evt->event_handler(evt);
+               ret = IRQ_HANDLED;
+       }
+
+       do_stolen_accounting();
+
+       return ret;
+}
+
+void xen_setup_timer(int cpu)
+{
+       const char *name;
+       struct clock_event_device *evt;
+       int irq;
+
+       printk(KERN_INFO "installing Xen timer for CPU %d\n", cpu);
+
+       name = kasprintf(GFP_KERNEL, "timer%d", cpu);
+       if (!name)
+               name = "<timer kasprintf failed>";
+
+       irq = bind_virq_to_irqhandler(VIRQ_TIMER, cpu, xen_timer_interrupt,
+                                     IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+                                     name, NULL);
+
+       evt = &per_cpu(xen_clock_events, cpu);
+       memcpy(evt, xen_clockevent, sizeof(*evt));
+
+       evt->cpumask = cpumask_of_cpu(cpu);
+       evt->irq = irq;
+
+       setup_runstate_info(cpu);
+}
+
+void xen_setup_cpu_clockevents(void)
+{
+       BUG_ON(preemptible());
+
+       clockevents_register_device(&__get_cpu_var(xen_clock_events));
+}
+
+__init void xen_time_init(void)
+{
+       int cpu = smp_processor_id();
+
+       get_time_values_from_xen();
+
+       clocksource_register(&xen_clocksource);
+
+       if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL) == 0) {
+               /* Successfully turned off 100Hz tick, so we have the
+                  vcpuop-based timer interface */
+               printk(KERN_DEBUG "Xen: using vcpuop timer interface\n");
+               xen_clockevent = &xen_vcpuop_clockevent;
+       }
+
+       /* Set initial system time with full resolution */
+       xen_read_wallclock(&xtime);
+       set_normalized_timespec(&wall_to_monotonic,
+                               -xtime.tv_sec, -xtime.tv_nsec);
+
+       tsc_disable = 0;
+
+       xen_setup_timer(cpu);
+       xen_setup_cpu_clockevents();
+}
diff --git a/arch/i386/xen/xen-asm.S b/arch/i386/xen/xen-asm.S
new file mode 100644 (file)
index 0000000..1a43b60
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+       Asm versions of Xen pv-ops, suitable for either direct use or inlining.
+       The inline versions are the same as the direct-use versions, with the
+       pre- and post-amble chopped off.
+
+       This code is encoded for size rather than absolute efficiency,
+       with a view to being able to inline as much as possible.
+
+       We only bother with direct forms (ie, vcpu in pda) of the operations
+       here; the indirect forms are better handled in C, since they're
+       generally too large to inline anyway.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+#include <asm/percpu.h>
+#include <asm/processor-flags.h>
+#include <asm/segment.h>
+
+#include <xen/interface/xen.h>
+
+#define RELOC(x, v)    .globl x##_reloc; x##_reloc=v
+#define ENDPATCH(x)    .globl x##_end; x##_end=.
+
+/* Pseudo-flag used for virtual NMI, which we don't implement yet */
+#define XEN_EFLAGS_NMI 0x80000000
+
+/*
+       Enable events.  This clears the event mask and tests the pending
+       event status with one and operation.  If there are pending
+       events, then enter the hypervisor to get them handled.
+ */
+ENTRY(xen_irq_enable_direct)
+       /* Clear mask and test pending */
+       andw $0x00ff, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_pending
+       /* Preempt here doesn't matter because that will deal with
+          any pending interrupts.  The pending check may end up being
+          run on the wrong CPU, but that doesn't hurt. */
+       jz 1f
+2:     call check_events
+1:
+ENDPATCH(xen_irq_enable_direct)
+       ret
+       ENDPROC(xen_irq_enable_direct)
+       RELOC(xen_irq_enable_direct, 2b+1)
+
+
+/*
+       Disabling events is simply a matter of making the event mask
+       non-zero.
+ */
+ENTRY(xen_irq_disable_direct)
+       movb $1, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_mask
+ENDPATCH(xen_irq_disable_direct)
+       ret
+       ENDPROC(xen_irq_disable_direct)
+       RELOC(xen_irq_disable_direct, 0)
+
+/*
+       (xen_)save_fl is used to get the current interrupt enable status.
+       Callers expect the status to be in X86_EFLAGS_IF, and other bits
+       may be set in the return value.  We take advantage of this by
+       making sure that X86_EFLAGS_IF has the right value (and other bits
+       in that byte are 0), but other bits in the return value are
+       undefined.  We need to toggle the state of the bit, because
+       Xen and x86 use opposite senses (mask vs enable).
+ */
+ENTRY(xen_save_fl_direct)
+       testb $0xff, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_mask
+       setz %ah
+       addb %ah,%ah
+ENDPATCH(xen_save_fl_direct)
+       ret
+       ENDPROC(xen_save_fl_direct)
+       RELOC(xen_save_fl_direct, 0)
+
+
+/*
+       In principle the caller should be passing us a value return
+       from xen_save_fl_direct, but for robustness sake we test only
+       the X86_EFLAGS_IF flag rather than the whole byte. After
+       setting the interrupt mask state, it checks for unmasked
+       pending events and enters the hypervisor to get them delivered
+       if so.
+ */
+ENTRY(xen_restore_fl_direct)
+       testb $X86_EFLAGS_IF>>8, %ah
+       setz PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_mask
+       /* Preempt here doesn't matter because that will deal with
+          any pending interrupts.  The pending check may end up being
+          run on the wrong CPU, but that doesn't hurt. */
+
+       /* check for unmasked and pending */
+       cmpw $0x0001, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_pending
+       jz 1f
+2:     call check_events
+1:
+ENDPATCH(xen_restore_fl_direct)
+       ret
+       ENDPROC(xen_restore_fl_direct)
+       RELOC(xen_restore_fl_direct, 2b+1)
+
+/*
+       This is run where a normal iret would be run, with the same stack setup:
+             8: eflags
+             4: cs
+       esp-> 0: eip
+
+       This attempts to make sure that any pending events are dealt
+       with on return to usermode, but there is a small window in
+       which an event can happen just before entering usermode.  If
+       the nested interrupt ends up setting one of the TIF_WORK_MASK
+       pending work flags, they will not be tested again before
+       returning to usermode. This means that a process can end up
+       with pending work, which will be unprocessed until the process
+       enters and leaves the kernel again, which could be an
+       unbounded amount of time.  This means that a pending signal or
+       reschedule event could be indefinitely delayed.
+
+       The fix is to notice a nested interrupt in the critical
+       window, and if one occurs, then fold the nested interrupt into
+       the current interrupt stack frame, and re-process it
+       iteratively rather than recursively.  This means that it will
+       exit via the normal path, and all pending work will be dealt
+       with appropriately.
+
+       Because the nested interrupt handler needs to deal with the
+       current stack state in whatever form its in, we keep things
+       simple by only using a single register which is pushed/popped
+       on the stack.
+
+       Non-direct iret could be done in the same way, but it would
+       require an annoying amount of code duplication.  We'll assume
+       that direct mode will be the common case once the hypervisor
+       support becomes commonplace.
+ */
+ENTRY(xen_iret_direct)
+       /* test eflags for special cases */
+       testl $(X86_EFLAGS_VM | XEN_EFLAGS_NMI), 8(%esp)
+       jnz hyper_iret
+
+       push %eax
+       ESP_OFFSET=4    # bytes pushed onto stack
+
+       /* Store vcpu_info pointer for easy access.  Do it this
+          way to avoid having to reload %fs */
+#ifdef CONFIG_SMP
+       GET_THREAD_INFO(%eax)
+       movl TI_cpu(%eax),%eax
+       movl __per_cpu_offset(,%eax,4),%eax
+       lea per_cpu__xen_vcpu_info(%eax),%eax
+#else
+       movl $per_cpu__xen_vcpu_info, %eax
+#endif
+
+       /* check IF state we're restoring */
+       testb $X86_EFLAGS_IF>>8, 8+1+ESP_OFFSET(%esp)
+
+       /* Maybe enable events.  Once this happens we could get a
+          recursive event, so the critical region starts immediately
+          afterwards.  However, if that happens we don't end up
+          resuming the code, so we don't have to be worried about
+          being preempted to another CPU. */
+       setz XEN_vcpu_info_mask(%eax)
+xen_iret_start_crit:
+
+       /* check for unmasked and pending */
+       cmpw $0x0001, XEN_vcpu_info_pending(%eax)
+
+       /* If there's something pending, mask events again so we
+          can jump back into xen_hypervisor_callback */
+       sete XEN_vcpu_info_mask(%eax)
+
+       popl %eax
+
+       /* From this point on the registers are restored and the stack
+          updated, so we don't need to worry about it if we're preempted */
+iret_restore_end:
+
+       /* Jump to hypervisor_callback after fixing up the stack.
+          Events are masked, so jumping out of the critical
+          region is OK. */
+       je xen_hypervisor_callback
+
+       iret
+xen_iret_end_crit:
+
+hyper_iret:
+       /* put this out of line since its very rarely used */
+       jmp hypercall_page + __HYPERVISOR_iret * 32
+
+       .globl xen_iret_start_crit, xen_iret_end_crit
+
+/*
+   This is called by xen_hypervisor_callback in entry.S when it sees
+   that the EIP at the time of interrupt was between xen_iret_start_crit
+   and xen_iret_end_crit.  We're passed the EIP in %eax so we can do
+   a more refined determination of what to do.
+
+   The stack format at this point is:
+       ----------------
+        ss             : (ss/esp may be present if we came from usermode)
+        esp            :
+        eflags         }  outer exception info
+        cs             }
+        eip            }
+       ---------------- <- edi (copy dest)
+        eax            :  outer eax if it hasn't been restored
+       ----------------
+        eflags         }  nested exception info
+        cs             }   (no ss/esp because we're nested
+        eip            }    from the same ring)
+        orig_eax       }<- esi (copy src)
+        - - - - - - - -
+        fs             }
+        es             }
+        ds             }  SAVE_ALL state
+        eax            }
+         :             :
+        ebx            }
+       ----------------
+        return addr     <- esp
+       ----------------
+
+   In order to deliver the nested exception properly, we need to shift
+   everything from the return addr up to the error code so it
+   sits just under the outer exception info.  This means that when we
+   handle the exception, we do it in the context of the outer exception
+   rather than starting a new one.
+
+   The only caveat is that if the outer eax hasn't been
+   restored yet (ie, it's still on stack), we need to insert
+   its value into the SAVE_ALL state before going on, since
+   it's usermode state which we eventually need to restore.
+ */
+ENTRY(xen_iret_crit_fixup)
+       /* offsets +4 for return address */
+
+       /*
+          Paranoia: Make sure we're really coming from userspace.
+          One could imagine a case where userspace jumps into the
+          critical range address, but just before the CPU delivers a GP,
+          it decides to deliver an interrupt instead.  Unlikely?
+          Definitely.  Easy to avoid?  Yes.  The Intel documents
+          explicitly say that the reported EIP for a bad jump is the
+          jump instruction itself, not the destination, but some virtual
+          environments get this wrong.
+        */
+       movl PT_CS+4(%esp), %ecx
+       andl $SEGMENT_RPL_MASK, %ecx
+       cmpl $USER_RPL, %ecx
+       je 2f
+
+       lea PT_ORIG_EAX+4(%esp), %esi
+       lea PT_EFLAGS+4(%esp), %edi
+
+       /* If eip is before iret_restore_end then stack
+          hasn't been restored yet. */
+       cmp $iret_restore_end, %eax
+       jae 1f
+
+       movl 0+4(%edi),%eax             /* copy EAX */
+       movl %eax, PT_EAX+4(%esp)
+
+       lea ESP_OFFSET(%edi),%edi       /* move dest up over saved regs */
+
+       /* set up the copy */
+1:     std
+       mov $(PT_EIP+4) / 4, %ecx       /* copy ret+saved regs up to orig_eax */
+       rep movsl
+       cld
+
+       lea 4(%edi),%esp                /* point esp to new frame */
+2:     ret
+
+
+/*
+       Force an event check by making a hypercall,
+       but preserve regs before making the call.
+ */
+check_events:
+       push %eax
+       push %ecx
+       push %edx
+       call force_evtchn_callback
+       pop %edx
+       pop %ecx
+       pop %eax
+       ret
diff --git a/arch/i386/xen/xen-head.S b/arch/i386/xen/xen-head.S
new file mode 100644 (file)
index 0000000..2998d55
--- /dev/null
@@ -0,0 +1,36 @@
+/* Xen-specific pieces of head.S, intended to be included in the right
+       place in head.S */
+
+#ifdef CONFIG_XEN
+
+#include <linux/elfnote.h>
+#include <asm/boot.h>
+#include <xen/interface/elfnote.h>
+
+ENTRY(startup_xen)
+       movl %esi,xen_start_info
+       cld
+       movl $(init_thread_union+THREAD_SIZE),%esp
+       jmp xen_start_kernel
+
+.pushsection ".bss.page_aligned"
+       .align PAGE_SIZE_asm
+ENTRY(hypercall_page)
+       .skip 0x1000
+.popsection
+
+       ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS,       .asciz "linux")
+       ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION,  .asciz "2.6")
+       ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION,    .asciz "xen-3.0")
+       ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE,      .long  __PAGE_OFFSET)
+       ELFNOTE(Xen, XEN_ELFNOTE_ENTRY,          .long  startup_xen)
+       ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .long  hypercall_page)
+       ELFNOTE(Xen, XEN_ELFNOTE_FEATURES,       .asciz "!writable_page_tables|pae_pgdir_above_4gb")
+#ifdef CONFIG_X86_PAE
+       ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE,       .asciz "yes")
+#else
+       ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE,       .asciz "no")
+#endif
+       ELFNOTE(Xen, XEN_ELFNOTE_LOADER,         .asciz "generic")
+
+#endif /*CONFIG_XEN */
diff --git a/arch/i386/xen/xen-ops.h b/arch/i386/xen/xen-ops.h
new file mode 100644 (file)
index 0000000..b9aaea4
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef XEN_OPS_H
+#define XEN_OPS_H
+
+#include <linux/init.h>
+
+/* These are code, but not functions.  Defined in entry.S */
+extern const char xen_hypervisor_callback[];
+extern const char xen_failsafe_callback[];
+
+void xen_copy_trap_info(struct trap_info *traps);
+
+DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
+DECLARE_PER_CPU(unsigned long, xen_cr3);
+
+extern struct start_info *xen_start_info;
+extern struct shared_info *HYPERVISOR_shared_info;
+
+char * __init xen_memory_setup(void);
+void __init xen_arch_setup(void);
+void __init xen_init_IRQ(void);
+
+void xen_setup_timer(int cpu);
+void xen_setup_cpu_clockevents(void);
+unsigned long xen_cpu_khz(void);
+void __init xen_time_init(void);
+unsigned long xen_get_wallclock(void);
+int xen_set_wallclock(unsigned long time);
+unsigned long long xen_sched_clock(void);
+
+void xen_mark_init_mm_pinned(void);
+
+DECLARE_PER_CPU(enum paravirt_lazy_mode, xen_lazy_mode);
+
+static inline unsigned xen_get_lazy_mode(void)
+{
+       return x86_read_percpu(xen_lazy_mode);
+}
+
+void __init xen_fill_possible_map(void);
+
+void __init xen_setup_vcpu_info_placement(void);
+void xen_smp_prepare_boot_cpu(void);
+void xen_smp_prepare_cpus(unsigned int max_cpus);
+int xen_cpu_up(unsigned int cpu);
+void xen_smp_cpus_done(unsigned int max_cpus);
+
+void xen_smp_send_stop(void);
+void xen_smp_send_reschedule(int cpu);
+int xen_smp_call_function (void (*func) (void *info), void *info, int nonatomic,
+                          int wait);
+int xen_smp_call_function_single(int cpu, void (*func) (void *info), void *info,
+                                int nonatomic, int wait);
+
+int xen_smp_call_function_mask(cpumask_t mask, void (*func)(void *),
+                              void *info, int wait);
+
+
+/* Declare an asm function, along with symbols needed to make it
+   inlineable */
+#define DECL_ASM(ret, name, ...)               \
+       ret name(__VA_ARGS__);                  \
+       extern char name##_end[];               \
+       extern char name##_reloc[]              \
+
+DECL_ASM(void, xen_irq_enable_direct, void);
+DECL_ASM(void, xen_irq_disable_direct, void);
+DECL_ASM(unsigned long, xen_save_fl_direct, void);
+DECL_ASM(void, xen_restore_fl_direct, unsigned long);
+
+void xen_iret_direct(void);
+#endif /* XEN_OPS_H */
index c1dca226b479ef1be7ca1e605529b0a899cdaf9d..cd4adf52f174ece99c323b0804f839391b020d61 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/efi.h>
 #include <linux/nodemask.h>
 #include <linux/bitops.h>         /* hweight64() */
+#include <linux/crash_dump.h>
 
 #include <asm/delay.h>         /* ia64_get_itc() */
 #include <asm/io.h>
@@ -43,6 +44,8 @@
 
 #include <asm/acpi-ext.h>
 
+extern int swiotlb_late_init_with_default_size (size_t size);
+
 #define PFX "IOC: "
 
 /*
@@ -2026,11 +2029,24 @@ sba_init(void)
        if (!ia64_platform_is("hpzx1") && !ia64_platform_is("hpzx1_swiotlb"))
                return 0;
 
+#if defined(CONFIG_IA64_GENERIC) && defined(CONFIG_CRASH_DUMP)
+       /* If we are booting a kdump kernel, the sba_iommu will
+        * cause devices that were not shutdown properly to MCA
+        * as soon as they are turned back on.  Our only option for
+        * a successful kdump kernel boot is to use the swiotlb.
+        */
+       if (elfcorehdr_addr < ELFCORE_ADDR_MAX) {
+               if (swiotlb_late_init_with_default_size(64 * (1<<20)) != 0)
+                       panic("Unable to initialize software I/O TLB:"
+                                 " Try machvec=dig boot option");
+               machvec_init("dig");
+               return 0;
+       }
+#endif
+
        acpi_bus_register_driver(&acpi_sba_ioc_driver);
        if (!ioc_list) {
 #ifdef CONFIG_IA64_GENERIC
-               extern int swiotlb_late_init_with_default_size (size_t size);
-
                /*
                 * If we didn't find something sba_iommu can claim, we
                 * need to setup the swiotlb and switch to the dig machvec.
index 300acd913d9c5df9d7fa8aa396a58a6b71c2e9fa..1189d035d316e6f853e464b5736d81eafe72f937 100644 (file)
@@ -329,11 +329,6 @@ sys_fw_init (const char *args, int arglen)
        strcpy(sal_systab->product_id, "HP-simulator");
 #endif
 
-#ifdef CONFIG_IA64_SDV
-       strcpy(sal_systab->oem_id, "Intel");
-       strcpy(sal_systab->product_id, "SDV");
-#endif
-
        /* fill in an entry point: */
        sal_ed->type = SAL_DESC_ENTRY_POINT;
        sal_ed->pal_proc = __pa(pal_desc[0]);
index 324ea7565e2c14f90df86a561e202eb0d63a4382..ef252df50e1e7a32097d881957e83b307cb167a2 100644 (file)
 #include <asm/hw_irq.h>
 #include <asm/uaccess.h>
 
-#ifdef CONFIG_KDB
-# include <linux/kdb.h>
-#endif
-
 #undef SIMSERIAL_DEBUG /* define this to get some debug information */
 
 #define KEYBOARD_INTR  3       /* must match with simulator! */
index 8589e84a27c66119e9297757673faa198d70a4fa..3f926c2dc708044542a0b34be94f42e0b58912f2 100644 (file)
@@ -247,6 +247,9 @@ ENTRY(fsys_gettimeofday)
 .time_redo:
        .pred.rel.mutex p8,p9,p10
        ld4.acq r28 = [r29]     // xtime_lock.sequence. Must come first for locking purposes
+       ;;
+       and r28 = ~1,r28        // Make sequence even to force retry if odd
+       ;;
 (p8)   mov r2 = ar.itc         // CPU_TIMER. 36 clocks latency!!!
        add r22 = IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET,r20
 (p9)   ld8 r2 = [r30]          // readq(ti->address). Could also have latency issues..
@@ -284,7 +287,6 @@ EX(.fail_efault, probe.w.fault r31, 3)      // This takes 5 cycles and we have spare
 (p15)  ld8 r17 = [r19],-IA64_TIMESPEC_TV_NSEC_OFFSET
 (p7)   cmp.ne p7,p0 = r25,r3   // if cmpxchg not successful redo
        // simulate tbit.nz.or p7,p0 = r28,0
-       and r28 = ~1,r28        // Make sequence even to force retry if odd
        getf.sig r2 = f8
        mf
        add r8 = r8,r18         // Add time interpolator offset
index 4411d9baeb21699130d4665d03fea6bf30d2c102..9fc955026f866b5fda8fb196fb72311fbcc7f0dc 100644 (file)
@@ -60,6 +60,7 @@ csum_tcpudp_nofold (__be32 saddr, __be32 daddr, unsigned short len,
        result = (result & 0xffffffff) + (result >> 32);
        return (__force __wsum)result;
 }
+EXPORT_SYMBOL(csum_tcpudp_nofold);
 
 extern unsigned long do_csum (const unsigned char *, long);
 
index 6da9854751cd9be20d0035fa32b037f6ef6590c0..df8d5bed6119f210f7e5d2b234654536000a7168 100644 (file)
@@ -750,9 +750,10 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg)
                        goto error;
                } else
                if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) {
+                       int cpuobj_index = 0;
+
                        memset(p, 0, a.sz);
                        for (i = 0; i < nobj; i++) {
-                               int cpuobj_index = 0;
                                if (!SN_HWPERF_IS_NODE(objs + i))
                                        continue;
                                node = sn_hwperf_obj_to_cnode(objs + i);
index cf6bb51945a24f317a6acdebd2f4ac62dff70cfb..6216f12a756b56121361639116794e35d8356ad2 100644 (file)
@@ -422,3 +422,4 @@ csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
            );
     return(sum);
 }
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
index 2f0e4c08eb04ce283240d795385985d37242ad98..56003188f17c67be9709d568c43c6017aa3c3341 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/tty.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
+#include <linux/serial_8250.h>
 #include <linux/ioport.h>
 #include <linux/spinlock.h>
 #include <asm/bootinfo.h>
index ea965529e5e06600893fd4a2fbadcce9aa67e072..ed58c13b6032d06438e5d1571917b1f93bcfa2e9 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 #include <linux/pm.h>
 
 #include <asm/io.h>
index 1cc6ebbedfdd8cc89d611f71522478dd90f96adf..c68358a476dd13e03b2121e998dcb75599544ab7 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 
 #include <asm/cpu.h>
 #include <asm/bootinfo.h>
index bb801409d39b10eefeefb7ce4ca42f73c168425b..5f70eaf01fab1f5f491f26aeb05a9c7e05c208c5 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 
 #include <asm/cpu.h>
 #include <asm/bootinfo.h>
index 60e66906be659089d4b5e07d19f30be8a5c13d64..17819b59410542aea42ead3ed9873e344ff3f36e 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 
 #include <asm/cpu.h>
 #include <asm/bootinfo.h>
index c41b53faa8f6af695c32e3f38c9ffcf4d6f24e4e..e25bac537d77b4688db6c3854424461495e9e5d2 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/serial.h>
+#include <linux/serial_8250.h>
 
 #include <msp_prom.h>
 #include <msp_int.h>
index 6a6e15e400095cd0c3c42a920f1f64960f51d147..f7f93ae24c3491ce33b4b10da46fda2931ce131a 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 
 #include <asm/time.h>
 #include <asm/bootinfo.h>
index faf5ef3e90d0e66b01d07c9ee679cfb5169d5b50..94b4a028232a957b5e65321204de4cdf327f5c18 100644 (file)
@@ -156,11 +156,14 @@ static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);
 #endif /* CONFIG_PPC_OF */
 
 /* Add sysfs properties */
-void pcibios_add_platform_entries(struct pci_dev *pdev)
+int pcibios_add_platform_entries(struct pci_dev *pdev)
 {
 #ifdef CONFIG_PPC_OF
-       device_create_file(&pdev->dev, &dev_attr_devspec);
+       return device_create_file(&pdev->dev, &dev_attr_devspec);
+#else
+       return 0;
 #endif /* CONFIG_PPC_OF */
+
 }
 
 char __init *pcibios_setup(char *str)
index bc43bba05cf84e3793dc01aa1b692364cecf331b..6018178708a55f76be298d405c0fd8d76c9af6b2 100644 (file)
@@ -350,11 +350,13 @@ void __init setup_system(void)
 {
        DBG(" -> setup_system()\n");
 
-       /* Apply CPUs-specific fixups to kernel text (nop out sections
-        * not relevant to this CPU)
+       /* Apply the CPUs-specific and firmware specific fixups to kernel
+        * text (nop out sections not relevant to this CPU or this firmware)
         */
        do_feature_fixups(cur_cpu_spec->cpu_features,
                          &__start___ftr_fixup, &__stop___ftr_fixup);
+       do_feature_fixups(powerpc_firmware_features,
+                         &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
 
        /*
         * Unflatten the device-tree passed by prom_init or kexec
@@ -392,12 +394,6 @@ void __init setup_system(void)
        if (ppc_md.init_early)
                ppc_md.init_early();
 
-       /* Apply firmware specific fixups to kernel text (nop out
-        * sections not relevant to this firmware)
-        */
-       do_feature_fixups(powerpc_firmware_features,
-                         &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
-
        /*
         * We can discover serial ports now since the above did setup the
         * hash table management for us, thus ioremap works. We do that early
index b42cbf1e2d7d8f650a5ca6901629efc780777024..bd85b5fd08c818763fda919135ca3268ff0e4520 100644 (file)
@@ -773,6 +773,13 @@ asmlinkage int compat_sys_truncate64(const char __user * path, u32 reg4,
        return sys_truncate(path, (high << 32) | low);
 }
 
+asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo,
+                                    u32 lenhi, u32 lenlo)
+{
+       return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo,
+                            ((loff_t)lenhi << 32) | lenlo);
+}
+
 asmlinkage int compat_sys_ftruncate64(unsigned int fd, u32 reg4, unsigned long high,
                                 unsigned long low)
 {
index 349660b84a02a88ee3f33da44f65d5dde772eade..017623c9bc4b1ab80e71368a9ba79501796b54dd 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 #include <linux/ethtool.h>
 
 #include <asm/system.h>
index 1a7f075b754f23a21d512f822832a7462716819f..cd696be55aca11ce0c0b5560519bdea52966b7b6 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 
 #include <asm/system.h>
 #include <asm/pci-bridge.h>
index 8474b05b795aaf3b5dd5e3a7e33c87526eceafa8..2e7e25dd84cbc705b06e09d5533ab3139d5b908d 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/todc.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 #include <asm/ocp.h>
 #include <asm/ibm_ocp_pci.h>
 #include <platforms/4xx/ibm405gp.h>
index f0f9cc8480ca94d1e788e321112a700dcf94eaa0..05d7184d7e1454ec2f85022fb82e4513ca38de3d 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
index 61706ef37112046cc2538e53ababb57c1a76d817..4b169610f15425865e3993726390123c60350c30 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
index 5e994e146ba864858c05159cd7c52efb2aa909b0..fd0f971881d67763c0b6fc36ee0708c674e14f38 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
index 5d9af8ddb155d84da625a147c2bf19b582ba0498..888c492b4a4535dea8730f56a42d52ad66f2cc4b 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
index 346787df0ddb14f3211b295532042596a1d6d897..a83b0baea011f17811cda760540dab989e1f631c 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
index 1d10ab98f66dda9d1e63554768e0f7ca277ac984..3d7addbdecfdd84fbe0bfe2057265b988f321844 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/serial.h>
 #include <linux/tty.h> /* for linux/serial_core.h */
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 #include <linux/initrd.h>
 #include <linux/module.h>
 #include <linux/fsl_devices.h>
index a764ae71cbcbb7248f9f13b4322061d203c35db1..248684f50dd9e4c7754503951259b0639d2cdba6 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/ide.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 #include <linux/mtd/physmap.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
index 4957a7bcde2296ce5c9b04bf51076233ca1b9e1f..976270d537c1947480f3d8e573d5c4b2fae7d089 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/serial.h>
 #include <linux/tty.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 #else
 #include <linux/mv643xx.h>
 #endif
index b55860734a722b03d4ba1f8a85d877fbd5d96417..44d4398a36ff8379a970f9d39a50727f8c0e2236 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/serial.h>
 #include <linux/tty.h>         /* for linux/serial_core.h */
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 #include <linux/mv643xx.h>
 #include <linux/netdevice.h>
 #include <linux/platform_device.h>
index 3c784278487647416ca75c73860fc5371cc14e73..f4de50ba292e1195947e2cab031a8263f1b5d069 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/serial.h>
 #include <linux/tty.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
index 485b60c1983ce8d2efa2a348c0464bb384d890f3..2aae23dba4bbc8b2a087c3a36b8145a7cdfb5656 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21
-# Thu May 10 15:18:19 2007
+# Linux kernel version: 2.6.22
+# Tue Jul 17 12:50:23 2007
 #
 CONFIG_MMU=y
 CONFIG_ZONE_DMA=y
@@ -32,12 +32,11 @@ CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
 CONFIG_AUDIT=y
 # CONFIG_AUDITSYSCALL is not set
 CONFIG_IKCONFIG=y
@@ -61,20 +60,19 @@ CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLUB_DEBUG=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
@@ -82,12 +80,9 @@ CONFIG_MODVERSIONS=y
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_BLK_DEV_IO_TRACE is not set
+CONFIG_BLK_DEV_BSG=y
 
 #
 # IO Schedulers
@@ -151,6 +146,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=1
+CONFIG_VIRT_TO_BUS=y
 CONFIG_HOLES_IN_ZONE=y
 
 #
@@ -248,25 +244,13 @@ CONFIG_IPV6_SIT=y
 # CONFIG_IPV6_MULTIPLE_TABLES is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 CONFIG_IP_SCTP=m
 # CONFIG_SCTP_DBG_MSG is not set
 # CONFIG_SCTP_DBG_OBJCNT is not set
 # CONFIG_SCTP_HMAC_NONE is not set
 # CONFIG_SCTP_HMAC_SHA1 is not set
 CONFIG_SCTP_HMAC_MD5=y
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -293,6 +277,7 @@ CONFIG_NET_SCH_CBQ=m
 # CONFIG_NET_SCH_HTB is not set
 # CONFIG_NET_SCH_HFSC is not set
 CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RR=m
 CONFIG_NET_SCH_RED=m
 CONFIG_NET_SCH_SFQ=m
 CONFIG_NET_SCH_TEQL=m
@@ -317,10 +302,14 @@ CONFIG_CLS_U32_MARK=y
 CONFIG_NET_CLS_RSVP=m
 CONFIG_NET_CLS_RSVP6=m
 # CONFIG_NET_EMATCH is not set
-# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+# CONFIG_NET_ACT_GACT is not set
+# CONFIG_NET_ACT_MIRRED is not set
+# CONFIG_NET_ACT_PEDIT is not set
+# CONFIG_NET_ACT_SIMP is not set
 CONFIG_NET_CLS_POLICE=y
 # CONFIG_NET_CLS_IND is not set
-CONFIG_NET_ESTIMATOR=y
 
 #
 # Network testing
@@ -329,6 +318,7 @@ CONFIG_NET_ESTIMATOR=y
 # CONFIG_NET_TCPPROBE is not set
 # CONFIG_AF_RXRPC is not set
 # CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 # CONFIG_PCMCIA is not set
 CONFIG_CCW=y
 
@@ -345,15 +335,8 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 CONFIG_SYS_HYPERVISOR=y
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=m
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
@@ -376,17 +359,15 @@ CONFIG_DASD_ECKD=y
 CONFIG_DASD_FBA=y
 CONFIG_DASD_DIAG=y
 CONFIG_DASD_EER=y
-
-#
-# Misc devices
-#
-# CONFIG_BLINK is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
 
 #
 # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+# CONFIG_SCSI_DMA is not set
 # CONFIG_SCSI_TGT is not set
 CONFIG_SCSI_NETLINK=y
 CONFIG_SCSI_PROC_FS=y
@@ -447,40 +428,21 @@ CONFIG_DM_MIRROR=y
 CONFIG_DM_ZERO=y
 CONFIG_DM_MULTIPATH=y
 # CONFIG_DM_MULTIPATH_EMC is not set
+# CONFIG_DM_MULTIPATH_RDAC is not set
 # CONFIG_DM_DELAY is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_IFB is not set
 CONFIG_DUMMY=m
 CONFIG_BONDING=m
+# CONFIG_MACVLAN is not set
 CONFIG_EQUALIZER=m
 CONFIG_TUN=m
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-CONFIG_MLX4_DEBUG=y
-
-#
-# Token Ring devices
-#
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
 # CONFIG_TR is not set
-
-#
-# Wan interfaces
-#
 # CONFIG_WAN is not set
 
 #
@@ -511,10 +473,6 @@ CONFIG_CCWGROUP=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# Watchdog Cards
-#
 # CONFIG_WATCHDOG is not set
 CONFIG_HW_RANDOM=m
 # CONFIG_R3964 is not set
@@ -554,6 +512,8 @@ CONFIG_S390_TAPE_34XX=m
 # CONFIG_VMCP is not set
 # CONFIG_MONREADER is not set
 CONFIG_MONWRITER=m
+CONFIG_S390_VMUR=m
+# CONFIG_POWER_SUPPLY is not set
 
 #
 # File systems
@@ -655,7 +615,6 @@ CONFIG_SUNRPC=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -712,6 +671,7 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
 CONFIG_HEADERS_CHECK=y
 CONFIG_DEBUG_KERNEL=y
+# CONFIG_SCHED_DEBUG is not set
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_SLAB is not set
@@ -740,10 +700,6 @@ CONFIG_FORCED_INLINING=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_BLKCIPHER=y
@@ -782,10 +738,7 @@ CONFIG_CRYPTO_FCRYPT=m
 # CONFIG_CRYPTO_CRC32C is not set
 CONFIG_CRYPTO_CAMELLIA=m
 # CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_SHA1_S390 is not set
 # CONFIG_CRYPTO_SHA256_S390 is not set
 # CONFIG_CRYPTO_DES_S390 is not set
@@ -800,6 +753,7 @@ CONFIG_ZCRYPT=m
 CONFIG_BITREVERSE=m
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=m
 # CONFIG_LIBCRC32C is not set
 CONFIG_PLIST=y
index a057ebf108a7733a413e3470f4c9f788817eecbb..d3057318f2bfc21e0f20524b3a9e1830e077c1eb 100644 (file)
@@ -240,8 +240,8 @@ static const unsigned char formats[][7] = {
        [INSTR_RXY_FRRD]  = { 0xff, F_8,D20_20,X_12,B_16,0,0 },/* e.g. ley   */
        [INSTR_RX_FRRD]   = { 0xff, F_8,D_20,X_12,B_16,0,0 },  /* e.g. ae    */
        [INSTR_RX_RRRD]   = { 0xff, R_8,D_20,X_12,B_16,0,0 },  /* e.g. l     */
-       [INSTR_RX_URRD]   = { 0x00, U4_8,D_20,X_12,B_16,0,0 }, /* e.g. bc    */
-       [INSTR_SI_URD]    = { 0x00, D_20,B_16,U8_8,0,0,0 },    /* e.g. cli   */
+       [INSTR_RX_URRD]   = { 0xff, U4_8,D_20,X_12,B_16,0,0 }, /* e.g. bc    */
+       [INSTR_SI_URD]    = { 0xff, D_20,B_16,U8_8,0,0,0 },    /* e.g. cli   */
        [INSTR_SIY_URD]   = { 0xff, D20_20,B_16,U8_8,0,0,0 },  /* e.g. tmy   */
        [INSTR_SSE_RDRD]  = { 0xff, D_20,B_16,D_36,B_32,0,0 }, /* e.g. mvsdk */
        [INSTR_SS_L0RDRD] = { 0xff, D_20,L8_8,B_16,D_36,B_32,0 },
@@ -1190,7 +1190,8 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
                        else if (operand->flags & OPERAND_CR)
                                ptr += sprintf(ptr, "%%c%i", value);
                        else if (operand->flags & OPERAND_PCREL)
-                               ptr += sprintf(ptr, "%lx", value + addr);
+                               ptr += sprintf(ptr, "%lx", (signed int) value
+                                                                     + addr);
                        else if (operand->flags & OPERAND_SIGNED)
                                ptr += sprintf(ptr, "%i", value);
                        else
index 515ff9011dd742e33a5bfb54c4d55d99818937d9..da692472996449fa6daa83e79a56273f56ac4be8 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/kallsyms.h>
 
 static unsigned long save_context_stack(struct stack_trace *trace,
-                                       unsigned int *skip,
                                        unsigned long sp,
                                        unsigned long low,
                                        unsigned long high)
@@ -28,10 +27,10 @@ static unsigned long save_context_stack(struct stack_trace *trace,
                sf = (struct stack_frame *)sp;
                while(1) {
                        addr = sf->gprs[8] & PSW_ADDR_INSN;
-                       if (!(*skip))
+                       if (!trace->skip)
                                trace->entries[trace->nr_entries++] = addr;
                        else
-                               (*skip)--;
+                               trace->skip--;
                        if (trace->nr_entries >= trace->max_entries)
                                return sp;
                        low = sp;
@@ -48,10 +47,10 @@ static unsigned long save_context_stack(struct stack_trace *trace,
                        return sp;
                regs = (struct pt_regs *)sp;
                addr = regs->psw.addr & PSW_ADDR_INSN;
-               if (!(*skip))
+               if (!trace->skip)
                        trace->entries[trace->nr_entries++] = addr;
                else
-                       (*skip)--;
+                       trace->skip--;
                if (trace->nr_entries >= trace->max_entries)
                        return sp;
                low = sp;
@@ -65,20 +64,17 @@ void save_stack_trace(struct stack_trace *trace)
        unsigned long orig_sp, new_sp;
 
        orig_sp = sp & PSW_ADDR_INSN;
-
-       new_sp = save_context_stack(trace, &trace->skip, orig_sp,
-                               S390_lowcore.panic_stack - PAGE_SIZE,
-                               S390_lowcore.panic_stack);
+       new_sp = save_context_stack(trace, orig_sp,
+                                   S390_lowcore.panic_stack - PAGE_SIZE,
+                                   S390_lowcore.panic_stack);
        if (new_sp != orig_sp)
                return;
-       new_sp = save_context_stack(trace, &trace->skip, new_sp,
-                               S390_lowcore.async_stack - ASYNC_SIZE,
-                               S390_lowcore.async_stack);
+       new_sp = save_context_stack(trace, new_sp,
+                                   S390_lowcore.async_stack - ASYNC_SIZE,
+                                   S390_lowcore.async_stack);
        if (new_sp != orig_sp)
                return;
-
-       save_context_stack(trace, &trace->skip, new_sp,
+       save_context_stack(trace, new_sp,
                           S390_lowcore.thread_info,
                           S390_lowcore.thread_info + THREAD_SIZE);
-       return;
 }
index 4b2676380deb60a47ce1fe7a11c2c77c6851cd2d..bd55017602408165e9d721abacb04a22e0a5f7a6 100644 (file)
@@ -213,3 +213,4 @@ __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
 
        return (__wsum)result;
 }
+EXPORT_SYMBOL(csum_tcpudp_nofold);
index 8567cc901942be09a40178388919afea7fdc1d4c..603d83ad65c8f0012e11c3c300273424d24c1098 100644 (file)
@@ -21,6 +21,9 @@ config GENERIC_ISA_DMA
        bool
        default y
 
+config ARCH_NO_VIRT_TO_BUS
+       def_bool y
+
 source "init/Kconfig"
 
 menu "General machine setup"
@@ -217,6 +220,9 @@ source "drivers/pci/Kconfig"
 
 endif
 
+config NO_DMA
+       def_bool !PCI
+
 config SUN_OPENPROMFS
        tristate "Openprom tree appears in /proc/openprom"
        help
index b84b6af1241ef55ae943db3fa7c0828164a12132..df6ee71894d1f3228a6ddf59a599df3eeced3e9d 100644 (file)
@@ -62,6 +62,9 @@ config AUDIT_ARCH
        bool
        default y
 
+config ARCH_NO_VIRT_TO_BUS
+       def_bool y
+
 choice
        prompt "Kernel page size"
        default SPARC64_PAGE_SIZE_8KB
index 65840a62bb9c5c3f758de270741ac124c3937f30..45ebf91a280ce048a812f3350418db966a480242 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc1
-# Mon May 14 04:17:48 2007
+# Linux kernel version: 2.6.22
+# Tue Jul 17 01:19:52 2007
 #
 CONFIG_SPARC=y
 CONFIG_SPARC64=y
@@ -42,12 +42,11 @@ CONFIG_LOCALVERSION=""
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=18
@@ -82,22 +81,15 @@ CONFIG_SLUB=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_KMOD=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_BLK_DEV_BSG=y
 
 #
 # IO Schedulers
@@ -156,12 +148,15 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=0
 CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
 CONFIG_SBUS=y
 CONFIG_SBUSCHAR=y
 CONFIG_SUN_AUXIO=y
 CONFIG_SUN_IO=y
+# CONFIG_SUN_LDOMS is not set
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
 CONFIG_ARCH_SUPPORTS_MSI=y
 CONFIG_PCI_MSI=y
 # CONFIG_PCI_DEBUG is not set
@@ -246,10 +241,6 @@ CONFIG_IPV6_TUNNEL=m
 # CONFIG_IPV6_MULTIPLE_TABLES is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 CONFIG_IP_DCCP=m
 CONFIG_INET_DCCP_DIAG=m
 CONFIG_IP_DCCP_ACKVEC=y
@@ -269,15 +260,7 @@ CONFIG_IP_DCCP_CCID3_RTO=100
 #
 # CONFIG_IP_DCCP_DEBUG is not set
 # CONFIG_NET_DCCPPROBE is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -314,6 +297,7 @@ CONFIG_NET_TCPPROBE=m
 # CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
 # CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -328,26 +312,10 @@ CONFIG_FW_LOADER=y
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 CONFIG_CONNECTOR=m
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
@@ -364,18 +332,11 @@ CONFIG_CDROM_PKTCDVD=m
 CONFIG_CDROM_PKTCDVD_BUFFERS=8
 CONFIG_CDROM_PKTCDVD_WCACHE=y
 CONFIG_ATA_OVER_ETH=m
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
 # CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
-# CONFIG_BLINK is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDE=y
 
@@ -440,6 +401,7 @@ CONFIG_BLK_DEV_IDEDMA=y
 #
 CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 CONFIG_SCSI_NETLINK=y
 CONFIG_SCSI_PROC_FS=y
@@ -505,7 +467,6 @@ CONFIG_ISCSI_TCP=m
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_ESP_CORE is not set
 # CONFIG_SCSI_SUNESP is not set
 # CONFIG_SCSI_SRP is not set
 # CONFIG_ATA is not set
@@ -545,30 +506,16 @@ CONFIG_DM_ZERO=m
 #
 # CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
 # CONFIG_ARCNET is not set
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
 # CONFIG_SUNLANCE is not set
@@ -578,10 +525,6 @@ CONFIG_MII=m
 # CONFIG_SUNGEM is not set
 CONFIG_CASSINI=m
 # CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
 # CONFIG_NET_TULIP is not set
 # CONFIG_HP100 is not set
 CONFIG_NET_PCI=y
@@ -617,7 +560,6 @@ CONFIG_E1000_NAPI=y
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=m
 CONFIG_BNX2=m
@@ -631,11 +573,6 @@ CONFIG_NETDEV_10000=y
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_MLX4_CORE is not set
-CONFIG_MLX4_DEBUG=y
-
-#
-# Token Ring devices
-#
 # CONFIG_TR is not set
 
 #
@@ -665,6 +602,7 @@ CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
 CONFIG_PPP_MPPE=m
 CONFIG_PPPOE=m
+# CONFIG_PPPOL2TP is not set
 # CONFIG_SLIP is not set
 CONFIG_SLHC=m
 # CONFIG_NET_FC is not set
@@ -677,10 +615,6 @@ CONFIG_SLHC=m
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -688,6 +622,7 @@ CONFIG_SLHC=m
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -733,7 +668,6 @@ CONFIG_INPUT_SPARCSPKR=y
 # CONFIG_INPUT_POWERMATE is not set
 # CONFIG_INPUT_YEALINK is not set
 # CONFIG_INPUT_UINPUT is not set
-# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Hardware I/O ports
@@ -773,10 +707,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 # CONFIG_LEGACY_PTYS is not set
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
@@ -785,10 +715,6 @@ CONFIG_RTC=y
 # CONFIG_APPLICOM is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
 CONFIG_DEVPORT=y
 CONFIG_I2C=y
@@ -822,6 +748,7 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_TAOS_EVM is not set
 # CONFIG_I2C_STUB is not set
 # CONFIG_I2C_TINY_USB is not set
 # CONFIG_I2C_VIA is not set
@@ -833,11 +760,13 @@ CONFIG_I2C_ALGOBIT=y
 #
 # CONFIG_SENSORS_DS1337 is not set
 # CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
 # CONFIG_SENSORS_EEPROM is not set
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_SENSORS_PCA9539 is not set
 # CONFIG_SENSORS_PCF8591 is not set
 # CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
@@ -848,11 +777,8 @@ CONFIG_I2C_ALGOBIT=y
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
@@ -949,6 +875,8 @@ CONFIG_FB_TILEBLITTING=y
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
 # CONFIG_FB_SBUS is not set
+# CONFIG_FB_XVR500 is not set
+# CONFIG_FB_XVR2500 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_RIVA is not set
@@ -970,9 +898,6 @@ CONFIG_FB_RADEON_I2C=y
 # CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_ARK is not set
 # CONFIG_FB_PM3 is not set
-# CONFIG_FB_XVR500 is not set
-# CONFIG_FB_XVR2500 is not set
-# CONFIG_FB_PCI is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -1118,10 +1043,7 @@ CONFIG_SND_SUN_CS4231=m
 #
 # CONFIG_SOUND_PRIME is not set
 CONFIG_AC97_BUS=m
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
 
@@ -1132,10 +1054,7 @@ CONFIG_USB_HID=y
 # CONFIG_USB_HIDINPUT_POWERBOOK is not set
 # CONFIG_HID_FF is not set
 CONFIG_USB_HIDDEV=y
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
@@ -1157,7 +1076,6 @@ CONFIG_USB_EHCI_HCD=m
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
-# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
 # CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
@@ -1165,6 +1083,7 @@ CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=m
 # CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
 
 #
 # USB Device Class drivers
@@ -1256,16 +1175,8 @@ CONFIG_USB_STORAGE=m
 #
 # LED Triggers
 #
-
-#
-# InfiniBand support
-#
 # CONFIG_INFINIBAND is not set
 
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
 #
 # Real Time Clock
 #
@@ -1387,7 +1298,6 @@ CONFIG_RAMFS=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1465,8 +1375,10 @@ CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHED_DEBUG is not set
 CONFIG_SCHEDSTATS=y
 # CONFIG_TIMER_STATS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
@@ -1496,10 +1408,10 @@ CONFIG_FORCED_INLINING=y
 CONFIG_KEYS=y
 # CONFIG_KEYS_DEBUG_PROC_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
+CONFIG_XOR_BLOCKS=m
+CONFIG_ASYNC_CORE=m
+CONFIG_ASYNC_MEMCPY=m
+CONFIG_ASYNC_XOR=m
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_BLKCIPHER=y
@@ -1539,10 +1451,7 @@ CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_TEST=m
-
-#
-# Hardware crypto devices
-#
+CONFIG_CRYPTO_HW=y
 
 #
 # Library routines
index ba01533f4e036004db74520070c1200ed309a04b..fa1f04d756a286381ffb741602774ea546594481 100644 (file)
@@ -1013,6 +1013,19 @@ static void ds_up(struct ds_info *dp)
                dp->hs_state = DS_HS_START;
 }
 
+static void ds_reset(struct ds_info *dp)
+{
+       int i;
+
+       dp->hs_state = 0;
+
+       for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
+               struct ds_cap_state *cp = &ds_states[i];
+
+               cp->state = CAP_STATE_UNKNOWN;
+       }
+}
+
 static void ds_event(void *arg, int event)
 {
        struct ds_info *dp = arg;
@@ -1028,6 +1041,12 @@ static void ds_event(void *arg, int event)
                return;
        }
 
+       if (event == LDC_EVENT_RESET) {
+               ds_reset(dp);
+               spin_unlock_irqrestore(&ds_lock, flags);
+               return;
+       }
+
        if (event != LDC_EVENT_DATA_READY) {
                printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
                spin_unlock_irqrestore(&ds_lock, flags);
index 76a090e2c2a83ba901183fcb8f9f9e4adea3741c..a55c252e18ccd6df64a2d0bc144ffe25cc36a99a 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/hvtramp.h>
 #include <asm/pstate.h>
 #include <asm/ptrace.h>
+#include <asm/head.h>
 #include <asm/asi.h>
 
        .text
@@ -28,7 +29,7 @@
         * First setup basic privileged cpu state.
         */
 hv_cpu_startup:
-       wrpr            %g0, 0, %gl
+       SET_GL(0)
        wrpr            %g0, 15, %pil
        wrpr            %g0, 0, %canrestore
        wrpr            %g0, 0, %otherwin
index de5310ffdb480239903feec457fab1618e14520d..302ba5e5a0bb85d1b8c5f66b938c0177c9e504d2 100644 (file)
@@ -137,7 +137,7 @@ static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size)
                       sizeof(struct mdesc_hdr) +
                       mdesc_size);
 
-       base = kmalloc(handle_size + 15, GFP_KERNEL);
+       base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_NOFAIL);
        if (base) {
                struct mdesc_handle *hp;
                unsigned long addr;
@@ -214,18 +214,83 @@ void mdesc_release(struct mdesc_handle *hp)
 }
 EXPORT_SYMBOL(mdesc_release);
 
+static DEFINE_MUTEX(mdesc_mutex);
+static struct mdesc_notifier_client *client_list;
+
+void mdesc_register_notifier(struct mdesc_notifier_client *client)
+{
+       u64 node;
+
+       mutex_lock(&mdesc_mutex);
+       client->next = client_list;
+       client_list = client;
+
+       mdesc_for_each_node_by_name(cur_mdesc, node, client->node_name)
+               client->add(cur_mdesc, node);
+
+       mutex_unlock(&mdesc_mutex);
+}
+
+/* Run 'func' on nodes which are in A but not in B.  */
+static void invoke_on_missing(const char *name,
+                             struct mdesc_handle *a,
+                             struct mdesc_handle *b,
+                             void (*func)(struct mdesc_handle *, u64))
+{
+       u64 node;
+
+       mdesc_for_each_node_by_name(a, node, name) {
+               const u64 *id = mdesc_get_property(a, node, "id", NULL);
+               int found = 0;
+               u64 fnode;
+
+               mdesc_for_each_node_by_name(b, fnode, name) {
+                       const u64 *fid = mdesc_get_property(b, fnode,
+                                                           "id", NULL);
+
+                       if (*id == *fid) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if (!found)
+                       func(a, node);
+       }
+}
+
+static void notify_one(struct mdesc_notifier_client *p,
+                      struct mdesc_handle *old_hp,
+                      struct mdesc_handle *new_hp)
+{
+       invoke_on_missing(p->node_name, old_hp, new_hp, p->remove);
+       invoke_on_missing(p->node_name, new_hp, old_hp, p->add);
+}
+
+static void mdesc_notify_clients(struct mdesc_handle *old_hp,
+                                struct mdesc_handle *new_hp)
+{
+       struct mdesc_notifier_client *p = client_list;
+
+       while (p) {
+               notify_one(p, old_hp, new_hp);
+               p = p->next;
+       }
+}
+
 void mdesc_update(void)
 {
        unsigned long len, real_len, status;
        struct mdesc_handle *hp, *orig_hp;
        unsigned long flags;
 
+       mutex_lock(&mdesc_mutex);
+
        (void) sun4v_mach_desc(0UL, 0UL, &len);
 
        hp = mdesc_alloc(len, &kmalloc_mdesc_memops);
        if (!hp) {
                printk(KERN_ERR "MD: mdesc alloc fails\n");
-               return;
+               goto out;
        }
 
        status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len);
@@ -234,18 +299,25 @@ void mdesc_update(void)
                       status);
                atomic_dec(&hp->refcnt);
                mdesc_free(hp);
-               return;
+               goto out;
        }
 
        spin_lock_irqsave(&mdesc_lock, flags);
        orig_hp = cur_mdesc;
        cur_mdesc = hp;
+       spin_unlock_irqrestore(&mdesc_lock, flags);
 
+       mdesc_notify_clients(orig_hp, hp);
+
+       spin_lock_irqsave(&mdesc_lock, flags);
        if (atomic_dec_and_test(&orig_hp->refcnt))
                mdesc_free(orig_hp);
        else
                list_add(&orig_hp->list, &mdesc_zombie_list);
        spin_unlock_irqrestore(&mdesc_lock, flags);
+
+out:
+       mutex_unlock(&mdesc_mutex);
 }
 
 static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
index 203e87301005c985a95d08208c94def7222d47a2..fb13775b36823b7f5cdbd707026c9782a0aaf291 100644 (file)
@@ -289,9 +289,7 @@ void do_rt_sigreturn(struct pt_regs *regs)
        struct rt_signal_frame __user *sf;
        unsigned long tpc, tnpc, tstate;
        __siginfo_fpu_t __user *fpu_save;
-       mm_segment_t old_fs;
        sigset_t set;
-       stack_t st;
        int err;
 
        /* Always make any pending restarted system calls return -EINTR */
@@ -327,20 +325,13 @@ void do_rt_sigreturn(struct pt_regs *regs)
                err |= restore_fpu_state(regs, &sf->fpu_state);
 
        err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
-       err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t));
-       
+       err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf);
+
        if (err)
                goto segv;
-               
+
        regs->tpc = tpc;
        regs->tnpc = tnpc;
-       
-       /* It is more difficult to avoid calling this function than to
-          call it and ignore errors.  */
-       old_fs = get_fs();
-       set_fs(KERNEL_DS);
-       do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf);
-       set_fs(old_fs);
 
        sigdelsetmask(&set, ~_BLOCKABLE);
        spin_lock_irq(&current->sighand->siglock);
index 49569b44ea1fc7ef323ef95adf8c8c561feed1de..8d3cc4fdb557018740e1f38076ef6a09b9a2f265 100644 (file)
@@ -201,10 +201,11 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
 static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
                                      struct device *parent)
 {
-       const char *type, *compat;
+       const char *type, *compat, *bus_id_name;
        struct device_node *dp;
        struct vio_dev *vdev;
        int err, tlen, clen;
+       const u64 *id;
 
        type = mdesc_get_property(hp, mp, "device-type", &tlen);
        if (!type) {
@@ -220,6 +221,16 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
                return NULL;
        }
 
+       bus_id_name = type;
+       if (!strcmp(type, "domain-services-port"))
+               bus_id_name = "ds";
+
+       if (strlen(bus_id_name) >= KOBJ_NAME_LEN - 4) {
+               printk(KERN_ERR "VIO: bus_id_name [%s] is too long.\n",
+                      bus_id_name);
+               return NULL;
+       }
+
        compat = mdesc_get_property(hp, mp, "device-type", &clen);
        if (!compat) {
                clen = 0;
@@ -249,7 +260,14 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
 
        vio_fill_channel_info(hp, mp, vdev);
 
-       snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%lx", mp);
+       id = mdesc_get_property(hp, mp, "id", NULL);
+       if (!id)
+               snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s",
+                        bus_id_name);
+       else
+               snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu",
+                        bus_id_name, *id);
+
        vdev->dev.parent = parent;
        vdev->dev.bus = &vio_bus_type;
        vdev->dev.release = vio_dev_release;
@@ -269,6 +287,8 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
        }
        vdev->dp = dp;
 
+       printk(KERN_ERR "VIO: Adding device %s\n", vdev->dev.bus_id);
+
        err = device_register(&vdev->dev);
        if (err) {
                printk(KERN_ERR "VIO: Could not register device %s, err=%d\n",
@@ -283,46 +303,46 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
        return vdev;
 }
 
-static void walk_tree(struct mdesc_handle *hp, u64 n, struct vio_dev *parent)
+static void vio_add(struct mdesc_handle *hp, u64 node)
 {
-       u64 a;
-
-       mdesc_for_each_arc(a, hp, n, MDESC_ARC_TYPE_FWD) {
-               struct vio_dev *vdev;
-               u64 target;
-
-               target = mdesc_arc_target(hp, a);
-               vdev = vio_create_one(hp, target, &parent->dev);
-               if (vdev)
-                       walk_tree(hp, target, vdev);
-       }
+       (void) vio_create_one(hp, node, &root_vdev->dev);
 }
 
-static void create_devices(struct mdesc_handle *hp, u64 root)
+static int vio_md_node_match(struct device *dev, void *arg)
 {
-       u64 mp;
+       struct vio_dev *vdev = to_vio_dev(dev);
 
-       root_vdev = vio_create_one(hp, root, NULL);
-       if (!root_vdev) {
-               printk(KERN_ERR "VIO: Coult not create root device.\n");
-               return;
-       }
+       if (vdev->mp == (u64) arg)
+               return 1;
 
-       walk_tree(hp, root, root_vdev);
+       return 0;
+}
+
+static void vio_remove(struct mdesc_handle *hp, u64 node)
+{
+       struct device *dev;
 
-       /* Domain services is odd as it doesn't sit underneath the
-        * channel-devices node, so we plug it in manually.
-        */
-       mp = mdesc_node_by_name(hp, MDESC_NODE_NULL, "domain-services");
-       if (mp != MDESC_NODE_NULL) {
-               struct vio_dev *parent = vio_create_one(hp, mp,
-                                                       &root_vdev->dev);
+       dev = device_find_child(&root_vdev->dev, (void *) node,
+                               vio_md_node_match);
+       if (dev) {
+               printk(KERN_INFO "VIO: Removing device %s\n", dev->bus_id);
 
-               if (parent)
-                       walk_tree(hp, mp, parent);
+               device_unregister(dev);
        }
 }
 
+static struct mdesc_notifier_client vio_device_notifier = {
+       .add            = vio_add,
+       .remove         = vio_remove,
+       .node_name      = "virtual-device-port",
+};
+
+static struct mdesc_notifier_client vio_ds_notifier = {
+       .add            = vio_add,
+       .remove         = vio_remove,
+       .node_name      = "domain-services-port",
+};
+
 const char *channel_devices_node = "channel-devices";
 const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
 const char *cfg_handle_prop = "cfg-handle";
@@ -381,11 +401,19 @@ static int __init vio_init(void)
 
        cdev_cfg_handle = *cfg_handle;
 
-       create_devices(hp, root);
+       root_vdev = vio_create_one(hp, root, NULL);
+       err = -ENODEV;
+       if (!root_vdev) {
+               printk(KERN_ERR "VIO: Coult not create root device.\n");
+               goto out_release;
+       }
+
+       mdesc_register_notifier(&vio_device_notifier);
+       mdesc_register_notifier(&vio_ds_notifier);
 
        mdesc_release(hp);
 
-       return 0;
+       return err;
 
 out_release:
        mdesc_release(hp);
index 15613add45d1c429d93a25e64490baddce5d4bf6..09126fc338ba70ef28774af051146bebe5f1fa46 100644 (file)
@@ -78,6 +78,24 @@ static int start_handshake(struct vio_driver_state *vio)
        return 0;
 }
 
+static void flush_rx_dring(struct vio_driver_state *vio)
+{
+       struct vio_dring_state *dr;
+       u64 ident;
+
+       BUG_ON(!(vio->dr_state & VIO_DR_STATE_RXREG));
+
+       dr = &vio->drings[VIO_DRIVER_RX_RING];
+       ident = dr->ident;
+
+       BUG_ON(!vio->desc_buf);
+       kfree(vio->desc_buf);
+       vio->desc_buf = NULL;
+
+       memset(dr, 0, sizeof(*dr));
+       dr->ident = ident;
+}
+
 void vio_link_state_change(struct vio_driver_state *vio, int event)
 {
        if (event == LDC_EVENT_UP) {
@@ -98,6 +116,16 @@ void vio_link_state_change(struct vio_driver_state *vio, int event)
                        break;
                }
                start_handshake(vio);
+       } else if (event == LDC_EVENT_RESET) {
+               vio->hs_state = VIO_HS_INVALID;
+
+               if (vio->dr_state & VIO_DR_STATE_RXREG)
+                       flush_rx_dring(vio);
+
+               vio->dr_state = 0x00;
+               memset(&vio->ver, 0, sizeof(vio->ver));
+
+               ldc_disconnect(vio->lp);
        }
 }
 EXPORT_SYMBOL(vio_link_state_change);
@@ -396,6 +424,8 @@ static int process_dreg_info(struct vio_driver_state *vio,
        if (vio->dr_state & VIO_DR_STATE_RXREG)
                goto send_nack;
 
+       BUG_ON(vio->desc_buf);
+
        vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC);
        if (!vio->desc_buf)
                goto send_nack;
index 483aa15222a4b71976c29358f0fb61ee6a90e65a..1316456e2a2854237ec715e0b2625d5da81c21b4 100644 (file)
@@ -53,7 +53,7 @@ static int pcap_open(void *data)
                        return -EIO;
                }
 
-               pri->compiled = um_kmalloc(sizeof(struct bpf_program));
+               pri->compiled = kmalloc(sizeof(struct bpf_program), UM_GFP_KERNEL);
                if(pri->compiled == NULL){
                        printk(UM_KERN_ERR "pcap_open : kmalloc failed\n");
                        return -ENOMEM;
index 782dea8194384e2f4024400d937a5649102af91d..3f66e970d86fc692f4a4d1b205e87de279d76351 100644 (file)
@@ -719,4 +719,5 @@ ia32_sys_call_table:
        .quad compat_sys_signalfd
        .quad compat_sys_timerfd
        .quad sys_eventfd
+       .quad sys32_fallocate
 ia32_syscall_end:
index 99a78a3cce7c34ab69a8b781c3a0e88522a36bc4..bee96d6144326fa553019cbbc86998d898f52491 100644 (file)
@@ -879,3 +879,11 @@ asmlinkage long sys32_fadvise64(int fd, unsigned offset_lo, unsigned offset_hi,
        return sys_fadvise64_64(fd, ((u64)offset_hi << 32) | offset_lo,
                                len, advice);
 }
+
+asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_lo,
+                               unsigned offset_hi, unsigned len_lo,
+                               unsigned len_hi)
+{
+       return sys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo,
+                            ((u64)len_hi << 32) | len_lo);
+}
index 296d2b0c5d886cf8e79e990cda8baca95604df68..fd9aff3f389011d1a1e3c2cf7a4674325624005d 100644 (file)
@@ -6,6 +6,7 @@
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/fcntl.h>
+#include <xen/hvc-console.h>
 
 /* Simple VGA output */
 
@@ -242,6 +243,10 @@ static int __init setup_early_printk(char *buf)
                simnow_init(buf + 6);
                early_console = &simnow_console;
                keep_early = 1;
+#ifdef CONFIG_HVC_XEN
+       } else if (!strncmp(buf, "xen", 3)) {
+               early_console = &xenboot_console;
+#endif
        }
 
        if (keep_early)
index aa1d1599179433b1e116cd834dfebebe2ab3c67f..f3fb8174559e43000a0a1defa029e5026c8469d7 100644 (file)
@@ -174,7 +174,7 @@ static void do_mce_trigger(void)
        if (events != atomic_read(&mce_logged) && trigger[0]) {
                /* Small race window, but should be harmless.  */
                atomic_set(&mce_logged, events);
-               call_usermodehelper(trigger, trigger_argv, NULL, -1);
+               call_usermodehelper(trigger, trigger_argv, NULL, UMH_NO_WAIT);
        }
 }
 
index fa6775ef729f4a076f7a19341d48f50dd2248fe7..e83cc67155ac253cbbec207b8ef246bc55f0a408 100644 (file)
@@ -102,16 +102,25 @@ unsigned long convert_rip_to_linear(struct task_struct *child, struct pt_regs *r
                u32 *desc;
                unsigned long base;
 
-               down(&child->mm->context.sem);
-               desc = child->mm->context.ldt + (seg & ~7);
-               base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000);
+               seg &= ~7UL;
 
-               /* 16-bit code segment? */
-               if (!((desc[1] >> 22) & 1))
-                       addr &= 0xffff;
-               addr += base;
+               down(&child->mm->context.sem);
+               if (unlikely((seg >> 3) >= child->mm->context.size))
+                       addr = -1L; /* bogus selector, access would fault */
+               else {
+                       desc = child->mm->context.ldt + seg;
+                       base = ((desc[0] >> 16) |
+                               ((desc[1] & 0xff) << 16) |
+                               (desc[1] & 0xff000000));
+
+                       /* 16-bit code segment? */
+                       if (!((desc[1] >> 22) & 1))
+                               addr &= 0xffff;
+                       addr += base;
+               }
                up(&child->mm->context.sem);
        }
+
        return addr;
 }
 
index 2ff46859162516f99412d450034d9f2614621edd..0694940b2e730b3160ade5d6046ec349ad3c351a 100644 (file)
@@ -357,7 +357,7 @@ __smp_call_function_single(int cpu, void (*func) (void *info), void *info,
 }
 
 /*
- * smp_call_function_single - Run a function on another CPU
+ * smp_call_function_single - Run a function on a specific CPU
  * @func: The function to run. This must be fast and non-blocking.
  * @info: An arbitrary pointer to pass to the function.
  * @nonatomic: Currently unused.
@@ -374,14 +374,18 @@ int smp_call_function_single (int cpu, void (*func) (void *info), void *info,
 {
        /* prevent preemption and reschedule on another processor */
        int me = get_cpu();
+
+       /* Can deadlock when called with interrupts disabled */
+       WARN_ON(irqs_disabled());
+
        if (cpu == me) {
+               local_irq_disable();
+               func(info);
+               local_irq_enable();
                put_cpu();
                return 0;
        }
 
-       /* Can deadlock when called with interrupts disabled */
-       WARN_ON(irqs_disabled());
-
        spin_lock_bh(&call_lock);
        __smp_call_function_single(cpu, func, info, nonatomic, wait);
        spin_unlock_bh(&call_lock);
index 6597b60e8e69a58e71e3c8d997dc8c8d6e7af8a9..0768741d681364d1ee71bbd82ace768b31271d9d 100644 (file)
@@ -52,11 +52,16 @@ config LSF
 endif # BLOCK
 
 config BLK_DEV_BSG
-       bool "Block layer SG support"
+       bool "Block layer SG support v4 (EXPERIMENTAL)"
        depends on (SCSI=y) && EXPERIMENTAL
-       default y
        ---help---
-       Saying Y here will enable generic SG (SCSI generic) v4
-       support for any block device.
+       Saying Y here will enable generic SG (SCSI generic) v4 support
+       for any block device.
+
+       Unlike SG v3 (aka block/scsi_ioctl.c drivers/scsi/sg.c), SG v4
+       can handle complicated SCSI commands: tagged variable length cdbs
+       with bidirectional data transfers and generic request/response
+       protocols (e.g. Task Management Functions and SMP in Serial
+       Attached SCSI).
 
 source block/Kconfig.iosched
index 576933fe1860ff1c07d4603ecad5a0726447f830..baa04e7adf197331c34d4b0b46f8956f92b7b4b9 100644 (file)
@@ -33,7 +33,8 @@
 #include <scsi/scsi_driver.h>
 #include <scsi/sg.h>
 
-static char bsg_version[] = "block layer sg (bsg) 0.4";
+#define BSG_DESCRIPTION        "Block layer SCSI generic (bsg) driver"
+#define BSG_VERSION    "0.4"
 
 struct bsg_device {
        request_queue_t *queue;
@@ -68,22 +69,15 @@ enum {
 #define dprintk(fmt, args...)
 #endif
 
-#define list_entry_bc(entry)   list_entry((entry), struct bsg_command, list)
-
-/*
- * just for testing
- */
-#define BSG_MAJOR      (240)
-
 static DEFINE_MUTEX(bsg_mutex);
 static int bsg_device_nr, bsg_minor_idx;
 
-#define BSG_LIST_SIZE  (8)
-#define bsg_list_idx(minor)    ((minor) & (BSG_LIST_SIZE - 1))
-static struct hlist_head bsg_device_list[BSG_LIST_SIZE];
+#define BSG_LIST_ARRAY_SIZE    8
+static struct hlist_head bsg_device_list[BSG_LIST_ARRAY_SIZE];
 
 static struct class *bsg_class;
 static LIST_HEAD(bsg_class_list);
+static int bsg_major;
 
 static struct kmem_cache *bsg_cmd_cachep;
 
@@ -128,7 +122,7 @@ static struct bsg_command *bsg_alloc_command(struct bsg_device *bd)
        bd->queued_cmds++;
        spin_unlock_irq(&bd->lock);
 
-       bc = kmem_cache_alloc(bsg_cmd_cachep, GFP_USER);
+       bc = kmem_cache_zalloc(bsg_cmd_cachep, GFP_KERNEL);
        if (unlikely(!bc)) {
                spin_lock_irq(&bd->lock);
                bd->queued_cmds--;
@@ -136,7 +130,6 @@ static struct bsg_command *bsg_alloc_command(struct bsg_device *bd)
                goto out;
        }
 
-       memset(bc, 0, sizeof(*bc));
        bc->bd = bd;
        INIT_LIST_HEAD(&bc->list);
        dprintk("%s: returning free cmd %p\n", bd->name, bc);
@@ -146,22 +139,12 @@ out:
        return bc;
 }
 
-static inline void
-bsg_del_done_cmd(struct bsg_device *bd, struct bsg_command *bc)
-{
-       bd->done_cmds--;
-       list_del(&bc->list);
-}
-
-static inline void
-bsg_add_done_cmd(struct bsg_device *bd, struct bsg_command *bc)
+static inline struct hlist_head *bsg_dev_idx_hash(int index)
 {
-       bd->done_cmds++;
-       list_add_tail(&bc->list, &bd->done_list);
-       wake_up(&bd->wq_done);
+       return &bsg_device_list[index & (BSG_LIST_ARRAY_SIZE - 1)];
 }
 
-static inline int bsg_io_schedule(struct bsg_device *bd, int state)
+static int bsg_io_schedule(struct bsg_device *bd)
 {
        DEFINE_WAIT(wait);
        int ret = 0;
@@ -186,14 +169,11 @@ static inline int bsg_io_schedule(struct bsg_device *bd, int state)
                goto unlock;
        }
 
-       prepare_to_wait(&bd->wq_done, &wait, state);
+       prepare_to_wait(&bd->wq_done, &wait, TASK_UNINTERRUPTIBLE);
        spin_unlock_irq(&bd->lock);
        io_schedule();
        finish_wait(&bd->wq_done, &wait);
 
-       if ((state == TASK_INTERRUPTIBLE) && signal_pending(current))
-               ret = -ERESTARTSYS;
-
        return ret;
 unlock:
        spin_unlock_irq(&bd->lock);
@@ -272,7 +252,7 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr)
 {
        request_queue_t *q = bd->queue;
        struct request *rq, *next_rq = NULL;
-       int ret, rw = 0; /* shut up gcc */
+       int ret, rw;
        unsigned int dxfer_len;
        void *dxferp = NULL;
 
@@ -354,9 +334,11 @@ static void bsg_rq_end_io(struct request *rq, int uptodate)
        bc->hdr.duration = jiffies_to_msecs(jiffies - bc->hdr.duration);
 
        spin_lock_irqsave(&bd->lock, flags);
-       list_del(&bc->list);
-       bsg_add_done_cmd(bd, bc);
+       list_move_tail(&bc->list, &bd->done_list);
+       bd->done_cmds++;
        spin_unlock_irqrestore(&bd->lock, flags);
+
+       wake_up(&bd->wq_done);
 }
 
 /*
@@ -387,14 +369,15 @@ static void bsg_add_command(struct bsg_device *bd, request_queue_t *q,
        blk_execute_rq_nowait(q, NULL, rq, 1, bsg_rq_end_io);
 }
 
-static inline struct bsg_command *bsg_next_done_cmd(struct bsg_device *bd)
+static struct bsg_command *bsg_next_done_cmd(struct bsg_device *bd)
 {
        struct bsg_command *bc = NULL;
 
        spin_lock_irq(&bd->lock);
        if (bd->done_cmds) {
-               bc = list_entry_bc(bd->done_list.next);
-               bsg_del_done_cmd(bd, bc);
+               bc = list_entry(bd->done_list.next, struct bsg_command, list);
+               list_del(&bc->list);
+               bd->done_cmds--;
        }
        spin_unlock_irq(&bd->lock);
 
@@ -450,8 +433,8 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
        hdr->response_len = 0;
 
        if (rq->sense_len && hdr->response) {
-               int len = min((unsigned int) hdr->max_response_len,
-                             rq->sense_len);
+               int len = min_t(unsigned int, hdr->max_response_len,
+                                       rq->sense_len);
 
                ret = copy_to_user((void*)(unsigned long)hdr->response,
                                   rq->sense, len);
@@ -486,7 +469,7 @@ static int bsg_complete_all_commands(struct bsg_device *bd)
         */
        ret = 0;
        do {
-               ret = bsg_io_schedule(bd, TASK_UNINTERRUPTIBLE);
+               ret = bsg_io_schedule(bd);
                /*
                 * look for -ENODATA specifically -- we'll sometimes get
                 * -ERESTARTSYS when we've taken a signal, but we can't
@@ -523,7 +506,7 @@ static int bsg_complete_all_commands(struct bsg_device *bd)
        return ret;
 }
 
-static ssize_t
+static int
 __bsg_read(char __user *buf, size_t count, struct bsg_device *bd,
           const struct iovec *iov, ssize_t *bytes_read)
 {
@@ -550,7 +533,7 @@ __bsg_read(char __user *buf, size_t count, struct bsg_device *bd,
                ret = blk_complete_sgv4_hdr_rq(bc->rq, &bc->hdr, bc->bio,
                                               bc->bidi_bio);
 
-               if (copy_to_user(buf, (char *) &bc->hdr, sizeof(bc->hdr)))
+               if (copy_to_user(buf, &bc->hdr, sizeof(bc->hdr)))
                        ret = -EFAULT;
 
                bsg_free_command(bc);
@@ -582,6 +565,9 @@ static inline void bsg_set_write_perm(struct bsg_device *bd, struct file *file)
                clear_bit(BSG_F_WRITE_PERM, &bd->flags);
 }
 
+/*
+ * Check if the error is a "real" error that we should return.
+ */
 static inline int err_block_err(int ret)
 {
        if (ret && ret != -ENOSPC && ret != -ENODATA && ret != -EAGAIN)
@@ -610,8 +596,8 @@ bsg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
        return bytes_read;
 }
 
-static ssize_t __bsg_write(struct bsg_device *bd, const char __user *buf,
-                          size_t count, ssize_t *bytes_read)
+static int __bsg_write(struct bsg_device *bd, const char __user *buf,
+                      size_t count, ssize_t *bytes_written)
 {
        struct bsg_command *bc;
        struct request *rq;
@@ -655,7 +641,7 @@ static ssize_t __bsg_write(struct bsg_device *bd, const char __user *buf,
                rq = NULL;
                nr_commands--;
                buf += sizeof(struct sg_io_v4);
-               *bytes_read += sizeof(struct sg_io_v4);
+               *bytes_written += sizeof(struct sg_io_v4);
        }
 
        if (bc)
@@ -668,7 +654,7 @@ static ssize_t
 bsg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
 {
        struct bsg_device *bd = file->private_data;
-       ssize_t bytes_read;
+       ssize_t bytes_written;
        int ret;
 
        dprintk("%s: write %Zd bytes\n", bd->name, count);
@@ -676,18 +662,18 @@ bsg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
        bsg_set_block(bd, file);
        bsg_set_write_perm(bd, file);
 
-       bytes_read = 0;
-       ret = __bsg_write(bd, buf, count, &bytes_read);
-       *ppos = bytes_read;
+       bytes_written = 0;
+       ret = __bsg_write(bd, buf, count, &bytes_written);
+       *ppos = bytes_written;
 
        /*
         * return bytes written on non-fatal errors
         */
-       if (!bytes_read || (bytes_read && err_block_err(ret)))
-               bytes_read = ret;
+       if (!bytes_written || (bytes_written && err_block_err(ret)))
+               bytes_written = ret;
 
-       dprintk("%s: returning %Zd\n", bd->name, bytes_read);
-       return bytes_read;
+       dprintk("%s: returning %Zd\n", bd->name, bytes_written);
+       return bytes_written;
 }
 
 static struct bsg_device *bsg_alloc_device(void)
@@ -746,7 +732,7 @@ static struct bsg_device *bsg_add_device(struct inode *inode,
                                         struct request_queue *rq,
                                         struct file *file)
 {
-       struct bsg_device *bd = NULL;
+       struct bsg_device *bd;
 #ifdef BSG_DEBUG
        unsigned char buf[32];
 #endif
@@ -762,7 +748,7 @@ static struct bsg_device *bsg_add_device(struct inode *inode,
        atomic_set(&bd->ref_count, 1);
        bd->minor = iminor(inode);
        mutex_lock(&bsg_mutex);
-       hlist_add_head(&bd->dev_list, &bsg_device_list[bsg_list_idx(bd->minor)]);
+       hlist_add_head(&bd->dev_list, bsg_dev_idx_hash(bd->minor));
 
        strncpy(bd->name, rq->bsg_dev.class_dev->class_id, sizeof(bd->name) - 1);
        dprintk("bound to <%s>, max queue %d\n",
@@ -774,13 +760,12 @@ static struct bsg_device *bsg_add_device(struct inode *inode,
 
 static struct bsg_device *__bsg_get_device(int minor)
 {
-       struct hlist_head *list = &bsg_device_list[bsg_list_idx(minor)];
        struct bsg_device *bd = NULL;
        struct hlist_node *entry;
 
        mutex_lock(&bsg_mutex);
 
-       hlist_for_each(entry, list) {
+       hlist_for_each(entry, bsg_dev_idx_hash(minor)) {
                bd = hlist_entry(entry, struct bsg_device, dev_list);
                if (bd->minor == minor) {
                        atomic_inc(&bd->ref_count);
@@ -858,16 +843,11 @@ static unsigned int bsg_poll(struct file *file, poll_table *wait)
        return mask;
 }
 
-static int
-bsg_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-         unsigned long arg)
+static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct bsg_device *bd = file->private_data;
        int __user *uarg = (int __user *) arg;
 
-       if (!bd)
-               return -ENXIO;
-
        switch (cmd) {
                /*
                 * our own ioctls
@@ -944,7 +924,7 @@ static struct file_operations bsg_fops = {
        .poll           =       bsg_poll,
        .open           =       bsg_open,
        .release        =       bsg_release,
-       .ioctl          =       bsg_ioctl,
+       .unlocked_ioctl =       bsg_ioctl,
        .owner          =       THIS_MODULE,
 };
 
@@ -952,12 +932,11 @@ void bsg_unregister_queue(struct request_queue *q)
 {
        struct bsg_class_device *bcd = &q->bsg_dev;
 
-       if (!bcd->class_dev)
-               return;
+       WARN_ON(!bcd->class_dev);
 
        mutex_lock(&bsg_mutex);
        sysfs_remove_link(&q->kobj, "bsg");
-       class_device_destroy(bsg_class, MKDEV(BSG_MAJOR, bcd->minor));
+       class_device_destroy(bsg_class, MKDEV(bsg_major, bcd->minor));
        bcd->class_dev = NULL;
        list_del_init(&bcd->list);
        bsg_device_nr--;
@@ -1003,7 +982,7 @@ retry:
                bsg_minor_idx = 0;
 
        bcd->queue = q;
-       dev = MKDEV(BSG_MAJOR, bcd->minor);
+       dev = MKDEV(bsg_major, bcd->minor);
        class_dev = class_device_create(bsg_class, NULL, dev, bcd->dev, "%s", name);
        if (IS_ERR(class_dev)) {
                ret = PTR_ERR(class_dev);
@@ -1024,7 +1003,7 @@ retry:
        return 0;
 err:
        if (class_dev)
-               class_device_destroy(bsg_class, MKDEV(BSG_MAJOR, bcd->minor));
+               class_device_destroy(bsg_class, MKDEV(bsg_major, bcd->minor));
        mutex_unlock(&bsg_mutex);
        return ret;
 }
@@ -1061,6 +1040,7 @@ static struct cdev bsg_cdev = {
 static int __init bsg_init(void)
 {
        int ret, i;
+       dev_t devid;
 
        bsg_cmd_cachep = kmem_cache_create("bsg_cmd",
                                sizeof(struct bsg_command), 0, 0, NULL, NULL);
@@ -1069,46 +1049,47 @@ static int __init bsg_init(void)
                return -ENOMEM;
        }
 
-       for (i = 0; i < BSG_LIST_SIZE; i++)
+       for (i = 0; i < BSG_LIST_ARRAY_SIZE; i++)
                INIT_HLIST_HEAD(&bsg_device_list[i]);
 
        bsg_class = class_create(THIS_MODULE, "bsg");
        if (IS_ERR(bsg_class)) {
-               kmem_cache_destroy(bsg_cmd_cachep);
-               return PTR_ERR(bsg_class);
+               ret = PTR_ERR(bsg_class);
+               goto destroy_kmemcache;
        }
 
-       ret = register_chrdev_region(MKDEV(BSG_MAJOR, 0), BSG_MAX_DEVS, "bsg");
-       if (ret) {
-               kmem_cache_destroy(bsg_cmd_cachep);
-               class_destroy(bsg_class);
-               return ret;
-       }
+       ret = alloc_chrdev_region(&devid, 0, BSG_MAX_DEVS, "bsg");
+       if (ret)
+               goto destroy_bsg_class;
+
+       bsg_major = MAJOR(devid);
 
        cdev_init(&bsg_cdev, &bsg_fops);
-       ret = cdev_add(&bsg_cdev, MKDEV(BSG_MAJOR, 0), BSG_MAX_DEVS);
-       if (ret) {
-               kmem_cache_destroy(bsg_cmd_cachep);
-               class_destroy(bsg_class);
-               unregister_chrdev_region(MKDEV(BSG_MAJOR, 0), BSG_MAX_DEVS);
-               return ret;
-       }
+       ret = cdev_add(&bsg_cdev, MKDEV(bsg_major, 0), BSG_MAX_DEVS);
+       if (ret)
+               goto unregister_chrdev;
 
        ret = scsi_register_interface(&bsg_intf);
-       if (ret) {
-               printk(KERN_ERR "bsg: failed register scsi interface %d\n", ret);
-               kmem_cache_destroy(bsg_cmd_cachep);
-               class_destroy(bsg_class);
-               unregister_chrdev(BSG_MAJOR, "bsg");
-               return ret;
-       }
+       if (ret)
+               goto remove_cdev;
 
-       printk(KERN_INFO "%s loaded\n", bsg_version);
+       printk(KERN_INFO BSG_DESCRIPTION " version " BSG_VERSION
+              " loaded (major %d)\n", bsg_major);
        return 0;
+remove_cdev:
+       printk(KERN_ERR "bsg: failed register scsi interface %d\n", ret);
+       cdev_del(&bsg_cdev);
+unregister_chrdev:
+       unregister_chrdev_region(MKDEV(bsg_major, 0), BSG_MAX_DEVS);
+destroy_bsg_class:
+       class_destroy(bsg_class);
+destroy_kmemcache:
+       kmem_cache_destroy(bsg_cmd_cachep);
+       return ret;
 }
 
 MODULE_AUTHOR("Jens Axboe");
-MODULE_DESCRIPTION("Block layer SGSI generic (sg) driver");
+MODULE_DESCRIPTION(BSG_DESCRIPTION);
 MODULE_LICENSE("GPL");
 
 device_initcall(bsg_init);
index 503d82569449f2e8eeb9884cd0ddd46919dd5a83..6d9d7fab77f5bd0f0815eaf8cf9da06a1451c9f8 100644 (file)
@@ -15,6 +15,8 @@ obj-$(CONFIG_ACPI)            += acpi/
 obj-$(CONFIG_PNP)              += pnp/
 obj-$(CONFIG_ARM_AMBA)         += amba/
 
+obj-$(CONFIG_XEN)              += xen/
+
 # char/ comes before serial/ etc so that the VT console is the boot-time
 # default.
 obj-y                          += char/
index 88a6fc7fd271e54dd63d1fabd537878276bf3a21..58f1338981bca1d93ec525eb6a26a8532a392bbc 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/jiffies.h>
 #include <linux/kmod.h>
 #include <linux/seq_file.h>
+#include <linux/reboot.h>
 #include <asm/uaccess.h>
 
 #include <acpi/acpi_bus.h>
@@ -59,7 +60,6 @@
 #define ACPI_THERMAL_NOTIFY_CRITICAL   0xF0
 #define ACPI_THERMAL_NOTIFY_HOT                0xF1
 #define ACPI_THERMAL_MODE_ACTIVE       0x00
-#define ACPI_THERMAL_PATH_POWEROFF     "/sbin/poweroff"
 
 #define ACPI_THERMAL_MAX_ACTIVE        10
 #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
@@ -419,26 +419,6 @@ static int acpi_thermal_get_devices(struct acpi_thermal *tz)
        return 0;
 }
 
-static int acpi_thermal_call_usermode(char *path)
-{
-       char *argv[2] = { NULL, NULL };
-       char *envp[3] = { NULL, NULL, NULL };
-
-
-       if (!path)
-               return -EINVAL;
-
-       argv[0] = path;
-
-       /* minimal command environment */
-       envp[0] = "HOME=/";
-       envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-
-       call_usermodehelper(argv[0], argv, envp, 0);
-
-       return 0;
-}
-
 static int acpi_thermal_critical(struct acpi_thermal *tz)
 {
        if (!tz || !tz->trips.critical.flags.valid)
@@ -456,7 +436,7 @@ static int acpi_thermal_critical(struct acpi_thermal *tz)
        acpi_bus_generate_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
                                tz->trips.critical.flags.enabled);
 
-       acpi_thermal_call_usermode(ACPI_THERMAL_PATH_POWEROFF);
+       orderly_poweroff(true);
 
        return 0;
 }
index 5d576435fcccddd5fe0498c57c90c058e436de65..fb8a749423ca6634f3f8dff199db09841a24d497 100644 (file)
@@ -2666,7 +2666,7 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        mv_print_info(host);
 
        pci_set_master(pdev);
-       pci_set_mwi(pdev);
+       pci_try_set_mwi(pdev);
        return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
                                 IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht);
 }
index bb4ae6281491a88186b1bae5ac905475004626ad..bed9f58c2d5a78805f663a18ce58e46fbc92e72f 100644 (file)
@@ -172,7 +172,7 @@ config ATM_ZATM_DEBUG
 
 config ATM_NICSTAR
        tristate "IDT 77201 (NICStAR) (ForeRunnerLE)"
-       depends on PCI && !64BIT
+       depends on PCI && !64BIT && VIRT_TO_BUS
        help
          The NICStAR chipset family is used in a large number of ATM NICs for
          25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE
index 59651abfa4f8b683bc82d33fb7077224ee3256e2..b34b3829f6a9a1fa5a37fe4df0dd607dd3e76c13 100644 (file)
@@ -1040,7 +1040,7 @@ static int amb_open (struct atm_vcc * atm_vcc)
   struct atm_qos * qos;
   struct atm_trafprm * txtp;
   struct atm_trafprm * rxtp;
-  u16 tx_rate_bits;
+  u16 tx_rate_bits = -1; // hush gcc
   u16 tx_vc_bits = -1; // hush gcc
   u16 tx_frame_bits = -1; // hush gcc
   
@@ -1096,6 +1096,8 @@ static int amb_open (struct atm_vcc * atm_vcc)
            r = round_up;
          }
          error = make_rate (pcr, r, &tx_rate_bits, NULL);
+         if (error)
+           return error;
          tx_vc_bits = TX_UBR_CAPPED;
          tx_frame_bits = TX_FRAME_CAPPED;
        }
index 77637e780d4150eee9713b7117e0fd0adcdb1573..41b2204ebc6e1341dbc4b12d256309e0a33c3f18 100644 (file)
@@ -1738,7 +1738,8 @@ static int __devinit eni_do_init(struct atm_dev *dev)
                        printk(KERN_ERR KERN_ERR DEV_LABEL "(itf %d): bad "
                            "magic - expected 0x%x, got 0x%x\n",dev->number,
                            ENI155_MAGIC,(unsigned) readl(&eprom->magic));
-                       return -EINVAL;
+                       error = -EINVAL;
+                       goto unmap;
                }
        }
        eni_dev->phy = base+PHY_BASE;
@@ -1765,17 +1766,27 @@ static int __devinit eni_do_init(struct atm_dev *dev)
                printk(")\n");
                printk(KERN_ERR DEV_LABEL "(itf %d): ERROR - wrong id 0x%x\n",
                    dev->number,(unsigned) eni_in(MID_RES_ID_MCON));
-               return -EINVAL;
+               error = -EINVAL;
+               goto unmap;
        }
        error = eni_dev->asic ? get_esi_asic(dev) : get_esi_fpga(dev,base);
-       if (error) return error;
+       if (error)
+               goto unmap;
        for (i = 0; i < ESI_LEN; i++)
                printk("%s%02X",i ? "-" : "",dev->esi[i]);
        printk(")\n");
        printk(KERN_NOTICE DEV_LABEL "(itf %d): %s,%s\n",dev->number,
            eni_in(MID_RES_ID_MCON) & 0x200 ? "ASIC" : "FPGA",
            media_name[eni_in(MID_RES_ID_MCON) & DAUGTHER_ID]);
-       return suni_init(dev);
+
+       error = suni_init(dev);
+       if (error)
+               goto unmap;
+out:
+       return error;
+unmap:
+       iounmap(base);
+       goto out;
 }
 
 
index 38b688f9f6a98166fef19efbbd81543b3e06005c..737cea49f8721b57e766650365b4221d8efc2af8 100644 (file)
@@ -1710,7 +1710,7 @@ static int __devinit fs_init (struct fs_dev *dev)
                /* This bit is documented as "RESERVED" */
                if (isr & ISR_INIT_ERR) {
                        printk (KERN_ERR "Error initializing the FS... \n");
-                       return 1;
+                       goto unmap;
                }
                if (isr & ISR_INIT) {
                        fs_dprintk (FS_DEBUG_INIT, "Ha! Initialized OK!\n");
@@ -1723,7 +1723,7 @@ static int __devinit fs_init (struct fs_dev *dev)
 
        if (!to) {
                printk (KERN_ERR "timeout initializing the FS... \n");
-               return 1;
+               goto unmap;
        }
 
        /* XXX fix for fs155 */
@@ -1803,7 +1803,7 @@ static int __devinit fs_init (struct fs_dev *dev)
        if (!dev->atm_vccs) {
                printk (KERN_WARNING "Couldn't allocate memory for VCC buffers. Woops!\n");
                /* XXX Clean up..... */
-               return 1;
+               goto unmap;
        }
 
        dev->tx_inuse = kzalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL);
@@ -1813,7 +1813,7 @@ static int __devinit fs_init (struct fs_dev *dev)
        if (!dev->tx_inuse) {
                printk (KERN_WARNING "Couldn't allocate memory for tx_inuse bits!\n");
                /* XXX Clean up..... */
-               return 1;
+               goto unmap;
        }
        /* -- RAS1 : FS155 and 50 differ. Default (0) should be OK for both */
        /* -- RAS2 : FS50 only: Default is OK. */
@@ -1840,7 +1840,7 @@ static int __devinit fs_init (struct fs_dev *dev)
        if (request_irq (dev->irq, fs_irq, IRQF_SHARED, "firestream", dev)) {
                printk (KERN_WARNING "couldn't get irq %d for firestream.\n", pci_dev->irq);
                /* XXX undo all previous stuff... */
-               return 1;
+               goto unmap;
        }
        fs_dprintk (FS_DEBUG_INIT, "Grabbed irq %d for dev at %p.\n", dev->irq, dev);
   
@@ -1890,6 +1890,9 @@ static int __devinit fs_init (struct fs_dev *dev)
   
        func_exit ();
        return 0;
+unmap:
+       iounmap(dev->base);
+       return 1;
 }
 
 static int __devinit firestream_init_one (struct pci_dev *pci_dev,
@@ -2012,6 +2015,7 @@ static void __devexit firestream_remove_one (struct pci_dev *pdev)
                for (i=0;i < FS_NR_RX_QUEUES;i++)
                        free_queue (dev, &dev->rx_rq[i]);
 
+               iounmap(dev->base);
                fs_dprintk (FS_DEBUG_ALLOC, "Free fs-dev: %p\n", dev);
                nxtdev = dev->next;
                kfree (dev);
index 8f995ce8d73b460a7fb88e25d70d05298477a483..f8b1700f4c16df01d40401d83df1df811dd10889 100644 (file)
@@ -65,7 +65,7 @@ static char const rcsid[] =
 static unsigned int vpibits = 1;
 
 
-#define CONFIG_ATM_IDT77252_SEND_IDLE 1
+#define ATM_IDT77252_SEND_IDLE 1
 
 
 /*
@@ -3404,7 +3404,7 @@ init_card(struct atm_dev *dev)
        conf =  SAR_CFG_TX_FIFO_SIZE_9 |        /* Use maximum fifo size */
                SAR_CFG_RXSTQ_SIZE_8k |         /* Receive Status Queue is 8k */
                SAR_CFG_IDLE_CLP |              /* Set CLP on idle cells */
-#ifndef CONFIG_ATM_IDT77252_SEND_IDLE
+#ifndef ATM_IDT77252_SEND_IDLE
                SAR_CFG_NO_IDLE |               /* Do not send idle cells */
 #endif
                0;
@@ -3541,7 +3541,7 @@ init_card(struct atm_dev *dev)
        printk("%s: Linkrate on ATM line : %u bit/s, %u cell/s.\n",
               card->name, linkrate, card->link_pcr);
 
-#ifdef CONFIG_ATM_IDT77252_SEND_IDLE
+#ifdef ATM_IDT77252_SEND_IDLE
        card->utopia_pcr = card->link_pcr;
 #else
        card->utopia_pcr = (160000000 / 8 / 54);
index 0e2c1ae650e7f9b4cfeb15342bd9a26ea9bfbf1d..55fd1b4543fdc5e034e8c358fc05967259f339b4 100644 (file)
@@ -552,8 +552,8 @@ static inline void sram_write(const struct lanai_dev *lanai,
        writel(val, sram_addr(lanai, offset));
 }
 
-static int __init sram_test_word(
-       const struct lanai_dev *lanai, int offset, u32 pattern)
+static int __devinit sram_test_word(const struct lanai_dev *lanai,
+                                   int offset, u32 pattern)
 {
        u32 readback;
        sram_write(lanai, pattern, offset);
index 480947f4e01e8ded8b84f243e065dcf40c423524..842e26c45557f850d4f3d0280f353eae4adb71e6 100644 (file)
@@ -134,7 +134,7 @@ nicstar_read_eprom_status( virt_addr_t base )
    /* Send read instruction */
    val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0;
 
-   for (i=0; i<sizeof rdsrtab/sizeof rdsrtab[0]; i++)
+   for (i=0; i<ARRAY_SIZE(rdsrtab); i++)
    {
        NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
                (val | rdsrtab[i]) );
index 020a87a476c813945d1f1f1ffc55c398704dc502..58583c6ac5be556f1297ae0353e1f5b95dc56d17 100644 (file)
@@ -915,7 +915,7 @@ static int open_tx_first(struct atm_vcc *vcc)
        unsigned long flags;
        u32 *loop;
        unsigned short chan;
-       int pcr,unlimited;
+       int unlimited;
 
        DPRINTK("open_tx_first\n");
        zatm_dev = ZATM_DEV(vcc->dev);
@@ -936,6 +936,8 @@ static int open_tx_first(struct atm_vcc *vcc)
            vcc->qos.txtp.max_pcr >= ATM_OC3_PCR);
        if (unlimited && zatm_dev->ubr != -1) zatm_vcc->shaper = zatm_dev->ubr;
        else {
+               int uninitialized_var(pcr);
+
                if (unlimited) vcc->qos.txtp.max_sdu = ATM_MAX_AAL5_PDU;
                if ((zatm_vcc->shaper = alloc_shaper(vcc->dev,&pcr,
                    vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,unlimited))
index 8f65b88cf7113bdcf0c29b67cdabc93c36091fc4..a4a311992408f5eda8ab093bebbca107dd04faea 100644 (file)
@@ -427,4 +427,13 @@ config XILINX_SYSACE
        help
          Include support for the Xilinx SystemACE CompactFlash interface
 
+config XEN_BLKDEV_FRONTEND
+       tristate "Xen virtual block device support"
+       depends on XEN
+       default y
+       help
+         This driver implements the front-end of the Xen virtual
+         block device driver.  It communicates with a back-end driver
+         in another domain which drives the actual block device.
+
 endif # BLK_DEV
index 9ee08ab4ffa8a474465564e8df17a99932a48059..3e31532df0eda9bfa6266ad5db9058d238220b68 100644 (file)
@@ -29,3 +29,4 @@ obj-$(CONFIG_VIODASD)         += viodasd.o
 obj-$(CONFIG_BLK_DEV_SX8)      += sx8.o
 obj-$(CONFIG_BLK_DEV_UB)       += ub.o
 
+obj-$(CONFIG_XEN_BLKDEV_FRONTEND)      += xen-blkfront.o
index 0f5e3caf85d763738f5f30eb6728d909aa315d38..2288b55d916f9e12fc3ea2332acf40c3dfe67dff 100644 (file)
@@ -45,8 +45,6 @@ struct vdc_req_entry {
 struct vdc_port {
        struct vio_driver_state vio;
 
-       struct vdc              *vp;
-
        struct gendisk          *disk;
 
        struct vdc_completion   *cmp;
@@ -72,8 +70,6 @@ struct vdc_port {
 
        struct vio_disk_geom    geom;
        struct vio_disk_vtoc    label;
-
-       struct list_head        list;
 };
 
 static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
@@ -81,15 +77,6 @@ static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
        return container_of(vio, struct vdc_port, vio);
 }
 
-struct vdc {
-       /* Protects prot_list.  */
-       spinlock_t              lock;
-
-       struct vio_dev          *dev;
-
-       struct list_head        port_list;
-};
-
 /* Ordered from largest major to lowest */
 static struct vio_version vdc_versions[] = {
        { .major = 1, .minor = 0 },
@@ -747,21 +734,23 @@ static struct vio_driver_ops vdc_vio_ops = {
        .handshake_complete     = vdc_handshake_complete,
 };
 
+static void print_version(void)
+{
+       static int version_printed;
+
+       if (version_printed++ == 0)
+               printk(KERN_INFO "%s", version);
+}
+
 static int __devinit vdc_port_probe(struct vio_dev *vdev,
                                    const struct vio_device_id *id)
 {
        struct mdesc_handle *hp;
        struct vdc_port *port;
-       unsigned long flags;
-       struct vdc *vp;
        const u64 *port_id;
        int err;
 
-       vp = dev_get_drvdata(vdev->dev.parent);
-       if (!vp) {
-               printk(KERN_ERR PFX "Cannot find port parent vdc.\n");
-               return -ENODEV;
-       }
+       print_version();
 
        hp = mdesc_grab();
 
@@ -783,7 +772,6 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev,
                goto err_out_release_mdesc;
        }
 
-       port->vp = vp;
        port->dev_no = *port_id;
 
        if (port->dev_no >= 26)
@@ -818,12 +806,6 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev,
        if (err)
                goto err_out_free_tx_ring;
 
-       INIT_LIST_HEAD(&port->list);
-
-       spin_lock_irqsave(&vp->lock, flags);
-       list_add(&port->list, &vp->port_list);
-       spin_unlock_irqrestore(&vp->lock, flags);
-
        dev_set_drvdata(&vdev->dev, port);
 
        mdesc_release(hp);
@@ -879,58 +861,6 @@ static struct vio_driver vdc_port_driver = {
        }
 };
 
-static int __devinit vdc_probe(struct vio_dev *vdev,
-                              const struct vio_device_id *id)
-{
-       static int vdc_version_printed;
-       struct vdc *vp;
-
-       if (vdc_version_printed++ == 0)
-               printk(KERN_INFO "%s", version);
-
-       vp = kzalloc(sizeof(struct vdc), GFP_KERNEL);
-       if (!vp)
-               return -ENOMEM;
-
-       spin_lock_init(&vp->lock);
-       vp->dev = vdev;
-       INIT_LIST_HEAD(&vp->port_list);
-
-       dev_set_drvdata(&vdev->dev, vp);
-
-       return 0;
-}
-
-static int vdc_remove(struct vio_dev *vdev)
-{
-
-       struct vdc *vp = dev_get_drvdata(&vdev->dev);
-
-       if (vp) {
-               kfree(vp);
-               dev_set_drvdata(&vdev->dev, NULL);
-       }
-       return 0;
-}
-
-static struct vio_device_id vdc_match[] = {
-       {
-               .type = "block",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(vio, vdc_match);
-
-static struct vio_driver vdc_driver = {
-       .id_table       = vdc_match,
-       .probe          = vdc_probe,
-       .remove         = vdc_remove,
-       .driver         = {
-               .name   = "vdc",
-               .owner  = THIS_MODULE,
-       }
-};
-
 static int __init vdc_init(void)
 {
        int err;
@@ -940,19 +870,13 @@ static int __init vdc_init(void)
                goto out_err;
 
        vdc_major = err;
-       err = vio_register_driver(&vdc_driver);
-       if (err)
-               goto out_unregister_blkdev;
 
        err = vio_register_driver(&vdc_port_driver);
        if (err)
-               goto out_unregister_vdc;
+               goto out_unregister_blkdev;
 
        return 0;
 
-out_unregister_vdc:
-       vio_unregister_driver(&vdc_driver);
-
 out_unregister_blkdev:
        unregister_blkdev(vdc_major, VDCBLK_NAME);
        vdc_major = 0;
@@ -964,7 +888,6 @@ out_err:
 static void __exit vdc_exit(void)
 {
        vio_unregister_driver(&vdc_port_driver);
-       vio_unregister_driver(&vdc_driver);
        unregister_blkdev(vdc_major, VDCBLK_NAME);
 }
 
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
new file mode 100644 (file)
index 0000000..6746c29
--- /dev/null
@@ -0,0 +1,988 @@
+/*
+ * blkfront.c
+ *
+ * XenLinux virtual block device driver.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
+ * Copyright (c) 2004, Christian Limpach
+ * Copyright (c) 2004, Andrew Warfield
+ * Copyright (c) 2005, Christopher Clark
+ * Copyright (c) 2005, XenSource Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/module.h>
+
+#include <xen/xenbus.h>
+#include <xen/grant_table.h>
+#include <xen/events.h>
+#include <xen/page.h>
+
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/blkif.h>
+
+#include <asm/xen/hypervisor.h>
+
+enum blkif_state {
+       BLKIF_STATE_DISCONNECTED,
+       BLKIF_STATE_CONNECTED,
+       BLKIF_STATE_SUSPENDED,
+};
+
+struct blk_shadow {
+       struct blkif_request req;
+       unsigned long request;
+       unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+
+static struct block_device_operations xlvbd_block_fops;
+
+#define BLK_RING_SIZE __RING_SIZE((struct blkif_sring *)0, PAGE_SIZE)
+
+/*
+ * We have one of these per vbd, whether ide, scsi or 'other'.  They
+ * hang in private_data off the gendisk structure. We may end up
+ * putting all kinds of interesting stuff here :-)
+ */
+struct blkfront_info
+{
+       struct xenbus_device *xbdev;
+       dev_t dev;
+       struct gendisk *gd;
+       int vdevice;
+       blkif_vdev_t handle;
+       enum blkif_state connected;
+       int ring_ref;
+       struct blkif_front_ring ring;
+       unsigned int evtchn, irq;
+       struct request_queue *rq;
+       struct work_struct work;
+       struct gnttab_free_callback callback;
+       struct blk_shadow shadow[BLK_RING_SIZE];
+       unsigned long shadow_free;
+       int feature_barrier;
+
+       /**
+        * The number of people holding this device open.  We won't allow a
+        * hot-unplug unless this is 0.
+        */
+       int users;
+};
+
+static DEFINE_SPINLOCK(blkif_io_lock);
+
+#define MAXIMUM_OUTSTANDING_BLOCK_REQS \
+       (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE)
+#define GRANT_INVALID_REF      0
+
+#define PARTS_PER_DISK         16
+
+#define BLKIF_MAJOR(dev) ((dev)>>8)
+#define BLKIF_MINOR(dev) ((dev) & 0xff)
+
+#define DEV_NAME       "xvd"   /* name in /dev */
+
+/* Information about our VBDs. */
+#define MAX_VBDS 64
+static LIST_HEAD(vbds_list);
+
+static int get_id_from_freelist(struct blkfront_info *info)
+{
+       unsigned long free = info->shadow_free;
+       BUG_ON(free > BLK_RING_SIZE);
+       info->shadow_free = info->shadow[free].req.id;
+       info->shadow[free].req.id = 0x0fffffee; /* debug */
+       return free;
+}
+
+static void add_id_to_freelist(struct blkfront_info *info,
+                              unsigned long id)
+{
+       info->shadow[id].req.id  = info->shadow_free;
+       info->shadow[id].request = 0;
+       info->shadow_free = id;
+}
+
+static void blkif_restart_queue_callback(void *arg)
+{
+       struct blkfront_info *info = (struct blkfront_info *)arg;
+       schedule_work(&info->work);
+}
+
+/*
+ * blkif_queue_request
+ *
+ * request block io
+ *
+ * id: for guest use only.
+ * operation: BLKIF_OP_{READ,WRITE,PROBE}
+ * buffer: buffer to read/write into. this should be a
+ *   virtual address in the guest os.
+ */
+static int blkif_queue_request(struct request *req)
+{
+       struct blkfront_info *info = req->rq_disk->private_data;
+       unsigned long buffer_mfn;
+       struct blkif_request *ring_req;
+       struct bio *bio;
+       struct bio_vec *bvec;
+       int idx;
+       unsigned long id;
+       unsigned int fsect, lsect;
+       int ref;
+       grant_ref_t gref_head;
+
+       if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
+               return 1;
+
+       if (gnttab_alloc_grant_references(
+               BLKIF_MAX_SEGMENTS_PER_REQUEST, &gref_head) < 0) {
+               gnttab_request_free_callback(
+                       &info->callback,
+                       blkif_restart_queue_callback,
+                       info,
+                       BLKIF_MAX_SEGMENTS_PER_REQUEST);
+               return 1;
+       }
+
+       /* Fill out a communications ring structure. */
+       ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
+       id = get_id_from_freelist(info);
+       info->shadow[id].request = (unsigned long)req;
+
+       ring_req->id = id;
+       ring_req->sector_number = (blkif_sector_t)req->sector;
+       ring_req->handle = info->handle;
+
+       ring_req->operation = rq_data_dir(req) ?
+               BLKIF_OP_WRITE : BLKIF_OP_READ;
+       if (blk_barrier_rq(req))
+               ring_req->operation = BLKIF_OP_WRITE_BARRIER;
+
+       ring_req->nr_segments = 0;
+       rq_for_each_bio (bio, req) {
+               bio_for_each_segment (bvec, bio, idx) {
+                       BUG_ON(ring_req->nr_segments
+                              == BLKIF_MAX_SEGMENTS_PER_REQUEST);
+                       buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page));
+                       fsect = bvec->bv_offset >> 9;
+                       lsect = fsect + (bvec->bv_len >> 9) - 1;
+                       /* install a grant reference. */
+                       ref = gnttab_claim_grant_reference(&gref_head);
+                       BUG_ON(ref == -ENOSPC);
+
+                       gnttab_grant_foreign_access_ref(
+                               ref,
+                               info->xbdev->otherend_id,
+                               buffer_mfn,
+                               rq_data_dir(req) );
+
+                       info->shadow[id].frame[ring_req->nr_segments] =
+                               mfn_to_pfn(buffer_mfn);
+
+                       ring_req->seg[ring_req->nr_segments] =
+                               (struct blkif_request_segment) {
+                                       .gref       = ref,
+                                       .first_sect = fsect,
+                                       .last_sect  = lsect };
+
+                       ring_req->nr_segments++;
+               }
+       }
+
+       info->ring.req_prod_pvt++;
+
+       /* Keep a private copy so we can reissue requests when recovering. */
+       info->shadow[id].req = *ring_req;
+
+       gnttab_free_grant_references(gref_head);
+
+       return 0;
+}
+
+
+static inline void flush_requests(struct blkfront_info *info)
+{
+       int notify;
+
+       RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify);
+
+       if (notify)
+               notify_remote_via_irq(info->irq);
+}
+
+/*
+ * do_blkif_request
+ *  read a block; request is in a request queue
+ */
+static void do_blkif_request(request_queue_t *rq)
+{
+       struct blkfront_info *info = NULL;
+       struct request *req;
+       int queued;
+
+       pr_debug("Entered do_blkif_request\n");
+
+       queued = 0;
+
+       while ((req = elv_next_request(rq)) != NULL) {
+               info = req->rq_disk->private_data;
+               if (!blk_fs_request(req)) {
+                       end_request(req, 0);
+                       continue;
+               }
+
+               if (RING_FULL(&info->ring))
+                       goto wait;
+
+               pr_debug("do_blk_req %p: cmd %p, sec %lx, "
+                        "(%u/%li) buffer:%p [%s]\n",
+                        req, req->cmd, (unsigned long)req->sector,
+                        req->current_nr_sectors,
+                        req->nr_sectors, req->buffer,
+                        rq_data_dir(req) ? "write" : "read");
+
+
+               blkdev_dequeue_request(req);
+               if (blkif_queue_request(req)) {
+                       blk_requeue_request(rq, req);
+wait:
+                       /* Avoid pointless unplugs. */
+                       blk_stop_queue(rq);
+                       break;
+               }
+
+               queued++;
+       }
+
+       if (queued != 0)
+               flush_requests(info);
+}
+
+static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
+{
+       request_queue_t *rq;
+
+       rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
+       if (rq == NULL)
+               return -1;
+
+       elevator_init(rq, "noop");
+
+       /* Hard sector size and max sectors impersonate the equiv. hardware. */
+       blk_queue_hardsect_size(rq, sector_size);
+       blk_queue_max_sectors(rq, 512);
+
+       /* Each segment in a request is up to an aligned page in size. */
+       blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
+       blk_queue_max_segment_size(rq, PAGE_SIZE);
+
+       /* Ensure a merged request will fit in a single I/O ring slot. */
+       blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+       blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+
+       /* Make sure buffer addresses are sector-aligned. */
+       blk_queue_dma_alignment(rq, 511);
+
+       gd->queue = rq;
+
+       return 0;
+}
+
+
+static int xlvbd_barrier(struct blkfront_info *info)
+{
+       int err;
+
+       err = blk_queue_ordered(info->rq,
+                               info->feature_barrier ? QUEUE_ORDERED_DRAIN : QUEUE_ORDERED_NONE,
+                               NULL);
+
+       if (err)
+               return err;
+
+       printk(KERN_INFO "blkfront: %s: barriers %s\n",
+              info->gd->disk_name,
+              info->feature_barrier ? "enabled" : "disabled");
+       return 0;
+}
+
+
+static int xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity,
+                              int vdevice, u16 vdisk_info, u16 sector_size,
+                              struct blkfront_info *info)
+{
+       struct gendisk *gd;
+       int nr_minors = 1;
+       int err = -ENODEV;
+
+       BUG_ON(info->gd != NULL);
+       BUG_ON(info->rq != NULL);
+
+       if ((minor % PARTS_PER_DISK) == 0)
+               nr_minors = PARTS_PER_DISK;
+
+       gd = alloc_disk(nr_minors);
+       if (gd == NULL)
+               goto out;
+
+       if (nr_minors > 1)
+               sprintf(gd->disk_name, "%s%c", DEV_NAME,
+                       'a' + minor / PARTS_PER_DISK);
+       else
+               sprintf(gd->disk_name, "%s%c%d", DEV_NAME,
+                       'a' + minor / PARTS_PER_DISK,
+                       minor % PARTS_PER_DISK);
+
+       gd->major = XENVBD_MAJOR;
+       gd->first_minor = minor;
+       gd->fops = &xlvbd_block_fops;
+       gd->private_data = info;
+       gd->driverfs_dev = &(info->xbdev->dev);
+       set_capacity(gd, capacity);
+
+       if (xlvbd_init_blk_queue(gd, sector_size)) {
+               del_gendisk(gd);
+               goto out;
+       }
+
+       info->rq = gd->queue;
+       info->gd = gd;
+
+       if (info->feature_barrier)
+               xlvbd_barrier(info);
+
+       if (vdisk_info & VDISK_READONLY)
+               set_disk_ro(gd, 1);
+
+       if (vdisk_info & VDISK_REMOVABLE)
+               gd->flags |= GENHD_FL_REMOVABLE;
+
+       if (vdisk_info & VDISK_CDROM)
+               gd->flags |= GENHD_FL_CD;
+
+       return 0;
+
+ out:
+       return err;
+}
+
+static void kick_pending_request_queues(struct blkfront_info *info)
+{
+       if (!RING_FULL(&info->ring)) {
+               /* Re-enable calldowns. */
+               blk_start_queue(info->rq);
+               /* Kick things off immediately. */
+               do_blkif_request(info->rq);
+       }
+}
+
+static void blkif_restart_queue(struct work_struct *work)
+{
+       struct blkfront_info *info = container_of(work, struct blkfront_info, work);
+
+       spin_lock_irq(&blkif_io_lock);
+       if (info->connected == BLKIF_STATE_CONNECTED)
+               kick_pending_request_queues(info);
+       spin_unlock_irq(&blkif_io_lock);
+}
+
+static void blkif_free(struct blkfront_info *info, int suspend)
+{
+       /* Prevent new requests being issued until we fix things up. */
+       spin_lock_irq(&blkif_io_lock);
+       info->connected = suspend ?
+               BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED;
+       /* No more blkif_request(). */
+       if (info->rq)
+               blk_stop_queue(info->rq);
+       /* No more gnttab callback work. */
+       gnttab_cancel_free_callback(&info->callback);
+       spin_unlock_irq(&blkif_io_lock);
+
+       /* Flush gnttab callback work. Must be done with no locks held. */
+       flush_scheduled_work();
+
+       /* Free resources associated with old device channel. */
+       if (info->ring_ref != GRANT_INVALID_REF) {
+               gnttab_end_foreign_access(info->ring_ref, 0,
+                                         (unsigned long)info->ring.sring);
+               info->ring_ref = GRANT_INVALID_REF;
+               info->ring.sring = NULL;
+       }
+       if (info->irq)
+               unbind_from_irqhandler(info->irq, info);
+       info->evtchn = info->irq = 0;
+
+}
+
+static void blkif_completion(struct blk_shadow *s)
+{
+       int i;
+       for (i = 0; i < s->req.nr_segments; i++)
+               gnttab_end_foreign_access(s->req.seg[i].gref, 0, 0UL);
+}
+
+static irqreturn_t blkif_interrupt(int irq, void *dev_id)
+{
+       struct request *req;
+       struct blkif_response *bret;
+       RING_IDX i, rp;
+       unsigned long flags;
+       struct blkfront_info *info = (struct blkfront_info *)dev_id;
+       int uptodate;
+
+       spin_lock_irqsave(&blkif_io_lock, flags);
+
+       if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) {
+               spin_unlock_irqrestore(&blkif_io_lock, flags);
+               return IRQ_HANDLED;
+       }
+
+ again:
+       rp = info->ring.sring->rsp_prod;
+       rmb(); /* Ensure we see queued responses up to 'rp'. */
+
+       for (i = info->ring.rsp_cons; i != rp; i++) {
+               unsigned long id;
+               int ret;
+
+               bret = RING_GET_RESPONSE(&info->ring, i);
+               id   = bret->id;
+               req  = (struct request *)info->shadow[id].request;
+
+               blkif_completion(&info->shadow[id]);
+
+               add_id_to_freelist(info, id);
+
+               uptodate = (bret->status == BLKIF_RSP_OKAY);
+               switch (bret->operation) {
+               case BLKIF_OP_WRITE_BARRIER:
+                       if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
+                               printk(KERN_WARNING "blkfront: %s: write barrier op failed\n",
+                                      info->gd->disk_name);
+                               uptodate = -EOPNOTSUPP;
+                               info->feature_barrier = 0;
+                               xlvbd_barrier(info);
+                       }
+                       /* fall through */
+               case BLKIF_OP_READ:
+               case BLKIF_OP_WRITE:
+                       if (unlikely(bret->status != BLKIF_RSP_OKAY))
+                               dev_dbg(&info->xbdev->dev, "Bad return from blkdev data "
+                                       "request: %x\n", bret->status);
+
+                       ret = end_that_request_first(req, uptodate,
+                               req->hard_nr_sectors);
+                       BUG_ON(ret);
+                       end_that_request_last(req, uptodate);
+                       break;
+               default:
+                       BUG();
+               }
+       }
+
+       info->ring.rsp_cons = i;
+
+       if (i != info->ring.req_prod_pvt) {
+               int more_to_do;
+               RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do);
+               if (more_to_do)
+                       goto again;
+       } else
+               info->ring.sring->rsp_event = i + 1;
+
+       kick_pending_request_queues(info);
+
+       spin_unlock_irqrestore(&blkif_io_lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+
+static int setup_blkring(struct xenbus_device *dev,
+                        struct blkfront_info *info)
+{
+       struct blkif_sring *sring;
+       int err;
+
+       info->ring_ref = GRANT_INVALID_REF;
+
+       sring = (struct blkif_sring *)__get_free_page(GFP_KERNEL);
+       if (!sring) {
+               xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
+               return -ENOMEM;
+       }
+       SHARED_RING_INIT(sring);
+       FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
+
+       err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
+       if (err < 0) {
+               free_page((unsigned long)sring);
+               info->ring.sring = NULL;
+               goto fail;
+       }
+       info->ring_ref = err;
+
+       err = xenbus_alloc_evtchn(dev, &info->evtchn);
+       if (err)
+               goto fail;
+
+       err = bind_evtchn_to_irqhandler(info->evtchn,
+                                       blkif_interrupt,
+                                       IRQF_SAMPLE_RANDOM, "blkif", info);
+       if (err <= 0) {
+               xenbus_dev_fatal(dev, err,
+                                "bind_evtchn_to_irqhandler failed");
+               goto fail;
+       }
+       info->irq = err;
+
+       return 0;
+fail:
+       blkif_free(info, 0);
+       return err;
+}
+
+
+/* Common code used when first setting up, and when resuming. */
+static int talk_to_backend(struct xenbus_device *dev,
+                          struct blkfront_info *info)
+{
+       const char *message = NULL;
+       struct xenbus_transaction xbt;
+       int err;
+
+       /* Create shared ring, alloc event channel. */
+       err = setup_blkring(dev, info);
+       if (err)
+               goto out;
+
+again:
+       err = xenbus_transaction_start(&xbt);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "starting transaction");
+               goto destroy_blkring;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename,
+                           "ring-ref", "%u", info->ring_ref);
+       if (err) {
+               message = "writing ring-ref";
+               goto abort_transaction;
+       }
+       err = xenbus_printf(xbt, dev->nodename,
+                           "event-channel", "%u", info->evtchn);
+       if (err) {
+               message = "writing event-channel";
+               goto abort_transaction;
+       }
+
+       err = xenbus_transaction_end(xbt, 0);
+       if (err) {
+               if (err == -EAGAIN)
+                       goto again;
+               xenbus_dev_fatal(dev, err, "completing transaction");
+               goto destroy_blkring;
+       }
+
+       xenbus_switch_state(dev, XenbusStateInitialised);
+
+       return 0;
+
+ abort_transaction:
+       xenbus_transaction_end(xbt, 1);
+       if (message)
+               xenbus_dev_fatal(dev, err, "%s", message);
+ destroy_blkring:
+       blkif_free(info, 0);
+ out:
+       return err;
+}
+
+
+/**
+ * Entry point to this code when a new device is created.  Allocate the basic
+ * structures and the ring buffer for communication with the backend, and
+ * inform the backend of the appropriate details for those.  Switch to
+ * Initialised state.
+ */
+static int blkfront_probe(struct xenbus_device *dev,
+                         const struct xenbus_device_id *id)
+{
+       int err, vdevice, i;
+       struct blkfront_info *info;
+
+       /* FIXME: Use dynamic device id if this is not set. */
+       err = xenbus_scanf(XBT_NIL, dev->nodename,
+                          "virtual-device", "%i", &vdevice);
+       if (err != 1) {
+               xenbus_dev_fatal(dev, err, "reading virtual-device");
+               return err;
+       }
+
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (!info) {
+               xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
+               return -ENOMEM;
+       }
+
+       info->xbdev = dev;
+       info->vdevice = vdevice;
+       info->connected = BLKIF_STATE_DISCONNECTED;
+       INIT_WORK(&info->work, blkif_restart_queue);
+
+       for (i = 0; i < BLK_RING_SIZE; i++)
+               info->shadow[i].req.id = i+1;
+       info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
+
+       /* Front end dir is a number, which is used as the id. */
+       info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0);
+       dev->dev.driver_data = info;
+
+       err = talk_to_backend(dev, info);
+       if (err) {
+               kfree(info);
+               dev->dev.driver_data = NULL;
+               return err;
+       }
+
+       return 0;
+}
+
+
+static int blkif_recover(struct blkfront_info *info)
+{
+       int i;
+       struct blkif_request *req;
+       struct blk_shadow *copy;
+       int j;
+
+       /* Stage 1: Make a safe copy of the shadow state. */
+       copy = kmalloc(sizeof(info->shadow), GFP_KERNEL);
+       if (!copy)
+               return -ENOMEM;
+       memcpy(copy, info->shadow, sizeof(info->shadow));
+
+       /* Stage 2: Set up free list. */
+       memset(&info->shadow, 0, sizeof(info->shadow));
+       for (i = 0; i < BLK_RING_SIZE; i++)
+               info->shadow[i].req.id = i+1;
+       info->shadow_free = info->ring.req_prod_pvt;
+       info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
+
+       /* Stage 3: Find pending requests and requeue them. */
+       for (i = 0; i < BLK_RING_SIZE; i++) {
+               /* Not in use? */
+               if (copy[i].request == 0)
+                       continue;
+
+               /* Grab a request slot and copy shadow state into it. */
+               req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
+               *req = copy[i].req;
+
+               /* We get a new request id, and must reset the shadow state. */
+               req->id = get_id_from_freelist(info);
+               memcpy(&info->shadow[req->id], &copy[i], sizeof(copy[i]));
+
+               /* Rewrite any grant references invalidated by susp/resume. */
+               for (j = 0; j < req->nr_segments; j++)
+                       gnttab_grant_foreign_access_ref(
+                               req->seg[j].gref,
+                               info->xbdev->otherend_id,
+                               pfn_to_mfn(info->shadow[req->id].frame[j]),
+                               rq_data_dir(
+                                       (struct request *)
+                                       info->shadow[req->id].request));
+               info->shadow[req->id].req = *req;
+
+               info->ring.req_prod_pvt++;
+       }
+
+       kfree(copy);
+
+       xenbus_switch_state(info->xbdev, XenbusStateConnected);
+
+       spin_lock_irq(&blkif_io_lock);
+
+       /* Now safe for us to use the shared ring */
+       info->connected = BLKIF_STATE_CONNECTED;
+
+       /* Send off requeued requests */
+       flush_requests(info);
+
+       /* Kick any other new requests queued since we resumed */
+       kick_pending_request_queues(info);
+
+       spin_unlock_irq(&blkif_io_lock);
+
+       return 0;
+}
+
+/**
+ * We are reconnecting to the backend, due to a suspend/resume, or a backend
+ * driver restart.  We tear down our blkif structure and recreate it, but
+ * leave the device-layer structures intact so that this is transparent to the
+ * rest of the kernel.
+ */
+static int blkfront_resume(struct xenbus_device *dev)
+{
+       struct blkfront_info *info = dev->dev.driver_data;
+       int err;
+
+       dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename);
+
+       blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
+
+       err = talk_to_backend(dev, info);
+       if (info->connected == BLKIF_STATE_SUSPENDED && !err)
+               err = blkif_recover(info);
+
+       return err;
+}
+
+
+/*
+ * Invoked when the backend is finally 'ready' (and has told produced
+ * the details about the physical device - #sectors, size, etc).
+ */
+static void blkfront_connect(struct blkfront_info *info)
+{
+       unsigned long long sectors;
+       unsigned long sector_size;
+       unsigned int binfo;
+       int err;
+
+       if ((info->connected == BLKIF_STATE_CONNECTED) ||
+           (info->connected == BLKIF_STATE_SUSPENDED) )
+               return;
+
+       dev_dbg(&info->xbdev->dev, "%s:%s.\n",
+               __func__, info->xbdev->otherend);
+
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                           "sectors", "%llu", &sectors,
+                           "info", "%u", &binfo,
+                           "sector-size", "%lu", &sector_size,
+                           NULL);
+       if (err) {
+               xenbus_dev_fatal(info->xbdev, err,
+                                "reading backend fields at %s",
+                                info->xbdev->otherend);
+               return;
+       }
+
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                           "feature-barrier", "%lu", &info->feature_barrier,
+                           NULL);
+       if (err)
+               info->feature_barrier = 0;
+
+       err = xlvbd_alloc_gendisk(BLKIF_MINOR(info->vdevice),
+                                 sectors, info->vdevice,
+                                 binfo, sector_size, info);
+       if (err) {
+               xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
+                                info->xbdev->otherend);
+               return;
+       }
+
+       xenbus_switch_state(info->xbdev, XenbusStateConnected);
+
+       /* Kick pending requests. */
+       spin_lock_irq(&blkif_io_lock);
+       info->connected = BLKIF_STATE_CONNECTED;
+       kick_pending_request_queues(info);
+       spin_unlock_irq(&blkif_io_lock);
+
+       add_disk(info->gd);
+}
+
+/**
+ * Handle the change of state of the backend to Closing.  We must delete our
+ * device-layer structures now, to ensure that writes are flushed through to
+ * the backend.  Once is this done, we can switch to Closed in
+ * acknowledgement.
+ */
+static void blkfront_closing(struct xenbus_device *dev)
+{
+       struct blkfront_info *info = dev->dev.driver_data;
+       unsigned long flags;
+
+       dev_dbg(&dev->dev, "blkfront_closing: %s removed\n", dev->nodename);
+
+       if (info->rq == NULL)
+               goto out;
+
+       spin_lock_irqsave(&blkif_io_lock, flags);
+
+       del_gendisk(info->gd);
+
+       /* No more blkif_request(). */
+       blk_stop_queue(info->rq);
+
+       /* No more gnttab callback work. */
+       gnttab_cancel_free_callback(&info->callback);
+       spin_unlock_irqrestore(&blkif_io_lock, flags);
+
+       /* Flush gnttab callback work. Must be done with no locks held. */
+       flush_scheduled_work();
+
+       blk_cleanup_queue(info->rq);
+       info->rq = NULL;
+
+ out:
+       xenbus_frontend_closed(dev);
+}
+
+/**
+ * Callback received when the backend's state changes.
+ */
+static void backend_changed(struct xenbus_device *dev,
+                           enum xenbus_state backend_state)
+{
+       struct blkfront_info *info = dev->dev.driver_data;
+       struct block_device *bd;
+
+       dev_dbg(&dev->dev, "blkfront:backend_changed.\n");
+
+       switch (backend_state) {
+       case XenbusStateInitialising:
+       case XenbusStateInitWait:
+       case XenbusStateInitialised:
+       case XenbusStateUnknown:
+       case XenbusStateClosed:
+               break;
+
+       case XenbusStateConnected:
+               blkfront_connect(info);
+               break;
+
+       case XenbusStateClosing:
+               bd = bdget(info->dev);
+               if (bd == NULL)
+                       xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
+
+               mutex_lock(&bd->bd_mutex);
+               if (info->users > 0)
+                       xenbus_dev_error(dev, -EBUSY,
+                                        "Device in use; refusing to close");
+               else
+                       blkfront_closing(dev);
+               mutex_unlock(&bd->bd_mutex);
+               bdput(bd);
+               break;
+       }
+}
+
+static int blkfront_remove(struct xenbus_device *dev)
+{
+       struct blkfront_info *info = dev->dev.driver_data;
+
+       dev_dbg(&dev->dev, "blkfront_remove: %s removed\n", dev->nodename);
+
+       blkif_free(info, 0);
+
+       kfree(info);
+
+       return 0;
+}
+
+static int blkif_open(struct inode *inode, struct file *filep)
+{
+       struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
+       info->users++;
+       return 0;
+}
+
+static int blkif_release(struct inode *inode, struct file *filep)
+{
+       struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
+       info->users--;
+       if (info->users == 0) {
+               /* Check whether we have been instructed to close.  We will
+                  have ignored this request initially, as the device was
+                  still mounted. */
+               struct xenbus_device *dev = info->xbdev;
+               enum xenbus_state state = xenbus_read_driver_state(dev->otherend);
+
+               if (state == XenbusStateClosing)
+                       blkfront_closing(dev);
+       }
+       return 0;
+}
+
+static struct block_device_operations xlvbd_block_fops =
+{
+       .owner = THIS_MODULE,
+       .open = blkif_open,
+       .release = blkif_release,
+};
+
+
+static struct xenbus_device_id blkfront_ids[] = {
+       { "vbd" },
+       { "" }
+};
+
+static struct xenbus_driver blkfront = {
+       .name = "vbd",
+       .owner = THIS_MODULE,
+       .ids = blkfront_ids,
+       .probe = blkfront_probe,
+       .remove = blkfront_remove,
+       .resume = blkfront_resume,
+       .otherend_changed = backend_changed,
+};
+
+static int __init xlblk_init(void)
+{
+       if (!is_running_on_xen())
+               return -ENODEV;
+
+       if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) {
+               printk(KERN_WARNING "xen_blk: can't get major %d with name %s\n",
+                      XENVBD_MAJOR, DEV_NAME);
+               return -ENODEV;
+       }
+
+       return xenbus_register_frontend(&blkfront);
+}
+module_init(xlblk_init);
+
+
+static void xlblk_exit(void)
+{
+       return xenbus_unregister_driver(&blkfront);
+}
+module_exit(xlblk_exit);
+
+MODULE_DESCRIPTION("Xen virtual block device frontend");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_BLOCKDEV_MAJOR(XENVBD_MAJOR);
index 01332786bc4b962c5d69cda47ab37469f4e0409e..9e8f21410d2d06a3f499c5d22397a45fb5ff0472 100644 (file)
@@ -114,7 +114,7 @@ config COMPUTONE
 
 config ROCKETPORT
        tristate "Comtrol RocketPort support"
-       depends on SERIAL_NONSTANDARD
+       depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
        help
          This driver supports Comtrol RocketPort and RocketModem PCI boards.   
           These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or
@@ -157,7 +157,7 @@ config CYZ_INTR
 
 config DIGIEPCA
        tristate "Digiboard Intelligent Async Support"
-       depends on SERIAL_NONSTANDARD
+       depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
        ---help---
          This is a driver for Digi International's Xx, Xeve, and Xem series
          of cards which provide multiple serial ports. You would need
@@ -352,7 +352,7 @@ config STALDRV
 
 config STALLION
        tristate "Stallion EasyIO or EC8/32 support"
-       depends on STALDRV && BROKEN_ON_SMP
+       depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
        help
          If you have an EasyIO or EasyConnection 8/32 multiport Stallion
          card, then this is for you; say Y.  Make sure to read
@@ -363,7 +363,7 @@ config STALLION
 
 config ISTALLION
        tristate "Stallion EC8/64, ONboard, Brumby support"
-       depends on STALDRV && BROKEN_ON_SMP
+       depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
        help
          If you have an EasyConnection 8/64, ONboard, Brumby or Stallion
          serial multiport card, say Y here. Make sure to read
@@ -372,39 +372,6 @@ config ISTALLION
          To compile this driver as a module, choose M here: the
          module will be called istallion.
 
-config SERIAL_DEC
-       bool "DECstation serial support"
-       depends on MACH_DECSTATION
-       default y
-       help
-         This selects whether you want to be asked about drivers for
-         DECstation serial ports.
-
-         Note that the answer to this question won't directly affect the
-         kernel: saying N will just cause the configurator to skip all
-         the questions about DECstation serial ports.
-
-config SERIAL_DEC_CONSOLE
-       bool "Support for console on a DECstation serial port"
-       depends on SERIAL_DEC
-       default y
-       help
-         If you say Y here, it will be possible to use a serial port as the
-         system console (the system console is the device which receives all
-         kernel messages and warnings and which allows logins in single user
-         mode).  Note that the firmware uses ttyS0 as the serial console on
-         the Maxine and ttyS2 on the others.
-
-         If unsure, say Y.
-
-config ZS
-       bool "Z85C30 Serial Support"
-       depends on SERIAL_DEC
-       default y
-       help
-         Documentation on the Zilog 85C350 serial communications controller
-         is downloadable at <http://www.zilog.com/pdfs/serial/z85c30.pdf>
-
 config A2232
        tristate "Commodore A2232 serial support (EXPERIMENTAL)"
        depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP
@@ -637,6 +604,14 @@ config HVC_BEAT
        help
          Toshiba's Cell Reference Set Beat Console device driver
 
+config HVC_XEN
+       bool "Xen Hypervisor Console support"
+       depends on XEN
+       select HVC_DRIVER
+       default y
+       help
+         Xen virtual console device driver
+
 config HVCS
        tristate "IBM Hypervisor Virtual Console Server support"
        depends on PPC_PSERIES
index f2996a95eb070e9e37057446c731f05667117131..8852b8d643cfb35e2a178f397637139bf0bb0eac 100644 (file)
@@ -48,6 +48,7 @@ obj-$(CONFIG_HVC_ISERIES)     += hvc_iseries.o
 obj-$(CONFIG_HVC_RTAS)         += hvc_rtas.o
 obj-$(CONFIG_HVC_BEAT)         += hvc_beat.o
 obj-$(CONFIG_HVC_DRIVER)       += hvc_console.o
+obj-$(CONFIG_HVC_XEN)          += hvc_xen.o
 obj-$(CONFIG_RAW_DRIVER)       += raw.o
 obj-$(CONFIG_SGI_SNSC)         += snsc.o snsc_event.o
 obj-$(CONFIG_MSPEC)            += mspec.o
index 7b0839426e189a05dd179c27f3cb090113f95d2e..9e0adfe27c12d56cf8d36515f0c6061a47db4a8a 100644 (file)
@@ -4466,10 +4466,10 @@ static void cy_hangup(struct tty_struct *tty)
 static int __devinit cy_init_card(struct cyclades_card *cinfo)
 {
        struct cyclades_port *info;
-       u32 mailbox;
+       u32 uninitialized_var(mailbox);
        unsigned int nports;
        unsigned short chip_number;
-       int index, port;
+       int uninitialized_var(index), port;
 
        spin_lock_init(&cinfo->card_lock);
 
diff --git a/drivers/char/decserial.c b/drivers/char/decserial.c
deleted file mode 100644 (file)
index 8ea2bea..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * sercons.c
- *      choose the right serial device at boot time
- *
- * triemer 6-SEP-1998
- *      sercons.c is designed to allow the three different kinds 
- *      of serial devices under the decstation world to co-exist
- *      in the same kernel.  The idea here is to abstract 
- *      the pieces of the drivers that are common to this file
- *      so that they do not clash at compile time and runtime.
- *
- * HK 16-SEP-1998 v0.002
- *      removed the PROM console as this is not a real serial
- *      device. Added support for PROM console in drivers/char/tty_io.c
- *      instead. Although it may work to enable more than one 
- *      console device I strongly recommend to use only one.
- */
-
-#include <linux/init.h>
-#include <asm/dec/machtype.h>
-
-#ifdef CONFIG_ZS
-extern int zs_init(void);
-#endif
-
-#ifdef CONFIG_SERIAL_CONSOLE
-
-#ifdef CONFIG_ZS
-extern void zs_serial_console_init(void);
-#endif
-
-#endif
-
-/* rs_init - starts up the serial interface -
-   handle normal case of starting up the serial interface */
-
-#ifdef CONFIG_SERIAL
-
-int __init rs_init(void)
-{
-#ifdef CONFIG_ZS
-    if (IOASIC)
-       return zs_init();
-#endif
-    return -ENXIO;
-}
-
-__initcall(rs_init);
-
-#endif
-
-#ifdef CONFIG_SERIAL_CONSOLE
-
-/* serial_console_init handles the special case of starting
- *   up the console on the serial port
- */
-static int __init decserial_console_init(void)
-{
-#ifdef CONFIG_ZS
-    if (IOASIC)
-       zs_serial_console_init();
-#endif
-    return 0;
-}
-console_initcall(decserial_console_init);
-
-#endif
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
new file mode 100644 (file)
index 0000000..dd68f85
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * xen console driver interface to hvc_console.c
+ *
+ * (c) 2007 Gerd Hoffmann <kraxel@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <asm/xen/hypervisor.h>
+#include <xen/page.h>
+#include <xen/events.h>
+#include <xen/interface/io/console.h>
+#include <xen/hvc-console.h>
+
+#include "hvc_console.h"
+
+#define HVC_COOKIE   0x58656e /* "Xen" in hex */
+
+static struct hvc_struct *hvc;
+static int xencons_irq;
+
+/* ------------------------------------------------------------------ */
+
+static inline struct xencons_interface *xencons_interface(void)
+{
+       return mfn_to_virt(xen_start_info->console.domU.mfn);
+}
+
+static inline void notify_daemon(void)
+{
+       /* Use evtchn: this is called early, before irq is set up. */
+       notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
+}
+
+static int write_console(uint32_t vtermno, const char *data, int len)
+{
+       struct xencons_interface *intf = xencons_interface();
+       XENCONS_RING_IDX cons, prod;
+       int sent = 0;
+
+       cons = intf->out_cons;
+       prod = intf->out_prod;
+       mb();                   /* update queue values before going on */
+       BUG_ON((prod - cons) > sizeof(intf->out));
+
+       while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
+               intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
+
+       wmb();                  /* write ring before updating pointer */
+       intf->out_prod = prod;
+
+       notify_daemon();
+       return sent;
+}
+
+static int read_console(uint32_t vtermno, char *buf, int len)
+{
+       struct xencons_interface *intf = xencons_interface();
+       XENCONS_RING_IDX cons, prod;
+       int recv = 0;
+
+       cons = intf->in_cons;
+       prod = intf->in_prod;
+       mb();                   /* get pointers before reading ring */
+       BUG_ON((prod - cons) > sizeof(intf->in));
+
+       while (cons != prod && recv < len)
+               buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
+
+       mb();                   /* read ring before consuming */
+       intf->in_cons = cons;
+
+       notify_daemon();
+       return recv;
+}
+
+static struct hv_ops hvc_ops = {
+       .get_chars = read_console,
+       .put_chars = write_console,
+};
+
+static int __init xen_init(void)
+{
+       struct hvc_struct *hp;
+
+       if (!is_running_on_xen())
+               return 0;
+
+       xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
+       if (xencons_irq < 0)
+               xencons_irq = 0 /* NO_IRQ */;
+       hp = hvc_alloc(HVC_COOKIE, xencons_irq, &hvc_ops, 256);
+       if (IS_ERR(hp))
+               return PTR_ERR(hp);
+
+       hvc = hp;
+       return 0;
+}
+
+static void __exit xen_fini(void)
+{
+       if (hvc)
+               hvc_remove(hvc);
+}
+
+static int xen_cons_init(void)
+{
+       if (!is_running_on_xen())
+               return 0;
+
+       hvc_instantiate(HVC_COOKIE, 0, &hvc_ops);
+       return 0;
+}
+
+module_init(xen_init);
+module_exit(xen_fini);
+console_initcall(xen_cons_init);
+
+static void xenboot_write_console(struct console *console, const char *string,
+                                 unsigned len)
+{
+       unsigned int linelen, off = 0;
+       const char *pos;
+
+       while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
+               linelen = pos-string+off;
+               if (off + linelen > len)
+                       break;
+               write_console(0, string+off, linelen);
+               write_console(0, "\r\n", 2);
+               off += linelen + 1;
+       }
+       if (off < len)
+               write_console(0, string+off, len-off);
+}
+
+struct console xenboot_console = {
+       .name           = "xenboot",
+       .write          = xenboot_write_console,
+       .flags          = CON_PRINTBUFFER | CON_BOOT,
+};
index 53f5538c0c05e69d056f7cbf8c48c57f1e821074..2f48ba329961ae6eb7537609709e72e412d0aa8d 100644 (file)
@@ -187,6 +187,15 @@ config PNX4008_WATCHDOG
 
          Say N if you are unsure.
 
+# AVR32 Architecture
+
+config AT32AP700X_WDT
+       tristate "AT32AP700x watchdog"
+       depends on WATCHDOG && CPU_AT32AP7000
+       help
+         Watchdog timer embedded into AT32AP700x devices. This will reboot
+         your system when the timeout is reached.
+
 # X86 (i386 + ia64 + x86_64) Architecture
 
 config ACQUIRE_WDT
index d90f649038c2bc7d87626e274affb8942c740ce3..3907ec04a4e5f2ce729b90ac732eaa7c83ec9aec 100644 (file)
@@ -36,6 +36,9 @@ obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
 obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
 obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
 
+# AVR32 Architecture
+obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
+
 # X86 (i386 + ia64 + x86_64) Architecture
 obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
 obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
diff --git a/drivers/char/watchdog/at32ap700x_wdt.c b/drivers/char/watchdog/at32ap700x_wdt.c
new file mode 100644 (file)
index 0000000..54a5161
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * Watchdog driver for Atmel AT32AP700X devices
+ *
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+
+#define TIMEOUT_MIN            1
+#define TIMEOUT_MAX            2
+#define TIMEOUT_DEFAULT                TIMEOUT_MAX
+
+/* module parameters */
+static int timeout =  TIMEOUT_DEFAULT;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout,
+               "Timeout value. Limited to be 1 or 2 seconds. (default="
+               __MODULE_STRING(TIMEOUT_DEFAULT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+/* Watchdog registers and write/read macro */
+#define WDT_CTRL               0x00
+#define WDT_CTRL_EN               0
+#define WDT_CTRL_PSEL             8
+#define WDT_CTRL_KEY             24
+
+#define WDT_CLR                        0x04
+
+#define WDT_BIT(name)          (1 << WDT_##name)
+#define WDT_BF(name, value)    ((value) << WDT_##name)
+
+#define wdt_readl(dev, reg)                            \
+       __raw_readl((dev)->regs + WDT_##reg)
+#define wdt_writel(dev, reg, value)                    \
+       __raw_writel((value), (dev)->regs + WDT_##reg)
+
+struct wdt_at32ap700x {
+       void __iomem            *regs;
+       spinlock_t              io_lock;
+       int                     timeout;
+       unsigned long           users;
+       struct miscdevice       miscdev;
+};
+
+static struct wdt_at32ap700x *wdt;
+static char expect_release;
+
+/*
+ * Disable the watchdog.
+ */
+static inline void at32_wdt_stop(void)
+{
+       unsigned long psel;
+
+       spin_lock(&wdt->io_lock);
+       psel = wdt_readl(wdt, CTRL) & WDT_BF(CTRL_PSEL, 0x0f);
+       wdt_writel(wdt, CTRL, psel | WDT_BF(CTRL_KEY, 0x55));
+       wdt_writel(wdt, CTRL, psel | WDT_BF(CTRL_KEY, 0xaa));
+       spin_unlock(&wdt->io_lock);
+}
+
+/*
+ * Enable and reset the watchdog.
+ */
+static inline void at32_wdt_start(void)
+{
+       /* 0xf is 2^16 divider = 2 sec, 0xe is 2^15 divider = 1 sec */
+       unsigned long psel = (wdt->timeout > 1) ? 0xf : 0xe;
+
+       spin_lock(&wdt->io_lock);
+       wdt_writel(wdt, CTRL, WDT_BIT(CTRL_EN)
+                       | WDT_BF(CTRL_PSEL, psel)
+                       | WDT_BF(CTRL_KEY, 0x55));
+       wdt_writel(wdt, CTRL, WDT_BIT(CTRL_EN)
+                       | WDT_BF(CTRL_PSEL, psel)
+                       | WDT_BF(CTRL_KEY, 0xaa));
+       spin_unlock(&wdt->io_lock);
+}
+
+/*
+ * Pat the watchdog timer.
+ */
+static inline void at32_wdt_pat(void)
+{
+       spin_lock(&wdt->io_lock);
+       wdt_writel(wdt, CLR, 0x42);
+       spin_unlock(&wdt->io_lock);
+}
+
+/*
+ * Watchdog device is opened, and watchdog starts running.
+ */
+static int at32_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(1, &wdt->users))
+               return -EBUSY;
+
+       at32_wdt_start();
+       return nonseekable_open(inode, file);
+}
+
+/*
+ * Close the watchdog device.
+ */
+static int at32_wdt_close(struct inode *inode, struct file *file)
+{
+       if (expect_release == 42) {
+               at32_wdt_stop();
+       } else {
+               dev_dbg(wdt->miscdev.parent,
+                       "Unexpected close, not stopping watchdog!\n");
+               at32_wdt_pat();
+       }
+       clear_bit(1, &wdt->users);
+       expect_release = 0;
+       return 0;
+}
+
+/*
+ * Change the watchdog time interval.
+ */
+static int at32_wdt_settimeout(int time)
+{
+       /*
+        * All counting occurs at 1 / SLOW_CLOCK (32 kHz) and max prescaler is
+        * 2 ^ 16 allowing up to 2 seconds timeout.
+        */
+       if ((time < TIMEOUT_MIN) || (time > TIMEOUT_MAX))
+               return -EINVAL;
+
+       /*
+        * Set new watchdog time. It will be used when at32_wdt_start() is
+        * called.
+        */
+       wdt->timeout = time;
+       return 0;
+}
+
+static struct watchdog_info at32_wdt_info = {
+       .identity       = "at32ap700x watchdog",
+       .options        = WDIOF_SETTIMEOUT |
+                         WDIOF_KEEPALIVEPING |
+                         WDIOF_MAGICCLOSE,
+};
+
+/*
+ * Handle commands from user-space.
+ */
+static int at32_wdt_ioctl(struct inode *inode, struct file *file,
+               unsigned int cmd, unsigned long arg)
+{
+       int ret = -ENOTTY;
+       int time;
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+
+       switch (cmd) {
+       case WDIOC_KEEPALIVE:
+               at32_wdt_pat();
+               ret = 0;
+               break;
+       case WDIOC_GETSUPPORT:
+               ret = copy_to_user(argp, &at32_wdt_info,
+                               sizeof(at32_wdt_info)) ? -EFAULT : 0;
+               break;
+       case WDIOC_SETTIMEOUT:
+               ret = get_user(time, p);
+               if (ret)
+                       break;
+               ret = at32_wdt_settimeout(time);
+               if (ret)
+                       break;
+               /* Enable new time value */
+               at32_wdt_start();
+               /* fall through */
+       case WDIOC_GETTIMEOUT:
+               ret = put_user(wdt->timeout, p);
+               break;
+       case WDIOC_GETSTATUS: /* fall through */
+       case WDIOC_GETBOOTSTATUS:
+               ret = put_user(0, p);
+               break;
+       case WDIOC_SETOPTIONS:
+               ret = get_user(time, p);
+               if (ret)
+                       break;
+               if (time & WDIOS_DISABLECARD)
+                       at32_wdt_stop();
+               if (time & WDIOS_ENABLECARD)
+                       at32_wdt_start();
+               ret = 0;
+               break;
+       }
+
+       return ret;
+}
+
+static ssize_t at32_wdt_write(struct file *file, const char __user *data,
+                               size_t len, loff_t *ppos)
+{
+       /* See if we got the magic character 'V' and reload the timer */
+       if (len) {
+               if (!nowayout) {
+                       size_t i;
+
+                       /*
+                        * note: just in case someone wrote the magic
+                        * character five months ago...
+                        */
+                       expect_release = 0;
+
+                       /*
+                        * scan to see whether or not we got the magic
+                        * character
+                        */
+                       for (i = 0; i != len; i++) {
+                               char c;
+                               if (get_user(c, data+i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       expect_release = 42;
+                       }
+               }
+               /* someone wrote to us, we should pat the watchdog */
+               at32_wdt_pat();
+       }
+       return len;
+}
+
+static const struct file_operations at32_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .ioctl          = at32_wdt_ioctl,
+       .open           = at32_wdt_open,
+       .release        = at32_wdt_close,
+       .write          = at32_wdt_write,
+};
+
+static int __init at32_wdt_probe(struct platform_device *pdev)
+{
+       struct resource *regs;
+       int ret;
+
+       if (wdt) {
+               dev_dbg(&pdev->dev, "only 1 wdt instance supported.\n");
+               return -EBUSY;
+       }
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!regs) {
+               dev_dbg(&pdev->dev, "missing mmio resource\n");
+               return -ENXIO;
+       }
+
+       wdt = kzalloc(sizeof(struct wdt_at32ap700x), GFP_KERNEL);
+       if (!wdt) {
+               dev_dbg(&pdev->dev, "no memory for wdt structure\n");
+               return -ENOMEM;
+       }
+
+       wdt->regs = ioremap(regs->start, regs->end - regs->start + 1);
+       if (!wdt->regs) {
+               ret = -ENOMEM;
+               dev_dbg(&pdev->dev, "could not map I/O memory\n");
+               goto err_free;
+       }
+       spin_lock_init(&wdt->io_lock);
+       wdt->users = 0;
+       wdt->miscdev.minor = WATCHDOG_MINOR;
+       wdt->miscdev.name = "watchdog";
+       wdt->miscdev.fops = &at32_wdt_fops;
+
+       if (at32_wdt_settimeout(timeout)) {
+               at32_wdt_settimeout(TIMEOUT_DEFAULT);
+               dev_dbg(&pdev->dev,
+                       "default timeout invalid, set to %d sec.\n",
+                       TIMEOUT_DEFAULT);
+       }
+
+       ret = misc_register(&wdt->miscdev);
+       if (ret) {
+               dev_dbg(&pdev->dev, "failed to register wdt miscdev\n");
+               goto err_iounmap;
+       }
+
+       platform_set_drvdata(pdev, wdt);
+       wdt->miscdev.parent = &pdev->dev;
+       dev_info(&pdev->dev,
+               "AT32AP700X WDT at 0x%p, timeout %d sec (nowayout=%d)\n",
+               wdt->regs, wdt->timeout, nowayout);
+
+       return 0;
+
+err_iounmap:
+       iounmap(wdt->regs);
+err_free:
+       kfree(wdt);
+       wdt = NULL;
+       return ret;
+}
+
+static int __exit at32_wdt_remove(struct platform_device *pdev)
+{
+       if (wdt && platform_get_drvdata(pdev) == wdt) {
+               /* Stop the timer before we leave */
+               if (!nowayout)
+                       at32_wdt_stop();
+
+               misc_deregister(&wdt->miscdev);
+               iounmap(wdt->regs);
+               kfree(wdt);
+               wdt = NULL;
+               platform_set_drvdata(pdev, NULL);
+       }
+
+       return 0;
+}
+
+static void at32_wdt_shutdown(struct platform_device *pdev)
+{
+       at32_wdt_stop();
+}
+
+#ifdef CONFIG_PM
+static int at32_wdt_suspend(struct platform_device *pdev, pm_message_t message)
+{
+       at32_wdt_stop();
+       return 0;
+}
+
+static int at32_wdt_resume(struct platform_device *pdev)
+{
+       if (wdt->users)
+               at32_wdt_start();
+       return 0;
+}
+#else
+#define at32_wdt_suspend NULL
+#define at32_wdt_resume NULL
+#endif
+
+static struct platform_driver at32_wdt_driver = {
+       .remove         = __exit_p(at32_wdt_remove),
+       .suspend        = at32_wdt_suspend,
+       .resume         = at32_wdt_resume,
+       .driver         = {
+               .name   = "at32_wdt",
+               .owner  = THIS_MODULE,
+       },
+       .shutdown       = at32_wdt_shutdown,
+};
+
+static int __init at32_wdt_init(void)
+{
+       return platform_driver_probe(&at32_wdt_driver, at32_wdt_probe);
+}
+module_init(at32_wdt_init);
+
+static void __exit at32_wdt_exit(void)
+{
+       platform_driver_unregister(&at32_wdt_driver);
+}
+module_exit(at32_wdt_exit);
+
+MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
+MODULE_DESCRIPTION("Watchdog driver for Atmel AT32AP700X");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index 01cf123b1616db2eebda898dafbd167e994d8099..0e4787a0bb87d7d8af46161274b669f33970371b 100644 (file)
@@ -107,10 +107,6 @@ static ssize_t
 ep93xx_wdt_write(struct file *file, const char __user *data, size_t len,
                 loff_t *ppos)
 {
-       /* Can't seek (pwrite) on this device */
-       if (*ppos != file->f_pos)
-               return -ESPIPE;
-
        if (len) {
                if (!nowayout) {
                        size_t i;
index f35e2848aa3eb35fd4fb49fc5ade7ced904c2a45..db2ccb864412f6ce24842c4db8bbf87e67560b11 100644 (file)
  *             - support for one more type board
  *
  * Version 0.5 (2001/12/14) Matt Domsch <Matt_Domsch@dell.com>
- *              - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ *             - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ *
+ * Version 0.6 (2002/04/12): Rob Radez <rob@osinvestor.com>
+ *             - make mixcomwd_opened unsigned,
+ *               removed lock_kernel/unlock_kernel from mixcomwd_release,
+ *               modified ioctl a bit to conform to API
  *
  */
 
-#define VERSION "0.5"
+#define VERSION "0.6"
+#define WATCHDOG_NAME "mixcomwd"
+#define PFX WATCHDOG_NAME ": "
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-static int mixcomwd_ioports[] = { 0x180, 0x280, 0x380, 0x000 };
-
-#define MIXCOM_WATCHDOG_OFFSET 0xc10
+/*
+ * We have two types of cards that can be probed:
+ * 1) The Mixcom cards: these cards can be found at addresses
+ *    0x180, 0x280, 0x380 with an additional offset of 0xc10.
+ *    (Or 0xd90, 0xe90, 0xf90).
+ * 2) The FlashCOM cards: these cards can be set up at
+ *    0x300 -> 0x378, in 0x8 jumps with an offset of 0x04.
+ *    (Or 0x304 -> 0x37c in 0x8 jumps).
+ *    Each card has it's own ID.
+ */
 #define MIXCOM_ID 0x11
-#define FLASHCOM_WATCHDOG_OFFSET 0x4
 #define FLASHCOM_ID 0x18
+static struct {
+       int ioport;
+       int id;
+} mixcomwd_io_info[] __devinitdata = {
+       /* The Mixcom cards */
+       {0x0d90, MIXCOM_ID},
+       {0x0e90, MIXCOM_ID},
+       {0x0f90, MIXCOM_ID},
+       /* The FlashCOM cards */
+       {0x0304, FLASHCOM_ID},
+       {0x030c, FLASHCOM_ID},
+       {0x0314, FLASHCOM_ID},
+       {0x031c, FLASHCOM_ID},
+       {0x0324, FLASHCOM_ID},
+       {0x032c, FLASHCOM_ID},
+       {0x0334, FLASHCOM_ID},
+       {0x033c, FLASHCOM_ID},
+       {0x0344, FLASHCOM_ID},
+       {0x034c, FLASHCOM_ID},
+       {0x0354, FLASHCOM_ID},
+       {0x035c, FLASHCOM_ID},
+       {0x0364, FLASHCOM_ID},
+       {0x036c, FLASHCOM_ID},
+       {0x0374, FLASHCOM_ID},
+       {0x037c, FLASHCOM_ID},
+       /* The end of the list */
+       {0x0000, 0},
+};
 
 static void mixcomwd_timerfun(unsigned long d);
 
@@ -113,13 +154,13 @@ static int mixcomwd_release(struct inode *inode, struct file *file)
 {
        if (expect_close == 42) {
                if(mixcomwd_timer_alive) {
-                       printk(KERN_ERR "mixcomwd: release called while internal timer alive");
+                       printk(KERN_ERR PFX "release called while internal timer alive");
                        return -EBUSY;
                }
                mixcomwd_timer_alive=1;
                mod_timer(&mixcomwd_timer, jiffies + 5 * HZ);
        } else {
-               printk(KERN_CRIT "mixcomwd: WDT device closed unexpectedly.  WDT will not stop!\n");
+               printk(KERN_CRIT PFX "WDT device closed unexpectedly.  WDT will not stop!\n");
        }
 
        clear_bit(0,&mixcomwd_opened);
@@ -188,8 +229,7 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file,
        return 0;
 }
 
-static const struct file_operations mixcomwd_fops=
-{
+static const struct file_operations mixcomwd_fops = {
        .owner          = THIS_MODULE,
        .llseek         = no_llseek,
        .write          = mixcomwd_write,
@@ -198,46 +238,30 @@ static const struct file_operations mixcomwd_fops=
        .release        = mixcomwd_release,
 };
 
-static struct miscdevice mixcomwd_miscdev=
-{
+static struct miscdevice mixcomwd_miscdev = {
        .minor  = WATCHDOG_MINOR,
        .name   = "watchdog",
        .fops   = &mixcomwd_fops,
 };
 
-static int __init mixcomwd_checkcard(int port)
+static int __init checkcard(int port, int card_id)
 {
        int id;
 
-       port += MIXCOM_WATCHDOG_OFFSET;
-       if (!request_region(port, 1, "MixCOM watchdog")) {
-               return 0;
-       }
-
-       id=inb_p(port) & 0x3f;
-       if(id!=MIXCOM_ID) {
-               release_region(port, 1);
-               return 0;
-       }
-       return port;
-}
-
-static int __init flashcom_checkcard(int port)
-{
-       int id;
-
-       port += FLASHCOM_WATCHDOG_OFFSET;
        if (!request_region(port, 1, "MixCOM watchdog")) {
                return 0;
        }
 
        id=inb_p(port);
-       if(id!=FLASHCOM_ID) {
+       if (card_id==MIXCOM_ID)
+               id &= 0x3f;
+
+       if (id!=card_id) {
                release_region(port, 1);
                return 0;
        }
-       return port;
- }
+       return 1;
+}
 
 static int __init mixcomwd_init(void)
 {
@@ -245,50 +269,50 @@ static int __init mixcomwd_init(void)
        int ret;
        int found=0;
 
-       for (i = 0; !found && mixcomwd_ioports[i] != 0; i++) {
-               watchdog_port = mixcomwd_checkcard(mixcomwd_ioports[i]);
-               if (watchdog_port) {
-                       found = 1;
-               }
-       }
-
-       /* The FlashCOM card can be set up at 0x300 -> 0x378, in 0x8 jumps */
-       for (i = 0x300; !found && i < 0x380; i+=0x8) {
-               watchdog_port = flashcom_checkcard(i);
-               if (watchdog_port) {
+       for (i = 0; !found && mixcomwd_io_info[i].ioport != 0; i++) {
+               if (checkcard(mixcomwd_io_info[i].ioport,
+                             mixcomwd_io_info[i].id)) {
                        found = 1;
+                       watchdog_port = mixcomwd_io_info[i].ioport;
                }
        }
 
        if (!found) {
-               printk("mixcomwd: No card detected, or port not available.\n");
+               printk(KERN_ERR PFX "No card detected, or port not available.\n");
                return -ENODEV;
        }
 
        ret = misc_register(&mixcomwd_miscdev);
        if (ret)
        {
-               release_region(watchdog_port, 1);
-               return ret;
+               printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+                       WATCHDOG_MINOR, ret);
+               goto error_misc_register_watchdog;
        }
 
-       printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",VERSION,watchdog_port);
+       printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",
+               VERSION, watchdog_port);
 
        return 0;
+
+error_misc_register_watchdog:
+       release_region(watchdog_port, 1);
+       watchdog_port = 0x0000;
+       return ret;
 }
 
 static void __exit mixcomwd_exit(void)
 {
        if (!nowayout) {
                if(mixcomwd_timer_alive) {
-                       printk(KERN_WARNING "mixcomwd: I quit now, hardware will"
+                       printk(KERN_WARNING PFX "I quit now, hardware will"
                               " probably reboot!\n");
                        del_timer_sync(&mixcomwd_timer);
                        mixcomwd_timer_alive=0;
                }
        }
-       release_region(watchdog_port,1);
        misc_deregister(&mixcomwd_miscdev);
+       release_region(watchdog_port,1);
 }
 
 module_init(mixcomwd_init);
@@ -296,5 +320,6 @@ module_exit(mixcomwd_exit);
 
 MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
 MODULE_DESCRIPTION("MixCom Watchdog driver");
+MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index 5991add702b00e32efaf83711ebdb2a60dc8b832..22f8873dd092e72f5e25140eea95146ed817f4f1 100644 (file)
@@ -148,10 +148,6 @@ static ssize_t
 pnx4008_wdt_write(struct file *file, const char *data, size_t len,
                  loff_t * ppos)
 {
-       /*  Can't seek (pwrite) on this device  */
-       if (ppos != &file->f_pos)
-               return -ESPIPE;
-
        if (len) {
                if (!nowayout) {
                        size_t i;
index 20fa29ca7404655ade0c16d8d04bcef29cfd7d13..50430bced2f26c8ddf8b684327e5e02dcd058de3 100644 (file)
@@ -92,6 +92,7 @@ typedef enum close_state {
 
 static DECLARE_MUTEX(open_lock);
 
+static struct device    *wdt_dev;      /* platform device attached to */
 static struct resource *wdt_mem;
 static struct resource *wdt_irq;
 static struct clk      *wdt_clock;
@@ -180,7 +181,7 @@ static int s3c2410wdt_set_heartbeat(int timeout)
                }
 
                if ((count / divisor) >= 0x10000) {
-                       printk(KERN_ERR PFX "timeout %d too big\n", timeout);
+                       dev_err(wdt_dev, "timeout %d too big\n", timeout);
                        return -EINVAL;
                }
        }
@@ -233,7 +234,7 @@ static int s3c2410wdt_release(struct inode *inode, struct file *file)
        if (allow_close == CLOSE_STATE_ALLOW) {
                s3c2410wdt_stop();
        } else {
-               printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+               dev_err(wdt_dev, "Unexpected close, not stopping watchdog\n");
                s3c2410wdt_keepalive();
        }
 
@@ -338,7 +339,7 @@ static struct miscdevice s3c2410wdt_miscdev = {
 
 static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
 {
-       printk(KERN_INFO PFX "Watchdog timer expired!\n");
+       dev_info(wdt_dev, "watchdog timer expired (irq)\n");
 
        s3c2410wdt_keepalive();
        return IRQ_HANDLED;
@@ -348,31 +349,36 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
 static int s3c2410wdt_probe(struct platform_device *pdev)
 {
        struct resource *res;
+       struct device *dev;
+       unsigned int wtcon;
        int started = 0;
        int ret;
        int size;
 
        DBG("%s: probe=%p\n", __FUNCTION__, pdev);
 
+       dev = &pdev->dev;
+       wdt_dev = &pdev->dev;
+
        /* get the memory region for the watchdog timer */
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
-               printk(KERN_INFO PFX "failed to get memory region resouce\n");
+               dev_err(dev, "no memory resource specified\n");
                return -ENOENT;
        }
 
        size = (res->end-res->start)+1;
        wdt_mem = request_mem_region(res->start, size, pdev->name);
        if (wdt_mem == NULL) {
-               printk(KERN_INFO PFX "failed to get memory region\n");
+               dev_err(dev, "failed to get memory region\n");
                ret = -ENOENT;
                goto err_req;
        }
 
        wdt_base = ioremap(res->start, size);
        if (wdt_base == 0) {
-               printk(KERN_INFO PFX "failed to ioremap() region\n");
+               dev_err(dev, "failed to ioremap() region\n");
                ret = -EINVAL;
                goto err_req;
        }
@@ -381,20 +387,20 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
 
        wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (wdt_irq == NULL) {
-               printk(KERN_INFO PFX "failed to get irq resource\n");
+               dev_err(dev, "no irq resource specified\n");
                ret = -ENOENT;
                goto err_map;
        }
 
        ret = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev);
        if (ret != 0) {
-               printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
+               dev_err(dev, "failed to install irq (%d)\n", ret);
                goto err_map;
        }
 
        wdt_clock = clk_get(&pdev->dev, "watchdog");
        if (IS_ERR(wdt_clock)) {
-               printk(KERN_INFO PFX "failed to find watchdog clock source\n");
+               dev_err(dev, "failed to find watchdog clock source\n");
                ret = PTR_ERR(wdt_clock);
                goto err_irq;
        }
@@ -408,22 +414,22 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
                started = s3c2410wdt_set_heartbeat(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
 
                if (started == 0) {
-                       printk(KERN_INFO PFX "tmr_margin value out of range, default %d used\n",
+                       dev_info(dev,"tmr_margin value out of range, default %d used\n",
                               CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
                } else {
-                       printk(KERN_INFO PFX "default timer value is out of range, cannot start\n");
+                       dev_info(dev, "default timer value is out of range, cannot start\n");
                }
        }
 
        ret = misc_register(&s3c2410wdt_miscdev);
        if (ret) {
-               printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n",
+               dev_err(dev, "cannot register miscdev on minor=%d (%d)\n",
                        WATCHDOG_MINOR, ret);
                goto err_clk;
        }
 
        if (tmr_atboot && started == 0) {
-               printk(KERN_INFO PFX "Starting Watchdog Timer\n");
+               dev_info(dev, "starting watchdog timer\n");
                s3c2410wdt_start();
        } else if (!tmr_atboot) {
                /* if we're not enabling the watchdog, then ensure it is
@@ -433,6 +439,15 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
                s3c2410wdt_stop();
        }
 
+       /* print out a statement of readiness */
+
+       wtcon = readl(wdt_base + S3C2410_WTCON);
+
+       dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n",
+                (wtcon & S3C2410_WTCON_ENABLE) ?  "" : "in",
+                (wtcon & S3C2410_WTCON_RSTEN) ? "" : "dis",
+                (wtcon & S3C2410_WTCON_INTEN) ? "" : "en");
+       
        return 0;
 
  err_clk:
index 8cd7694593c9a47d34dd67ad09f74b0c7f8f4c0f..077fb674a96df3002a11bac7bd72777341e224ba 100644 (file)
@@ -1049,13 +1049,9 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
        unsigned long flags;
        ide_driver_t *drv;
        void __user *p = (void __user *)arg;
-       int err, (*setfunc)(ide_drive_t *, int);
+       int err = 0, (*setfunc)(ide_drive_t *, int);
        u8 *val;
 
-       err = scsi_cmd_ioctl(file, bdev->bd_disk->queue, bdev->bd_disk, cmd, p);
-       if (err != -ENOTTY)
-               return err;
-
        switch (cmd) {
        case HDIO_GET_32BIT:        val = &drive->io_32bit;      goto read_val;
        case HDIO_GET_KEEPSETTINGS: val = &drive->keep_settings; goto read_val;
@@ -1175,6 +1171,10 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
                        return 0;
                }
 
+               case CDROMEJECT:
+               case CDROMCLOSETRAY:
+                       return scsi_cmd_ioctl(file, bdev->bd_disk->queue, bdev->bd_disk, cmd, p);
+
                case HDIO_GET_BUSSTATE:
                        if (!capable(CAP_SYS_ADMIN))
                                return -EACCES;
index eef415b12b2ebda3d60043bf4b7f9cf8fee72563..11f1d99db40b5896698d98bf81a90a48e3c54879 100644 (file)
@@ -1591,7 +1591,7 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
        int i;
        int size;
        int size0 = 0;
-       u32 f0;
+       u32 f0 = 0;
        int ind;
        u8 op0 = 0;
 
@@ -1946,7 +1946,7 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
        int i;
        int size;
        int size0 = 0;
-       u32 f0;
+       u32 f0 = 0;
        int ind;
        u8 op0 = 0;
 
index 871310d56a6e2cc7eb27c58047883815890db404..3d1bdc8431ada97b5b779b984628e1e2de1f4f5a 100644 (file)
@@ -255,54 +255,38 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return (0);
 }
 
-static struct pci_dev *dev_a4t __devinitdata = NULL;
+static int __devinit a4t_pci_probe(struct pci_dev *dev_a4t,
+                                  struct IsdnCardState *cs,
+                                  u_int *found,
+                                  u_int *pci_memaddr)
+{
+       u16 sub_sys;
+       u16 sub_vendor;
+
+       sub_vendor = dev_a4t->subsystem_vendor;
+       sub_sys = dev_a4t->subsystem_device;
+       if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) {
+               if (pci_enable_device(dev_a4t))
+                       return (0);     /* end loop & function */
+               *found = 1;
+               *pci_memaddr = pci_resource_start(dev_a4t, 0);
+               cs->irq = dev_a4t->irq;
+               return (1);             /* end loop */
+       }
 
-int __devinit
-setup_bkm_a4t(struct IsdnCard *card)
+       return (-1);                    /* continue looping */
+}
+
+static int __devinit a4t_cs_init(struct IsdnCard *card,
+                                struct IsdnCardState *cs,
+                                u_int pci_memaddr)
 {
-       struct IsdnCardState *cs = card->cs;
-       char tmp[64];
-       u_int pci_memaddr = 0, found = 0;
        I20_REGISTER_FILE *pI20_Regs;
-#ifdef CONFIG_PCI
-#endif
-
-       strcpy(tmp, bkm_a4t_revision);
-       printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
-       if (cs->typ == ISDN_CTYPE_BKM_A4T) {
-               cs->subtyp = BKM_A4T;
-       } else
-               return (0);
 
-#ifdef CONFIG_PCI
-       while ((dev_a4t = pci_find_device(PCI_VENDOR_ID_ZORAN,
-               PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) {
-               u16 sub_sys;
-               u16 sub_vendor;
-
-               sub_vendor = dev_a4t->subsystem_vendor;
-               sub_sys = dev_a4t->subsystem_device;
-               if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) {
-                       if (pci_enable_device(dev_a4t))
-                               return(0);
-                       found = 1;
-                       pci_memaddr = pci_resource_start(dev_a4t, 0);
-                       cs->irq = dev_a4t->irq;
-                       break;
-               }
-       }
-       if (!found) {
-               printk(KERN_WARNING "HiSax: %s: Card not found\n", CardType[card->typ]);
-               return (0);
-       }
        if (!cs->irq) {         /* IRQ range check ?? */
                printk(KERN_WARNING "HiSax: %s: No IRQ\n", CardType[card->typ]);
                return (0);
        }
-       if (!pci_memaddr) {
-               printk(KERN_WARNING "HiSax: %s: No Memory base address\n", CardType[card->typ]);
-               return (0);
-       }
        cs->hw.ax.base = (long) ioremap(pci_memaddr, 4096);
        /* Check suspecious address */
        pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
@@ -317,11 +301,7 @@ setup_bkm_a4t(struct IsdnCard *card)
        cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET;
        cs->hw.ax.isac_ale = GCS_1;
        cs->hw.ax.jade_ale = GCS_3;
-#else
-       printk(KERN_WARNING "HiSax: %s: NO_PCI_BIOS\n", CardType[card->typ]);
-       printk(KERN_WARNING "HiSax: %s: unable to configure\n", CardType[card->typ]);
-       return (0);
-#endif                         /* CONFIG_PCI */
+
        printk(KERN_INFO "HiSax: %s: Card configured at 0x%lX IRQ %d\n",
               CardType[card->typ], cs->hw.ax.base, cs->irq);
 
@@ -339,5 +319,43 @@ setup_bkm_a4t(struct IsdnCard *card)
        ISACVersion(cs, "Telekom A4T:");
        /* Jade version */
        JadeVersion(cs, "Telekom A4T:");
+
        return (1);
 }
+
+static struct pci_dev *dev_a4t __devinitdata = NULL;
+
+int __devinit
+setup_bkm_a4t(struct IsdnCard *card)
+{
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+       u_int pci_memaddr = 0, found = 0;
+       int ret;
+
+       strcpy(tmp, bkm_a4t_revision);
+       printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ == ISDN_CTYPE_BKM_A4T) {
+               cs->subtyp = BKM_A4T;
+       } else
+               return (0);
+
+       while ((dev_a4t = pci_find_device(PCI_VENDOR_ID_ZORAN,
+               PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) {
+               ret = a4t_pci_probe(dev_a4t, cs, &found, &pci_memaddr);
+               if (!ret)
+                       return (0);
+               if (ret > 0)
+                       break;
+       }
+       if (!found) {
+               printk(KERN_WARNING "HiSax: %s: Card not found\n", CardType[card->typ]);
+               return (0);
+       }
+       if (!pci_memaddr) {
+               printk(KERN_WARNING "HiSax: %s: No Memory base address\n", CardType[card->typ]);
+               return (0);
+       }
+
+       return a4t_cs_init(card, cs, pci_memaddr);
+}
index a43162c2ef1589f5cf609643863755400acef2f1..5f7907e57090cc93c259d81629ee9e602577cf67 100644 (file)
@@ -847,95 +847,10 @@ static int init_card(struct IsdnCardState *cs)
        return 3;
 }
 
-static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockowner)
+static int hisax_cs_setup_card(struct IsdnCard *card)
 {
-       int ret = 0;
-       struct IsdnCard *card = cards + cardnr;
-       struct IsdnCardState *cs;
+       int ret;
 
-       cs = kzalloc(sizeof(struct IsdnCardState), GFP_ATOMIC);
-       if (!cs) {
-               printk(KERN_WARNING
-                      "HiSax: No memory for IsdnCardState(card %d)\n",
-                      cardnr + 1);
-               goto out;
-       }
-       card->cs = cs;
-       spin_lock_init(&cs->statlock);
-       spin_lock_init(&cs->lock);
-       cs->chanlimit = 2;      /* maximum B-channel number */
-       cs->logecho = 0;        /* No echo logging */
-       cs->cardnr = cardnr;
-       cs->debug = L1_DEB_WARN;
-       cs->HW_Flags = 0;
-       cs->busy_flag = busy_flag;
-       cs->irq_flags = I4L_IRQ_FLAG;
-#if TEI_PER_CARD
-       if (card->protocol == ISDN_PTYPE_NI1)
-               test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
-#else
-       test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
-#endif
-       cs->protocol = card->protocol;
-
-       if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) {
-               printk(KERN_WARNING
-                      "HiSax: Card Type %d out of range\n", card->typ);
-               goto outf_cs;
-       }
-       if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
-               printk(KERN_WARNING
-                      "HiSax: No memory for dlog(card %d)\n", cardnr + 1);
-               goto outf_cs;
-       }
-       if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
-               printk(KERN_WARNING
-                      "HiSax: No memory for status_buf(card %d)\n",
-                      cardnr + 1);
-               goto outf_dlog;
-       }
-       cs->stlist = NULL;
-       cs->status_read = cs->status_buf;
-       cs->status_write = cs->status_buf;
-       cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1;
-       cs->typ = card->typ;
-#ifdef MODULE
-       cs->iif.owner = lockowner;
-#endif
-       strcpy(cs->iif.id, id);
-       cs->iif.channels = 2;
-       cs->iif.maxbufsize = MAX_DATA_SIZE;
-       cs->iif.hl_hdrlen = MAX_HEADER_LEN;
-       cs->iif.features =
-               ISDN_FEATURE_L2_X75I |
-               ISDN_FEATURE_L2_HDLC |
-               ISDN_FEATURE_L2_HDLC_56K |
-               ISDN_FEATURE_L2_TRANS |
-               ISDN_FEATURE_L3_TRANS |
-#ifdef CONFIG_HISAX_1TR6
-               ISDN_FEATURE_P_1TR6 |
-#endif
-#ifdef CONFIG_HISAX_EURO
-               ISDN_FEATURE_P_EURO |
-#endif
-#ifdef CONFIG_HISAX_NI1
-               ISDN_FEATURE_P_NI1 |
-#endif
-               0;
-
-       cs->iif.command = HiSax_command;
-       cs->iif.writecmd = NULL;
-       cs->iif.writebuf_skb = HiSax_writebuf_skb;
-       cs->iif.readstat = HiSax_readstatus;
-       register_isdn(&cs->iif);
-       cs->myid = cs->iif.channels;
-       printk(KERN_INFO
-              "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1,
-              (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
-              (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
-              (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
-              (card->protocol == ISDN_PTYPE_NI1) ? "NI1" :
-              "NONE", cs->iif.id, cs->myid);
        switch (card->typ) {
 #if CARD_TELES0
        case ISDN_CTYPE_16_0:
@@ -1094,13 +1009,115 @@ static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockow
                printk(KERN_WARNING
                       "HiSax: Support for %s Card not selected\n",
                       CardType[card->typ]);
-               ll_unload(cs);
+               ret = 0;
+               break;
+       }
+
+       return ret;
+}
+
+static int hisax_cs_new(int cardnr, char *id, struct IsdnCard *card,
+                       struct IsdnCardState **cs_out, int *busy_flag,
+                       struct module *lockowner)
+{
+       struct IsdnCardState *cs;
+
+       *cs_out = NULL;
+
+       cs = kzalloc(sizeof(struct IsdnCardState), GFP_ATOMIC);
+       if (!cs) {
+               printk(KERN_WARNING
+                      "HiSax: No memory for IsdnCardState(card %d)\n",
+                      cardnr + 1);
+               goto out;
+       }
+       card->cs = cs;
+       spin_lock_init(&cs->statlock);
+       spin_lock_init(&cs->lock);
+       cs->chanlimit = 2;      /* maximum B-channel number */
+       cs->logecho = 0;        /* No echo logging */
+       cs->cardnr = cardnr;
+       cs->debug = L1_DEB_WARN;
+       cs->HW_Flags = 0;
+       cs->busy_flag = busy_flag;
+       cs->irq_flags = I4L_IRQ_FLAG;
+#if TEI_PER_CARD
+       if (card->protocol == ISDN_PTYPE_NI1)
+               test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
+#else
+       test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
+#endif
+       cs->protocol = card->protocol;
+
+       if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) {
+               printk(KERN_WARNING
+                      "HiSax: Card Type %d out of range\n", card->typ);
                goto outf_cs;
        }
-       if (!ret) {
-               ll_unload(cs);
+       if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
+               printk(KERN_WARNING
+                      "HiSax: No memory for dlog(card %d)\n", cardnr + 1);
                goto outf_cs;
        }
+       if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
+               printk(KERN_WARNING
+                      "HiSax: No memory for status_buf(card %d)\n",
+                      cardnr + 1);
+               goto outf_dlog;
+       }
+       cs->stlist = NULL;
+       cs->status_read = cs->status_buf;
+       cs->status_write = cs->status_buf;
+       cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1;
+       cs->typ = card->typ;
+#ifdef MODULE
+       cs->iif.owner = lockowner;
+#endif
+       strcpy(cs->iif.id, id);
+       cs->iif.channels = 2;
+       cs->iif.maxbufsize = MAX_DATA_SIZE;
+       cs->iif.hl_hdrlen = MAX_HEADER_LEN;
+       cs->iif.features =
+               ISDN_FEATURE_L2_X75I |
+               ISDN_FEATURE_L2_HDLC |
+               ISDN_FEATURE_L2_HDLC_56K |
+               ISDN_FEATURE_L2_TRANS |
+               ISDN_FEATURE_L3_TRANS |
+#ifdef CONFIG_HISAX_1TR6
+               ISDN_FEATURE_P_1TR6 |
+#endif
+#ifdef CONFIG_HISAX_EURO
+               ISDN_FEATURE_P_EURO |
+#endif
+#ifdef CONFIG_HISAX_NI1
+               ISDN_FEATURE_P_NI1 |
+#endif
+               0;
+
+       cs->iif.command = HiSax_command;
+       cs->iif.writecmd = NULL;
+       cs->iif.writebuf_skb = HiSax_writebuf_skb;
+       cs->iif.readstat = HiSax_readstatus;
+       register_isdn(&cs->iif);
+       cs->myid = cs->iif.channels;
+
+       *cs_out = cs;
+       return 1;       /* success */
+
+outf_dlog:
+       kfree(cs->dlog);
+outf_cs:
+       kfree(cs);
+       card->cs = NULL;
+out:
+       return 0;       /* error */
+}
+
+static int hisax_cs_setup(int cardnr, struct IsdnCard *card,
+                         struct IsdnCardState *cs)
+{
+       int ret;
+
        if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) {
                printk(KERN_WARNING "HiSax: No memory for isac rcvbuf\n");
                ll_unload(cs);
@@ -1143,11 +1160,41 @@ static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockow
        if (!test_bit(HW_ISAR, &cs->HW_Flags))
                ll_run(cs, 0);
 
-       ret = 1;
+       return 1;
+
+outf_cs:
+       kfree(cs);
+       card->cs = NULL;
+       return ret;
+}
+
+static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockowner)
+{
+       int ret;
+       struct IsdnCard *card = cards + cardnr;
+       struct IsdnCardState *cs;
+
+       ret = hisax_cs_new(cardnr, id, card, &cs, busy_flag, lockowner);
+       if (!ret)
+               return 0;
+
+       printk(KERN_INFO
+              "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1,
+              (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
+              (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
+              (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
+              (card->protocol == ISDN_PTYPE_NI1) ? "NI1" :
+              "NONE", cs->iif.id, cs->myid);
+
+       ret = hisax_cs_setup_card(card);
+       if (!ret) {
+               ll_unload(cs);
+               goto outf_cs;
+       }
+
+       ret = hisax_cs_setup(cardnr, card, cs);
        goto out;
 
- outf_dlog:
-       kfree(cs->dlog);
  outf_cs:
        kfree(cs);
        card->cs = NULL;
index b45de9d408d150eca9e91d60baef0ceb2e13b6a3..b73027ff50e88784747325f3367ae1aaf26f3bce 100644 (file)
@@ -300,98 +300,72 @@ enpci_interrupt(int intno, void *dev_id)
        return IRQ_HANDLED;
 }
 
-
-static struct pci_dev *dev_netjet __devinitdata = NULL;
-
-/* called by config.c */
-int __devinit
-setup_enternow_pci(struct IsdnCard *card)
+static int __devinit en_pci_probe(struct pci_dev *dev_netjet,
+                                 struct IsdnCardState *cs)
 {
-       int bytecnt;
-       struct IsdnCardState *cs = card->cs;
-       char tmp[64];
-
-#ifdef CONFIG_PCI
-#ifdef __BIG_ENDIAN
-#error "not running on big endian machines now"
-#endif
-        strcpy(tmp, enternow_pci_rev);
-       printk(KERN_INFO "HiSax: Formula-n Europe AG enter:now ISDN PCI driver Rev. %s\n", HiSax_getrev(tmp));
-       if (cs->typ != ISDN_CTYPE_ENTERNOW)
+       if (pci_enable_device(dev_netjet))
                return(0);
-       test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
-
-       for ( ;; )
-       {
-               if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
-                       PCI_DEVICE_ID_TIGERJET_300,  dev_netjet))) {
-                       if (pci_enable_device(dev_netjet))
-                               return(0);
-                       cs->irq = dev_netjet->irq;
-                       if (!cs->irq) {
-                               printk(KERN_WARNING "enter:now PCI: No IRQ for PCI card found\n");
-                               return(0);
-                       }
-                       cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
-                       if (!cs->hw.njet.base) {
-                               printk(KERN_WARNING "enter:now PCI: No IO-Adr for PCI card found\n");
-                               return(0);
-                       }
-                        /* checks Sub-Vendor ID because system crashes with Traverse-Card */
-                       if ((dev_netjet->subsystem_vendor != 0x55) ||
-                               (dev_netjet->subsystem_device != 0x02)) {
-                               printk(KERN_WARNING "enter:now: You tried to load this driver with an incompatible TigerJet-card\n");
-                                printk(KERN_WARNING "Use type=20 for Traverse NetJet PCI Card.\n");
-                                return(0);
-                        }
-               } else {
-                        printk(KERN_WARNING "enter:now PCI: No PCI card found\n");
-                       return(0);
-               }
-
-               cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
-               cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD
-
-               /* Reset an */
-               cs->hw.njet.ctrl_reg = 0x07;  // geändert von 0xff
-               outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
-               /* 20 ms Pause */
-               mdelay(20);
+       cs->irq = dev_netjet->irq;
+       if (!cs->irq) {
+               printk(KERN_WARNING "enter:now PCI: No IRQ for PCI card found\n");
+               return(0);
+       }
+       cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
+       if (!cs->hw.njet.base) {
+               printk(KERN_WARNING "enter:now PCI: No IO-Adr for PCI card found\n");
+               return(0);
+       }
+       /* checks Sub-Vendor ID because system crashes with Traverse-Card */
+       if ((dev_netjet->subsystem_vendor != 0x55) ||
+           (dev_netjet->subsystem_device != 0x02)) {
+               printk(KERN_WARNING "enter:now: You tried to load this driver with an incompatible TigerJet-card\n");
+               printk(KERN_WARNING "Use type=20 for Traverse NetJet PCI Card.\n");
+               return(0);
+       }
 
-               cs->hw.njet.ctrl_reg = 0x30;  /* Reset Off and status read clear */
-               outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
-               mdelay(10);
+       return(1);
+}
 
-               cs->hw.njet.auxd = 0x00; // war 0xc0
-               cs->hw.njet.dmactrl = 0;
+static void __devinit en_cs_init(struct IsdnCard *card,
+                                struct IsdnCardState *cs)
+{
+       cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+       cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD
 
-               outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL);
-               outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1);
-               outb(cs->hw.njet.auxd, cs->hw.njet.auxa);
+       /* Reset an */
+       cs->hw.njet.ctrl_reg = 0x07;  // geändert von 0xff
+       outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
+       /* 20 ms Pause */
+       mdelay(20);
 
-               break;
-       }
-#else
+       cs->hw.njet.ctrl_reg = 0x30;  /* Reset Off and status read clear */
+       outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
+       mdelay(10);
 
-       printk(KERN_WARNING "enter:now PCI: NO_PCI_BIOS\n");
-       printk(KERN_WARNING "enter:now PCI: unable to config Formula-n enter:now ISDN PCI ab\n");
-       return (0);
+       cs->hw.njet.auxd = 0x00; // war 0xc0
+       cs->hw.njet.dmactrl = 0;
 
-#endif /* CONFIG_PCI */
+       outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL);
+       outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1);
+       outb(cs->hw.njet.auxd, cs->hw.njet.auxa);
+}
 
-       bytecnt = 256;
+static int __devinit en_cs_init_rest(struct IsdnCard *card,
+                                    struct IsdnCardState *cs)
+{
+       const int bytecnt = 256;
 
        printk(KERN_INFO
                "enter:now PCI: PCI card configured at 0x%lx IRQ %d\n",
                cs->hw.njet.base, cs->irq);
        if (!request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN")) {
                printk(KERN_WARNING
-                          "HiSax: %s config port %lx-%lx already in use\n",
-                          CardType[card->typ],
-                          cs->hw.njet.base,
-                          cs->hw.njet.base + bytecnt);
+                      "HiSax: enter:now config port %lx-%lx already in use\n",
+                      cs->hw.njet.base,
+                      cs->hw.njet.base + bytecnt);
                return (0);
        }
+
        setup_Amd7930(cs);
        cs->hw.njet.last_is0 = 0;
         /* macro rByteAMD */
@@ -407,5 +381,44 @@ setup_enternow_pci(struct IsdnCard *card)
        cs->irq_func = &enpci_interrupt;
        cs->irq_flags |= IRQF_SHARED;
 
-        return (1);
+       return (1);
+}
+
+static struct pci_dev *dev_netjet __devinitdata = NULL;
+
+/* called by config.c */
+int __devinit
+setup_enternow_pci(struct IsdnCard *card)
+{
+       int ret;
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
+
+        strcpy(tmp, enternow_pci_rev);
+       printk(KERN_INFO "HiSax: Formula-n Europe AG enter:now ISDN PCI driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_ENTERNOW)
+               return(0);
+       test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+
+       for ( ;; )
+       {
+               if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+                       PCI_DEVICE_ID_TIGERJET_300,  dev_netjet))) {
+                       ret = en_pci_probe(dev_netjet, cs);
+                       if (!ret)
+                               return(0);
+               } else {
+                        printk(KERN_WARNING "enter:now PCI: No PCI card found\n");
+                       return(0);
+               }
+
+               en_cs_init(card, cs);
+               break;
+       }
+
+        return en_cs_init_rest(card, cs);
 }
index 8a48a3ce0a55a39204945b2acedb15463bae607a..077080aca79973366d8c13ccce686f4ec0d226f1 100644 (file)
@@ -6,7 +6,7 @@
  *              based on existing driver for CCD hfc ISA cards
  * Copyright    by Werner Cornelius  <werner@isdn4linux.de>
  *              by Karsten Keil      <keil@isdn4linux.de>
- * 
+ *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
  *
@@ -67,8 +67,6 @@ static const PCI_ENTRY id_list[] =
 };
 
 
-#ifdef CONFIG_PCI
-
 /******************************************/
 /* free hardware resources used by driver */
 /******************************************/
@@ -237,7 +235,7 @@ static void hfcpci_clear_fifo_rx(struct IsdnCardState *cs, int fifo)
        if (fifo_state)
                cs->hw.hfcpci.fifo_en |= fifo_state;
        Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
-}   
+}
 
 /***************************************/
 /* clear the desired B-channel tx fifo */
@@ -263,7 +261,7 @@ static void hfcpci_clear_fifo_tx(struct IsdnCardState *cs, int fifo)
        if (fifo_state)
                cs->hw.hfcpci.fifo_en |= fifo_state;
        Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
-}   
+}
 
 /*********************************************/
 /* read a complete B-frame out of the buffer */
@@ -511,7 +509,6 @@ main_rec_hfcpci(struct BCState *bcs)
        test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
        if (count && receive)
                goto Begin;
-       return;
 }
 
 /**************************/
@@ -582,7 +579,6 @@ hfcpci_fill_dfifo(struct IsdnCardState *cs)
 
        dev_kfree_skb_any(cs->tx_skb);
        cs->tx_skb = NULL;
-       return;
 }
 
 /**************************/
@@ -729,7 +725,6 @@ hfcpci_fill_fifo(struct BCState *bcs)
        dev_kfree_skb_any(bcs->tx_skb);
        bcs->tx_skb = NULL;
        test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
-       return;
 }
 
 /**********************************************/
@@ -924,7 +919,6 @@ receive_emsg(struct IsdnCardState *cs)
        test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
        if (count && receive)
                goto Begin;
-       return;
 }                              /* receive_emsg */
 
 /*********************/
@@ -1350,13 +1344,13 @@ mode_hfcpci(struct BCState *bcs, int mode, int bc)
                                cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
                        }
                        if (fifo2) {
-                               cs->hw.hfcpci.last_bfifo_cnt[1] = 0;  
+                               cs->hw.hfcpci.last_bfifo_cnt[1] = 0;
                                cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
                                cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
                                cs->hw.hfcpci.ctmt &= ~2;
                                cs->hw.hfcpci.conn &= ~0x18;
                        } else {
-                               cs->hw.hfcpci.last_bfifo_cnt[0] = 0;  
+                               cs->hw.hfcpci.last_bfifo_cnt[0] = 0;
                                cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1;
                                cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
                                cs->hw.hfcpci.ctmt &= ~1;
@@ -1642,8 +1636,6 @@ hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 /* this variable is used as card index when more than one cards are present */
 static struct pci_dev *dev_hfcpci __devinitdata = NULL;
 
-#endif                         /* CONFIG_PCI */
-
 int __devinit
 setup_hfcpci(struct IsdnCard *card)
 {
@@ -1656,96 +1648,99 @@ setup_hfcpci(struct IsdnCard *card)
 #ifdef __BIG_ENDIAN
 #error "not running on big endian machines now"
 #endif
+
        strcpy(tmp, hfcpci_revision);
        printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
-#ifdef CONFIG_PCI
+
        cs->hw.hfcpci.int_s1 = 0;
        cs->dc.hfcpci.ph_state = 0;
        cs->hw.hfcpci.fifo = 255;
-       if (cs->typ == ISDN_CTYPE_HFC_PCI) {
-               i = 0;
-               while (id_list[i].vendor_id) {
-                       tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
-                                                    id_list[i].device_id,
-                                                    dev_hfcpci);
-                       i++;
-                       if (tmp_hfcpci) {
-                               if (pci_enable_device(tmp_hfcpci))
-                                       continue;
-                               pci_set_master(tmp_hfcpci);
-                               if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK)))
-                                       continue;
-                               else
-                                       break;
-                       }
-               }
-
+       if (cs->typ != ISDN_CTYPE_HFC_PCI)
+               return(0);
+
+       i = 0;
+       while (id_list[i].vendor_id) {
+               tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
+                                            id_list[i].device_id,
+                                            dev_hfcpci);
+               i++;
                if (tmp_hfcpci) {
-                       i--;
-                       dev_hfcpci = tmp_hfcpci;        /* old device */
-                       cs->hw.hfcpci.dev = dev_hfcpci;
-                       cs->irq = dev_hfcpci->irq;
-                       if (!cs->irq) {
-                               printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
-                               return (0);
-                       }
-                       cs->hw.hfcpci.pci_io = (char *)(unsigned long)dev_hfcpci->resource[1].start;
-                       printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
-               } else {
-                       printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
-                       return (0);
-               }
-               if (!cs->hw.hfcpci.pci_io) {
-                       printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
-                       return (0);
-               }
-               /* Allocate memory for FIFOS */
-               /* Because the HFC-PCI needs a 32K physical alignment, we */
-               /* need to allocate the double mem and align the address */
-               if (!(cs->hw.hfcpci.share_start = kmalloc(65536, GFP_KERNEL))) {
-                       printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n");
-                       return 0;
+                       if (pci_enable_device(tmp_hfcpci))
+                               continue;
+                       pci_set_master(tmp_hfcpci);
+                       if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK)))
+                               continue;
+                       else
+                               break;
                }
-               cs->hw.hfcpci.fifos = (void *)
-                   (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000;
-               pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u_int) virt_to_bus(cs->hw.hfcpci.fifos));
-               cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
-               printk(KERN_INFO
-                      "HFC-PCI: defined at mem %p fifo %p(%#x) IRQ %d HZ %d\n",
-                      cs->hw.hfcpci.pci_io,
-                      cs->hw.hfcpci.fifos,
-                      (u_int) virt_to_bus(cs->hw.hfcpci.fifos),
-                      cs->irq, HZ);
-               spin_lock_irqsave(&cs->lock, flags);
-               pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO);   /* enable memory mapped ports, disable busmaster */
-               cs->hw.hfcpci.int_m2 = 0;       /* disable alle interrupts */
-               cs->hw.hfcpci.int_m1 = 0;
-               Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
-               Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
-               /* At this point the needed PCI config is done */
-               /* fifos are still not enabled */
-               INIT_WORK(&cs->tqueue,  hfcpci_bh);
-               cs->setstack_d = setstack_hfcpci;
-               cs->BC_Send_Data = &hfcpci_send_data;
-               cs->readisac = NULL;
-               cs->writeisac = NULL;
-               cs->readisacfifo = NULL;
-               cs->writeisacfifo = NULL;
-               cs->BC_Read_Reg = NULL;
-               cs->BC_Write_Reg = NULL;
-               cs->irq_func = &hfcpci_interrupt;
-               cs->irq_flags |= IRQF_SHARED;
-               cs->hw.hfcpci.timer.function = (void *) hfcpci_Timer;
-               cs->hw.hfcpci.timer.data = (long) cs;
-               init_timer(&cs->hw.hfcpci.timer);
-               cs->cardmsg = &hfcpci_card_msg;
-               cs->auxcmd = &hfcpci_auxcmd;
-               spin_unlock_irqrestore(&cs->lock, flags);
-               return (1);
-       } else
-               return (0);     /* no valid card type */
-#else
-       printk(KERN_WARNING "HFC-PCI: NO_PCI_BIOS\n");
-       return (0);
-#endif                         /* CONFIG_PCI */
+       }
+
+       if (!tmp_hfcpci) {
+               printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
+               return (0);
+       }
+
+       i--;
+       dev_hfcpci = tmp_hfcpci;        /* old device */
+       cs->hw.hfcpci.dev = dev_hfcpci;
+       cs->irq = dev_hfcpci->irq;
+       if (!cs->irq) {
+               printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
+               return (0);
+       }
+       cs->hw.hfcpci.pci_io = (char *)(unsigned long)dev_hfcpci->resource[1].start;
+       printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
+
+       if (!cs->hw.hfcpci.pci_io) {
+               printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
+               return (0);
+       }
+       /* Allocate memory for FIFOS */
+       /* Because the HFC-PCI needs a 32K physical alignment, we */
+       /* need to allocate the double mem and align the address */
+       if (!(cs->hw.hfcpci.share_start = kmalloc(65536, GFP_KERNEL))) {
+               printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n");
+               return 0;
+       }
+       cs->hw.hfcpci.fifos = (void *)
+           (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000;
+       pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u_int) virt_to_bus(cs->hw.hfcpci.fifos));
+       cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
+       printk(KERN_INFO
+              "HFC-PCI: defined at mem %p fifo %p(%#x) IRQ %d HZ %d\n",
+              cs->hw.hfcpci.pci_io,
+              cs->hw.hfcpci.fifos,
+              (u_int) virt_to_bus(cs->hw.hfcpci.fifos),
+              cs->irq, HZ);
+
+       spin_lock_irqsave(&cs->lock, flags);
+
+       pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO);   /* enable memory mapped ports, disable busmaster */
+       cs->hw.hfcpci.int_m2 = 0;       /* disable alle interrupts */
+       cs->hw.hfcpci.int_m1 = 0;
+       Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+       Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
+       /* At this point the needed PCI config is done */
+       /* fifos are still not enabled */
+
+       INIT_WORK(&cs->tqueue,  hfcpci_bh);
+       cs->setstack_d = setstack_hfcpci;
+       cs->BC_Send_Data = &hfcpci_send_data;
+       cs->readisac = NULL;
+       cs->writeisac = NULL;
+       cs->readisacfifo = NULL;
+       cs->writeisacfifo = NULL;
+       cs->BC_Read_Reg = NULL;
+       cs->BC_Write_Reg = NULL;
+       cs->irq_func = &hfcpci_interrupt;
+       cs->irq_flags |= IRQF_SHARED;
+       cs->hw.hfcpci.timer.function = (void *) hfcpci_Timer;
+       cs->hw.hfcpci.timer.data = (long) cs;
+       init_timer(&cs->hw.hfcpci.timer);
+       cs->cardmsg = &hfcpci_card_msg;
+       cs->auxcmd = &hfcpci_auxcmd;
+
+       spin_unlock_irqrestore(&cs->lock, flags);
+
+       return (1);
 }
index c09ffb135330ef1363f74edb207302a14ba4364e..fa2db87667c8367f3100d7e071b1a010895ff17e 100644 (file)
@@ -148,107 +148,87 @@ NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-static struct pci_dev *dev_netjet __devinitdata = NULL;
-
-int __devinit
-setup_netjet_s(struct IsdnCard *card)
+static int __devinit njs_pci_probe(struct pci_dev *dev_netjet,
+                                  struct IsdnCardState *cs)
 {
-       int bytecnt,cfg;
-       struct IsdnCardState *cs = card->cs;
-       char tmp[64];
+       int cfg;
 
-#ifdef __BIG_ENDIAN
-#error "not running on big endian machines now"
-#endif
-       strcpy(tmp, NETjet_S_revision);
-       printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", HiSax_getrev(tmp));
-       if (cs->typ != ISDN_CTYPE_NETJET_S)
+       if (pci_enable_device(dev_netjet))
                return(0);
-       test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+       pci_set_master(dev_netjet);
+       cs->irq = dev_netjet->irq;
+       if (!cs->irq) {
+               printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n");
+               return(0);
+       }
+       cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
+       if (!cs->hw.njet.base) {
+               printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n");
+               return(0);
+       }
+       /* the TJ300 and TJ320 must be detected, the IRQ handling is different
+        * unfortunatly the chips use the same device ID, but the TJ320 has
+        * the bit20 in status PCI cfg register set
+        */
+       pci_read_config_dword(dev_netjet, 0x04, &cfg);
+       if (cfg & 0x00100000)
+               cs->subtyp = 1; /* TJ320 */
+       else
+               cs->subtyp = 0; /* TJ300 */
+       /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */
+       if ((dev_netjet->subsystem_vendor == 0x55) &&
+               (dev_netjet->subsystem_device == 0x02)) {
+               printk(KERN_WARNING "Netjet: You tried to load this driver with an incompatible TigerJet-card\n");
+               printk(KERN_WARNING "Use type=41 for Formula-n enter:now ISDN PCI and compatible\n");
+               return(0);
+       }
+       /* end new code */
 
-#ifdef CONFIG_PCI
+       return(1);
+}
 
-       for ( ;; )
-       {
-               if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
-                       PCI_DEVICE_ID_TIGERJET_300,  dev_netjet))) {
-                       if (pci_enable_device(dev_netjet))
-                               return(0);
-                       pci_set_master(dev_netjet);
-                       cs->irq = dev_netjet->irq;
-                       if (!cs->irq) {
-                               printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n");
-                               return(0);
-                       }
-                       cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
-                       if (!cs->hw.njet.base) {
-                               printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n");
-                               return(0);
-                       }
-                       /* the TJ300 and TJ320 must be detected, the IRQ handling is different
-                        * unfortunatly the chips use the same device ID, but the TJ320 has
-                        * the bit20 in status PCI cfg register set
-                        */
-                       pci_read_config_dword(dev_netjet, 0x04, &cfg);
-                       if (cfg & 0x00100000)
-                               cs->subtyp = 1; /* TJ320 */
-                       else
-                               cs->subtyp = 0; /* TJ300 */
-                       /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */
-                       if ((dev_netjet->subsystem_vendor == 0x55) &&
-                               (dev_netjet->subsystem_device == 0x02)) {
-                               printk(KERN_WARNING "Netjet: You tried to load this driver with an incompatible TigerJet-card\n");
-                               printk(KERN_WARNING "Use type=41 for Formula-n enter:now ISDN PCI and compatible\n");
-                               return(0);
-                       }
-                       /* end new code */
-               } else {
-                       printk(KERN_WARNING "NETjet-S: No PCI card found\n");
-                       return(0);
-               }
+static int __devinit njs_cs_init(struct IsdnCard *card,
+                                struct IsdnCardState *cs)
+{
 
-               cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
-               cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
+       cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+       cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
 
-               cs->hw.njet.ctrl_reg = 0xff;  /* Reset On */
-               byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-               mdelay(10);
+       cs->hw.njet.ctrl_reg = 0xff;  /* Reset On */
+       byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+       mdelay(10);
 
-               cs->hw.njet.ctrl_reg = 0x00;  /* Reset Off and status read clear */
-               byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-               mdelay(10);
+       cs->hw.njet.ctrl_reg = 0x00;  /* Reset Off and status read clear */
+       byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+       mdelay(10);
 
-               cs->hw.njet.auxd = 0xC0;
-               cs->hw.njet.dmactrl = 0;
+       cs->hw.njet.auxd = 0xC0;
+       cs->hw.njet.dmactrl = 0;
 
-               byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
-               byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
-               byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+       byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
+       byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
+       byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
 
-               switch ( ( ( NETjet_ReadIC( cs, ISAC_RBCH ) >> 5 ) & 3 ) )
-               {
-                       case 0 :
-                               break;
+       switch ( ( ( NETjet_ReadIC( cs, ISAC_RBCH ) >> 5 ) & 3 ) )
+       {
+               case 0 :
+                       return 1;       /* end loop */
 
-                       case 3 :
-                               printk( KERN_WARNING "NETjet-S: NETspider-U PCI card found\n" );
-                               continue;
+               case 3 :
+                       printk( KERN_WARNING "NETjet-S: NETspider-U PCI card found\n" );
+                       return -1;      /* continue looping */
 
-                       default :
-                               printk( KERN_WARNING "NETjet-S: No PCI card found\n" );
-                               return 0;
-                }
-                break;
+               default :
+                       printk( KERN_WARNING "NETjet-S: No PCI card found\n" );
+                       return 0;       /* end loop & function */
        }
-#else
-
-       printk(KERN_WARNING "NETjet-S: NO_PCI_BIOS\n");
-       printk(KERN_WARNING "NETjet-S: unable to config NETJET-S PCI\n");
-       return (0);
-
-#endif /* CONFIG_PCI */
+       return 1;                       /* end loop */
+}
 
-       bytecnt = 256;
+static int __devinit njs_cs_init_rest(struct IsdnCard *card,
+                                     struct IsdnCardState *cs)
+{
+       const int bytecnt = 256;
 
        printk(KERN_INFO
                "NETjet-S: %s card configured at %#lx IRQ %d\n",
@@ -273,5 +253,47 @@ setup_netjet_s(struct IsdnCard *card)
        cs->irq_func = &netjet_s_interrupt;
        cs->irq_flags |= IRQF_SHARED;
        ISACVersion(cs, "NETjet-S:");
+
        return (1);
 }
+
+static struct pci_dev *dev_netjet __devinitdata = NULL;
+
+int __devinit
+setup_netjet_s(struct IsdnCard *card)
+{
+       int ret;
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
+       strcpy(tmp, NETjet_S_revision);
+       printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_NETJET_S)
+               return(0);
+       test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+
+       for ( ;; )
+       {
+               if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+                       PCI_DEVICE_ID_TIGERJET_300,  dev_netjet))) {
+                       ret = njs_pci_probe(dev_netjet, cs);
+                       if (!ret)
+                               return(0);
+               } else {
+                       printk(KERN_WARNING "NETjet-S: No PCI card found\n");
+                       return(0);
+               }
+
+               ret = njs_cs_init(card, cs);
+               if (!ret)
+                       return(0);
+               if (ret > 0)
+                       break;
+               /* otherwise, ret < 0, continue looping */
+       }
+
+       return njs_cs_init_rest(card, cs);
+}
index 8202cf34ecae729a9f2641f55fc991696f00cd83..f017d3816b1dcb1e36039a21f89a7f2b40f152d3 100644 (file)
@@ -128,93 +128,69 @@ NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-static struct pci_dev *dev_netjet __devinitdata = NULL;
-
-int __devinit
-setup_netjet_u(struct IsdnCard *card)
+static int __devinit nju_pci_probe(struct pci_dev *dev_netjet,
+                                  struct IsdnCardState *cs)
 {
-       int bytecnt;
-       struct IsdnCardState *cs = card->cs;
-       char tmp[64];
-#ifdef CONFIG_PCI
-#endif
-#ifdef __BIG_ENDIAN
-#error "not running on big endian machines now"
-#endif
-       strcpy(tmp, NETjet_U_revision);
-       printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", HiSax_getrev(tmp));
-       if (cs->typ != ISDN_CTYPE_NETJET_U)
+       if (pci_enable_device(dev_netjet))
                return(0);
-       test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
-
-#ifdef CONFIG_PCI
+       pci_set_master(dev_netjet);
+       cs->irq = dev_netjet->irq;
+       if (!cs->irq) {
+               printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n");
+               return(0);
+       }
+       cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
+       if (!cs->hw.njet.base) {
+               printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n");
+               return(0);
+       }
 
-       for ( ;; )
-       {
-               if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
-                       PCI_DEVICE_ID_TIGERJET_300,  dev_netjet))) {
-                       if (pci_enable_device(dev_netjet))
-                               return(0);
-                       pci_set_master(dev_netjet);
-                       cs->irq = dev_netjet->irq;
-                       if (!cs->irq) {
-                               printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n");
-                               return(0);
-                       }
-                       cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
-                       if (!cs->hw.njet.base) {
-                               printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n");
-                               return(0);
-                       }
-               } else {
-                       printk(KERN_WARNING "NETspider-U: No PCI card found\n");
-                       return(0);
-               }
+       return (1);
+}
 
-               cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
-               cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
-               mdelay(10);
+static int __devinit nju_cs_init(struct IsdnCard *card,
+                                struct IsdnCardState *cs)
+{
+       cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+       cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
+       mdelay(10);
 
-               cs->hw.njet.ctrl_reg = 0xff;  /* Reset On */
-               byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-               mdelay(10);
+       cs->hw.njet.ctrl_reg = 0xff;  /* Reset On */
+       byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+       mdelay(10);
 
-               cs->hw.njet.ctrl_reg = 0x00;  /* Reset Off and status read clear */
-               byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-               mdelay(10);
+       cs->hw.njet.ctrl_reg = 0x00;  /* Reset Off and status read clear */
+       byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+       mdelay(10);
 
-               cs->hw.njet.auxd = 0xC0;
-               cs->hw.njet.dmactrl = 0;
+       cs->hw.njet.auxd = 0xC0;
+       cs->hw.njet.dmactrl = 0;
 
-               byteout(cs->hw.njet.auxa, 0);
-               byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
-               byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
-               byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+       byteout(cs->hw.njet.auxa, 0);
+       byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
+       byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
+       byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
 
-               switch ( ( ( NETjet_ReadIC( cs, ICC_RBCH ) >> 5 ) & 3 ) )
-               {
-                       case 3 :
-                               break;
+       switch ( ( ( NETjet_ReadIC( cs, ICC_RBCH ) >> 5 ) & 3 ) )
+       {
+               case 3 :
+                       return 1;       /* end loop */
 
-                       case 0 :
-                               printk( KERN_WARNING "NETspider-U: NETjet-S PCI card found\n" );
-                               continue;
+               case 0 :
+                       printk( KERN_WARNING "NETspider-U: NETjet-S PCI card found\n" );
+                       return -1;      /* continue looping */
 
-                       default :
-                               printk( KERN_WARNING "NETspider-U: No PCI card found\n" );
-                               return 0;
-                }
-                break;
+               default :
+                       printk( KERN_WARNING "NETspider-U: No PCI card found\n" );
+                       return 0;       /* end loop & function */
        }
-#else
-
-       printk(KERN_WARNING "NETspider-U: NO_PCI_BIOS\n");
-       printk(KERN_WARNING "NETspider-U: unable to config NETspider-U PCI\n");
-       return (0);
-
-#endif /* CONFIG_PCI */
+       return 1;                       /* end loop */
+}
 
-       bytecnt = 256;
+static int __devinit nju_cs_init_rest(struct IsdnCard *card,
+                                     struct IsdnCardState *cs)
+{
+       const int bytecnt = 256;
 
        printk(KERN_INFO
                "NETspider-U: PCI card configured at %#lx IRQ %d\n",
@@ -239,5 +215,48 @@ setup_netjet_u(struct IsdnCard *card)
        cs->irq_func = &netjet_u_interrupt;
        cs->irq_flags |= IRQF_SHARED;
        ICCVersion(cs, "NETspider-U:");
+
        return (1);
 }
+
+static struct pci_dev *dev_netjet __devinitdata = NULL;
+
+int __devinit
+setup_netjet_u(struct IsdnCard *card)
+{
+       int ret;
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
+
+       strcpy(tmp, NETjet_U_revision);
+       printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_NETJET_U)
+               return(0);
+       test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+
+       for ( ;; )
+       {
+               if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+                       PCI_DEVICE_ID_TIGERJET_300,  dev_netjet))) {
+                       ret = nju_pci_probe(dev_netjet, cs);
+                       if (!ret)
+                               return(0);
+               } else {
+                       printk(KERN_WARNING "NETspider-U: No PCI card found\n");
+                       return(0);
+               }
+
+               ret = nju_cs_init(card, cs);
+               if (!ret)
+                       return (0);
+               if (ret > 0)
+                       break;
+               /* ret < 0 == continue looping */
+       }
+
+       return nju_cs_init_rest(card, cs);
+}
index e8e37d826478842df2d95d7f4d65db77623c8dfe..33fa28a8c1993d5dd3cc258ec3896e41b0941cbb 100644 (file)
@@ -1,12 +1,17 @@
 #
 # KVM configuration
 #
-menu "Virtualization"
+menuconfig VIRTUALIZATION
+       bool "Virtualization"
        depends on X86
+       default y
+
+if VIRTUALIZATION
 
 config KVM
        tristate "Kernel-based Virtual Machine (KVM) support"
        depends on X86 && EXPERIMENTAL
+       depends on X86_CMPXCHG64 || 64BIT
        ---help---
          Support hosting fully virtualized guest machines using hardware
          virtualization extensions.  You will need a fairly recent
@@ -35,4 +40,4 @@ config KVM_AMD
          Provides support for KVM on AMD processors equipped with the AMD-V
          (SVM) extensions.
 
-endmenu
+endif # VIRTUALIZATION
index 152312c1fafa3dcfd26cbf5583d27b688c8b3660..a7c5e6bee034e0b9d178f6cda5122756112d319b 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
 #include <linux/mm.h>
 #include <asm/signal.h>
 
@@ -18,6 +20,7 @@
 #include <linux/kvm_para.h>
 
 #define CR0_PE_MASK (1ULL << 0)
+#define CR0_MP_MASK (1ULL << 1)
 #define CR0_TS_MASK (1ULL << 3)
 #define CR0_NE_MASK (1ULL << 5)
 #define CR0_WP_MASK (1ULL << 16)
@@ -42,7 +45,8 @@
        (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK \
         | CR0_NW_MASK | CR0_CD_MASK)
 #define KVM_VM_CR0_ALWAYS_ON \
-       (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK)
+       (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK | CR0_TS_MASK \
+        | CR0_MP_MASK)
 #define KVM_GUEST_CR4_MASK \
        (CR4_PSE_MASK | CR4_PAE_MASK | CR4_PGE_MASK | CR4_VMXE_MASK | CR4_VME_MASK)
 #define KVM_PMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK)
 #define INVALID_PAGE (~(hpa_t)0)
 #define UNMAPPED_GVA (~(gpa_t)0)
 
-#define KVM_MAX_VCPUS 1
+#define KVM_MAX_VCPUS 4
 #define KVM_ALIAS_SLOTS 4
 #define KVM_MEMORY_SLOTS 4
-#define KVM_NUM_MMU_PAGES 256
+#define KVM_NUM_MMU_PAGES 1024
 #define KVM_MIN_FREE_MMU_PAGES 5
 #define KVM_REFILL_PAGES 25
 #define KVM_MAX_CPUID_ENTRIES 40
 
 #define KVM_PIO_PAGE_OFFSET 1
 
+/*
+ * vcpu->requests bit members
+ */
+#define KVM_TLB_FLUSH 0
+
 /*
  * Address types:
  *
@@ -137,7 +146,7 @@ struct kvm_mmu_page {
        gfn_t gfn;
        union kvm_mmu_page_role role;
 
-       hpa_t page_hpa;
+       u64 *spt;
        unsigned long slot_bitmap; /* One bit set per slot which has memory
                                    * in this shadow page.
                                    */
@@ -232,6 +241,7 @@ struct kvm_pio_request {
        struct page *guest_pages[2];
        unsigned guest_page_offset;
        int in;
+       int port;
        int size;
        int string;
        int down;
@@ -252,8 +262,70 @@ struct kvm_stat {
        u32 halt_exits;
        u32 request_irq_exits;
        u32 irq_exits;
+       u32 light_exits;
+       u32 efer_reload;
+};
+
+struct kvm_io_device {
+       void (*read)(struct kvm_io_device *this,
+                    gpa_t addr,
+                    int len,
+                    void *val);
+       void (*write)(struct kvm_io_device *this,
+                     gpa_t addr,
+                     int len,
+                     const void *val);
+       int (*in_range)(struct kvm_io_device *this, gpa_t addr);
+       void (*destructor)(struct kvm_io_device *this);
+
+       void             *private;
+};
+
+static inline void kvm_iodevice_read(struct kvm_io_device *dev,
+                                    gpa_t addr,
+                                    int len,
+                                    void *val)
+{
+       dev->read(dev, addr, len, val);
+}
+
+static inline void kvm_iodevice_write(struct kvm_io_device *dev,
+                                     gpa_t addr,
+                                     int len,
+                                     const void *val)
+{
+       dev->write(dev, addr, len, val);
+}
+
+static inline int kvm_iodevice_inrange(struct kvm_io_device *dev, gpa_t addr)
+{
+       return dev->in_range(dev, addr);
+}
+
+static inline void kvm_iodevice_destructor(struct kvm_io_device *dev)
+{
+       if (dev->destructor)
+               dev->destructor(dev);
+}
+
+/*
+ * It would be nice to use something smarter than a linear search, TBD...
+ * Thankfully we dont expect many devices to register (famous last words :),
+ * so until then it will suffice.  At least its abstracted so we can change
+ * in one place.
+ */
+struct kvm_io_bus {
+       int                   dev_count;
+#define NR_IOBUS_DEVS 6
+       struct kvm_io_device *devs[NR_IOBUS_DEVS];
 };
 
+void kvm_io_bus_init(struct kvm_io_bus *bus);
+void kvm_io_bus_destroy(struct kvm_io_bus *bus);
+struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr);
+void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
+                            struct kvm_io_device *dev);
+
 struct kvm_vcpu {
        struct kvm *kvm;
        union {
@@ -266,6 +338,8 @@ struct kvm_vcpu {
        u64 host_tsc;
        struct kvm_run *run;
        int interrupt_window_open;
+       int guest_mode;
+       unsigned long requests;
        unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */
 #define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long)
        unsigned long irq_pending[NR_IRQ_WORDS];
@@ -285,15 +359,20 @@ struct kvm_vcpu {
        u64 apic_base;
        u64 ia32_misc_enable_msr;
        int nmsrs;
+       int save_nmsrs;
+       int msr_offset_efer;
+#ifdef CONFIG_X86_64
+       int msr_offset_kernel_gs_base;
+#endif
        struct vmx_msr_entry *guest_msrs;
        struct vmx_msr_entry *host_msrs;
 
-       struct list_head free_pages;
-       struct kvm_mmu_page page_header_buf[KVM_NUM_MMU_PAGES];
        struct kvm_mmu mmu;
 
        struct kvm_mmu_memory_cache mmu_pte_chain_cache;
        struct kvm_mmu_memory_cache mmu_rmap_desc_cache;
+       struct kvm_mmu_memory_cache mmu_page_cache;
+       struct kvm_mmu_memory_cache mmu_page_header_cache;
 
        gfn_t last_pt_write_gfn;
        int   last_pt_write_count;
@@ -305,6 +384,11 @@ struct kvm_vcpu {
        char *guest_fx_image;
        int fpu_active;
        int guest_fpu_loaded;
+       struct vmx_host_state {
+               int loaded;
+               u16 fs_sel, gs_sel, ldt_sel;
+               int fs_gs_ldt_reload_needed;
+       } vmx_host_state;
 
        int mmio_needed;
        int mmio_read_completed;
@@ -331,6 +415,7 @@ struct kvm_vcpu {
                        u32 ar;
                } tr, es, ds, fs, gs;
        } rmode;
+       int halt_request; /* real mode on Intel only */
 
        int cpuid_nent;
        struct kvm_cpuid_entry cpuid_entries[KVM_MAX_CPUID_ENTRIES];
@@ -362,12 +447,15 @@ struct kvm {
        struct list_head active_mmu_pages;
        int n_free_mmu_pages;
        struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
+       int nvcpus;
        struct kvm_vcpu vcpus[KVM_MAX_VCPUS];
        int memory_config_version;
        int busy;
        unsigned long rmap_overflow;
        struct list_head vm_list;
        struct file *filp;
+       struct kvm_io_bus mmio_bus;
+       struct kvm_io_bus pio_bus;
 };
 
 struct descriptor_table {
@@ -488,6 +576,7 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
                  int size, unsigned long count, int string, int down,
                  gva_t address, int rep, unsigned port);
 void kvm_emulate_cpuid(struct kvm_vcpu *vcpu);
+int kvm_emulate_halt(struct kvm_vcpu *vcpu);
 int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address);
 int emulate_clts(struct kvm_vcpu *vcpu);
 int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr,
@@ -511,6 +600,7 @@ void save_msrs(struct vmx_msr_entry *e, int n);
 void kvm_resched(struct kvm_vcpu *vcpu);
 void kvm_load_guest_fpu(struct kvm_vcpu *vcpu);
 void kvm_put_guest_fpu(struct kvm_vcpu *vcpu);
+void kvm_flush_remote_tlbs(struct kvm *kvm);
 
 int kvm_read_guest(struct kvm_vcpu *vcpu,
               gva_t addr,
@@ -524,10 +614,12 @@ int kvm_write_guest(struct kvm_vcpu *vcpu,
 
 unsigned long segment_base(u16 selector);
 
-void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes);
-void kvm_mmu_post_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes);
+void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
+                      const u8 *old, const u8 *new, int bytes);
 int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva);
 void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
+int kvm_mmu_load(struct kvm_vcpu *vcpu);
+void kvm_mmu_unload(struct kvm_vcpu *vcpu);
 
 int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run);
 
@@ -539,6 +631,14 @@ static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
        return vcpu->mmu.page_fault(vcpu, gva, error_code);
 }
 
+static inline int kvm_mmu_reload(struct kvm_vcpu *vcpu)
+{
+       if (likely(vcpu->mmu.root_hpa != INVALID_PAGE))
+               return 0;
+
+       return kvm_mmu_load(vcpu);
+}
+
 static inline int is_long_mode(struct kvm_vcpu *vcpu)
 {
 #ifdef CONFIG_X86_64
index 8f1f07adb04e914ce61ea6c595ce90ed53030e01..1b206f197c6b5a4d2cd015ea57fcf554ef1a772b 100644 (file)
  */
 
 #include "kvm.h"
+#include "x86_emulate.h"
+#include "segment_descriptor.h"
 
 #include <linux/kvm.h>
 #include <linux/module.h>
 #include <linux/errno.h>
-#include <linux/magic.h>
-#include <asm/processor.h>
 #include <linux/percpu.h>
 #include <linux/gfp.h>
-#include <asm/msr.h>
 #include <linux/mm.h>
 #include <linux/miscdevice.h>
 #include <linux/vmalloc.h>
-#include <asm/uaccess.h>
 #include <linux/reboot.h>
-#include <asm/io.h>
 #include <linux/debugfs.h>
 #include <linux/highmem.h>
 #include <linux/file.h>
-#include <asm/desc.h>
 #include <linux/sysdev.h>
 #include <linux/cpu.h>
-#include <linux/file.h>
-#include <linux/fs.h>
-#include <linux/mount.h>
 #include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/smp.h>
+#include <linux/anon_inodes.h>
 
-#include "x86_emulate.h"
-#include "segment_descriptor.h"
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/desc.h>
 
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
@@ -51,8 +50,12 @@ MODULE_LICENSE("GPL");
 static DEFINE_SPINLOCK(kvm_lock);
 static LIST_HEAD(vm_list);
 
+static cpumask_t cpus_hardware_enabled;
+
 struct kvm_arch_ops *kvm_arch_ops;
 
+static void hardware_disable(void *ignored);
+
 #define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x)
 
 static struct kvm_stats_debugfs_item {
@@ -72,13 +75,13 @@ static struct kvm_stats_debugfs_item {
        { "halt_exits", STAT_OFFSET(halt_exits) },
        { "request_irq", STAT_OFFSET(request_irq_exits) },
        { "irq_exits", STAT_OFFSET(irq_exits) },
+       { "light_exits", STAT_OFFSET(light_exits) },
+       { "efer_reload", STAT_OFFSET(efer_reload) },
        { NULL }
 };
 
 static struct dentry *debugfs_dir;
 
-struct vfsmount *kvmfs_mnt;
-
 #define MAX_IO_MSRS 256
 
 #define CR0_RESEVED_BITS 0xffffffff1ffaffc0ULL
@@ -100,55 +103,6 @@ struct segment_descriptor_64 {
 static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,
                           unsigned long arg);
 
-static struct inode *kvmfs_inode(struct file_operations *fops)
-{
-       int error = -ENOMEM;
-       struct inode *inode = new_inode(kvmfs_mnt->mnt_sb);
-
-       if (!inode)
-               goto eexit_1;
-
-       inode->i_fop = fops;
-
-       /*
-        * Mark the inode dirty from the very beginning,
-        * that way it will never be moved to the dirty
-        * list because mark_inode_dirty() will think
-        * that it already _is_ on the dirty list.
-        */
-       inode->i_state = I_DIRTY;
-       inode->i_mode = S_IRUSR | S_IWUSR;
-       inode->i_uid = current->fsuid;
-       inode->i_gid = current->fsgid;
-       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-       return inode;
-
-eexit_1:
-       return ERR_PTR(error);
-}
-
-static struct file *kvmfs_file(struct inode *inode, void *private_data)
-{
-       struct file *file = get_empty_filp();
-
-       if (!file)
-               return ERR_PTR(-ENFILE);
-
-       file->f_path.mnt = mntget(kvmfs_mnt);
-       file->f_path.dentry = d_alloc_anon(inode);
-       if (!file->f_path.dentry)
-               return ERR_PTR(-ENOMEM);
-       file->f_mapping = inode->i_mapping;
-
-       file->f_pos = 0;
-       file->f_flags = O_RDWR;
-       file->f_op = inode->i_fop;
-       file->f_mode = FMODE_READ | FMODE_WRITE;
-       file->f_version = 0;
-       file->private_data = private_data;
-       return file;
-}
-
 unsigned long segment_base(u16 selector)
 {
        struct descriptor_table gdt;
@@ -307,6 +261,48 @@ static void vcpu_put(struct kvm_vcpu *vcpu)
        mutex_unlock(&vcpu->mutex);
 }
 
+static void ack_flush(void *_completed)
+{
+       atomic_t *completed = _completed;
+
+       atomic_inc(completed);
+}
+
+void kvm_flush_remote_tlbs(struct kvm *kvm)
+{
+       int i, cpu, needed;
+       cpumask_t cpus;
+       struct kvm_vcpu *vcpu;
+       atomic_t completed;
+
+       atomic_set(&completed, 0);
+       cpus_clear(cpus);
+       needed = 0;
+       for (i = 0; i < kvm->nvcpus; ++i) {
+               vcpu = &kvm->vcpus[i];
+               if (test_and_set_bit(KVM_TLB_FLUSH, &vcpu->requests))
+                       continue;
+               cpu = vcpu->cpu;
+               if (cpu != -1 && cpu != raw_smp_processor_id())
+                       if (!cpu_isset(cpu, cpus)) {
+                               cpu_set(cpu, cpus);
+                               ++needed;
+                       }
+       }
+
+       /*
+        * We really want smp_call_function_mask() here.  But that's not
+        * available, so ipi all cpus in parallel and wait for them
+        * to complete.
+        */
+       for (cpu = first_cpu(cpus); cpu != NR_CPUS; cpu = next_cpu(cpu, cpus))
+               smp_call_function_single(cpu, ack_flush, &completed, 1, 0);
+       while (atomic_read(&completed) != needed) {
+               cpu_relax();
+               barrier();
+       }
+}
+
 static struct kvm *kvm_create_vm(void)
 {
        struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
@@ -315,8 +311,13 @@ static struct kvm *kvm_create_vm(void)
        if (!kvm)
                return ERR_PTR(-ENOMEM);
 
+       kvm_io_bus_init(&kvm->pio_bus);
        spin_lock_init(&kvm->lock);
        INIT_LIST_HEAD(&kvm->active_mmu_pages);
+       spin_lock(&kvm_lock);
+       list_add(&kvm->vm_list, &vm_list);
+       spin_unlock(&kvm_lock);
+       kvm_io_bus_init(&kvm->mmio_bus);
        for (i = 0; i < KVM_MAX_VCPUS; ++i) {
                struct kvm_vcpu *vcpu = &kvm->vcpus[i];
 
@@ -324,10 +325,6 @@ static struct kvm *kvm_create_vm(void)
                vcpu->cpu = -1;
                vcpu->kvm = kvm;
                vcpu->mmu.root_hpa = INVALID_PAGE;
-               INIT_LIST_HEAD(&vcpu->free_pages);
-               spin_lock(&kvm_lock);
-               list_add(&kvm->vm_list, &vm_list);
-               spin_unlock(&kvm_lock);
        }
        return kvm;
 }
@@ -380,6 +377,16 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu)
                }
 }
 
+static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu)
+{
+       if (!vcpu->vmcs)
+               return;
+
+       vcpu_load(vcpu);
+       kvm_mmu_unload(vcpu);
+       vcpu_put(vcpu);
+}
+
 static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
 {
        if (!vcpu->vmcs)
@@ -400,6 +407,11 @@ static void kvm_free_vcpus(struct kvm *kvm)
 {
        unsigned int i;
 
+       /*
+        * Unpin any mmu pages first.
+        */
+       for (i = 0; i < KVM_MAX_VCPUS; ++i)
+               kvm_unload_vcpu_mmu(&kvm->vcpus[i]);
        for (i = 0; i < KVM_MAX_VCPUS; ++i)
                kvm_free_vcpu(&kvm->vcpus[i]);
 }
@@ -414,6 +426,8 @@ static void kvm_destroy_vm(struct kvm *kvm)
        spin_lock(&kvm_lock);
        list_del(&kvm->vm_list);
        spin_unlock(&kvm_lock);
+       kvm_io_bus_destroy(&kvm->pio_bus);
+       kvm_io_bus_destroy(&kvm->mmio_bus);
        kvm_free_vcpus(kvm);
        kvm_free_physmem(kvm);
        kfree(kvm);
@@ -969,7 +983,7 @@ EXPORT_SYMBOL_GPL(gfn_to_page);
 void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
 {
        int i;
-       struct kvm_memory_slot *memslot = NULL;
+       struct kvm_memory_slot *memslot;
        unsigned long rel_gfn;
 
        for (i = 0; i < kvm->nmemslots; ++i) {
@@ -978,7 +992,7 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
                if (gfn >= memslot->base_gfn
                    && gfn < memslot->base_gfn + memslot->npages) {
 
-                       if (!memslot || !memslot->dirty_bitmap)
+                       if (!memslot->dirty_bitmap)
                                return;
 
                        rel_gfn = gfn - memslot->base_gfn;
@@ -1037,12 +1051,31 @@ static int emulator_write_std(unsigned long addr,
        return X86EMUL_UNHANDLEABLE;
 }
 
+static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
+                                               gpa_t addr)
+{
+       /*
+        * Note that its important to have this wrapper function because
+        * in the very near future we will be checking for MMIOs against
+        * the LAPIC as well as the general MMIO bus
+        */
+       return kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
+}
+
+static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
+                                              gpa_t addr)
+{
+       return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr);
+}
+
 static int emulator_read_emulated(unsigned long addr,
                                  void *val,
                                  unsigned int bytes,
                                  struct x86_emulate_ctxt *ctxt)
 {
-       struct kvm_vcpu *vcpu = ctxt->vcpu;
+       struct kvm_vcpu      *vcpu = ctxt->vcpu;
+       struct kvm_io_device *mmio_dev;
+       gpa_t                 gpa;
 
        if (vcpu->mmio_read_completed) {
                memcpy(val, vcpu->mmio_data, bytes);
@@ -1051,18 +1084,26 @@ static int emulator_read_emulated(unsigned long addr,
        } else if (emulator_read_std(addr, val, bytes, ctxt)
                   == X86EMUL_CONTINUE)
                return X86EMUL_CONTINUE;
-       else {
-               gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
 
-               if (gpa == UNMAPPED_GVA)
-                       return X86EMUL_PROPAGATE_FAULT;
-               vcpu->mmio_needed = 1;
-               vcpu->mmio_phys_addr = gpa;
-               vcpu->mmio_size = bytes;
-               vcpu->mmio_is_write = 0;
+       gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
+       if (gpa == UNMAPPED_GVA)
+               return X86EMUL_PROPAGATE_FAULT;
 
-               return X86EMUL_UNHANDLEABLE;
+       /*
+        * Is this MMIO handled locally?
+        */
+       mmio_dev = vcpu_find_mmio_dev(vcpu, gpa);
+       if (mmio_dev) {
+               kvm_iodevice_read(mmio_dev, gpa, bytes, val);
+               return X86EMUL_CONTINUE;
        }
+
+       vcpu->mmio_needed = 1;
+       vcpu->mmio_phys_addr = gpa;
+       vcpu->mmio_size = bytes;
+       vcpu->mmio_is_write = 0;
+
+       return X86EMUL_UNHANDLEABLE;
 }
 
 static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
@@ -1070,18 +1111,20 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
 {
        struct page *page;
        void *virt;
+       unsigned offset = offset_in_page(gpa);
 
        if (((gpa + bytes - 1) >> PAGE_SHIFT) != (gpa >> PAGE_SHIFT))
                return 0;
        page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
        if (!page)
                return 0;
-       kvm_mmu_pre_write(vcpu, gpa, bytes);
        mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT);
        virt = kmap_atomic(page, KM_USER0);
-       memcpy(virt + offset_in_page(gpa), val, bytes);
+       if (memcmp(virt + offset_in_page(gpa), val, bytes)) {
+               kvm_mmu_pte_write(vcpu, gpa, virt + offset, val, bytes);
+               memcpy(virt + offset_in_page(gpa), val, bytes);
+       }
        kunmap_atomic(virt, KM_USER0);
-       kvm_mmu_post_write(vcpu, gpa, bytes);
        return 1;
 }
 
@@ -1090,8 +1133,9 @@ static int emulator_write_emulated(unsigned long addr,
                                   unsigned int bytes,
                                   struct x86_emulate_ctxt *ctxt)
 {
-       struct kvm_vcpu *vcpu = ctxt->vcpu;
-       gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
+       struct kvm_vcpu      *vcpu = ctxt->vcpu;
+       struct kvm_io_device *mmio_dev;
+       gpa_t                 gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
 
        if (gpa == UNMAPPED_GVA) {
                kvm_arch_ops->inject_page_fault(vcpu, addr, 2);
@@ -1101,6 +1145,15 @@ static int emulator_write_emulated(unsigned long addr,
        if (emulator_write_phys(vcpu, gpa, val, bytes))
                return X86EMUL_CONTINUE;
 
+       /*
+        * Is this MMIO handled locally?
+        */
+       mmio_dev = vcpu_find_mmio_dev(vcpu, gpa);
+       if (mmio_dev) {
+               kvm_iodevice_write(mmio_dev, gpa, bytes, val);
+               return X86EMUL_CONTINUE;
+       }
+
        vcpu->mmio_needed = 1;
        vcpu->mmio_phys_addr = gpa;
        vcpu->mmio_size = bytes;
@@ -1269,6 +1322,17 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
 }
 EXPORT_SYMBOL_GPL(emulate_instruction);
 
+int kvm_emulate_halt(struct kvm_vcpu *vcpu)
+{
+       if (vcpu->irq_summary)
+               return 1;
+
+       vcpu->run->exit_reason = KVM_EXIT_HLT;
+       ++vcpu->stat.halt_exits;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_emulate_halt);
+
 int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
        unsigned long nr, a0, a1, a2, a3, a4, a5, ret;
@@ -1469,6 +1533,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
        case MSR_IA32_MC0_MISC+16:
        case MSR_IA32_UCODE_REV:
        case MSR_IA32_PERF_STATUS:
+       case MSR_IA32_EBL_CR_POWERON:
                /* MTRR registers */
        case 0xfe:
        case 0x200 ... 0x2ff:
@@ -1727,6 +1792,20 @@ static int complete_pio(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+void kernel_pio(struct kvm_io_device *pio_dev, struct kvm_vcpu *vcpu)
+{
+       /* TODO: String I/O for in kernel device */
+
+       if (vcpu->pio.in)
+               kvm_iodevice_read(pio_dev, vcpu->pio.port,
+                                 vcpu->pio.size,
+                                 vcpu->pio_data);
+       else
+               kvm_iodevice_write(pio_dev, vcpu->pio.port,
+                                  vcpu->pio.size,
+                                  vcpu->pio_data);
+}
+
 int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
                  int size, unsigned long count, int string, int down,
                  gva_t address, int rep, unsigned port)
@@ -1735,6 +1814,7 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
        int i;
        int nr_pages = 1;
        struct page *page;
+       struct kvm_io_device *pio_dev;
 
        vcpu->run->exit_reason = KVM_EXIT_IO;
        vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
@@ -1746,17 +1826,27 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
        vcpu->pio.cur_count = count;
        vcpu->pio.size = size;
        vcpu->pio.in = in;
+       vcpu->pio.port = port;
        vcpu->pio.string = string;
        vcpu->pio.down = down;
        vcpu->pio.guest_page_offset = offset_in_page(address);
        vcpu->pio.rep = rep;
 
+       pio_dev = vcpu_find_pio_dev(vcpu, port);
        if (!string) {
                kvm_arch_ops->cache_regs(vcpu);
                memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4);
                kvm_arch_ops->decache_regs(vcpu);
+               if (pio_dev) {
+                       kernel_pio(pio_dev, vcpu);
+                       complete_pio(vcpu);
+                       return 1;
+               }
                return 0;
        }
+       /* TODO: String I/O for in kernel device */
+       if (pio_dev)
+               printk(KERN_ERR "kvm_setup_pio: no string io support\n");
 
        if (!count) {
                kvm_arch_ops->skip_emulated_instruction(vcpu);
@@ -2273,34 +2363,12 @@ static int create_vcpu_fd(struct kvm_vcpu *vcpu)
        struct inode *inode;
        struct file *file;
 
+       r = anon_inode_getfd(&fd, &inode, &file,
+                            "kvm-vcpu", &kvm_vcpu_fops, vcpu);
+       if (r)
+               return r;
        atomic_inc(&vcpu->kvm->filp->f_count);
-       inode = kvmfs_inode(&kvm_vcpu_fops);
-       if (IS_ERR(inode)) {
-               r = PTR_ERR(inode);
-               goto out1;
-       }
-
-       file = kvmfs_file(inode, vcpu);
-       if (IS_ERR(file)) {
-               r = PTR_ERR(file);
-               goto out2;
-       }
-
-       r = get_unused_fd();
-       if (r < 0)
-               goto out3;
-       fd = r;
-       fd_install(fd, file);
-
        return fd;
-
-out3:
-       fput(file);
-out2:
-       iput(inode);
-out1:
-       fput(vcpu->kvm->filp);
-       return r;
 }
 
 /*
@@ -2363,6 +2431,11 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
        if (r < 0)
                goto out_free_vcpus;
 
+       spin_lock(&kvm_lock);
+       if (n >= kvm->nvcpus)
+               kvm->nvcpus = n + 1;
+       spin_unlock(&kvm_lock);
+
        return r;
 
 out_free_vcpus:
@@ -2376,6 +2449,27 @@ out:
        return r;
 }
 
+static void cpuid_fix_nx_cap(struct kvm_vcpu *vcpu)
+{
+       u64 efer;
+       int i;
+       struct kvm_cpuid_entry *e, *entry;
+
+       rdmsrl(MSR_EFER, efer);
+       entry = NULL;
+       for (i = 0; i < vcpu->cpuid_nent; ++i) {
+               e = &vcpu->cpuid_entries[i];
+               if (e->function == 0x80000001) {
+                       entry = e;
+                       break;
+               }
+       }
+       if (entry && (entry->edx & EFER_NX) && !(efer & EFER_NX)) {
+               entry->edx &= ~(1 << 20);
+               printk(KERN_INFO ": guest NX capability removed\n");
+       }
+}
+
 static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
                                    struct kvm_cpuid *cpuid,
                                    struct kvm_cpuid_entry __user *entries)
@@ -2390,6 +2484,7 @@ static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
                           cpuid->nent * sizeof(struct kvm_cpuid_entry)))
                goto out;
        vcpu->cpuid_nent = cpuid->nent;
+       cpuid_fix_nx_cap(vcpu);
        return 0;
 
 out:
@@ -2738,41 +2833,18 @@ static int kvm_dev_ioctl_create_vm(void)
        struct file *file;
        struct kvm *kvm;
 
-       inode = kvmfs_inode(&kvm_vm_fops);
-       if (IS_ERR(inode)) {
-               r = PTR_ERR(inode);
-               goto out1;
-       }
-
        kvm = kvm_create_vm();
-       if (IS_ERR(kvm)) {
-               r = PTR_ERR(kvm);
-               goto out2;
+       if (IS_ERR(kvm))
+               return PTR_ERR(kvm);
+       r = anon_inode_getfd(&fd, &inode, &file, "kvm-vm", &kvm_vm_fops, kvm);
+       if (r) {
+               kvm_destroy_vm(kvm);
+               return r;
        }
 
-       file = kvmfs_file(inode, kvm);
-       if (IS_ERR(file)) {
-               r = PTR_ERR(file);
-               goto out3;
-       }
        kvm->filp = file;
 
-       r = get_unused_fd();
-       if (r < 0)
-               goto out4;
-       fd = r;
-       fd_install(fd, file);
-
        return fd;
-
-out4:
-       fput(file);
-out3:
-       kvm_destroy_vm(kvm);
-out2:
-       iput(inode);
-out1:
-       return r;
 }
 
 static long kvm_dev_ioctl(struct file *filp,
@@ -2862,7 +2934,7 @@ static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
                 * in vmx root mode.
                 */
                printk(KERN_INFO "kvm: exiting hardware virtualization\n");
-               on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
+               on_each_cpu(hardware_disable, NULL, 0, 1);
        }
        return NOTIFY_OK;
 }
@@ -2905,33 +2977,88 @@ static void decache_vcpus_on_cpu(int cpu)
        spin_unlock(&kvm_lock);
 }
 
+static void hardware_enable(void *junk)
+{
+       int cpu = raw_smp_processor_id();
+
+       if (cpu_isset(cpu, cpus_hardware_enabled))
+               return;
+       cpu_set(cpu, cpus_hardware_enabled);
+       kvm_arch_ops->hardware_enable(NULL);
+}
+
+static void hardware_disable(void *junk)
+{
+       int cpu = raw_smp_processor_id();
+
+       if (!cpu_isset(cpu, cpus_hardware_enabled))
+               return;
+       cpu_clear(cpu, cpus_hardware_enabled);
+       decache_vcpus_on_cpu(cpu);
+       kvm_arch_ops->hardware_disable(NULL);
+}
+
 static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
                           void *v)
 {
        int cpu = (long)v;
 
        switch (val) {
-       case CPU_DOWN_PREPARE:
-       case CPU_DOWN_PREPARE_FROZEN:
+       case CPU_DYING:
+       case CPU_DYING_FROZEN:
        case CPU_UP_CANCELED:
        case CPU_UP_CANCELED_FROZEN:
                printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
                       cpu);
-               decache_vcpus_on_cpu(cpu);
-               smp_call_function_single(cpu, kvm_arch_ops->hardware_disable,
-                                        NULL, 0, 1);
+               smp_call_function_single(cpu, hardware_disable, NULL, 0, 1);
                break;
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
                printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n",
                       cpu);
-               smp_call_function_single(cpu, kvm_arch_ops->hardware_enable,
-                                        NULL, 0, 1);
+               smp_call_function_single(cpu, hardware_enable, NULL, 0, 1);
                break;
        }
        return NOTIFY_OK;
 }
 
+void kvm_io_bus_init(struct kvm_io_bus *bus)
+{
+       memset(bus, 0, sizeof(*bus));
+}
+
+void kvm_io_bus_destroy(struct kvm_io_bus *bus)
+{
+       int i;
+
+       for (i = 0; i < bus->dev_count; i++) {
+               struct kvm_io_device *pos = bus->devs[i];
+
+               kvm_iodevice_destructor(pos);
+       }
+}
+
+struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr)
+{
+       int i;
+
+       for (i = 0; i < bus->dev_count; i++) {
+               struct kvm_io_device *pos = bus->devs[i];
+
+               if (pos->in_range(pos, addr))
+                       return pos;
+       }
+
+       return NULL;
+}
+
+void kvm_io_bus_register_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev)
+{
+       BUG_ON(bus->dev_count > (NR_IOBUS_DEVS-1));
+
+       bus->devs[bus->dev_count++] = dev;
+}
+
 static struct notifier_block kvm_cpu_notifier = {
        .notifier_call = kvm_cpu_hotplug,
        .priority = 20, /* must be > scheduler priority */
@@ -2983,14 +3110,13 @@ static void kvm_exit_debug(void)
 
 static int kvm_suspend(struct sys_device *dev, pm_message_t state)
 {
-       decache_vcpus_on_cpu(raw_smp_processor_id());
-       on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
+       hardware_disable(NULL);
        return 0;
 }
 
 static int kvm_resume(struct sys_device *dev)
 {
-       on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1);
+       hardware_enable(NULL);
        return 0;
 }
 
@@ -3007,18 +3133,6 @@ static struct sys_device kvm_sysdev = {
 
 hpa_t bad_page_address;
 
-static int kvmfs_get_sb(struct file_system_type *fs_type, int flags,
-                       const char *dev_name, void *data, struct vfsmount *mnt)
-{
-       return get_sb_pseudo(fs_type, "kvm:", NULL, KVMFS_SUPER_MAGIC, mnt);
-}
-
-static struct file_system_type kvm_fs_type = {
-       .name           = "kvmfs",
-       .get_sb         = kvmfs_get_sb,
-       .kill_sb        = kill_anon_super,
-};
-
 int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
 {
        int r;
@@ -3043,7 +3157,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
        if (r < 0)
                goto out;
 
-       on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1);
+       on_each_cpu(hardware_enable, NULL, 0, 1);
        r = register_cpu_notifier(&kvm_cpu_notifier);
        if (r)
                goto out_free_1;
@@ -3075,7 +3189,7 @@ out_free_2:
        unregister_reboot_notifier(&kvm_reboot_notifier);
        unregister_cpu_notifier(&kvm_cpu_notifier);
 out_free_1:
-       on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
+       on_each_cpu(hardware_disable, NULL, 0, 1);
        kvm_arch_ops->hardware_unsetup();
 out:
        kvm_arch_ops = NULL;
@@ -3089,7 +3203,7 @@ void kvm_exit_arch(void)
        sysdev_class_unregister(&kvm_sysdev_class);
        unregister_reboot_notifier(&kvm_reboot_notifier);
        unregister_cpu_notifier(&kvm_cpu_notifier);
-       on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
+       on_each_cpu(hardware_disable, NULL, 0, 1);
        kvm_arch_ops->hardware_unsetup();
        kvm_arch_ops = NULL;
 }
@@ -3103,14 +3217,6 @@ static __init int kvm_init(void)
        if (r)
                goto out4;
 
-       r = register_filesystem(&kvm_fs_type);
-       if (r)
-               goto out3;
-
-       kvmfs_mnt = kern_mount(&kvm_fs_type);
-       r = PTR_ERR(kvmfs_mnt);
-       if (IS_ERR(kvmfs_mnt))
-               goto out2;
        kvm_init_debug();
 
        kvm_init_msr_list();
@@ -3127,10 +3233,6 @@ static __init int kvm_init(void)
 
 out:
        kvm_exit_debug();
-       mntput(kvmfs_mnt);
-out2:
-       unregister_filesystem(&kvm_fs_type);
-out3:
        kvm_mmu_module_exit();
 out4:
        return r;
@@ -3140,8 +3242,6 @@ static __exit void kvm_exit(void)
 {
        kvm_exit_debug();
        __free_page(pfn_to_page(bad_page_address >> PAGE_SHIFT));
-       mntput(kvmfs_mnt);
-       unregister_filesystem(&kvm_fs_type);
        kvm_mmu_module_exit();
 }
 
index e8e228118de9be496660ac8fa9ece297a39c1b57..b297a6b111ac077074f3519e4dcbb8e6332ed8f8 100644 (file)
  * the COPYING file in the top-level directory.
  *
  */
+
+#include "vmx.h"
+#include "kvm.h"
+
 #include <linux/types.h>
 #include <linux/string.h>
-#include <asm/page.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
 #include <linux/module.h>
 
-#include "vmx.h"
-#include "kvm.h"
+#include <asm/page.h>
+#include <asm/cmpxchg.h>
 
 #undef MMU_DEBUG
 
@@ -90,25 +93,11 @@ static int dbg = 1;
 #define PT32_DIR_PSE36_MASK (((1ULL << PT32_DIR_PSE36_SIZE) - 1) << PT32_DIR_PSE36_SHIFT)
 
 
-#define PT32_PTE_COPY_MASK \
-       (PT_PRESENT_MASK | PT_ACCESSED_MASK | PT_DIRTY_MASK | PT_GLOBAL_MASK)
-
-#define PT64_PTE_COPY_MASK (PT64_NX_MASK | PT32_PTE_COPY_MASK)
-
 #define PT_FIRST_AVAIL_BITS_SHIFT 9
 #define PT64_SECOND_AVAIL_BITS_SHIFT 52
 
-#define PT_SHADOW_PS_MARK (1ULL << PT_FIRST_AVAIL_BITS_SHIFT)
 #define PT_SHADOW_IO_MARK (1ULL << PT_FIRST_AVAIL_BITS_SHIFT)
 
-#define PT_SHADOW_WRITABLE_SHIFT (PT_FIRST_AVAIL_BITS_SHIFT + 1)
-#define PT_SHADOW_WRITABLE_MASK (1ULL << PT_SHADOW_WRITABLE_SHIFT)
-
-#define PT_SHADOW_USER_SHIFT (PT_SHADOW_WRITABLE_SHIFT + 1)
-#define PT_SHADOW_USER_MASK (1ULL << (PT_SHADOW_USER_SHIFT))
-
-#define PT_SHADOW_BITS_OFFSET (PT_SHADOW_WRITABLE_SHIFT - PT_WRITABLE_SHIFT)
-
 #define VALID_PAGE(x) ((x) != INVALID_PAGE)
 
 #define PT64_LEVEL_BITS 9
@@ -165,6 +154,8 @@ struct kvm_rmap_desc {
 
 static struct kmem_cache *pte_chain_cache;
 static struct kmem_cache *rmap_desc_cache;
+static struct kmem_cache *mmu_page_cache;
+static struct kmem_cache *mmu_page_header_cache;
 
 static int is_write_protection(struct kvm_vcpu *vcpu)
 {
@@ -202,6 +193,15 @@ static int is_rmap_pte(u64 pte)
                == (PT_WRITABLE_MASK | PT_PRESENT_MASK);
 }
 
+static void set_shadow_pte(u64 *sptep, u64 spte)
+{
+#ifdef CONFIG_X86_64
+       set_64bit((unsigned long *)sptep, spte);
+#else
+       set_64bit((unsigned long long *)sptep, spte);
+#endif
+}
+
 static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
                                  struct kmem_cache *base_cache, int min,
                                  gfp_t gfp_flags)
@@ -235,6 +235,14 @@ static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
                goto out;
        r = mmu_topup_memory_cache(&vcpu->mmu_rmap_desc_cache,
                                   rmap_desc_cache, 1, gfp_flags);
+       if (r)
+               goto out;
+       r = mmu_topup_memory_cache(&vcpu->mmu_page_cache,
+                                  mmu_page_cache, 4, gfp_flags);
+       if (r)
+               goto out;
+       r = mmu_topup_memory_cache(&vcpu->mmu_page_header_cache,
+                                  mmu_page_header_cache, 4, gfp_flags);
 out:
        return r;
 }
@@ -258,6 +266,8 @@ static void mmu_free_memory_caches(struct kvm_vcpu *vcpu)
 {
        mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache);
        mmu_free_memory_cache(&vcpu->mmu_rmap_desc_cache);
+       mmu_free_memory_cache(&vcpu->mmu_page_cache);
+       mmu_free_memory_cache(&vcpu->mmu_page_header_cache);
 }
 
 static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc,
@@ -433,19 +443,18 @@ static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
                BUG_ON(!(*spte & PT_WRITABLE_MASK));
                rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
                rmap_remove(vcpu, spte);
-               kvm_arch_ops->tlb_flush(vcpu);
-               *spte &= ~(u64)PT_WRITABLE_MASK;
+               set_shadow_pte(spte, *spte & ~PT_WRITABLE_MASK);
+               kvm_flush_remote_tlbs(vcpu->kvm);
        }
 }
 
 #ifdef MMU_DEBUG
-static int is_empty_shadow_page(hpa_t page_hpa)
+static int is_empty_shadow_page(u64 *spt)
 {
        u64 *pos;
        u64 *end;
 
-       for (pos = __va(page_hpa), end = pos + PAGE_SIZE / sizeof(u64);
-                     pos != end; pos++)
+       for (pos = spt, end = pos + PAGE_SIZE / sizeof(u64); pos != end; pos++)
                if (*pos != 0) {
                        printk(KERN_ERR "%s: %p %llx\n", __FUNCTION__,
                               pos, *pos);
@@ -455,13 +464,13 @@ static int is_empty_shadow_page(hpa_t page_hpa)
 }
 #endif
 
-static void kvm_mmu_free_page(struct kvm_vcpu *vcpu, hpa_t page_hpa)
+static void kvm_mmu_free_page(struct kvm_vcpu *vcpu,
+                             struct kvm_mmu_page *page_head)
 {
-       struct kvm_mmu_page *page_head = page_header(page_hpa);
-
-       ASSERT(is_empty_shadow_page(page_hpa));
-       page_head->page_hpa = page_hpa;
-       list_move(&page_head->link, &vcpu->free_pages);
+       ASSERT(is_empty_shadow_page(page_head->spt));
+       list_del(&page_head->link);
+       mmu_memory_cache_free(&vcpu->mmu_page_cache, page_head->spt);
+       mmu_memory_cache_free(&vcpu->mmu_page_header_cache, page_head);
        ++vcpu->kvm->n_free_mmu_pages;
 }
 
@@ -475,12 +484,15 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
 {
        struct kvm_mmu_page *page;
 
-       if (list_empty(&vcpu->free_pages))
+       if (!vcpu->kvm->n_free_mmu_pages)
                return NULL;
 
-       page = list_entry(vcpu->free_pages.next, struct kvm_mmu_page, link);
-       list_move(&page->link, &vcpu->kvm->active_mmu_pages);
-       ASSERT(is_empty_shadow_page(page->page_hpa));
+       page = mmu_memory_cache_alloc(&vcpu->mmu_page_header_cache,
+                                     sizeof *page);
+       page->spt = mmu_memory_cache_alloc(&vcpu->mmu_page_cache, PAGE_SIZE);
+       set_page_private(virt_to_page(page->spt), (unsigned long)page);
+       list_add(&page->link, &vcpu->kvm->active_mmu_pages);
+       ASSERT(is_empty_shadow_page(page->spt));
        page->slot_bitmap = 0;
        page->multimapped = 0;
        page->parent_pte = parent_pte;
@@ -638,7 +650,7 @@ static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
        u64 *pt;
        u64 ent;
 
-       pt = __va(page->page_hpa);
+       pt = page->spt;
 
        if (page->role.level == PT_PAGE_TABLE_LEVEL) {
                for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
@@ -646,7 +658,7 @@ static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
                                rmap_remove(vcpu, &pt[i]);
                        pt[i] = 0;
                }
-               kvm_arch_ops->tlb_flush(vcpu);
+               kvm_flush_remote_tlbs(vcpu->kvm);
                return;
        }
 
@@ -659,6 +671,7 @@ static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
                ent &= PT64_BASE_ADDR_MASK;
                mmu_page_remove_parent_pte(vcpu, page_header(ent), &pt[i]);
        }
+       kvm_flush_remote_tlbs(vcpu->kvm);
 }
 
 static void kvm_mmu_put_page(struct kvm_vcpu *vcpu,
@@ -685,12 +698,12 @@ static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu,
                }
                BUG_ON(!parent_pte);
                kvm_mmu_put_page(vcpu, page, parent_pte);
-               *parent_pte = 0;
+               set_shadow_pte(parent_pte, 0);
        }
        kvm_mmu_page_unlink_children(vcpu, page);
        if (!page->root_count) {
                hlist_del(&page->hash_link);
-               kvm_mmu_free_page(vcpu, page->page_hpa);
+               kvm_mmu_free_page(vcpu, page);
        } else
                list_move(&page->link, &vcpu->kvm->active_mmu_pages);
 }
@@ -717,6 +730,17 @@ static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
        return r;
 }
 
+static void mmu_unshadow(struct kvm_vcpu *vcpu, gfn_t gfn)
+{
+       struct kvm_mmu_page *page;
+
+       while ((page = kvm_mmu_lookup_page(vcpu, gfn)) != NULL) {
+               pgprintk("%s: zap %lx %x\n",
+                        __FUNCTION__, gfn, page->role.word);
+               kvm_mmu_zap_page(vcpu, page);
+       }
+}
+
 static void page_header_update_slot(struct kvm *kvm, void *pte, gpa_t gpa)
 {
        int slot = memslot_id(kvm, gfn_to_memslot(kvm, gpa >> PAGE_SHIFT));
@@ -805,7 +829,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, hpa_t p)
                                return -ENOMEM;
                        }
 
-                       table[index] = new_table->page_hpa | PT_PRESENT_MASK
+                       table[index] = __pa(new_table->spt) | PT_PRESENT_MASK
                                | PT_WRITABLE_MASK | PT_USER_MASK;
                }
                table_addr = table[index] & PT64_BASE_ADDR_MASK;
@@ -817,11 +841,12 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu)
        int i;
        struct kvm_mmu_page *page;
 
+       if (!VALID_PAGE(vcpu->mmu.root_hpa))
+               return;
 #ifdef CONFIG_X86_64
        if (vcpu->mmu.shadow_root_level == PT64_ROOT_LEVEL) {
                hpa_t root = vcpu->mmu.root_hpa;
 
-               ASSERT(VALID_PAGE(root));
                page = page_header(root);
                --page->root_count;
                vcpu->mmu.root_hpa = INVALID_PAGE;
@@ -832,7 +857,6 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu)
                hpa_t root = vcpu->mmu.pae_root[i];
 
                if (root) {
-                       ASSERT(VALID_PAGE(root));
                        root &= PT64_BASE_ADDR_MASK;
                        page = page_header(root);
                        --page->root_count;
@@ -857,7 +881,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu)
                ASSERT(!VALID_PAGE(root));
                page = kvm_mmu_get_page(vcpu, root_gfn, 0,
                                        PT64_ROOT_LEVEL, 0, 0, NULL);
-               root = page->page_hpa;
+               root = __pa(page->spt);
                ++page->root_count;
                vcpu->mmu.root_hpa = root;
                return;
@@ -878,7 +902,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu)
                page = kvm_mmu_get_page(vcpu, root_gfn, i << 30,
                                        PT32_ROOT_LEVEL, !is_paging(vcpu),
                                        0, NULL);
-               root = page->page_hpa;
+               root = __pa(page->spt);
                ++page->root_count;
                vcpu->mmu.pae_root[i] = root | PT_PRESENT_MASK;
        }
@@ -928,9 +952,7 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu)
        context->free = nonpaging_free;
        context->root_level = 0;
        context->shadow_root_level = PT32E_ROOT_LEVEL;
-       mmu_alloc_roots(vcpu);
-       ASSERT(VALID_PAGE(context->root_hpa));
-       kvm_arch_ops->set_cr3(vcpu, context->root_hpa);
+       context->root_hpa = INVALID_PAGE;
        return 0;
 }
 
@@ -944,59 +966,6 @@ static void paging_new_cr3(struct kvm_vcpu *vcpu)
 {
        pgprintk("%s: cr3 %lx\n", __FUNCTION__, vcpu->cr3);
        mmu_free_roots(vcpu);
-       if (unlikely(vcpu->kvm->n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
-               kvm_mmu_free_some_pages(vcpu);
-       mmu_alloc_roots(vcpu);
-       kvm_mmu_flush_tlb(vcpu);
-       kvm_arch_ops->set_cr3(vcpu, vcpu->mmu.root_hpa);
-}
-
-static inline void set_pte_common(struct kvm_vcpu *vcpu,
-                            u64 *shadow_pte,
-                            gpa_t gaddr,
-                            int dirty,
-                            u64 access_bits,
-                            gfn_t gfn)
-{
-       hpa_t paddr;
-
-       *shadow_pte |= access_bits << PT_SHADOW_BITS_OFFSET;
-       if (!dirty)
-               access_bits &= ~PT_WRITABLE_MASK;
-
-       paddr = gpa_to_hpa(vcpu, gaddr & PT64_BASE_ADDR_MASK);
-
-       *shadow_pte |= access_bits;
-
-       if (is_error_hpa(paddr)) {
-               *shadow_pte |= gaddr;
-               *shadow_pte |= PT_SHADOW_IO_MARK;
-               *shadow_pte &= ~PT_PRESENT_MASK;
-               return;
-       }
-
-       *shadow_pte |= paddr;
-
-       if (access_bits & PT_WRITABLE_MASK) {
-               struct kvm_mmu_page *shadow;
-
-               shadow = kvm_mmu_lookup_page(vcpu, gfn);
-               if (shadow) {
-                       pgprintk("%s: found shadow page for %lx, marking ro\n",
-                                __FUNCTION__, gfn);
-                       access_bits &= ~PT_WRITABLE_MASK;
-                       if (is_writeble_pte(*shadow_pte)) {
-                                   *shadow_pte &= ~PT_WRITABLE_MASK;
-                                   kvm_arch_ops->tlb_flush(vcpu);
-                       }
-               }
-       }
-
-       if (access_bits & PT_WRITABLE_MASK)
-               mark_page_dirty(vcpu->kvm, gaddr >> PAGE_SHIFT);
-
-       page_header_update_slot(vcpu->kvm, shadow_pte, gaddr);
-       rmap_add(vcpu, shadow_pte);
 }
 
 static void inject_page_fault(struct kvm_vcpu *vcpu,
@@ -1006,23 +975,6 @@ static void inject_page_fault(struct kvm_vcpu *vcpu,
        kvm_arch_ops->inject_page_fault(vcpu, addr, err_code);
 }
 
-static inline int fix_read_pf(u64 *shadow_ent)
-{
-       if ((*shadow_ent & PT_SHADOW_USER_MASK) &&
-           !(*shadow_ent & PT_USER_MASK)) {
-               /*
-                * If supervisor write protect is disabled, we shadow kernel
-                * pages as user pages so we can trap the write access.
-                */
-               *shadow_ent |= PT_USER_MASK;
-               *shadow_ent &= ~PT_WRITABLE_MASK;
-
-               return 1;
-
-       }
-       return 0;
-}
-
 static void paging_free(struct kvm_vcpu *vcpu)
 {
        nonpaging_free(vcpu);
@@ -1047,10 +999,7 @@ static int paging64_init_context_common(struct kvm_vcpu *vcpu, int level)
        context->free = paging_free;
        context->root_level = level;
        context->shadow_root_level = level;
-       mmu_alloc_roots(vcpu);
-       ASSERT(VALID_PAGE(context->root_hpa));
-       kvm_arch_ops->set_cr3(vcpu, context->root_hpa |
-                   (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK)));
+       context->root_hpa = INVALID_PAGE;
        return 0;
 }
 
@@ -1069,10 +1018,7 @@ static int paging32_init_context(struct kvm_vcpu *vcpu)
        context->free = paging_free;
        context->root_level = PT32_ROOT_LEVEL;
        context->shadow_root_level = PT32E_ROOT_LEVEL;
-       mmu_alloc_roots(vcpu);
-       ASSERT(VALID_PAGE(context->root_hpa));
-       kvm_arch_ops->set_cr3(vcpu, context->root_hpa |
-                   (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK)));
+       context->root_hpa = INVALID_PAGE;
        return 0;
 }
 
@@ -1106,19 +1052,34 @@ static void destroy_kvm_mmu(struct kvm_vcpu *vcpu)
 }
 
 int kvm_mmu_reset_context(struct kvm_vcpu *vcpu)
+{
+       destroy_kvm_mmu(vcpu);
+       return init_kvm_mmu(vcpu);
+}
+
+int kvm_mmu_load(struct kvm_vcpu *vcpu)
 {
        int r;
 
-       destroy_kvm_mmu(vcpu);
-       r = init_kvm_mmu(vcpu);
-       if (r < 0)
-               goto out;
+       spin_lock(&vcpu->kvm->lock);
        r = mmu_topup_memory_caches(vcpu);
+       if (r)
+               goto out;
+       mmu_alloc_roots(vcpu);
+       kvm_arch_ops->set_cr3(vcpu, vcpu->mmu.root_hpa);
+       kvm_mmu_flush_tlb(vcpu);
 out:
+       spin_unlock(&vcpu->kvm->lock);
        return r;
 }
+EXPORT_SYMBOL_GPL(kvm_mmu_load);
+
+void kvm_mmu_unload(struct kvm_vcpu *vcpu)
+{
+       mmu_free_roots(vcpu);
+}
 
-static void mmu_pre_write_zap_pte(struct kvm_vcpu *vcpu,
+static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
                                  struct kvm_mmu_page *page,
                                  u64 *spte)
 {
@@ -1135,9 +1096,25 @@ static void mmu_pre_write_zap_pte(struct kvm_vcpu *vcpu,
                }
        }
        *spte = 0;
+       kvm_flush_remote_tlbs(vcpu->kvm);
+}
+
+static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
+                                 struct kvm_mmu_page *page,
+                                 u64 *spte,
+                                 const void *new, int bytes)
+{
+       if (page->role.level != PT_PAGE_TABLE_LEVEL)
+               return;
+
+       if (page->role.glevels == PT32_ROOT_LEVEL)
+               paging32_update_pte(vcpu, page, spte, new, bytes);
+       else
+               paging64_update_pte(vcpu, page, spte, new, bytes);
 }
 
-void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes)
+void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
+                      const u8 *old, const u8 *new, int bytes)
 {
        gfn_t gfn = gpa >> PAGE_SHIFT;
        struct kvm_mmu_page *page;
@@ -1149,6 +1126,7 @@ void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes)
        unsigned pte_size;
        unsigned page_offset;
        unsigned misaligned;
+       unsigned quadrant;
        int level;
        int flooded = 0;
        int npte;
@@ -1169,6 +1147,7 @@ void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes)
                        continue;
                pte_size = page->role.glevels == PT32_ROOT_LEVEL ? 4 : 8;
                misaligned = (offset ^ (offset + bytes - 1)) & ~(pte_size - 1);
+               misaligned |= bytes < 4;
                if (misaligned || flooded) {
                        /*
                         * Misaligned accesses are too much trouble to fix
@@ -1200,21 +1179,20 @@ void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes)
                                page_offset <<= 1;
                                npte = 2;
                        }
+                       quadrant = page_offset >> PAGE_SHIFT;
                        page_offset &= ~PAGE_MASK;
+                       if (quadrant != page->role.quadrant)
+                               continue;
                }
-               spte = __va(page->page_hpa);
-               spte += page_offset / sizeof(*spte);
+               spte = &page->spt[page_offset / sizeof(*spte)];
                while (npte--) {
-                       mmu_pre_write_zap_pte(vcpu, page, spte);
+                       mmu_pte_write_zap_pte(vcpu, page, spte);
+                       mmu_pte_write_new_pte(vcpu, page, spte, new, bytes);
                        ++spte;
                }
        }
 }
 
-void kvm_mmu_post_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes)
-{
-}
-
 int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva)
 {
        gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, gva);
@@ -1243,13 +1221,6 @@ static void free_mmu_pages(struct kvm_vcpu *vcpu)
                                    struct kvm_mmu_page, link);
                kvm_mmu_zap_page(vcpu, page);
        }
-       while (!list_empty(&vcpu->free_pages)) {
-               page = list_entry(vcpu->free_pages.next,
-                                 struct kvm_mmu_page, link);
-               list_del(&page->link);
-               __free_page(pfn_to_page(page->page_hpa >> PAGE_SHIFT));
-               page->page_hpa = INVALID_PAGE;
-       }
        free_page((unsigned long)vcpu->mmu.pae_root);
 }
 
@@ -1260,18 +1231,7 @@ static int alloc_mmu_pages(struct kvm_vcpu *vcpu)
 
        ASSERT(vcpu);
 
-       for (i = 0; i < KVM_NUM_MMU_PAGES; i++) {
-               struct kvm_mmu_page *page_header = &vcpu->page_header_buf[i];
-
-               INIT_LIST_HEAD(&page_header->link);
-               if ((page = alloc_page(GFP_KERNEL)) == NULL)
-                       goto error_1;
-               set_page_private(page, (unsigned long)page_header);
-               page_header->page_hpa = (hpa_t)page_to_pfn(page) << PAGE_SHIFT;
-               memset(__va(page_header->page_hpa), 0, PAGE_SIZE);
-               list_add(&page_header->link, &vcpu->free_pages);
-               ++vcpu->kvm->n_free_mmu_pages;
-       }
+       vcpu->kvm->n_free_mmu_pages = KVM_NUM_MMU_PAGES;
 
        /*
         * When emulating 32-bit mode, cr3 is only 32 bits even on x86_64.
@@ -1296,7 +1256,6 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu)
 {
        ASSERT(vcpu);
        ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa));
-       ASSERT(list_empty(&vcpu->free_pages));
 
        return alloc_mmu_pages(vcpu);
 }
@@ -1305,7 +1264,6 @@ int kvm_mmu_setup(struct kvm_vcpu *vcpu)
 {
        ASSERT(vcpu);
        ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa));
-       ASSERT(!list_empty(&vcpu->free_pages));
 
        return init_kvm_mmu(vcpu);
 }
@@ -1331,7 +1289,7 @@ void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot)
                if (!test_bit(slot, &page->slot_bitmap))
                        continue;
 
-               pt = __va(page->page_hpa);
+               pt = page->spt;
                for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
                        /* avoid RMW */
                        if (pt[i] & PT_WRITABLE_MASK) {
@@ -1354,7 +1312,7 @@ void kvm_mmu_zap_all(struct kvm_vcpu *vcpu)
        }
 
        mmu_free_memory_caches(vcpu);
-       kvm_arch_ops->tlb_flush(vcpu);
+       kvm_flush_remote_tlbs(vcpu->kvm);
        init_kvm_mmu(vcpu);
 }
 
@@ -1364,6 +1322,10 @@ void kvm_mmu_module_exit(void)
                kmem_cache_destroy(pte_chain_cache);
        if (rmap_desc_cache)
                kmem_cache_destroy(rmap_desc_cache);
+       if (mmu_page_cache)
+               kmem_cache_destroy(mmu_page_cache);
+       if (mmu_page_header_cache)
+               kmem_cache_destroy(mmu_page_header_cache);
 }
 
 int kvm_mmu_module_init(void)
@@ -1379,6 +1341,18 @@ int kvm_mmu_module_init(void)
        if (!rmap_desc_cache)
                goto nomem;
 
+       mmu_page_cache = kmem_cache_create("kvm_mmu_page",
+                                          PAGE_SIZE,
+                                          PAGE_SIZE, 0, NULL, NULL);
+       if (!mmu_page_cache)
+               goto nomem;
+
+       mmu_page_header_cache = kmem_cache_create("kvm_mmu_page_header",
+                                                 sizeof(struct kvm_mmu_page),
+                                                 0, 0, NULL, NULL);
+       if (!mmu_page_header_cache)
+               goto nomem;
+
        return 0;
 
 nomem:
@@ -1482,7 +1456,7 @@ static int count_writable_mappings(struct kvm_vcpu *vcpu)
        int i;
 
        list_for_each_entry(page, &vcpu->kvm->active_mmu_pages, link) {
-               u64 *pt = __va(page->page_hpa);
+               u64 *pt = page->spt;
 
                if (page->role.level != PT_PAGE_TABLE_LEVEL)
                        continue;
index 73ffbffb1097bf9b70d5cfd0e44a291870613384..a7c5cb0319ea8ae70a18dce47b3c3cafe580662d 100644 (file)
@@ -31,7 +31,6 @@
        #define PT_INDEX(addr, level) PT64_INDEX(addr, level)
        #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level)
        #define PT_LEVEL_MASK(level) PT64_LEVEL_MASK(level)
-       #define PT_PTE_COPY_MASK PT64_PTE_COPY_MASK
        #ifdef CONFIG_X86_64
        #define PT_MAX_FULL_LEVELS 4
        #else
@@ -46,7 +45,6 @@
        #define PT_INDEX(addr, level) PT32_INDEX(addr, level)
        #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level)
        #define PT_LEVEL_MASK(level) PT32_LEVEL_MASK(level)
-       #define PT_PTE_COPY_MASK PT32_PTE_COPY_MASK
        #define PT_MAX_FULL_LEVELS 2
 #else
        #error Invalid PTTYPE value
@@ -192,40 +190,143 @@ static void FNAME(mark_pagetable_dirty)(struct kvm *kvm,
        mark_page_dirty(kvm, walker->table_gfn[walker->level - 1]);
 }
 
-static void FNAME(set_pte)(struct kvm_vcpu *vcpu, u64 guest_pte,
-                          u64 *shadow_pte, u64 access_bits, gfn_t gfn)
+static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
+                                 u64 *shadow_pte,
+                                 gpa_t gaddr,
+                                 pt_element_t *gpte,
+                                 u64 access_bits,
+                                 int user_fault,
+                                 int write_fault,
+                                 int *ptwrite,
+                                 struct guest_walker *walker,
+                                 gfn_t gfn)
 {
-       ASSERT(*shadow_pte == 0);
-       access_bits &= guest_pte;
-       *shadow_pte = (guest_pte & PT_PTE_COPY_MASK);
-       set_pte_common(vcpu, shadow_pte, guest_pte & PT_BASE_ADDR_MASK,
-                      guest_pte & PT_DIRTY_MASK, access_bits, gfn);
+       hpa_t paddr;
+       int dirty = *gpte & PT_DIRTY_MASK;
+       u64 spte = *shadow_pte;
+       int was_rmapped = is_rmap_pte(spte);
+
+       pgprintk("%s: spte %llx gpte %llx access %llx write_fault %d"
+                " user_fault %d gfn %lx\n",
+                __FUNCTION__, spte, (u64)*gpte, access_bits,
+                write_fault, user_fault, gfn);
+
+       if (write_fault && !dirty) {
+               *gpte |= PT_DIRTY_MASK;
+               dirty = 1;
+               FNAME(mark_pagetable_dirty)(vcpu->kvm, walker);
+       }
+
+       spte |= PT_PRESENT_MASK | PT_ACCESSED_MASK | PT_DIRTY_MASK;
+       spte |= *gpte & PT64_NX_MASK;
+       if (!dirty)
+               access_bits &= ~PT_WRITABLE_MASK;
+
+       paddr = gpa_to_hpa(vcpu, gaddr & PT64_BASE_ADDR_MASK);
+
+       spte |= PT_PRESENT_MASK;
+       if (access_bits & PT_USER_MASK)
+               spte |= PT_USER_MASK;
+
+       if (is_error_hpa(paddr)) {
+               spte |= gaddr;
+               spte |= PT_SHADOW_IO_MARK;
+               spte &= ~PT_PRESENT_MASK;
+               set_shadow_pte(shadow_pte, spte);
+               return;
+       }
+
+       spte |= paddr;
+
+       if ((access_bits & PT_WRITABLE_MASK)
+           || (write_fault && !is_write_protection(vcpu) && !user_fault)) {
+               struct kvm_mmu_page *shadow;
+
+               spte |= PT_WRITABLE_MASK;
+               if (user_fault) {
+                       mmu_unshadow(vcpu, gfn);
+                       goto unshadowed;
+               }
+
+               shadow = kvm_mmu_lookup_page(vcpu, gfn);
+               if (shadow) {
+                       pgprintk("%s: found shadow page for %lx, marking ro\n",
+                                __FUNCTION__, gfn);
+                       access_bits &= ~PT_WRITABLE_MASK;
+                       if (is_writeble_pte(spte)) {
+                               spte &= ~PT_WRITABLE_MASK;
+                               kvm_arch_ops->tlb_flush(vcpu);
+                       }
+                       if (write_fault)
+                               *ptwrite = 1;
+               }
+       }
+
+unshadowed:
+
+       if (access_bits & PT_WRITABLE_MASK)
+               mark_page_dirty(vcpu->kvm, gaddr >> PAGE_SHIFT);
+
+       set_shadow_pte(shadow_pte, spte);
+       page_header_update_slot(vcpu->kvm, shadow_pte, gaddr);
+       if (!was_rmapped)
+               rmap_add(vcpu, shadow_pte);
 }
 
-static void FNAME(set_pde)(struct kvm_vcpu *vcpu, u64 guest_pde,
-                          u64 *shadow_pte, u64 access_bits, gfn_t gfn)
+static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t *gpte,
+                          u64 *shadow_pte, u64 access_bits,
+                          int user_fault, int write_fault, int *ptwrite,
+                          struct guest_walker *walker, gfn_t gfn)
+{
+       access_bits &= *gpte;
+       FNAME(set_pte_common)(vcpu, shadow_pte, *gpte & PT_BASE_ADDR_MASK,
+                             gpte, access_bits, user_fault, write_fault,
+                             ptwrite, walker, gfn);
+}
+
+static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
+                             u64 *spte, const void *pte, int bytes)
+{
+       pt_element_t gpte;
+
+       if (bytes < sizeof(pt_element_t))
+               return;
+       gpte = *(const pt_element_t *)pte;
+       if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK))
+               return;
+       pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte);
+       FNAME(set_pte)(vcpu, &gpte, spte, PT_USER_MASK | PT_WRITABLE_MASK, 0,
+                      0, NULL, NULL,
+                      (gpte & PT_BASE_ADDR_MASK) >> PAGE_SHIFT);
+}
+
+static void FNAME(set_pde)(struct kvm_vcpu *vcpu, pt_element_t *gpde,
+                          u64 *shadow_pte, u64 access_bits,
+                          int user_fault, int write_fault, int *ptwrite,
+                          struct guest_walker *walker, gfn_t gfn)
 {
        gpa_t gaddr;
 
-       ASSERT(*shadow_pte == 0);
-       access_bits &= guest_pde;
+       access_bits &= *gpde;
        gaddr = (gpa_t)gfn << PAGE_SHIFT;
        if (PTTYPE == 32 && is_cpuid_PSE36())
-               gaddr |= (guest_pde & PT32_DIR_PSE36_MASK) <<
+               gaddr |= (*gpde & PT32_DIR_PSE36_MASK) <<
                        (32 - PT32_DIR_PSE36_SHIFT);
-       *shadow_pte = guest_pde & PT_PTE_COPY_MASK;
-       set_pte_common(vcpu, shadow_pte, gaddr,
-                      guest_pde & PT_DIRTY_MASK, access_bits, gfn);
+       FNAME(set_pte_common)(vcpu, shadow_pte, gaddr,
+                             gpde, access_bits, user_fault, write_fault,
+                             ptwrite, walker, gfn);
 }
 
 /*
  * Fetch a shadow pte for a specific level in the paging hierarchy.
  */
 static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
-                             struct guest_walker *walker)
+                        struct guest_walker *walker,
+                        int user_fault, int write_fault, int *ptwrite)
 {
        hpa_t shadow_addr;
        int level;
+       u64 *shadow_ent;
        u64 *prev_shadow_ent = NULL;
        pt_element_t *guest_ent = walker->ptep;
 
@@ -242,37 +343,23 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
 
        for (; ; level--) {
                u32 index = SHADOW_PT_INDEX(addr, level);
-               u64 *shadow_ent = ((u64 *)__va(shadow_addr)) + index;
                struct kvm_mmu_page *shadow_page;
                u64 shadow_pte;
                int metaphysical;
                gfn_t table_gfn;
                unsigned hugepage_access = 0;
 
+               shadow_ent = ((u64 *)__va(shadow_addr)) + index;
                if (is_present_pte(*shadow_ent) || is_io_pte(*shadow_ent)) {
                        if (level == PT_PAGE_TABLE_LEVEL)
-                               return shadow_ent;
+                               break;
                        shadow_addr = *shadow_ent & PT64_BASE_ADDR_MASK;
                        prev_shadow_ent = shadow_ent;
                        continue;
                }
 
-               if (level == PT_PAGE_TABLE_LEVEL) {
-
-                       if (walker->level == PT_DIRECTORY_LEVEL) {
-                               if (prev_shadow_ent)
-                                       *prev_shadow_ent |= PT_SHADOW_PS_MARK;
-                               FNAME(set_pde)(vcpu, *guest_ent, shadow_ent,
-                                              walker->inherited_ar,
-                                              walker->gfn);
-                       } else {
-                               ASSERT(walker->level == PT_PAGE_TABLE_LEVEL);
-                               FNAME(set_pte)(vcpu, *guest_ent, shadow_ent,
-                                              walker->inherited_ar,
-                                              walker->gfn);
-                       }
-                       return shadow_ent;
-               }
+               if (level == PT_PAGE_TABLE_LEVEL)
+                       break;
 
                if (level - 1 == PT_PAGE_TABLE_LEVEL
                    && walker->level == PT_DIRECTORY_LEVEL) {
@@ -289,90 +376,24 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
                shadow_page = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1,
                                               metaphysical, hugepage_access,
                                               shadow_ent);
-               shadow_addr = shadow_page->page_hpa;
+               shadow_addr = __pa(shadow_page->spt);
                shadow_pte = shadow_addr | PT_PRESENT_MASK | PT_ACCESSED_MASK
                        | PT_WRITABLE_MASK | PT_USER_MASK;
                *shadow_ent = shadow_pte;
                prev_shadow_ent = shadow_ent;
        }
-}
 
-/*
- * The guest faulted for write.  We need to
- *
- * - check write permissions
- * - update the guest pte dirty bit
- * - update our own dirty page tracking structures
- */
-static int FNAME(fix_write_pf)(struct kvm_vcpu *vcpu,
-                              u64 *shadow_ent,
-                              struct guest_walker *walker,
-                              gva_t addr,
-                              int user,
-                              int *write_pt)
-{
-       pt_element_t *guest_ent;
-       int writable_shadow;
-       gfn_t gfn;
-       struct kvm_mmu_page *page;
-
-       if (is_writeble_pte(*shadow_ent))
-               return !user || (*shadow_ent & PT_USER_MASK);
-
-       writable_shadow = *shadow_ent & PT_SHADOW_WRITABLE_MASK;
-       if (user) {
-               /*
-                * User mode access.  Fail if it's a kernel page or a read-only
-                * page.
-                */
-               if (!(*shadow_ent & PT_SHADOW_USER_MASK) || !writable_shadow)
-                       return 0;
-               ASSERT(*shadow_ent & PT_USER_MASK);
-       } else
-               /*
-                * Kernel mode access.  Fail if it's a read-only page and
-                * supervisor write protection is enabled.
-                */
-               if (!writable_shadow) {
-                       if (is_write_protection(vcpu))
-                               return 0;
-                       *shadow_ent &= ~PT_USER_MASK;
-               }
-
-       guest_ent = walker->ptep;
-
-       if (!is_present_pte(*guest_ent)) {
-               *shadow_ent = 0;
-               return 0;
+       if (walker->level == PT_DIRECTORY_LEVEL) {
+               FNAME(set_pde)(vcpu, guest_ent, shadow_ent,
+                              walker->inherited_ar, user_fault, write_fault,
+                              ptwrite, walker, walker->gfn);
+       } else {
+               ASSERT(walker->level == PT_PAGE_TABLE_LEVEL);
+               FNAME(set_pte)(vcpu, guest_ent, shadow_ent,
+                              walker->inherited_ar, user_fault, write_fault,
+                              ptwrite, walker, walker->gfn);
        }
-
-       gfn = walker->gfn;
-
-       if (user) {
-               /*
-                * Usermode page faults won't be for page table updates.
-                */
-               while ((page = kvm_mmu_lookup_page(vcpu, gfn)) != NULL) {
-                       pgprintk("%s: zap %lx %x\n",
-                                __FUNCTION__, gfn, page->role.word);
-                       kvm_mmu_zap_page(vcpu, page);
-               }
-       } else if (kvm_mmu_lookup_page(vcpu, gfn)) {
-               pgprintk("%s: found shadow page for %lx, marking ro\n",
-                        __FUNCTION__, gfn);
-               mark_page_dirty(vcpu->kvm, gfn);
-               FNAME(mark_pagetable_dirty)(vcpu->kvm, walker);
-               *guest_ent |= PT_DIRTY_MASK;
-               *write_pt = 1;
-               return 0;
-       }
-       mark_page_dirty(vcpu->kvm, gfn);
-       *shadow_ent |= PT_WRITABLE_MASK;
-       FNAME(mark_pagetable_dirty)(vcpu->kvm, walker);
-       *guest_ent |= PT_DIRTY_MASK;
-       rmap_add(vcpu, shadow_ent);
-
-       return 1;
+       return shadow_ent;
 }
 
 /*
@@ -397,7 +418,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
        int fetch_fault = error_code & PFERR_FETCH_MASK;
        struct guest_walker walker;
        u64 *shadow_pte;
-       int fixed;
        int write_pt = 0;
        int r;
 
@@ -421,27 +441,20 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
                pgprintk("%s: guest page fault\n", __FUNCTION__);
                inject_page_fault(vcpu, addr, walker.error_code);
                FNAME(release_walker)(&walker);
+               vcpu->last_pt_write_count = 0; /* reset fork detector */
                return 0;
        }
 
-       shadow_pte = FNAME(fetch)(vcpu, addr, &walker);
-       pgprintk("%s: shadow pte %p %llx\n", __FUNCTION__,
-                shadow_pte, *shadow_pte);
-
-       /*
-        * Update the shadow pte.
-        */
-       if (write_fault)
-               fixed = FNAME(fix_write_pf)(vcpu, shadow_pte, &walker, addr,
-                                           user_fault, &write_pt);
-       else
-               fixed = fix_read_pf(shadow_pte);
-
-       pgprintk("%s: updated shadow pte %p %llx\n", __FUNCTION__,
-                shadow_pte, *shadow_pte);
+       shadow_pte = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault,
+                                 &write_pt);
+       pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __FUNCTION__,
+                shadow_pte, *shadow_pte, write_pt);
 
        FNAME(release_walker)(&walker);
 
+       if (!write_pt)
+               vcpu->last_pt_write_count = 0; /* reset fork detector */
+
        /*
         * mmio: emulate if accessible, otherwise its a guest fault.
         */
@@ -478,7 +491,5 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr)
 #undef PT_INDEX
 #undef SHADOW_PT_INDEX
 #undef PT_LEVEL_MASK
-#undef PT_PTE_COPY_MASK
-#undef PT_NON_PTE_COPY_MASK
 #undef PT_DIR_BASE_ADDR_MASK
 #undef PT_MAX_FULL_LEVELS
index fa17d6d4f0cb64f0052e41194ee15cbb775cd070..bc818cc126e385f7556df64614062aafc66b1102 100644 (file)
  *
  */
 
+#include "kvm_svm.h"
+#include "x86_emulate.h"
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/vmalloc.h>
 #include <linux/highmem.h>
 #include <linux/profile.h>
 #include <linux/sched.h>
-#include <asm/desc.h>
 
-#include "kvm_svm.h"
-#include "x86_emulate.h"
+#include <asm/desc.h>
 
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
@@ -378,7 +379,7 @@ static __init int svm_hardware_setup(void)
        int cpu;
        struct page *iopm_pages;
        struct page *msrpm_pages;
-       void *msrpm_va;
+       void *iopm_va, *msrpm_va;
        int r;
 
        kvm_emulator_want_group7_invlpg();
@@ -387,8 +388,10 @@ static __init int svm_hardware_setup(void)
 
        if (!iopm_pages)
                return -ENOMEM;
-       memset(page_address(iopm_pages), 0xff,
-                                       PAGE_SIZE * (1 << IOPM_ALLOC_ORDER));
+
+       iopm_va = page_address(iopm_pages);
+       memset(iopm_va, 0xff, PAGE_SIZE * (1 << IOPM_ALLOC_ORDER));
+       clear_bit(0x80, iopm_va); /* allow direct access to PC debug port */
        iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT;
 
 
@@ -579,7 +582,7 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu)
                goto out2;
 
        vcpu->svm->vmcb = page_address(page);
-       memset(vcpu->svm->vmcb, 0, PAGE_SIZE);
+       clear_page(vcpu->svm->vmcb);
        vcpu->svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
        vcpu->svm->asid_generation = 0;
        memset(vcpu->svm->db_regs, 0, sizeof(vcpu->svm->db_regs));
@@ -587,9 +590,9 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu)
 
        fx_init(vcpu);
        vcpu->fpu_active = 1;
-       vcpu->apic_base = 0xfee00000 |
-                       /*for vcpu 0*/ MSR_IA32_APICBASE_BSP |
-                       MSR_IA32_APICBASE_ENABLE;
+       vcpu->apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
+       if (vcpu == &vcpu->kvm->vcpus[0])
+               vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
 
        return 0;
 
@@ -955,7 +958,7 @@ static int shutdown_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
         * VMCB is undefined after a SHUTDOWN intercept
         * so reinitialize it.
         */
-       memset(vcpu->svm->vmcb, 0, PAGE_SIZE);
+       clear_page(vcpu->svm->vmcb);
        init_vmcb(vcpu->svm->vmcb);
 
        kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
@@ -1113,12 +1116,7 @@ static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
        vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 1;
        skip_emulated_instruction(vcpu);
-       if (vcpu->irq_summary)
-               return 1;
-
-       kvm_run->exit_reason = KVM_EXIT_HLT;
-       ++vcpu->stat.halt_exits;
-       return 0;
+       return kvm_emulate_halt(vcpu);
 }
 
 static int vmmcall_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -1473,6 +1471,11 @@ static void load_db_regs(unsigned long *db_regs)
        asm volatile ("mov %0, %%dr3" : : "r"(db_regs[3]));
 }
 
+static void svm_flush_tlb(struct kvm_vcpu *vcpu)
+{
+       force_new_asid(vcpu);
+}
+
 static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
        u16 fs_selector;
@@ -1481,11 +1484,20 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        int r;
 
 again:
+       r = kvm_mmu_reload(vcpu);
+       if (unlikely(r))
+               return r;
+
        if (!vcpu->mmio_read_completed)
                do_interrupt_requests(vcpu, kvm_run);
 
        clgi();
 
+       vcpu->guest_mode = 1;
+       if (vcpu->requests)
+               if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests))
+                   svm_flush_tlb(vcpu);
+
        pre_svm_run(vcpu);
 
        save_host_msrs(vcpu);
@@ -1617,6 +1629,8 @@ again:
 #endif
                : "cc", "memory" );
 
+       vcpu->guest_mode = 0;
+
        if (vcpu->fpu_active) {
                fx_save(vcpu->guest_fx_image);
                fx_restore(vcpu->host_fx_image);
@@ -1681,11 +1695,6 @@ again:
        return r;
 }
 
-static void svm_flush_tlb(struct kvm_vcpu *vcpu)
-{
-       force_new_asid(vcpu);
-}
-
 static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root)
 {
        vcpu->svm->vmcb->save.cr3 = root;
@@ -1727,6 +1736,12 @@ static void svm_inject_page_fault(struct kvm_vcpu *vcpu,
 
 static int is_disabled(void)
 {
+       u64 vm_cr;
+
+       rdmsrl(MSR_VM_CR, vm_cr);
+       if (vm_cr & (1 << SVM_VM_CR_SVM_DISABLE))
+               return 1;
+
        return 0;
 }
 
index 5e93814400ce3725db0fb6eb3a07289302f0a79f..3b1b0f35b6cba172ac5fbb58cdceec93cdc7221c 100644 (file)
@@ -175,8 +175,11 @@ struct __attribute__ ((__packed__)) vmcb {
 #define SVM_CPUID_FUNC 0x8000000a
 
 #define MSR_EFER_SVME_MASK (1ULL << 12)
+#define MSR_VM_CR       0xc0010114
 #define MSR_VM_HSAVE_PA 0xc0010117ULL
 
+#define SVM_VM_CR_SVM_DISABLE 4
+
 #define SVM_SELECTOR_S_SHIFT 4
 #define SVM_SELECTOR_DPL_SHIFT 5
 #define SVM_SELECTOR_P_SHIFT 7
index c1ac106ace8c1c99193c9b87667396f4adbfb2c5..80628f69916d85c0c58f02f126ff62cf778ea855 100644 (file)
 
 #include "kvm.h"
 #include "vmx.h"
+#include "segment_descriptor.h"
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
 #include <linux/profile.h>
 #include <linux/sched.h>
+
 #include <asm/io.h>
 #include <asm/desc.h>
 
-#include "segment_descriptor.h"
-
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
+static int init_rmode_tss(struct kvm *kvm);
+
 static DEFINE_PER_CPU(struct vmcs *, vmxarea);
 static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
 
+static struct page *vmx_io_bitmap_a;
+static struct page *vmx_io_bitmap_b;
+
 #ifdef CONFIG_X86_64
 #define HOST_IS_64 1
 #else
 #define HOST_IS_64 0
 #endif
+#define EFER_SAVE_RESTORE_BITS ((u64)EFER_SCE)
 
 static struct vmcs_descriptor {
        int size;
@@ -82,18 +89,17 @@ static const u32 vmx_msr_index[] = {
 };
 #define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index)
 
-#ifdef CONFIG_X86_64
-static unsigned msr_offset_kernel_gs_base;
-#define NR_64BIT_MSRS 4
-/*
- * avoid save/load MSR_SYSCALL_MASK and MSR_LSTAR by std vt
- * mechanism (cpu bug AA24)
- */
-#define NR_BAD_MSRS 2
-#else
-#define NR_64BIT_MSRS 0
-#define NR_BAD_MSRS 0
-#endif
+static inline u64 msr_efer_save_restore_bits(struct vmx_msr_entry msr)
+{
+       return (u64)msr.data & EFER_SAVE_RESTORE_BITS;
+}
+
+static inline int msr_efer_need_save_restore(struct kvm_vcpu *vcpu)
+{
+       int efer_offset = vcpu->msr_offset_efer;
+       return msr_efer_save_restore_bits(vcpu->host_msrs[efer_offset]) !=
+               msr_efer_save_restore_bits(vcpu->guest_msrs[efer_offset]);
+}
 
 static inline int is_page_fault(u32 intr_info)
 {
@@ -115,13 +121,23 @@ static inline int is_external_interrupt(u32 intr_info)
                == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
 }
 
-static struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr)
+static int __find_msr_index(struct kvm_vcpu *vcpu, u32 msr)
 {
        int i;
 
        for (i = 0; i < vcpu->nmsrs; ++i)
                if (vcpu->guest_msrs[i].index == msr)
-                       return &vcpu->guest_msrs[i];
+                       return i;
+       return -1;
+}
+
+static struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr)
+{
+       int i;
+
+       i = __find_msr_index(vcpu, msr);
+       if (i >= 0)
+               return &vcpu->guest_msrs[i];
        return NULL;
 }
 
@@ -147,6 +163,7 @@ static void __vcpu_clear(void *arg)
                vmcs_clear(vcpu->vmcs);
        if (per_cpu(current_vmcs, cpu) == vcpu->vmcs)
                per_cpu(current_vmcs, cpu) = NULL;
+       rdtscll(vcpu->host_tsc);
 }
 
 static void vcpu_clear(struct kvm_vcpu *vcpu)
@@ -234,6 +251,127 @@ static void vmcs_set_bits(unsigned long field, u32 mask)
        vmcs_writel(field, vmcs_readl(field) | mask);
 }
 
+static void update_exception_bitmap(struct kvm_vcpu *vcpu)
+{
+       u32 eb;
+
+       eb = 1u << PF_VECTOR;
+       if (!vcpu->fpu_active)
+               eb |= 1u << NM_VECTOR;
+       if (vcpu->guest_debug.enabled)
+               eb |= 1u << 1;
+       if (vcpu->rmode.active)
+               eb = ~0;
+       vmcs_write32(EXCEPTION_BITMAP, eb);
+}
+
+static void reload_tss(void)
+{
+#ifndef CONFIG_X86_64
+
+       /*
+        * VT restores TR but not its size.  Useless.
+        */
+       struct descriptor_table gdt;
+       struct segment_descriptor *descs;
+
+       get_gdt(&gdt);
+       descs = (void *)gdt.base;
+       descs[GDT_ENTRY_TSS].type = 9; /* available TSS */
+       load_TR_desc();
+#endif
+}
+
+static void load_transition_efer(struct kvm_vcpu *vcpu)
+{
+       u64 trans_efer;
+       int efer_offset = vcpu->msr_offset_efer;
+
+       trans_efer = vcpu->host_msrs[efer_offset].data;
+       trans_efer &= ~EFER_SAVE_RESTORE_BITS;
+       trans_efer |= msr_efer_save_restore_bits(
+                               vcpu->guest_msrs[efer_offset]);
+       wrmsrl(MSR_EFER, trans_efer);
+       vcpu->stat.efer_reload++;
+}
+
+static void vmx_save_host_state(struct kvm_vcpu *vcpu)
+{
+       struct vmx_host_state *hs = &vcpu->vmx_host_state;
+
+       if (hs->loaded)
+               return;
+
+       hs->loaded = 1;
+       /*
+        * Set host fs and gs selectors.  Unfortunately, 22.2.3 does not
+        * allow segment selectors with cpl > 0 or ti == 1.
+        */
+       hs->ldt_sel = read_ldt();
+       hs->fs_gs_ldt_reload_needed = hs->ldt_sel;
+       hs->fs_sel = read_fs();
+       if (!(hs->fs_sel & 7))
+               vmcs_write16(HOST_FS_SELECTOR, hs->fs_sel);
+       else {
+               vmcs_write16(HOST_FS_SELECTOR, 0);
+               hs->fs_gs_ldt_reload_needed = 1;
+       }
+       hs->gs_sel = read_gs();
+       if (!(hs->gs_sel & 7))
+               vmcs_write16(HOST_GS_SELECTOR, hs->gs_sel);
+       else {
+               vmcs_write16(HOST_GS_SELECTOR, 0);
+               hs->fs_gs_ldt_reload_needed = 1;
+       }
+
+#ifdef CONFIG_X86_64
+       vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE));
+       vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE));
+#else
+       vmcs_writel(HOST_FS_BASE, segment_base(hs->fs_sel));
+       vmcs_writel(HOST_GS_BASE, segment_base(hs->gs_sel));
+#endif
+
+#ifdef CONFIG_X86_64
+       if (is_long_mode(vcpu)) {
+               save_msrs(vcpu->host_msrs + vcpu->msr_offset_kernel_gs_base, 1);
+       }
+#endif
+       load_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
+       if (msr_efer_need_save_restore(vcpu))
+               load_transition_efer(vcpu);
+}
+
+static void vmx_load_host_state(struct kvm_vcpu *vcpu)
+{
+       struct vmx_host_state *hs = &vcpu->vmx_host_state;
+
+       if (!hs->loaded)
+               return;
+
+       hs->loaded = 0;
+       if (hs->fs_gs_ldt_reload_needed) {
+               load_ldt(hs->ldt_sel);
+               load_fs(hs->fs_sel);
+               /*
+                * If we have to reload gs, we must take care to
+                * preserve our gs base.
+                */
+               local_irq_disable();
+               load_gs(hs->gs_sel);
+#ifdef CONFIG_X86_64
+               wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE));
+#endif
+               local_irq_enable();
+
+               reload_tss();
+       }
+       save_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
+       load_msrs(vcpu->host_msrs, vcpu->save_nmsrs);
+       if (msr_efer_need_save_restore(vcpu))
+               load_msrs(vcpu->host_msrs + vcpu->msr_offset_efer, 1);
+}
+
 /*
  * Switches to specified vcpu, until a matching vcpu_put(), but assumes
  * vcpu mutex is already taken.
@@ -242,6 +380,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu)
 {
        u64 phys_addr = __pa(vcpu->vmcs);
        int cpu;
+       u64 tsc_this, delta;
 
        cpu = get_cpu();
 
@@ -275,15 +414,43 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu)
 
                rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp);
                vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */
+
+               /*
+                * Make sure the time stamp counter is monotonous.
+                */
+               rdtscll(tsc_this);
+               delta = vcpu->host_tsc - tsc_this;
+               vmcs_write64(TSC_OFFSET, vmcs_read64(TSC_OFFSET) + delta);
        }
 }
 
 static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
 {
+       vmx_load_host_state(vcpu);
        kvm_put_guest_fpu(vcpu);
        put_cpu();
 }
 
+static void vmx_fpu_activate(struct kvm_vcpu *vcpu)
+{
+       if (vcpu->fpu_active)
+               return;
+       vcpu->fpu_active = 1;
+       vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK);
+       if (vcpu->cr0 & CR0_TS_MASK)
+               vmcs_set_bits(GUEST_CR0, CR0_TS_MASK);
+       update_exception_bitmap(vcpu);
+}
+
+static void vmx_fpu_deactivate(struct kvm_vcpu *vcpu)
+{
+       if (!vcpu->fpu_active)
+               return;
+       vcpu->fpu_active = 0;
+       vmcs_set_bits(GUEST_CR0, CR0_TS_MASK);
+       update_exception_bitmap(vcpu);
+}
+
 static void vmx_vcpu_decache(struct kvm_vcpu *vcpu)
 {
        vcpu_clear(vcpu);
@@ -331,6 +498,20 @@ static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
                     INTR_INFO_VALID_MASK);
 }
 
+/*
+ * Swap MSR entry in host/guest MSR entry array.
+ */
+void move_msr_up(struct kvm_vcpu *vcpu, int from, int to)
+{
+       struct vmx_msr_entry tmp;
+       tmp = vcpu->guest_msrs[to];
+       vcpu->guest_msrs[to] = vcpu->guest_msrs[from];
+       vcpu->guest_msrs[from] = tmp;
+       tmp = vcpu->host_msrs[to];
+       vcpu->host_msrs[to] = vcpu->host_msrs[from];
+       vcpu->host_msrs[from] = tmp;
+}
+
 /*
  * Set up the vmcs to automatically save and restore system
  * msrs.  Don't touch the 64-bit msrs if the guest is in legacy
@@ -338,35 +519,41 @@ static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
  */
 static void setup_msrs(struct kvm_vcpu *vcpu)
 {
-       int nr_skip, nr_good_msrs;
-
-       if (is_long_mode(vcpu))
-               nr_skip = NR_BAD_MSRS;
-       else
-               nr_skip = NR_64BIT_MSRS;
-       nr_good_msrs = vcpu->nmsrs - nr_skip;
+       int save_nmsrs;
 
-       /*
-        * MSR_K6_STAR is only needed on long mode guests, and only
-        * if efer.sce is enabled.
-        */
-       if (find_msr_entry(vcpu, MSR_K6_STAR)) {
-               --nr_good_msrs;
+       save_nmsrs = 0;
 #ifdef CONFIG_X86_64
-               if (is_long_mode(vcpu) && (vcpu->shadow_efer & EFER_SCE))
-                       ++nr_good_msrs;
-#endif
+       if (is_long_mode(vcpu)) {
+               int index;
+
+               index = __find_msr_index(vcpu, MSR_SYSCALL_MASK);
+               if (index >= 0)
+                       move_msr_up(vcpu, index, save_nmsrs++);
+               index = __find_msr_index(vcpu, MSR_LSTAR);
+               if (index >= 0)
+                       move_msr_up(vcpu, index, save_nmsrs++);
+               index = __find_msr_index(vcpu, MSR_CSTAR);
+               if (index >= 0)
+                       move_msr_up(vcpu, index, save_nmsrs++);
+               index = __find_msr_index(vcpu, MSR_KERNEL_GS_BASE);
+               if (index >= 0)
+                       move_msr_up(vcpu, index, save_nmsrs++);
+               /*
+                * MSR_K6_STAR is only needed on long mode guests, and only
+                * if efer.sce is enabled.
+                */
+               index = __find_msr_index(vcpu, MSR_K6_STAR);
+               if ((index >= 0) && (vcpu->shadow_efer & EFER_SCE))
+                       move_msr_up(vcpu, index, save_nmsrs++);
        }
+#endif
+       vcpu->save_nmsrs = save_nmsrs;
 
-       vmcs_writel(VM_ENTRY_MSR_LOAD_ADDR,
-                   virt_to_phys(vcpu->guest_msrs + nr_skip));
-       vmcs_writel(VM_EXIT_MSR_STORE_ADDR,
-                   virt_to_phys(vcpu->guest_msrs + nr_skip));
-       vmcs_writel(VM_EXIT_MSR_LOAD_ADDR,
-                   virt_to_phys(vcpu->host_msrs + nr_skip));
-       vmcs_write32(VM_EXIT_MSR_STORE_COUNT, nr_good_msrs); /* 22.2.2 */
-       vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, nr_good_msrs);  /* 22.2.2 */
-       vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */
+#ifdef CONFIG_X86_64
+       vcpu->msr_offset_kernel_gs_base =
+               __find_msr_index(vcpu, MSR_KERNEL_GS_BASE);
+#endif
+       vcpu->msr_offset_efer = __find_msr_index(vcpu, MSR_EFER);
 }
 
 /*
@@ -394,23 +581,6 @@ static void guest_write_tsc(u64 guest_tsc)
        vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc);
 }
 
-static void reload_tss(void)
-{
-#ifndef CONFIG_X86_64
-
-       /*
-        * VT restores TR but not its size.  Useless.
-        */
-       struct descriptor_table gdt;
-       struct segment_descriptor *descs;
-
-       get_gdt(&gdt);
-       descs = (void *)gdt.base;
-       descs[GDT_ENTRY_TSS].type = 9; /* available TSS */
-       load_TR_desc();
-#endif
-}
-
 /*
  * Reads an msr value (of 'msr_index') into 'pdata'.
  * Returns 0 on success, non-0 otherwise.
@@ -470,10 +640,15 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
 static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
 {
        struct vmx_msr_entry *msr;
+       int ret = 0;
+
        switch (msr_index) {
 #ifdef CONFIG_X86_64
        case MSR_EFER:
-               return kvm_set_msr_common(vcpu, msr_index, data);
+               ret = kvm_set_msr_common(vcpu, msr_index, data);
+               if (vcpu->vmx_host_state.loaded)
+                       load_transition_efer(vcpu);
+               break;
        case MSR_FS_BASE:
                vmcs_writel(GUEST_FS_BASE, data);
                break;
@@ -497,14 +672,14 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
                msr = find_msr_entry(vcpu, msr_index);
                if (msr) {
                        msr->data = data;
+                       if (vcpu->vmx_host_state.loaded)
+                               load_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
                        break;
                }
-               return kvm_set_msr_common(vcpu, msr_index, data);
-               msr->data = data;
-               break;
+               ret = kvm_set_msr_common(vcpu, msr_index, data);
        }
 
-       return 0;
+       return ret;
 }
 
 /*
@@ -530,10 +705,8 @@ static void vcpu_put_rsp_rip(struct kvm_vcpu *vcpu)
 static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
 {
        unsigned long dr7 = 0x400;
-       u32 exception_bitmap;
        int old_singlestep;
 
-       exception_bitmap = vmcs_read32(EXCEPTION_BITMAP);
        old_singlestep = vcpu->guest_debug.singlestep;
 
        vcpu->guest_debug.enabled = dbg->enabled;
@@ -549,13 +722,9 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
                        dr7 |= 0 << (i*4+16); /* execution breakpoint */
                }
 
-               exception_bitmap |= (1u << 1);  /* Trap debug exceptions */
-
                vcpu->guest_debug.singlestep = dbg->singlestep;
-       } else {
-               exception_bitmap &= ~(1u << 1); /* Ignore debug exceptions */
+       } else
                vcpu->guest_debug.singlestep = 0;
-       }
 
        if (old_singlestep && !vcpu->guest_debug.singlestep) {
                unsigned long flags;
@@ -565,7 +734,7 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
                vmcs_writel(GUEST_RFLAGS, flags);
        }
 
-       vmcs_write32(EXCEPTION_BITMAP, exception_bitmap);
+       update_exception_bitmap(vcpu);
        vmcs_writel(GUEST_DR7, dr7);
 
        return 0;
@@ -679,14 +848,6 @@ static __exit void hardware_unsetup(void)
        free_kvm_area();
 }
 
-static void update_exception_bitmap(struct kvm_vcpu *vcpu)
-{
-       if (vcpu->rmode.active)
-               vmcs_write32(EXCEPTION_BITMAP, ~0);
-       else
-               vmcs_write32(EXCEPTION_BITMAP, 1 << PF_VECTOR);
-}
-
 static void fix_pmode_dataseg(int seg, struct kvm_save_segment *save)
 {
        struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
@@ -793,6 +954,8 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
        fix_rmode_seg(VCPU_SREG_DS, &vcpu->rmode.ds);
        fix_rmode_seg(VCPU_SREG_GS, &vcpu->rmode.gs);
        fix_rmode_seg(VCPU_SREG_FS, &vcpu->rmode.fs);
+
+       init_rmode_tss(vcpu->kvm);
 }
 
 #ifdef CONFIG_X86_64
@@ -837,6 +1000,8 @@ static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
 
 static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 {
+       vmx_fpu_deactivate(vcpu);
+
        if (vcpu->rmode.active && (cr0 & CR0_PE_MASK))
                enter_pmode(vcpu);
 
@@ -852,26 +1017,20 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
        }
 #endif
 
-       if (!(cr0 & CR0_TS_MASK)) {
-               vcpu->fpu_active = 1;
-               vmcs_clear_bits(EXCEPTION_BITMAP, CR0_TS_MASK);
-       }
-
        vmcs_writel(CR0_READ_SHADOW, cr0);
        vmcs_writel(GUEST_CR0,
                    (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
        vcpu->cr0 = cr0;
+
+       if (!(cr0 & CR0_TS_MASK) || !(cr0 & CR0_PE_MASK))
+               vmx_fpu_activate(vcpu);
 }
 
 static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
 {
        vmcs_writel(GUEST_CR3, cr3);
-
-       if (!(vcpu->cr0 & CR0_TS_MASK)) {
-               vcpu->fpu_active = 0;
-               vmcs_set_bits(GUEST_CR0, CR0_TS_MASK);
-               vmcs_set_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR);
-       }
+       if (vcpu->cr0 & CR0_PE_MASK)
+               vmx_fpu_deactivate(vcpu);
 }
 
 static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
@@ -937,23 +1096,11 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu,
        var->unusable = (ar >> 16) & 1;
 }
 
-static void vmx_set_segment(struct kvm_vcpu *vcpu,
-                           struct kvm_segment *var, int seg)
+static u32 vmx_segment_access_rights(struct kvm_segment *var)
 {
-       struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
        u32 ar;
 
-       vmcs_writel(sf->base, var->base);
-       vmcs_write32(sf->limit, var->limit);
-       vmcs_write16(sf->selector, var->selector);
-       if (vcpu->rmode.active && var->s) {
-               /*
-                * Hack real-mode segments into vm86 compatibility.
-                */
-               if (var->base == 0xffff0000 && var->selector == 0xf000)
-                       vmcs_writel(sf->base, 0xf0000);
-               ar = 0xf3;
-       } else if (var->unusable)
+       if (var->unusable)
                ar = 1 << 16;
        else {
                ar = var->type & 15;
@@ -967,6 +1114,35 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
        }
        if (ar == 0) /* a 0 value means unusable */
                ar = AR_UNUSABLE_MASK;
+
+       return ar;
+}
+
+static void vmx_set_segment(struct kvm_vcpu *vcpu,
+                           struct kvm_segment *var, int seg)
+{
+       struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+       u32 ar;
+
+       if (vcpu->rmode.active && seg == VCPU_SREG_TR) {
+               vcpu->rmode.tr.selector = var->selector;
+               vcpu->rmode.tr.base = var->base;
+               vcpu->rmode.tr.limit = var->limit;
+               vcpu->rmode.tr.ar = vmx_segment_access_rights(var);
+               return;
+       }
+       vmcs_writel(sf->base, var->base);
+       vmcs_write32(sf->limit, var->limit);
+       vmcs_write16(sf->selector, var->selector);
+       if (vcpu->rmode.active && var->s) {
+               /*
+                * Hack real-mode segments into vm86 compatibility.
+                */
+               if (var->base == 0xffff0000 && var->selector == 0xf000)
+                       vmcs_writel(sf->base, 0xf0000);
+               ar = 0xf3;
+       } else
+               ar = vmx_segment_access_rights(var);
        vmcs_write32(sf->ar_bytes, ar);
 }
 
@@ -1018,16 +1194,16 @@ static int init_rmode_tss(struct kvm* kvm)
        }
 
        page = kmap_atomic(p1, KM_USER0);
-       memset(page, 0, PAGE_SIZE);
+       clear_page(page);
        *(u16*)(page + 0x66) = TSS_BASE_SIZE + TSS_REDIRECTION_SIZE;
        kunmap_atomic(page, KM_USER0);
 
        page = kmap_atomic(p2, KM_USER0);
-       memset(page, 0, PAGE_SIZE);
+       clear_page(page);
        kunmap_atomic(page, KM_USER0);
 
        page = kmap_atomic(p3, KM_USER0);
-       memset(page, 0, PAGE_SIZE);
+       clear_page(page);
        *(page + RMODE_TSS_SIZE - 2 * PAGE_SIZE - 1) = ~0;
        kunmap_atomic(page, KM_USER0);
 
@@ -1066,7 +1242,7 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
        struct descriptor_table dt;
        int i;
        int ret = 0;
-       extern asmlinkage void kvm_vmx_return(void);
+       unsigned long kvm_vmx_return;
 
        if (!init_rmode_tss(vcpu->kvm)) {
                ret = -ENOMEM;
@@ -1076,9 +1252,9 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
        memset(vcpu->regs, 0, sizeof(vcpu->regs));
        vcpu->regs[VCPU_REGS_RDX] = get_rdx_init_val();
        vcpu->cr8 = 0;
-       vcpu->apic_base = 0xfee00000 |
-                       /*for vcpu 0*/ MSR_IA32_APICBASE_BSP |
-                       MSR_IA32_APICBASE_ENABLE;
+       vcpu->apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
+       if (vcpu == &vcpu->kvm->vcpus[0])
+               vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
 
        fx_init(vcpu);
 
@@ -1129,8 +1305,8 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
        vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0);
 
        /* I/O */
-       vmcs_write64(IO_BITMAP_A, 0);
-       vmcs_write64(IO_BITMAP_B, 0);
+       vmcs_write64(IO_BITMAP_A, page_to_phys(vmx_io_bitmap_a));
+       vmcs_write64(IO_BITMAP_B, page_to_phys(vmx_io_bitmap_b));
 
        guest_write_tsc(0);
 
@@ -1150,12 +1326,11 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
                               CPU_BASED_HLT_EXITING         /* 20.6.2 */
                               | CPU_BASED_CR8_LOAD_EXITING    /* 20.6.2 */
                               | CPU_BASED_CR8_STORE_EXITING   /* 20.6.2 */
-                              | CPU_BASED_UNCOND_IO_EXITING   /* 20.6.2 */
+                              | CPU_BASED_ACTIVATE_IO_BITMAP  /* 20.6.2 */
                               | CPU_BASED_MOV_DR_EXITING
                               | CPU_BASED_USE_TSC_OFFSETING   /* 21.3 */
                        );
 
-       vmcs_write32(EXCEPTION_BITMAP, 1 << PF_VECTOR);
        vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0);
        vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0);
        vmcs_write32(CR3_TARGET_COUNT, 0);           /* 22.2.1 */
@@ -1185,8 +1360,11 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
        get_idt(&dt);
        vmcs_writel(HOST_IDTR_BASE, dt.base);   /* 22.2.4 */
 
-
-       vmcs_writel(HOST_RIP, (unsigned long)kvm_vmx_return); /* 22.2.5 */
+       asm ("mov $.Lkvm_vmx_return, %0" : "=r"(kvm_vmx_return));
+       vmcs_writel(HOST_RIP, kvm_vmx_return); /* 22.2.5 */
+       vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0);
+       vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0);
+       vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0);
 
        rdmsr(MSR_IA32_SYSENTER_CS, host_sysenter_cs, junk);
        vmcs_write32(HOST_IA32_SYSENTER_CS, host_sysenter_cs);
@@ -1210,10 +1388,6 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
                vcpu->host_msrs[j].reserved = 0;
                vcpu->host_msrs[j].data = data;
                vcpu->guest_msrs[j] = vcpu->host_msrs[j];
-#ifdef CONFIG_X86_64
-               if (index == MSR_KERNEL_GS_BASE)
-                       msr_offset_kernel_gs_base = j;
-#endif
                ++vcpu->nmsrs;
        }
 
@@ -1241,6 +1415,8 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
 #ifdef CONFIG_X86_64
        vmx_set_efer(vcpu, 0);
 #endif
+       vmx_fpu_activate(vcpu);
+       update_exception_bitmap(vcpu);
 
        return 0;
 
@@ -1365,7 +1541,11 @@ static int handle_rmode_exception(struct kvm_vcpu *vcpu,
        if (!vcpu->rmode.active)
                return 0;
 
-       if (vec == GP_VECTOR && err_code == 0)
+       /*
+        * Instruction with address size override prefix opcode 0x67
+        * Cause the #SS fault with 0 error code in VM86 mode.
+        */
+       if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) && err_code == 0)
                if (emulate_instruction(vcpu, NULL, 0, 0) == EMULATE_DONE)
                        return 1;
        return 0;
@@ -1400,10 +1580,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        }
 
        if (is_no_device(intr_info)) {
-               vcpu->fpu_active = 1;
-               vmcs_clear_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR);
-               if (!(vcpu->cr0 & CR0_TS_MASK))
-                       vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK);
+               vmx_fpu_activate(vcpu);
                return 1;
        }
 
@@ -1445,8 +1622,13 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 
        if (vcpu->rmode.active &&
            handle_rmode_exception(vcpu, intr_info & INTR_INFO_VECTOR_MASK,
-                                                               error_code))
+                                                               error_code)) {
+               if (vcpu->halt_request) {
+                       vcpu->halt_request = 0;
+                       return kvm_emulate_halt(vcpu);
+               }
                return 1;
+       }
 
        if ((intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK)) == (INTR_TYPE_EXCEPTION | 1)) {
                kvm_run->exit_reason = KVM_EXIT_DEBUG;
@@ -1595,11 +1777,10 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                break;
        case 2: /* clts */
                vcpu_load_rsp_rip(vcpu);
-               vcpu->fpu_active = 1;
-               vmcs_clear_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR);
-               vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK);
+               vmx_fpu_deactivate(vcpu);
                vcpu->cr0 &= ~CR0_TS_MASK;
                vmcs_writel(CR0_READ_SHADOW, vcpu->cr0);
+               vmx_fpu_activate(vcpu);
                skip_emulated_instruction(vcpu);
                return 1;
        case 1: /*mov from cr*/
@@ -1734,12 +1915,7 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu,
 static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
        skip_emulated_instruction(vcpu);
-       if (vcpu->irq_summary)
-               return 1;
-
-       kvm_run->exit_reason = KVM_EXIT_HLT;
-       ++vcpu->stat.halt_exits;
-       return 0;
+       return kvm_emulate_halt(vcpu);
 }
 
 static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -1770,7 +1946,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
 };
 
 static const int kvm_vmx_max_exit_handlers =
-       sizeof(kvm_vmx_exit_handlers) / sizeof(*kvm_vmx_exit_handlers);
+       ARRAY_SIZE(kvm_vmx_exit_handlers);
 
 /*
  * The guest has exited.  See if we can fix it or if we need userspace
@@ -1810,61 +1986,44 @@ static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
                (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF));
 }
 
+static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
+{
+}
+
 static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
        u8 fail;
-       u16 fs_sel, gs_sel, ldt_sel;
-       int fs_gs_ldt_reload_needed;
        int r;
 
-again:
-       /*
-        * Set host fs and gs selectors.  Unfortunately, 22.2.3 does not
-        * allow segment selectors with cpl > 0 or ti == 1.
-        */
-       fs_sel = read_fs();
-       gs_sel = read_gs();
-       ldt_sel = read_ldt();
-       fs_gs_ldt_reload_needed = (fs_sel & 7) | (gs_sel & 7) | ldt_sel;
-       if (!fs_gs_ldt_reload_needed) {
-               vmcs_write16(HOST_FS_SELECTOR, fs_sel);
-               vmcs_write16(HOST_GS_SELECTOR, gs_sel);
-       } else {
-               vmcs_write16(HOST_FS_SELECTOR, 0);
-               vmcs_write16(HOST_GS_SELECTOR, 0);
-       }
-
-#ifdef CONFIG_X86_64
-       vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE));
-       vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE));
-#else
-       vmcs_writel(HOST_FS_BASE, segment_base(fs_sel));
-       vmcs_writel(HOST_GS_BASE, segment_base(gs_sel));
-#endif
+preempted:
+       if (vcpu->guest_debug.enabled)
+               kvm_guest_debug_pre(vcpu);
 
+again:
        if (!vcpu->mmio_read_completed)
                do_interrupt_requests(vcpu, kvm_run);
 
-       if (vcpu->guest_debug.enabled)
-               kvm_guest_debug_pre(vcpu);
-
+       vmx_save_host_state(vcpu);
        kvm_load_guest_fpu(vcpu);
 
+       r = kvm_mmu_reload(vcpu);
+       if (unlikely(r))
+               goto out;
+
        /*
         * Loading guest fpu may have cleared host cr0.ts
         */
        vmcs_writel(HOST_CR0, read_cr0());
 
-#ifdef CONFIG_X86_64
-       if (is_long_mode(vcpu)) {
-               save_msrs(vcpu->host_msrs + msr_offset_kernel_gs_base, 1);
-               load_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
-       }
-#endif
+       local_irq_disable();
+
+       vcpu->guest_mode = 1;
+       if (vcpu->requests)
+               if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests))
+                   vmx_flush_tlb(vcpu);
 
        asm (
                /* Store host registers */
-               "pushf \n\t"
 #ifdef CONFIG_X86_64
                "push %%rax; push %%rbx; push %%rdx;"
                "push %%rsi; push %%rdi; push %%rbp;"
@@ -1909,12 +2068,11 @@ again:
                "mov %c[rcx](%3), %%ecx \n\t" /* kills %3 (ecx) */
 #endif
                /* Enter guest mode */
-               "jne launched \n\t"
+               "jne .Llaunched \n\t"
                ASM_VMX_VMLAUNCH "\n\t"
-               "jmp kvm_vmx_return \n\t"
-               "launched: " ASM_VMX_VMRESUME "\n\t"
-               ".globl kvm_vmx_return \n\t"
-               "kvm_vmx_return: "
+               "jmp .Lkvm_vmx_return \n\t"
+               ".Llaunched: " ASM_VMX_VMRESUME "\n\t"
+               ".Lkvm_vmx_return: "
                /* Save guest registers, load host registers, keep flags */
 #ifdef CONFIG_X86_64
                "xchg %3,     (%%rsp) \n\t"
@@ -1957,7 +2115,6 @@ again:
                "pop %%ecx; popa \n\t"
 #endif
                "setbe %0 \n\t"
-               "popf \n\t"
              : "=q" (fail)
              : "r"(vcpu->launched), "d"((unsigned long)HOST_RSP),
                "c"(vcpu),
@@ -1981,84 +2138,61 @@ again:
                [cr2]"i"(offsetof(struct kvm_vcpu, cr2))
              : "cc", "memory" );
 
-       /*
-        * Reload segment selectors ASAP. (it's needed for a functional
-        * kernel: x86 relies on having __KERNEL_PDA in %fs and x86_64
-        * relies on having 0 in %gs for the CPU PDA to work.)
-        */
-       if (fs_gs_ldt_reload_needed) {
-               load_ldt(ldt_sel);
-               load_fs(fs_sel);
-               /*
-                * If we have to reload gs, we must take care to
-                * preserve our gs base.
-                */
-               local_irq_disable();
-               load_gs(gs_sel);
-#ifdef CONFIG_X86_64
-               wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE));
-#endif
-               local_irq_enable();
+       vcpu->guest_mode = 0;
+       local_irq_enable();
 
-               reload_tss();
-       }
        ++vcpu->stat.exits;
 
-#ifdef CONFIG_X86_64
-       if (is_long_mode(vcpu)) {
-               save_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
-               load_msrs(vcpu->host_msrs, NR_BAD_MSRS);
-       }
-#endif
-
        vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0;
 
        asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
 
-       if (fail) {
+       if (unlikely(fail)) {
                kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
                kvm_run->fail_entry.hardware_entry_failure_reason
                        = vmcs_read32(VM_INSTRUCTION_ERROR);
                r = 0;
-       } else {
-               /*
-                * Profile KVM exit RIPs:
-                */
-               if (unlikely(prof_on == KVM_PROFILING))
-                       profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP));
-
-               vcpu->launched = 1;
-               r = kvm_handle_exit(kvm_run, vcpu);
-               if (r > 0) {
-                       /* Give scheduler a change to reschedule. */
-                       if (signal_pending(current)) {
-                               ++vcpu->stat.signal_exits;
-                               post_kvm_run_save(vcpu, kvm_run);
-                               kvm_run->exit_reason = KVM_EXIT_INTR;
-                               return -EINTR;
-                       }
-
-                       if (dm_request_for_irq_injection(vcpu, kvm_run)) {
-                               ++vcpu->stat.request_irq_exits;
-                               post_kvm_run_save(vcpu, kvm_run);
-                               kvm_run->exit_reason = KVM_EXIT_INTR;
-                               return -EINTR;
-                       }
-
-                       kvm_resched(vcpu);
+               goto out;
+       }
+       /*
+        * Profile KVM exit RIPs:
+        */
+       if (unlikely(prof_on == KVM_PROFILING))
+               profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP));
+
+       vcpu->launched = 1;
+       r = kvm_handle_exit(kvm_run, vcpu);
+       if (r > 0) {
+               /* Give scheduler a change to reschedule. */
+               if (signal_pending(current)) {
+                       r = -EINTR;
+                       kvm_run->exit_reason = KVM_EXIT_INTR;
+                       ++vcpu->stat.signal_exits;
+                       goto out;
+               }
+
+               if (dm_request_for_irq_injection(vcpu, kvm_run)) {
+                       r = -EINTR;
+                       kvm_run->exit_reason = KVM_EXIT_INTR;
+                       ++vcpu->stat.request_irq_exits;
+                       goto out;
+               }
+               if (!need_resched()) {
+                       ++vcpu->stat.light_exits;
                        goto again;
                }
        }
 
+out:
+       if (r > 0) {
+               kvm_resched(vcpu);
+               goto preempted;
+       }
+
        post_kvm_run_save(vcpu, kvm_run);
        return r;
 }
 
-static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
-{
-       vmcs_writel(GUEST_CR3, vmcs_readl(GUEST_CR3));
-}
-
 static void vmx_inject_page_fault(struct kvm_vcpu *vcpu,
                                  unsigned long addr,
                                  u32 err_code)
@@ -2122,7 +2256,6 @@ static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
        vmcs_clear(vmcs);
        vcpu->vmcs = vmcs;
        vcpu->launched = 0;
-       vcpu->fpu_active = 1;
 
        return 0;
 
@@ -2188,11 +2321,50 @@ static struct kvm_arch_ops vmx_arch_ops = {
 
 static int __init vmx_init(void)
 {
-       return kvm_init_arch(&vmx_arch_ops, THIS_MODULE);
+       void *iova;
+       int r;
+
+       vmx_io_bitmap_a = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+       if (!vmx_io_bitmap_a)
+               return -ENOMEM;
+
+       vmx_io_bitmap_b = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+       if (!vmx_io_bitmap_b) {
+               r = -ENOMEM;
+               goto out;
+       }
+
+       /*
+        * Allow direct access to the PC debug port (it is often used for I/O
+        * delays, but the vmexits simply slow things down).
+        */
+       iova = kmap(vmx_io_bitmap_a);
+       memset(iova, 0xff, PAGE_SIZE);
+       clear_bit(0x80, iova);
+       kunmap(vmx_io_bitmap_a);
+
+       iova = kmap(vmx_io_bitmap_b);
+       memset(iova, 0xff, PAGE_SIZE);
+       kunmap(vmx_io_bitmap_b);
+
+       r = kvm_init_arch(&vmx_arch_ops, THIS_MODULE);
+       if (r)
+               goto out1;
+
+       return 0;
+
+out1:
+       __free_page(vmx_io_bitmap_b);
+out:
+       __free_page(vmx_io_bitmap_a);
+       return r;
 }
 
 static void __exit vmx_exit(void)
 {
+       __free_page(vmx_io_bitmap_b);
+       __free_page(vmx_io_bitmap_a);
+
        kvm_exit_arch();
 }
 
index 7ade09086aa51f02376da1acc0985cf1c17b449c..f60012d626104c45c449cd2c0055468cd835f189 100644 (file)
@@ -98,8 +98,11 @@ static u8 opcode_table[256] = {
        0, 0, 0, 0,
        /* 0x40 - 0x4F */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       /* 0x50 - 0x5F */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0x50 - 0x57 */
+       0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0x58 - 0x5F */
+       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+       ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
        /* 0x60 - 0x6F */
        0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -128,9 +131,9 @@ static u8 opcode_table[256] = {
        /* 0xB0 - 0xBF */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        /* 0xC0 - 0xC7 */
-       ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM, 0, 0,
-       0, 0, ByteOp | DstMem | SrcImm | ModRM | Mov,
-           DstMem | SrcImm | ModRM | Mov,
+       ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM,
+       0, ImplicitOps, 0, 0,
+       ByteOp | DstMem | SrcImm | ModRM | Mov, DstMem | SrcImm | ModRM | Mov,
        /* 0xC8 - 0xCF */
        0, 0, 0, 0, 0, 0, 0, 0,
        /* 0xD0 - 0xD7 */
@@ -143,7 +146,8 @@ static u8 opcode_table[256] = {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        /* 0xF0 - 0xF7 */
        0, 0, 0, 0,
-       0, 0, ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
+       ImplicitOps, 0,
+       ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
        /* 0xF8 - 0xFF */
        0, 0, 0, 0,
        0, 0, ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM
@@ -152,7 +156,7 @@ static u8 opcode_table[256] = {
 static u16 twobyte_table[256] = {
        /* 0x00 - 0x0F */
        0, SrcMem | ModRM | DstReg, 0, 0, 0, 0, ImplicitOps, 0,
-       0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0,
+       0, ImplicitOps, 0, 0, 0, ImplicitOps | ModRM, 0, 0,
        /* 0x10 - 0x1F */
        0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0,
        /* 0x20 - 0x2F */
@@ -481,6 +485,7 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
        int mode = ctxt->mode;
        unsigned long modrm_ea;
        int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0;
+       int no_wb = 0;
 
        /* Shadow copy of register state. Committed on successful emulation. */
        unsigned long _regs[NR_VCPU_REGS];
@@ -1047,7 +1052,7 @@ done_prefixes:
                                                      _regs[VCPU_REGS_RSP]),
                                     &dst.val, dst.bytes, ctxt)) != 0)
                                goto done;
-                       dst.val = dst.orig_val; /* skanky: disable writeback */
+                       no_wb = 1;
                        break;
                default:
                        goto cannot_emulate;
@@ -1056,7 +1061,7 @@ done_prefixes:
        }
 
 writeback:
-       if ((d & Mov) || (dst.orig_val != dst.val)) {
+       if (!no_wb) {
                switch (dst.type) {
                case OP_REG:
                        /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
@@ -1149,6 +1154,23 @@ special_insn:
        case 0xae ... 0xaf:     /* scas */
                DPRINTF("Urk! I don't handle SCAS.\n");
                goto cannot_emulate;
+       case 0xf4:              /* hlt */
+               ctxt->vcpu->halt_request = 1;
+               goto done;
+       case 0xc3: /* ret */
+               dst.ptr = &_eip;
+               goto pop_instruction;
+       case 0x58 ... 0x5f: /* pop reg */
+               dst.ptr = (unsigned long *)&_regs[b & 0x7];
+
+pop_instruction:
+               if ((rc = ops->read_std(register_address(ctxt->ss_base,
+                       _regs[VCPU_REGS_RSP]), dst.ptr, op_bytes, ctxt)) != 0)
+                       goto done;
+
+               register_address_increment(_regs[VCPU_REGS_RSP], op_bytes);
+               no_wb = 1; /* Disable writeback. */
+               break;
        }
        goto writeback;
 
@@ -1302,8 +1324,10 @@ twobyte_insn:
 
 twobyte_special_insn:
        /* Disable writeback. */
-       dst.orig_val = dst.val;
+       no_wb = 1;
        switch (b) {
+       case 0x09:              /* wbinvd */
+               break;
        case 0x0d:              /* GrpP (prefetch) */
        case 0x18:              /* Grp16 (prefetch/nop) */
                break;
index dbb22403979f034c5c060c17e0b4c5b1f64a82dc..3d90fc002097e9997ee7c5d874c73ca026904727 100644 (file)
@@ -1770,7 +1770,8 @@ static int call_critical_overtemp(void)
                                "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
                                NULL };
 
-       return call_usermodehelper(critical_overtemp_path, argv, envp, 0);
+       return call_usermodehelper(critical_overtemp_path,
+                                  argv, envp, UMH_WAIT_EXEC);
 }
 
 
index e18d265d5d33206f437c00e6bf56a8afaf1a4cea..516d943227e240750475c482c221de5dbdd066cb 100644 (file)
@@ -80,7 +80,8 @@ int wf_critical_overtemp(void)
                                "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
                                NULL };
 
-       return call_usermodehelper(critical_overtemp_path, argv, envp, 0);
+       return call_usermodehelper(critical_overtemp_path,
+                                  argv, envp, UMH_WAIT_EXEC);
 }
 EXPORT_SYMBOL_GPL(wf_critical_overtemp);
 
index 3d65917a1bbbe97e2336d75255d97fe7a9ca2bf9..8fe81e1807e0cc9c7e35202990bc419274143335 100644 (file)
@@ -623,6 +623,7 @@ int dm_create_persistent(struct exception_store *store)
 
        ps->metadata_wq = create_singlethread_workqueue("ksnaphd");
        if (!ps->metadata_wq) {
+               kfree(ps);
                DMERR("couldn't start header metadata update thread");
                return -ENOMEM;
        }
index 624b21cef5b398617a543e69f48307169788f18b..d9d033e07e197cb0496218fc3f334bc1b33f06cf 100644 (file)
@@ -80,8 +80,12 @@ config VIDEO_BUF_DVB
 config VIDEO_BTCX
        tristate
 
+config VIDEO_IR_I2C
+       tristate
+
 config VIDEO_IR
        tristate
+       select VIDEO_IR_I2C if I2C
 
 config VIDEO_TVEEPROM
        tristate
index fcb194135627f9e32bb01f8f33db53e4b2a41fdd..fe447a06e24efd9ad3961a8c07e056f6ff3feda0 100644 (file)
@@ -107,21 +107,20 @@ void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
 }
 
 /* -------------------------------------------------------------------------- */
-
+/* extract mask bits out of data and pack them into the result */
 u32 ir_extract_bits(u32 data, u32 mask)
 {
-       int mbit, vbit;
-       u32 value;
+       u32 vbit = 1, value = 0;
+
+       do {
+           if (mask&1) {
+               if (data&1)
+                       value |= vbit;
+               vbit<<=1;
+           }
+           data>>=1;
+       } while (mask>>=1);
 
-       value = 0;
-       vbit  = 0;
-       for (mbit = 0; mbit < 32; mbit++) {
-               if (!(mask & ((u32)1 << mbit)))
-                       continue;
-               if (data & ((u32)1 << mbit))
-                       value |= (1 << vbit);
-               vbit++;
-       }
        return value;
 }
 
index ef3e54cd9407a9dab7c41bcff42f7d9129afdd0b..ba6701e97671ad0d37c474f5f3498f2f10b1d2b4 100644 (file)
@@ -27,7 +27,7 @@ static int saa7146_num;
 
 unsigned int saa7146_debug;
 
-module_param(saa7146_debug, int, 0644);
+module_param(saa7146_debug, uint, 0644);
 MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");
 
 #if 0
@@ -130,10 +130,10 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
 /********************************************************************************/
 /* common page table functions */
 
-char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
+void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
 {
        int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;
-       char *mem = vmalloc_32(length);
+       void *mem = vmalloc_32(length);
        int slen = 0;
 
        if (NULL == mem)
@@ -168,7 +168,7 @@ err_null:
        return NULL;
 }
 
-void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, char *mem, struct saa7146_pgtable *pt)
+void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt)
 {
        pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
        saa7146_pgtable_free(pci, pt);
index e3d04a4cef4d4e7bf075b4d68bdcb3655921fe27..664280c78ff299ef6bfd1c9425c8a0a63a1b7e4f 100644 (file)
@@ -889,9 +889,9 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
 
                DEB_EE(("VIDIOC_QUERYCAP\n"));
 
-               strcpy(cap->driver, "saa7146 v4l2");
-               strlcpy(cap->card, dev->ext->name, sizeof(cap->card));
-               sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
+               strcpy((char *)cap->driver, "saa7146 v4l2");
+               strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
+               sprintf((char *)cap->bus_info,"PCI:%s", pci_name(dev->pci));
                cap->version = SAA7146_VERSION_CODE;
                cap->capabilities =
                        V4L2_CAP_VIDEO_CAPTURE |
@@ -968,7 +968,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
                        }
                        memset(f,0,sizeof(*f));
                        f->index = index;
-                       strlcpy(f->description,formats[index].name,sizeof(f->description));
+                       strlcpy((char *)f->description,formats[index].name,sizeof(f->description));
                        f->pixelformat = formats[index].pixelformat;
                        break;
                }
index a0dcd59da76e5833502814abf62d66eda780ae79..3197aeb61d1f88181261e3db244b8531e64f9706 100644 (file)
@@ -1,7 +1,7 @@
 config DVB_B2C2_FLEXCOP
        tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
        depends on DVB_CORE && I2C
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_STV0299 if !DVB_FE_CUSTOMISE
        select DVB_MT352 if !DVB_FE_CUSTOMISE
        select DVB_MT312 if !DVB_FE_CUSTOMISE
index bff00b58bf65309ecec1b2cc723b6c885f59fcff..e97ff60a1eff820c1c8df35d8d593c5d24240dfe 100644 (file)
@@ -12,4 +12,4 @@ obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o
 b2c2-flexcop-usb-objs = flexcop-usb.o
 obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
index b02c2fd65baa9110461293ca8d77c8bd674ee81a..0378fd64659141ec73933149637552d71aacc0f8 100644 (file)
@@ -500,13 +500,13 @@ int flexcop_frontend_init(struct flexcop_device *fc)
        /* try the air atsc 2nd generation (nxt2002) */
        if ((fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
                fc->dev_type          = FC_AIR_ATSC2;
-               dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, &dvb_pll_samsung_tbmv);
+               dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV);
                info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
        } else
        /* try the air atsc 3nd generation (lgdt3303) */
        if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
                fc->dev_type          = FC_AIR_ATSC3;
-               dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_lg_tdvs_h06xf);
+               dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, DVB_PLL_LG_TDVS_H06XF);
                info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
        } else
        /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
index cfd6fb729a613d9c83d93176faeec87ac42705d4..ea666174e98874a8d9bb5a3de78aac660e03bf4f 100644 (file)
@@ -7,7 +7,7 @@ config DVB_BT8XX
        select DVB_CX24110 if !DVB_FE_CUSTOMISE
        select DVB_OR51211 if !DVB_FE_CUSTOMISE
        select DVB_LGDT330X if !DVB_FE_CUSTOMISE
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
        select FW_LOADER
        help
index 9d197efb481d4a3f2f08cec1bda3f04882b0de83..84cf70504d17855ff8821aa0d6e6700c5ecded76 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
index e908e3cf1e506fe554bdf18b01c7a48b1686535d..b7a17e69ca4dd796bab6ea615540f41232972f48 100644 (file)
@@ -1652,7 +1652,7 @@ static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_paramet
 static int dst_tune_frontend(struct dvb_frontend* fe,
                            struct dvb_frontend_parameters* p,
                            unsigned int mode_flags,
-                           int *delay,
+                           unsigned int *delay,
                            fe_status_t *status)
 {
        struct dst_state *state = fe->demodulator_priv;
index 4f1c09bee538712d42071b04283541b872006f72..67613eb6fa3d5cc1327642b160afe544455b152f 100644 (file)
@@ -611,7 +611,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
                card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
                if (card->fe != NULL) {
                        dvb_attach(dvb_pll_attach, card->fe, 0x61,
-                                  card->i2c_adapter, &dvb_pll_lg_tdvs_h06xf);
+                                  card->i2c_adapter, DVB_PLL_LG_TDVS_H06XF);
                        dprintk ("dvb_bt8xx: lgdt330x detected\n");
                }
                break;
@@ -692,6 +692,9 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
 
        case BTTV_BOARD_PC_HDTV:
                card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter);
+               if (card->fe != NULL)
+                       dvb_attach(dvb_pll_attach, card->fe, 0x61,
+                                  card->i2c_adapter, DVB_PLL_FCV1236D);
                break;
        }
 
index c51aece20f9f2fe627d539986f13989e51988388..d762d8cb0cf1acc907d44b487e144a73cfe48e68 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_CINERGYT2) += cinergyT2.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
index b40af48a2edbdcb71f750c2038a202efe2e08f05..5a1449f485cf3a93efb668a2801b9a6d1fa3badd 100644 (file)
@@ -829,7 +829,7 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
        input_dev->id.vendor = cinergyt2->udev->descriptor.idVendor;
        input_dev->id.product = cinergyt2->udev->descriptor.idProduct;
        input_dev->id.version = 1;
-       input_dev->cdev.dev = &cinergyt2->udev->dev;
+       input_dev->dev.parent = &cinergyt2->udev->dev;
 
        err = input_register_device(input_dev);
        if (err) {
@@ -1000,18 +1000,15 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
        if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->wq_sem))
                return -ERESTARTSYS;
 
-       if (1) {
-               cinergyt2_suspend_rc(cinergyt2);
-               cancel_rearming_delayed_work(&cinergyt2->query_work);
+       cinergyt2_suspend_rc(cinergyt2);
+       cancel_rearming_delayed_work(&cinergyt2->query_work);
 
-               mutex_lock(&cinergyt2->sem);
-               if (cinergyt2->streaming)
-                       cinergyt2_stop_stream_xfer(cinergyt2);
-               cinergyt2_sleep(cinergyt2, 1);
-               mutex_unlock(&cinergyt2->sem);
-       }
+       mutex_lock(&cinergyt2->sem);
+       if (cinergyt2->streaming)
+               cinergyt2_stop_stream_xfer(cinergyt2);
+       cinergyt2_sleep(cinergyt2, 1);
+       mutex_unlock(&cinergyt2->sem);
 
-       mutex_unlock(&cinergyt2->wq_sem);
        return 0;
 }
 
index 275df65fde992680b82631f7ee1ca98750a6d256..5394de2e4ce05f2d54fe1e727d51055388c9839b 100644 (file)
@@ -97,7 +97,7 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
                if (avail > todo)
                        avail = todo;
 
-               ret = dvb_ringbuffer_read(src, buf, avail, 1);
+               ret = dvb_ringbuffer_read(src, (u8 *)buf, avail, 1);
                if (ret < 0)
                        break;
 
index 2a03bf53cb2960b2c23ac1c387924f9f284b8f54..4fadddb264d67d902a077e5d6bbbd73929ea6cf6 100644 (file)
@@ -175,7 +175,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * e
  * @param nlen Number of bytes in needle.
  * @return Pointer into haystack needle was found at, or NULL if not found.
  */
-static u8 *findstr(u8 * haystack, int hlen, u8 * needle, int nlen)
+static char *findstr(char * haystack, int hlen, char * needle, int nlen)
 {
        int i;
 
@@ -482,7 +482,7 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
        }
 
        /* check it contains the correct DVB string */
-       dvb_str = findstr(tuple, tupleLength, "DVB_CI_V", 8);
+       dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8);
        if (dvb_str == NULL)
                return -EINVAL;
        if (tupleLength < ((dvb_str - (char *) tuple) + 12))
@@ -513,8 +513,8 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
                        ca->slot_info[slot].config_option = tuple[0] & 0x3f;
 
                        /* OK, check it contains the correct strings */
-                       if ((findstr(tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
-                           (findstr(tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
+                       if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
+                           (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
                                break;
 
                        got_cftableentry = 1;
@@ -1300,7 +1300,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file,
        struct dvb_ca_private *ca = dvbdev->priv;
        u8 slot, connection_id;
        int status;
-       char fragbuf[HOST_LINK_BUF_SIZE];
+       u8 fragbuf[HOST_LINK_BUF_SIZE];
        int fragpos = 0;
        int fraglen;
        unsigned long timeout;
@@ -1486,7 +1486,7 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
                                }
 
                                if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2,
-                                                                     buf + pktlen, fraglen, 1)) < 0) {
+                                                                     (u8 *)buf + pktlen, fraglen, 1)) < 0) {
                                        goto exit;
                                }
                                pktlen += fraglen;
index 6d8d1c3df8631a4832b34954e44e5633cd3a34c6..cb6987fce26cb1b0da73b16d375e3cc5dc530d1e 100644 (file)
@@ -1068,7 +1068,7 @@ static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count)
 
        if (mutex_lock_interruptible(&dvbdemux->mutex))
                return -ERESTARTSYS;
-       dvb_dmx_swfilter(dvbdemux, buf, count);
+       dvb_dmx_swfilter(dvbdemux, (u8 *)buf, count);
        mutex_unlock(&dvbdemux->mutex);
 
        if (signal_pending(current))
index f233d78bc3644bfdd93670ac7447bb280e852e94..a770a87b9a93d0f68ed5610316e20f6d2374649d 100644 (file)
@@ -103,7 +103,7 @@ struct dvb_frontend_ops {
        int (*tune)(struct dvb_frontend* fe,
                    struct dvb_frontend_parameters* params,
                    unsigned int mode_flags,
-                   int *delay,
+                   unsigned int *delay,
                    fe_status_t *status);
        /* get frontend tuning algorithm from the module */
        int (*get_frontend_algo)(struct dvb_frontend *fe);
index 4ebf33a5ffa2b1c5bab38c1fafca0e0e83c06c9a..acf026342ec56edc0fe91ef8faddda518b8b80d4 100644 (file)
@@ -347,7 +347,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 {
        struct dvb_net_priv *priv = dev->priv;
        unsigned long skipped = 0L;
-       u8 *ts, *ts_end, *from_where = NULL, ts_remain = 0, how_much = 0, new_ts = 1;
+       const u8 *ts, *ts_end, *from_where = NULL;
+       u8 ts_remain = 0, how_much = 0, new_ts = 1;
        struct ethhdr *ethh = NULL;
 
 #ifdef ULE_DEBUG
@@ -364,7 +365,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
        /* For all TS cells in current buffer.
         * Appearently, we are called for every single TS cell.
         */
-       for (ts = (char *)buf, ts_end = (char *)buf + buf_len; ts < ts_end; /* no default incr. */ ) {
+       for (ts = buf, ts_end = buf + buf_len; ts < ts_end; /* no default incr. */ ) {
 
                if (new_ts) {
                        /* We are about to process a new TS cell. */
index a9fa3337dd81d653e20ae80c3acdb7235f2a37ab..9ef0c00605ee80a3d4a08b14f4be7f826a50d91f 100644 (file)
@@ -208,7 +208,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
        if ((id = dvbdev_get_free_id (adap, type)) < 0){
                mutex_unlock(&dvbdev_register_lock);
                *pdvbdev = NULL;
-               printk ("%s: could get find free device id...\n", __FUNCTION__);
+               printk(KERN_ERR "%s: couldn't find free device id\n", __FUNCTION__);
                return -ENFILE;
        }
 
@@ -252,7 +252,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
                return PTR_ERR(clsdev);
        }
 
-       dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
+       dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
                adap->num, dnames[type], id, nums2minor(adap->num, type, id),
                nums2minor(adap->num, type, id));
 
@@ -311,7 +311,7 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct modu
        memset (adap, 0, sizeof(struct dvb_adapter));
        INIT_LIST_HEAD (&adap->device_list);
 
-       printk ("DVB: registering new adapter (%s).\n", name);
+       printk(KERN_INFO "DVB: registering new adapter (%s)\n", name);
 
        adap->num = num;
        adap->name = name;
@@ -407,13 +407,13 @@ static int __init init_dvbdev(void)
        dev_t dev = MKDEV(DVB_MAJOR, 0);
 
        if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
-               printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
+               printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR);
                return retval;
        }
 
        cdev_init(&dvb_device_cdev, &dvb_device_fops);
        if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
-               printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
+               printk(KERN_ERR "dvb-core: unable register character device\n");
                goto error;
        }
 
index 54488737a08fb2e484cb1f59328014da1ba38426..40e41f2f5afea2fce7abe356ec53164d0870757c 100644 (file)
@@ -2,7 +2,6 @@ config DVB_USB
        tristate "Support for various USB DVB devices"
        depends on DVB_CORE && USB && I2C
        select FW_LOADER
-       select DVB_PLL
        help
          By enabling this you will be able to choose the various supported
          USB1.1 and USB2.0 DVB devices.
@@ -27,13 +26,14 @@ config DVB_USB_A800
        depends on DVB_USB
        select DVB_DIB3000MC
        select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
 
 config DVB_USB_DIBUSB_MB
        tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
        depends on DVB_USB
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_DIB3000MB
        select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
        help
@@ -89,7 +89,7 @@ config DVB_USB_DIB0700
 config DVB_USB_UMT_010
        tristate "HanfTek UMT-010 DVB-T USB2.0 support"
        depends on DVB_USB
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_DIB3000MC
        select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
        help
@@ -98,7 +98,7 @@ config DVB_USB_UMT_010
 config DVB_USB_CXUSB
        tristate "Conexant USB2.0 hybrid reference design support"
        depends on DVB_USB
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_CX22702 if !DVB_FE_CUSTOMISE
        select DVB_LGDT330X if !DVB_FE_CUSTOMISE
        select DVB_MT352 if !DVB_FE_CUSTOMISE
@@ -142,7 +142,7 @@ config DVB_USB_AU6610
 config DVB_USB_DIGITV
        tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
        depends on DVB_USB
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_NXT6000 if !DVB_FE_CUSTOMISE
        select DVB_MT352 if !DVB_FE_CUSTOMISE
        help
@@ -188,6 +188,7 @@ config DVB_USB_NOVA_T_USB2
        depends on DVB_USB
        select DVB_DIB3000MC
        select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
 
@@ -216,5 +217,23 @@ config DVB_USB_OPERA1
        tristate "Opera1 DVB-S USB2.0 receiver"
        depends on DVB_USB
        select DVB_STV0299 if !DVB_FE_CUSTOMISE
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the Opera DVB-S USB2.0 receiver.
+
+config DVB_USB_AF9005
+       tristate "Afatech AF9005 DVB-T USB1.1 support"
+       depends on DVB_USB && EXPERIMENTAL
+       select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+       select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+       help
+         Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
+         and the TerraTec Cinergy T USB XE (Rev.1)
+
+config DVB_USB_AF9005_REMOTE
+       tristate "Afatech AF9005 default remote control support"
+       depends on DVB_USB_AF9005
+       help
+         Say Y here to support the default remote control decoding for the
+         Afatech AF9005 based receiver.
+
index 976f840cc9047aa592f13fa76ad714232416d9ad..73ac0a93fdebdfe2a68af50c2798a046c7d59b56 100644 (file)
@@ -55,4 +55,10 @@ dvb-usb-opera-objs = opera1.o
 obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o
 
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+dvb-usb-af9005-objs = af9005.o af9005-fe.o
+obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o
+
+dvb-usb-af9005-remote-objs = af9005-remote.o
+obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/dvb-usb/af9005-fe.c b/drivers/media/dvb/dvb-usb/af9005-fe.c
new file mode 100644 (file)
index 0000000..7195c94
--- /dev/null
@@ -0,0 +1,1503 @@
+/* Frontend part of the Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "af9005.h"
+#include "af9005-script.h"
+#include "mt2060.h"
+#include "qt1010.h"
+#include <asm/div64.h>
+
+struct af9005_fe_state {
+       struct dvb_usb_device *d;
+       struct dvb_frontend *tuner;
+
+       fe_status_t stat;
+
+       /* retraining parameters */
+       u32 original_fcw;
+       u16 original_rf_top;
+       u16 original_if_top;
+       u16 original_if_min;
+       u16 original_aci0_if_top;
+       u16 original_aci1_if_top;
+       u16 original_aci0_if_min;
+       u8 original_if_unplug_th;
+       u8 original_rf_unplug_th;
+       u8 original_dtop_if_unplug_th;
+       u8 original_dtop_rf_unplug_th;
+
+       /* statistics */
+       u32 pre_vit_error_count;
+       u32 pre_vit_bit_count;
+       u32 ber;
+       u32 post_vit_error_count;
+       u32 post_vit_bit_count;
+       u32 unc;
+       u16 abort_count;
+
+       int opened;
+       int strong;
+       unsigned long next_status_check;
+       struct dvb_frontend frontend;
+};
+
+static int af9005_write_word_agc(struct dvb_usb_device *d, u16 reghi,
+                                u16 reglo, u8 pos, u8 len, u16 value)
+{
+       int ret;
+       u8 temp;
+
+       if ((ret = af9005_write_ofdm_register(d, reglo, (u8) (value & 0xff))))
+               return ret;
+       temp = (u8) ((value & 0x0300) >> 8);
+       return af9005_write_register_bits(d, reghi, pos, len,
+                                         (u8) ((value & 0x300) >> 8));
+}
+
+static int af9005_read_word_agc(struct dvb_usb_device *d, u16 reghi,
+                               u16 reglo, u8 pos, u8 len, u16 * value)
+{
+       int ret;
+       u8 temp0, temp1;
+
+       if ((ret = af9005_read_ofdm_register(d, reglo, &temp0)))
+               return ret;
+       if ((ret = af9005_read_ofdm_register(d, reghi, &temp1)))
+               return ret;
+       switch (pos) {
+       case 0:
+               *value = ((u16) (temp1 & 0x03) << 8) + (u16) temp0;
+               break;
+       case 2:
+               *value = ((u16) (temp1 & 0x0C) << 6) + (u16) temp0;
+               break;
+       case 4:
+               *value = ((u16) (temp1 & 0x30) << 4) + (u16) temp0;
+               break;
+       case 6:
+               *value = ((u16) (temp1 & 0xC0) << 2) + (u16) temp0;
+               break;
+       default:
+               err("invalid pos in read word agc");
+               return -EINVAL;
+       }
+       return 0;
+
+}
+
+static int af9005_is_fecmon_available(struct dvb_frontend *fe, int *available)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       int ret;
+       u8 temp;
+
+       *available = false;
+
+       ret = af9005_read_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en,
+                                       fec_vtb_rsd_mon_en_pos,
+                                       fec_vtb_rsd_mon_en_len, &temp);
+       if (ret)
+               return ret;
+       if (temp & 1) {
+               ret =
+                   af9005_read_register_bits(state->d,
+                                             xd_p_reg_ofsm_read_rbc_en,
+                                             reg_ofsm_read_rbc_en_pos,
+                                             reg_ofsm_read_rbc_en_len, &temp);
+               if (ret)
+                       return ret;
+               if ((temp & 1) == 0)
+                       *available = true;
+
+       }
+       return 0;
+}
+
+static int af9005_get_post_vit_err_cw_count(struct dvb_frontend *fe,
+                                           u32 * post_err_count,
+                                           u32 * post_cw_count,
+                                           u16 * abort_count)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       int ret;
+       u32 err_count;
+       u32 cw_count;
+       u8 temp, temp0, temp1, temp2;
+       u16 loc_abort_count;
+
+       *post_err_count = 0;
+       *post_cw_count = 0;
+
+       /* check if error bit count is ready */
+       ret =
+           af9005_read_register_bits(state->d, xd_r_fec_rsd_ber_rdy,
+                                     fec_rsd_ber_rdy_pos, fec_rsd_ber_rdy_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       if (!temp) {
+               deb_info("rsd counter not ready\n");
+               return 100;
+       }
+       /* get abort count */
+       ret =
+           af9005_read_ofdm_register(state->d,
+                                     xd_r_fec_rsd_abort_packet_cnt_7_0,
+                                     &temp0);
+       if (ret)
+               return ret;
+       ret =
+           af9005_read_ofdm_register(state->d,
+                                     xd_r_fec_rsd_abort_packet_cnt_15_8,
+                                     &temp1);
+       if (ret)
+               return ret;
+       loc_abort_count = ((u16) temp1 << 8) + temp0;
+
+       /* get error count */
+       ret =
+           af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_7_0,
+                                     &temp0);
+       if (ret)
+               return ret;
+       ret =
+           af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_15_8,
+                                     &temp1);
+       if (ret)
+               return ret;
+       ret =
+           af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_23_16,
+                                     &temp2);
+       if (ret)
+               return ret;
+       err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0;
+       *post_err_count = err_count - (u32) loc_abort_count *8 * 8;
+
+       /* get RSD packet number */
+       ret =
+           af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0,
+                                     &temp0);
+       if (ret)
+               return ret;
+       ret =
+           af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8,
+                                     &temp1);
+       if (ret)
+               return ret;
+       cw_count = ((u32) temp1 << 8) + temp0;
+       if (cw_count == 0) {
+               err("wrong RSD packet count");
+               return -EIO;
+       }
+       deb_info("POST abort count %d err count %d rsd packets %d\n",
+                loc_abort_count, err_count, cw_count);
+       *post_cw_count = cw_count - (u32) loc_abort_count;
+       *abort_count = loc_abort_count;
+       return 0;
+
+}
+
+static int af9005_get_post_vit_ber(struct dvb_frontend *fe,
+                                  u32 * post_err_count, u32 * post_cw_count,
+                                  u16 * abort_count)
+{
+       u32 loc_cw_count = 0, loc_err_count;
+       u16 loc_abort_count;
+       int ret;
+
+       ret =
+           af9005_get_post_vit_err_cw_count(fe, &loc_err_count, &loc_cw_count,
+                                            &loc_abort_count);
+       if (ret)
+               return ret;
+       *post_err_count = loc_err_count;
+       *post_cw_count = loc_cw_count * 204 * 8;
+       *abort_count = loc_abort_count;
+
+       return 0;
+}
+
+static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe,
+                                           u32 * pre_err_count,
+                                           u32 * pre_bit_count)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       u8 temp, temp0, temp1, temp2;
+       u32 super_frame_count, x, bits;
+       int ret;
+
+       ret =
+           af9005_read_register_bits(state->d, xd_r_fec_vtb_ber_rdy,
+                                     fec_vtb_ber_rdy_pos, fec_vtb_ber_rdy_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       if (!temp) {
+               deb_info("viterbi counter not ready\n");
+               return 101;     /* ERR_APO_VTB_COUNTER_NOT_READY; */
+       }
+       ret =
+           af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_7_0,
+                                     &temp0);
+       if (ret)
+               return ret;
+       ret =
+           af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_15_8,
+                                     &temp1);
+       if (ret)
+               return ret;
+       ret =
+           af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_23_16,
+                                     &temp2);
+       if (ret)
+               return ret;
+       *pre_err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0;
+
+       ret =
+           af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0,
+                                     &temp0);
+       if (ret)
+               return ret;
+       ret =
+           af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8,
+                                     &temp1);
+       if (ret)
+               return ret;
+       super_frame_count = ((u32) temp1 << 8) + temp0;
+       if (super_frame_count == 0) {
+               deb_info("super frame count 0\n");
+               return 102;
+       }
+
+       /* read fft mode */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod,
+                                     reg_tpsd_txmod_pos, reg_tpsd_txmod_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       if (temp == 0) {
+               /* 2K */
+               x = 1512;
+       } else if (temp == 1) {
+               /* 8k */
+               x = 6048;
+       } else {
+               err("Invalid fft mode");
+               return -EINVAL;
+       }
+
+       /* read constellation mode */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
+                                     reg_tpsd_const_pos, reg_tpsd_const_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       switch (temp) {
+       case 0:         /* QPSK */
+               bits = 2;
+               break;
+       case 1:         /* QAM_16 */
+               bits = 4;
+               break;
+       case 2:         /* QAM_64 */
+               bits = 6;
+               break;
+       default:
+               err("invalid constellation mode");
+               return -EINVAL;
+       }
+       *pre_bit_count = super_frame_count * 68 * 4 * x * bits;
+       deb_info("PRE err count %d frame count %d bit count %d\n",
+                *pre_err_count, super_frame_count, *pre_bit_count);
+       return 0;
+}
+
+static int af9005_reset_pre_viterbi(struct dvb_frontend *fe)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       int ret;
+
+       /* set super frame count to 1 */
+       ret =
+           af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0,
+                                      1 & 0xff);
+       if (ret)
+               return ret;
+       af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8,
+                                  1 >> 8);
+       if (ret)
+               return ret;
+       /* reset pre viterbi error count */
+       ret =
+           af9005_write_register_bits(state->d, xd_p_fec_vtb_ber_rst,
+                                      fec_vtb_ber_rst_pos, fec_vtb_ber_rst_len,
+                                      1);
+
+       return ret;
+}
+
+static int af9005_reset_post_viterbi(struct dvb_frontend *fe)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       int ret;
+
+       /* set packet unit */
+       ret =
+           af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0,
+                                      10000 & 0xff);
+       if (ret)
+               return ret;
+       ret =
+           af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8,
+                                      10000 >> 8);
+       if (ret)
+               return ret;
+       /* reset post viterbi error count */
+       ret =
+           af9005_write_register_bits(state->d, xd_p_fec_rsd_ber_rst,
+                                      fec_rsd_ber_rst_pos, fec_rsd_ber_rst_len,
+                                      1);
+
+       return ret;
+}
+
+static int af9005_get_statistic(struct dvb_frontend *fe)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       int ret, fecavailable;
+       u64 numerator, denominator;
+
+       deb_info("GET STATISTIC\n");
+       ret = af9005_is_fecmon_available(fe, &fecavailable);
+       if (ret)
+               return ret;
+       if (!fecavailable) {
+               deb_info("fecmon not available\n");
+               return 0;
+       }
+
+       ret = af9005_get_pre_vit_err_bit_count(fe, &state->pre_vit_error_count,
+                                              &state->pre_vit_bit_count);
+       if (ret == 0) {
+               af9005_reset_pre_viterbi(fe);
+               if (state->pre_vit_bit_count > 0) {
+                       /* according to v 0.0.4 of the dvb api ber should be a multiple
+                          of 10E-9 so we have to multiply the error count by
+                          10E9=1000000000 */
+                       numerator =
+                           (u64) state->pre_vit_error_count * (u64) 1000000000;
+                       denominator = (u64) state->pre_vit_bit_count;
+                       state->ber = do_div(numerator, denominator);
+               } else {
+                       state->ber = 0xffffffff;
+               }
+       }
+
+       ret = af9005_get_post_vit_ber(fe, &state->post_vit_error_count,
+                                     &state->post_vit_bit_count,
+                                     &state->abort_count);
+       if (ret == 0) {
+               ret = af9005_reset_post_viterbi(fe);
+               state->unc += state->abort_count;
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+static int af9005_fe_refresh_state(struct dvb_frontend *fe)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       if (time_after(jiffies, state->next_status_check)) {
+               deb_info("REFRESH STATE\n");
+
+               /* statistics */
+               if (af9005_get_statistic(fe))
+                       err("get_statistic_failed");
+               state->next_status_check = jiffies + 250 * HZ / 1000;
+       }
+       return 0;
+}
+
+static int af9005_fe_read_status(struct dvb_frontend *fe, fe_status_t * stat)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       u8 temp;
+       int ret;
+
+       if (state->tuner == NULL)
+               return -ENODEV;
+
+       *stat = 0;
+       ret = af9005_read_register_bits(state->d, xd_p_agc_lock,
+                                       agc_lock_pos, agc_lock_len, &temp);
+       if (ret)
+               return ret;
+       if (temp)
+               *stat |= FE_HAS_SIGNAL;
+
+       ret = af9005_read_register_bits(state->d, xd_p_fd_tpsd_lock,
+                                       fd_tpsd_lock_pos, fd_tpsd_lock_len,
+                                       &temp);
+       if (ret)
+               return ret;
+       if (temp)
+               *stat |= FE_HAS_CARRIER;
+
+       ret = af9005_read_register_bits(state->d,
+                                       xd_r_mp2if_sync_byte_locked,
+                                       mp2if_sync_byte_locked_pos,
+                                       mp2if_sync_byte_locked_pos, &temp);
+       if (ret)
+               return ret;
+       if (temp)
+               *stat |= FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_LOCK;
+       if (state->opened)
+               af9005_led_control(state->d, *stat & FE_HAS_LOCK);
+
+       ret =
+           af9005_read_register_bits(state->d, xd_p_reg_strong_sginal_detected,
+                                     reg_strong_sginal_detected_pos,
+                                     reg_strong_sginal_detected_len, &temp);
+       if (ret)
+               return ret;
+       if (temp != state->strong) {
+               deb_info("adjust for strong signal %d\n", temp);
+                       state->strong = temp;
+       }
+       return 0;
+}
+
+static int af9005_fe_read_ber(struct dvb_frontend *fe, u32 * ber)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       if (state->tuner == NULL)
+               return -ENODEV;
+       af9005_fe_refresh_state(fe);
+       *ber = state->ber;
+       return 0;
+}
+
+static int af9005_fe_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       if (state->tuner == NULL)
+               return -ENODEV;
+       af9005_fe_refresh_state(fe);
+       *unc = state->unc;
+       return 0;
+}
+
+static int af9005_fe_read_signal_strength(struct dvb_frontend *fe,
+                                         u16 * strength)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       int ret;
+       u8 if_gain, rf_gain;
+
+       if (state->tuner == NULL)
+               return -ENODEV;
+       ret =
+           af9005_read_ofdm_register(state->d, xd_r_reg_aagc_rf_gain,
+                                     &rf_gain);
+       if (ret)
+               return ret;
+       ret =
+           af9005_read_ofdm_register(state->d, xd_r_reg_aagc_if_gain,
+                                     &if_gain);
+       if (ret)
+               return ret;
+       /* this value has no real meaning, but i don't have the tables that relate
+          the rf and if gain with the dbm, so I just scale the value */
+       *strength = (512 - rf_gain - if_gain) << 7;
+       return 0;
+}
+
+static int af9005_fe_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+       /* the snr can be derived from the ber and the constellation
+          but I don't think this kind of complex calculations belong
+          in the driver. I may be wrong.... */
+       return -ENOSYS;
+}
+
+static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw)
+{
+       u8 temp0, temp1, temp2, temp3, buf[4];
+       int ret;
+       u32 NS_coeff1_2048Nu;
+       u32 NS_coeff1_8191Nu;
+       u32 NS_coeff1_8192Nu;
+       u32 NS_coeff1_8193Nu;
+       u32 NS_coeff2_2k;
+       u32 NS_coeff2_8k;
+
+       switch (bw) {
+       case BANDWIDTH_6_MHZ:
+               NS_coeff1_2048Nu = 0x2ADB6DC;
+               NS_coeff1_8191Nu = 0xAB7313;
+               NS_coeff1_8192Nu = 0xAB6DB7;
+               NS_coeff1_8193Nu = 0xAB685C;
+               NS_coeff2_2k = 0x156DB6E;
+               NS_coeff2_8k = 0x55B6DC;
+               break;
+
+       case BANDWIDTH_7_MHZ:
+               NS_coeff1_2048Nu = 0x3200001;
+               NS_coeff1_8191Nu = 0xC80640;
+               NS_coeff1_8192Nu = 0xC80000;
+               NS_coeff1_8193Nu = 0xC7F9C0;
+               NS_coeff2_2k = 0x1900000;
+               NS_coeff2_8k = 0x640000;
+               break;
+
+       case BANDWIDTH_8_MHZ:
+               NS_coeff1_2048Nu = 0x3924926;
+               NS_coeff1_8191Nu = 0xE4996E;
+               NS_coeff1_8192Nu = 0xE49249;
+               NS_coeff1_8193Nu = 0xE48B25;
+               NS_coeff2_2k = 0x1C92493;
+               NS_coeff2_8k = 0x724925;
+               break;
+       default:
+               err("Invalid bandwith %d.", bw);
+               return -EINVAL;
+       }
+
+       /*
+        *  write NS_coeff1_2048Nu
+        */
+
+       temp0 = (u8) (NS_coeff1_2048Nu & 0x000000FF);
+       temp1 = (u8) ((NS_coeff1_2048Nu & 0x0000FF00) >> 8);
+       temp2 = (u8) ((NS_coeff1_2048Nu & 0x00FF0000) >> 16);
+       temp3 = (u8) ((NS_coeff1_2048Nu & 0x03000000) >> 24);
+
+       /*  big endian to make 8051 happy */
+       buf[0] = temp3;
+       buf[1] = temp2;
+       buf[2] = temp1;
+       buf[3] = temp0;
+
+       /*  cfoe_NS_2k_coeff1_25_24 */
+       ret = af9005_write_ofdm_register(d, 0xAE00, buf[0]);
+       if (ret)
+               return ret;
+
+       /*  cfoe_NS_2k_coeff1_23_16 */
+       ret = af9005_write_ofdm_register(d, 0xAE01, buf[1]);
+       if (ret)
+               return ret;
+
+       /*  cfoe_NS_2k_coeff1_15_8 */
+       ret = af9005_write_ofdm_register(d, 0xAE02, buf[2]);
+       if (ret)
+               return ret;
+
+       /*  cfoe_NS_2k_coeff1_7_0 */
+       ret = af9005_write_ofdm_register(d, 0xAE03, buf[3]);
+       if (ret)
+               return ret;
+
+       /*
+        *  write NS_coeff2_2k
+        */
+
+       temp0 = (u8) ((NS_coeff2_2k & 0x0000003F));
+       temp1 = (u8) ((NS_coeff2_2k & 0x00003FC0) >> 6);
+       temp2 = (u8) ((NS_coeff2_2k & 0x003FC000) >> 14);
+       temp3 = (u8) ((NS_coeff2_2k & 0x01C00000) >> 22);
+
+       /*  big endian to make 8051 happy */
+       buf[0] = temp3;
+       buf[1] = temp2;
+       buf[2] = temp1;
+       buf[3] = temp0;
+
+       ret = af9005_write_ofdm_register(d, 0xAE04, buf[0]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE05, buf[1]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE06, buf[2]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE07, buf[3]);
+       if (ret)
+               return ret;
+
+       /*
+        *  write NS_coeff1_8191Nu
+        */
+
+       temp0 = (u8) ((NS_coeff1_8191Nu & 0x000000FF));
+       temp1 = (u8) ((NS_coeff1_8191Nu & 0x0000FF00) >> 8);
+       temp2 = (u8) ((NS_coeff1_8191Nu & 0x00FFC000) >> 16);
+       temp3 = (u8) ((NS_coeff1_8191Nu & 0x03000000) >> 24);
+
+       /*  big endian to make 8051 happy */
+       buf[0] = temp3;
+       buf[1] = temp2;
+       buf[2] = temp1;
+       buf[3] = temp0;
+
+       ret = af9005_write_ofdm_register(d, 0xAE08, buf[0]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE09, buf[1]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE0A, buf[2]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE0B, buf[3]);
+       if (ret)
+               return ret;
+
+       /*
+        *  write NS_coeff1_8192Nu
+        */
+
+       temp0 = (u8) (NS_coeff1_8192Nu & 0x000000FF);
+       temp1 = (u8) ((NS_coeff1_8192Nu & 0x0000FF00) >> 8);
+       temp2 = (u8) ((NS_coeff1_8192Nu & 0x00FFC000) >> 16);
+       temp3 = (u8) ((NS_coeff1_8192Nu & 0x03000000) >> 24);
+
+       /*  big endian to make 8051 happy */
+       buf[0] = temp3;
+       buf[1] = temp2;
+       buf[2] = temp1;
+       buf[3] = temp0;
+
+       ret = af9005_write_ofdm_register(d, 0xAE0C, buf[0]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE0D, buf[1]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE0E, buf[2]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE0F, buf[3]);
+       if (ret)
+               return ret;
+
+       /*
+        *  write NS_coeff1_8193Nu
+        */
+
+       temp0 = (u8) ((NS_coeff1_8193Nu & 0x000000FF));
+       temp1 = (u8) ((NS_coeff1_8193Nu & 0x0000FF00) >> 8);
+       temp2 = (u8) ((NS_coeff1_8193Nu & 0x00FFC000) >> 16);
+       temp3 = (u8) ((NS_coeff1_8193Nu & 0x03000000) >> 24);
+
+       /*  big endian to make 8051 happy */
+       buf[0] = temp3;
+       buf[1] = temp2;
+       buf[2] = temp1;
+       buf[3] = temp0;
+
+       ret = af9005_write_ofdm_register(d, 0xAE10, buf[0]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE11, buf[1]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE12, buf[2]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE13, buf[3]);
+       if (ret)
+               return ret;
+
+       /*
+        *  write NS_coeff2_8k
+        */
+
+       temp0 = (u8) ((NS_coeff2_8k & 0x0000003F));
+       temp1 = (u8) ((NS_coeff2_8k & 0x00003FC0) >> 6);
+       temp2 = (u8) ((NS_coeff2_8k & 0x003FC000) >> 14);
+       temp3 = (u8) ((NS_coeff2_8k & 0x01C00000) >> 22);
+
+       /*  big endian to make 8051 happy */
+       buf[0] = temp3;
+       buf[1] = temp2;
+       buf[2] = temp1;
+       buf[3] = temp0;
+
+       ret = af9005_write_ofdm_register(d, 0xAE14, buf[0]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE15, buf[1]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE16, buf[2]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE17, buf[3]);
+       return ret;
+
+}
+
+static int af9005_fe_select_bw(struct dvb_usb_device *d, fe_bandwidth_t bw)
+{
+       u8 temp;
+       switch (bw) {
+       case BANDWIDTH_6_MHZ:
+               temp = 0;
+               break;
+       case BANDWIDTH_7_MHZ:
+               temp = 1;
+               break;
+       case BANDWIDTH_8_MHZ:
+               temp = 2;
+               break;
+       default:
+               err("Invalid bandwith %d.", bw);
+               return -EINVAL;
+       }
+       return af9005_write_register_bits(d, xd_g_reg_bw, reg_bw_pos,
+                                         reg_bw_len, temp);
+}
+
+static int af9005_fe_power(struct dvb_frontend *fe, int on)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       u8 temp = on;
+       int ret;
+       deb_info("power %s tuner\n", on ? "on" : "off");
+       ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0);
+       return ret;
+}
+
+static struct mt2060_config af9005_mt2060_config = {
+       0xC0
+};
+
+static struct qt1010_config af9005_qt1010_config = {
+       0xC4
+};
+
+static int af9005_fe_init(struct dvb_frontend *fe)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       int ret, i, scriptlen;
+       u8 temp, temp0 = 0, temp1 = 0, temp2 = 0;
+       u8 buf[2];
+       u16 if1;
+
+       deb_info("in af9005_fe_init\n");
+
+       /* reset */
+       deb_info("reset\n");
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst_en,
+                                       4, 1, 0x01)))
+               return ret;
+       if ((ret = af9005_write_ofdm_register(state->d, APO_REG_RESET, 0)))
+               return ret;
+       /* clear ofdm reset */
+       deb_info("clear ofdm reset\n");
+       for (i = 0; i < 150; i++) {
+               if ((ret =
+                    af9005_read_ofdm_register(state->d,
+                                              xd_I2C_reg_ofdm_rst, &temp)))
+                       return ret;
+               if (temp & (regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos))
+                       break;
+               msleep(10);
+       }
+       if (i == 150)
+               return -ETIMEDOUT;
+
+       /*FIXME in the dump
+          write B200 A9
+          write xd_g_reg_ofsm_clk 7
+          read eepr c6 (2)
+          read eepr c7 (2)
+          misc ctrl 3 -> 1
+          read eepr ca (6)
+          write xd_g_reg_ofsm_clk 0
+          write B200 a1
+        */
+       ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa9);
+       if (ret)
+               return ret;
+       ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x07);
+       if (ret)
+               return ret;
+       temp = 0x01;
+       ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0);
+       if (ret)
+               return ret;
+       ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x00);
+       if (ret)
+               return ret;
+       ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa1);
+       if (ret)
+               return ret;
+
+       temp = regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos;
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst,
+                                       reg_ofdm_rst_pos, reg_ofdm_rst_len, 1)))
+               return ret;
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst,
+                                       reg_ofdm_rst_pos, reg_ofdm_rst_len, 0)))
+               return ret;
+
+       if (ret)
+               return ret;
+       /* don't know what register aefc is, but this is what the windows driver does */
+       ret = af9005_write_ofdm_register(state->d, 0xaefc, 0);
+       if (ret)
+               return ret;
+
+       /* set stand alone chip */
+       deb_info("set stand alone chip\n");
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_p_reg_dca_stand_alone,
+                                       reg_dca_stand_alone_pos,
+                                       reg_dca_stand_alone_len, 1)))
+               return ret;
+
+       /* set dca upper & lower chip */
+       deb_info("set dca upper & lower chip\n");
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_p_reg_dca_upper_chip,
+                                       reg_dca_upper_chip_pos,
+                                       reg_dca_upper_chip_len, 0)))
+               return ret;
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_p_reg_dca_lower_chip,
+                                       reg_dca_lower_chip_pos,
+                                       reg_dca_lower_chip_len, 0)))
+               return ret;
+
+       /* set 2wire master clock to 0x14 (for 60KHz) */
+       deb_info("set 2wire master clock to 0x14 (for 60KHz)\n");
+       if ((ret =
+            af9005_write_ofdm_register(state->d, xd_I2C_i2c_m_period, 0x14)))
+               return ret;
+
+       /* clear dca enable chip */
+       deb_info("clear dca enable chip\n");
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_p_reg_dca_en,
+                                       reg_dca_en_pos, reg_dca_en_len, 0)))
+               return ret;
+       /* FIXME these are register bits, but I don't know which ones */
+       ret = af9005_write_ofdm_register(state->d, 0xa16c, 1);
+       if (ret)
+               return ret;
+       ret = af9005_write_ofdm_register(state->d, 0xa3c1, 0);
+       if (ret)
+               return ret;
+
+       /* init other parameters: program cfoe and select bandwith */
+       deb_info("program cfoe\n");
+       if ((ret = af9005_fe_program_cfoe(state->d, BANDWIDTH_6_MHZ)))
+               return ret;
+       /* set read-update bit for constellation */
+       deb_info("set read-update bit for constellation\n");
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_p_reg_feq_read_update,
+                                       reg_feq_read_update_pos,
+                                       reg_feq_read_update_len, 1)))
+               return ret;
+
+       /* sample code has a set MPEG TS code here
+          but sniffing reveals that it doesn't do it */
+
+       /* set read-update bit to 1 for DCA constellation */
+       deb_info("set read-update bit 1 for DCA constellation\n");
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_p_reg_dca_read_update,
+                                       reg_dca_read_update_pos,
+                                       reg_dca_read_update_len, 1)))
+               return ret;
+
+       /* enable fec monitor */
+       deb_info("enable fec monitor\n");
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en,
+                                       fec_vtb_rsd_mon_en_pos,
+                                       fec_vtb_rsd_mon_en_len, 1)))
+               return ret;
+
+       /* FIXME should be register bits, I don't know which ones */
+       ret = af9005_write_ofdm_register(state->d, 0xa601, 0);
+
+       /* set api_retrain_never_freeze */
+       deb_info("set api_retrain_never_freeze\n");
+       if ((ret = af9005_write_ofdm_register(state->d, 0xaefb, 0x01)))
+               return ret;
+
+       /* load init script */
+       deb_info("load init script\n");
+       scriptlen = sizeof(script) / sizeof(RegDesc);
+       for (i = 0; i < scriptlen; i++) {
+               if ((ret =
+                    af9005_write_register_bits(state->d, script[i].reg,
+                                               script[i].pos,
+                                               script[i].len, script[i].val)))
+                       return ret;
+               /* save 3 bytes of original fcw */
+               if (script[i].reg == 0xae18)
+                       temp2 = script[i].val;
+               if (script[i].reg == 0xae19)
+                       temp1 = script[i].val;
+               if (script[i].reg == 0xae1a)
+                       temp0 = script[i].val;
+
+               /* save original unplug threshold */
+               if (script[i].reg == xd_p_reg_unplug_th)
+                       state->original_if_unplug_th = script[i].val;
+               if (script[i].reg == xd_p_reg_unplug_rf_gain_th)
+                       state->original_rf_unplug_th = script[i].val;
+               if (script[i].reg == xd_p_reg_unplug_dtop_if_gain_th)
+                       state->original_dtop_if_unplug_th = script[i].val;
+               if (script[i].reg == xd_p_reg_unplug_dtop_rf_gain_th)
+                       state->original_dtop_rf_unplug_th = script[i].val;
+
+       }
+       state->original_fcw =
+           ((u32) temp2 << 16) + ((u32) temp1 << 8) + (u32) temp0;
+
+
+       /* save original TOPs */
+       deb_info("save original TOPs\n");
+
+       /*  RF TOP */
+       ret =
+           af9005_read_word_agc(state->d,
+                                xd_p_reg_aagc_rf_top_numerator_9_8,
+                                xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2,
+                                &state->original_rf_top);
+       if (ret)
+               return ret;
+
+       /*  IF TOP */
+       ret =
+           af9005_read_word_agc(state->d,
+                                xd_p_reg_aagc_if_top_numerator_9_8,
+                                xd_p_reg_aagc_if_top_numerator_7_0, 0, 2,
+                                &state->original_if_top);
+       if (ret)
+               return ret;
+
+       /*  ACI 0 IF TOP */
+       ret =
+           af9005_read_word_agc(state->d, 0xA60E, 0xA60A, 4, 2,
+                                &state->original_aci0_if_top);
+       if (ret)
+               return ret;
+
+       /*  ACI 1 IF TOP */
+       ret =
+           af9005_read_word_agc(state->d, 0xA60E, 0xA60B, 6, 2,
+                                &state->original_aci1_if_top);
+       if (ret)
+               return ret;
+
+       /* attach tuner and init */
+       if (state->tuner == NULL) {
+               /* read tuner and board id from eeprom */
+               ret = af9005_read_eeprom(adap->dev, 0xc6, buf, 2);
+               if (ret) {
+                       err("Impossible to read EEPROM\n");
+                       return ret;
+               }
+               deb_info("Tuner id %d, board id %d\n", buf[0], buf[1]);
+               switch (buf[0]) {
+               case 2: /* MT2060 */
+                       /* read if1 from eeprom */
+                       ret = af9005_read_eeprom(adap->dev, 0xc8, buf, 2);
+                       if (ret) {
+                               err("Impossible to read EEPROM\n");
+                               return ret;
+                       }
+                       if1 = (u16) (buf[0] << 8) + buf[1];
+                       state->tuner =
+                           dvb_attach(mt2060_attach, fe, &adap->dev->i2c_adap,
+                                      &af9005_mt2060_config, if1);
+                       if (state->tuner == NULL) {
+                               deb_info("MT2060 attach failed\n");
+                               return -ENODEV;
+                       }
+                       break;
+               case 3: /* QT1010 */
+               case 9: /* QT1010B */
+                       state->tuner =
+                           dvb_attach(qt1010_attach, fe, &adap->dev->i2c_adap,
+                                      &af9005_qt1010_config);
+                       if (state->tuner == NULL) {
+                               deb_info("QT1010 attach failed\n");
+                               return -ENODEV;
+                       }
+                       break;
+               default:
+                       err("Unsupported tuner type %d", buf[0]);
+                       return -ENODEV;
+               }
+               ret = state->tuner->ops.tuner_ops.init(state->tuner);
+               if (ret)
+                       return ret;
+       }
+
+       deb_info("profit!\n");
+       return 0;
+}
+
+static int af9005_fe_sleep(struct dvb_frontend *fe)
+{
+       return af9005_fe_power(fe, 0);
+}
+
+static int af9005_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+
+       if (acquire) {
+               state->opened++;
+       } else {
+
+               state->opened--;
+               if (!state->opened)
+                       af9005_led_control(state->d, 0);
+       }
+       return 0;
+}
+
+static int af9005_fe_set_frontend(struct dvb_frontend *fe,
+                                 struct dvb_frontend_parameters *fep)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       int ret;
+       u8 temp, temp0, temp1, temp2;
+
+       deb_info("af9005_fe_set_frontend freq %d bw %d\n", fep->frequency,
+                fep->u.ofdm.bandwidth);
+       if (state->tuner == NULL) {
+               err("Tuner not attached");
+               return -ENODEV;
+       }
+
+       deb_info("turn off led\n");
+       /* not in the log */
+       ret = af9005_led_control(state->d, 0);
+       if (ret)
+               return ret;
+       /* not sure about the bits */
+       ret = af9005_write_register_bits(state->d, XD_MP2IF_MISC, 2, 1, 0);
+       if (ret)
+               return ret;
+
+       /* set FCW to default value */
+       deb_info("set FCW to default value\n");
+       temp0 = (u8) (state->original_fcw & 0x000000ff);
+       temp1 = (u8) ((state->original_fcw & 0x0000ff00) >> 8);
+       temp2 = (u8) ((state->original_fcw & 0x00ff0000) >> 16);
+       ret = af9005_write_ofdm_register(state->d, 0xae1a, temp0);
+       if (ret)
+               return ret;
+       ret = af9005_write_ofdm_register(state->d, 0xae19, temp1);
+       if (ret)
+               return ret;
+       ret = af9005_write_ofdm_register(state->d, 0xae18, temp2);
+       if (ret)
+               return ret;
+
+       /* restore original TOPs */
+       deb_info("restore original TOPs\n");
+       ret =
+           af9005_write_word_agc(state->d,
+                                 xd_p_reg_aagc_rf_top_numerator_9_8,
+                                 xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2,
+                                 state->original_rf_top);
+       if (ret)
+               return ret;
+       ret =
+           af9005_write_word_agc(state->d,
+                                 xd_p_reg_aagc_if_top_numerator_9_8,
+                                 xd_p_reg_aagc_if_top_numerator_7_0, 0, 2,
+                                 state->original_if_top);
+       if (ret)
+               return ret;
+       ret =
+           af9005_write_word_agc(state->d, 0xA60E, 0xA60A, 4, 2,
+                                 state->original_aci0_if_top);
+       if (ret)
+               return ret;
+       ret =
+           af9005_write_word_agc(state->d, 0xA60E, 0xA60B, 6, 2,
+                                 state->original_aci1_if_top);
+       if (ret)
+               return ret;
+
+       /* select bandwith */
+       deb_info("select bandwidth");
+       ret = af9005_fe_select_bw(state->d, fep->u.ofdm.bandwidth);
+       if (ret)
+               return ret;
+       ret = af9005_fe_program_cfoe(state->d, fep->u.ofdm.bandwidth);
+       if (ret)
+               return ret;
+
+       /* clear easy mode flag */
+       deb_info("clear easy mode flag\n");
+       ret = af9005_write_ofdm_register(state->d, 0xaefd, 0);
+       if (ret)
+               return ret;
+
+       /* set unplug threshold to original value */
+       deb_info("set unplug threshold to original value\n");
+       ret =
+           af9005_write_ofdm_register(state->d, xd_p_reg_unplug_th,
+                                      state->original_if_unplug_th);
+       if (ret)
+               return ret;
+       /* set tuner */
+       deb_info("set tuner\n");
+       ret = state->tuner->ops.tuner_ops.set_params(state->tuner, fep);
+       if (ret)
+               return ret;
+
+       /* trigger ofsm */
+       deb_info("trigger ofsm\n");
+       temp = 0;
+       ret = af9005_write_tuner_registers(state->d, 0xffff, &temp, 1);
+       if (ret)
+               return ret;
+
+       /* clear retrain and freeze flag */
+       deb_info("clear retrain and freeze flag\n");
+       ret =
+           af9005_write_register_bits(state->d,
+                                      xd_p_reg_api_retrain_request,
+                                      reg_api_retrain_request_pos, 2, 0);
+       if (ret)
+               return ret;
+
+       /* reset pre viterbi and post viterbi registers and statistics */
+       af9005_reset_pre_viterbi(fe);
+       af9005_reset_post_viterbi(fe);
+       state->pre_vit_error_count = 0;
+       state->pre_vit_bit_count = 0;
+       state->ber = 0;
+       state->post_vit_error_count = 0;
+       /* state->unc = 0; commented out since it should be ever increasing */
+       state->abort_count = 0;
+
+       state->next_status_check = jiffies;
+       state->strong = -1;
+
+       return 0;
+}
+
+static int af9005_fe_get_frontend(struct dvb_frontend *fe,
+                                 struct dvb_frontend_parameters *fep)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       int ret;
+       u8 temp;
+
+       /* mode */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
+                                     reg_tpsd_const_pos, reg_tpsd_const_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       deb_info("===== fe_get_frontend ==============\n");
+       deb_info("CONSTELLATION ");
+       switch (temp) {
+       case 0:
+               fep->u.ofdm.constellation = QPSK;
+               deb_info("QPSK\n");
+               break;
+       case 1:
+               fep->u.ofdm.constellation = QAM_16;
+               deb_info("QAM_16\n");
+               break;
+       case 2:
+               fep->u.ofdm.constellation = QAM_64;
+               deb_info("QAM_64\n");
+               break;
+       }
+
+       /* tps hierarchy and alpha value */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_tpsd_hier,
+                                     reg_tpsd_hier_pos, reg_tpsd_hier_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       deb_info("HIERARCHY ");
+       switch (temp) {
+       case 0:
+               fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+               deb_info("NONE\n");
+               break;
+       case 1:
+               fep->u.ofdm.hierarchy_information = HIERARCHY_1;
+               deb_info("1\n");
+               break;
+       case 2:
+               fep->u.ofdm.hierarchy_information = HIERARCHY_2;
+               deb_info("2\n");
+               break;
+       case 3:
+               fep->u.ofdm.hierarchy_information = HIERARCHY_4;
+               deb_info("4\n");
+               break;
+       }
+
+       /*  high/low priority     */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_dec_pri,
+                                     reg_dec_pri_pos, reg_dec_pri_len, &temp);
+       if (ret)
+               return ret;
+       /* if temp is set = high priority */
+       deb_info("PRIORITY %s\n", temp ? "high" : "low");
+
+       /* high coderate */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_tpsd_hpcr,
+                                     reg_tpsd_hpcr_pos, reg_tpsd_hpcr_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       deb_info("CODERATE HP ");
+       switch (temp) {
+       case 0:
+               fep->u.ofdm.code_rate_HP = FEC_1_2;
+               deb_info("FEC_1_2\n");
+               break;
+       case 1:
+               fep->u.ofdm.code_rate_HP = FEC_2_3;
+               deb_info("FEC_2_3\n");
+               break;
+       case 2:
+               fep->u.ofdm.code_rate_HP = FEC_3_4;
+               deb_info("FEC_3_4\n");
+               break;
+       case 3:
+               fep->u.ofdm.code_rate_HP = FEC_5_6;
+               deb_info("FEC_5_6\n");
+               break;
+       case 4:
+               fep->u.ofdm.code_rate_HP = FEC_7_8;
+               deb_info("FEC_7_8\n");
+               break;
+       }
+
+       /* low coderate */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_tpsd_lpcr,
+                                     reg_tpsd_lpcr_pos, reg_tpsd_lpcr_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       deb_info("CODERATE LP ");
+       switch (temp) {
+       case 0:
+               fep->u.ofdm.code_rate_LP = FEC_1_2;
+               deb_info("FEC_1_2\n");
+               break;
+       case 1:
+               fep->u.ofdm.code_rate_LP = FEC_2_3;
+               deb_info("FEC_2_3\n");
+               break;
+       case 2:
+               fep->u.ofdm.code_rate_LP = FEC_3_4;
+               deb_info("FEC_3_4\n");
+               break;
+       case 3:
+               fep->u.ofdm.code_rate_LP = FEC_5_6;
+               deb_info("FEC_5_6\n");
+               break;
+       case 4:
+               fep->u.ofdm.code_rate_LP = FEC_7_8;
+               deb_info("FEC_7_8\n");
+               break;
+       }
+
+       /* guard interval */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_tpsd_gi,
+                                     reg_tpsd_gi_pos, reg_tpsd_gi_len, &temp);
+       if (ret)
+               return ret;
+       deb_info("GUARD INTERVAL ");
+       switch (temp) {
+       case 0:
+               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+               deb_info("1_32\n");
+               break;
+       case 1:
+               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+               deb_info("1_16\n");
+               break;
+       case 2:
+               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+               deb_info("1_8\n");
+               break;
+       case 3:
+               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+               deb_info("1_4\n");
+               break;
+       }
+
+       /* fft */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod,
+                                     reg_tpsd_txmod_pos, reg_tpsd_txmod_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       deb_info("TRANSMISSION MODE ");
+       switch (temp) {
+       case 0:
+               fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+               deb_info("2K\n");
+               break;
+       case 1:
+               fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+               deb_info("8K\n");
+               break;
+       }
+
+       /* bandwidth      */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_bw, reg_bw_pos,
+                                     reg_bw_len, &temp);
+       deb_info("BANDWIDTH ");
+       switch (temp) {
+       case 0:
+               fep->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+               deb_info("6\n");
+               break;
+       case 1:
+               fep->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+               deb_info("7\n");
+               break;
+       case 2:
+               fep->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+               deb_info("8\n");
+               break;
+       }
+       return 0;
+}
+
+static void af9005_fe_release(struct dvb_frontend *fe)
+{
+       struct af9005_fe_state *state =
+           (struct af9005_fe_state *)fe->demodulator_priv;
+       if (state->tuner != NULL && state->tuner->ops.tuner_ops.release != NULL) {
+               state->tuner->ops.tuner_ops.release(state->tuner);
+#ifdef CONFIG_DVB_CORE_ATTACH
+               symbol_put_addr(state->tuner->ops.tuner_ops.release);
+#endif
+       }
+       kfree(state);
+}
+
+static struct dvb_frontend_ops af9005_fe_ops;
+
+struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d)
+{
+       struct af9005_fe_state *state = NULL;
+
+       /* allocate memory for the internal state */
+       state = kzalloc(sizeof(struct af9005_fe_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       deb_info("attaching frontend af9005\n");
+
+       state->d = d;
+       state->tuner = NULL;
+       state->opened = 0;
+
+       memcpy(&state->frontend.ops, &af9005_fe_ops,
+              sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+
+       return &state->frontend;
+      error:
+       return NULL;
+}
+
+static struct dvb_frontend_ops af9005_fe_ops = {
+       .info = {
+                .name = "AF9005 USB 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 = af9005_fe_release,
+
+       .init = af9005_fe_init,
+       .sleep = af9005_fe_sleep,
+       .ts_bus_ctrl = af9005_ts_bus_ctrl,
+
+       .set_frontend = af9005_fe_set_frontend,
+       .get_frontend = af9005_fe_get_frontend,
+
+       .read_status = af9005_fe_read_status,
+       .read_ber = af9005_fe_read_ber,
+       .read_signal_strength = af9005_fe_read_signal_strength,
+       .read_snr = af9005_fe_read_snr,
+       .read_ucblocks = af9005_fe_read_unc_blocks,
+};
diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c
new file mode 100644 (file)
index 0000000..ff00c0e
--- /dev/null
@@ -0,0 +1,157 @@
+/* DVB USB compliant Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Standard remote decode function
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/REDME.dvb-usb for more information
+ */
+#include "af9005.h"
+/* debug */
+int dvb_usb_af9005_remote_debug;
+module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+                "enable (1) or disable (0) debug messages."
+                DVB_USB_DEBUG_STATUS);
+
+#define deb_decode(args...)   dprintk(dvb_usb_af9005_remote_debug,0x01,args)
+
+struct dvb_usb_rc_key af9005_rc_keys[] = {
+
+       {0x01, 0xb7, KEY_POWER},
+       {0x01, 0xa7, KEY_VOLUMEUP},
+       {0x01, 0x87, KEY_CHANNELUP},
+       {0x01, 0x7f, KEY_MUTE},
+       {0x01, 0xbf, KEY_VOLUMEDOWN},
+       {0x01, 0x3f, KEY_CHANNELDOWN},
+       {0x01, 0xdf, KEY_1},
+       {0x01, 0x5f, KEY_2},
+       {0x01, 0x9f, KEY_3},
+       {0x01, 0x1f, KEY_4},
+       {0x01, 0xef, KEY_5},
+       {0x01, 0x6f, KEY_6},
+       {0x01, 0xaf, KEY_7},
+       {0x01, 0x27, KEY_8},
+       {0x01, 0x07, KEY_9},
+       {0x01, 0xcf, KEY_ZOOM},
+       {0x01, 0x4f, KEY_0},
+       {0x01, 0x8f, KEY_GOTO}, /* marked jump on the remote */
+
+       {0x00, 0xbd, KEY_POWER},
+       {0x00, 0x7d, KEY_VOLUMEUP},
+       {0x00, 0xfd, KEY_CHANNELUP},
+       {0x00, 0x9d, KEY_MUTE},
+       {0x00, 0x5d, KEY_VOLUMEDOWN},
+       {0x00, 0xdd, KEY_CHANNELDOWN},
+       {0x00, 0xad, KEY_1},
+       {0x00, 0x6d, KEY_2},
+       {0x00, 0xed, KEY_3},
+       {0x00, 0x8d, KEY_4},
+       {0x00, 0x4d, KEY_5},
+       {0x00, 0xcd, KEY_6},
+       {0x00, 0xb5, KEY_7},
+       {0x00, 0x75, KEY_8},
+       {0x00, 0xf5, KEY_9},
+       {0x00, 0x95, KEY_ZOOM},
+       {0x00, 0x55, KEY_0},
+       {0x00, 0xd5, KEY_GOTO}, /* marked jump on the remote */
+};
+
+int af9005_rc_keys_size = ARRAY_SIZE(af9005_rc_keys);
+
+static int repeatable_keys[] = {
+       KEY_VOLUMEUP,
+       KEY_VOLUMEDOWN,
+       KEY_CHANNELUP,
+       KEY_CHANNELDOWN
+};
+
+int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
+                    int *state)
+{
+       u16 mark, space;
+       u32 result;
+       u8 cust, dat, invdat;
+       int i;
+
+       if (len >= 6) {
+               mark = (u16) (data[0] << 8) + data[1];
+               space = (u16) (data[2] << 8) + data[3];
+               if (space * 3 < mark) {
+                       for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) {
+                               if (d->last_event == repeatable_keys[i]) {
+                                       *state = REMOTE_KEY_REPEAT;
+                                       *event = d->last_event;
+                                       deb_decode("repeat key, event %x\n",
+                                                  *event);
+                                       return 0;
+                               }
+                       }
+                       deb_decode("repeated key ignored (non repeatable)\n");
+                       return 0;
+               } else if (len >= 33 * 4) {     /*32 bits + start code */
+                       result = 0;
+                       for (i = 4; i < 4 + 32 * 4; i += 4) {
+                               result <<= 1;
+                               mark = (u16) (data[i] << 8) + data[i + 1];
+                               mark >>= 1;
+                               space = (u16) (data[i + 2] << 8) + data[i + 3];
+                               space >>= 1;
+                               if (mark * 2 > space)
+                                       result += 1;
+                       }
+                       deb_decode("key pressed, raw value %x\n", result);
+                       if ((result & 0xff000000) != 0xfe000000) {
+                               deb_decode
+                                   ("doesn't start with 0xfe, ignored\n");
+                               return 0;
+                       }
+                       cust = (result >> 16) & 0xff;
+                       dat = (result >> 8) & 0xff;
+                       invdat = (~result) & 0xff;
+                       if (dat != invdat) {
+                               deb_decode("code != inverted code\n");
+                               return 0;
+                       }
+                       for (i = 0; i < af9005_rc_keys_size; i++) {
+                               if (af9005_rc_keys[i].custom == cust
+                                   && af9005_rc_keys[i].data == dat) {
+                                       *event = af9005_rc_keys[i].event;
+                                       *state = REMOTE_KEY_PRESSED;
+                                       deb_decode
+                                           ("key pressed, event %x\n", *event);
+                                       return 0;
+                               }
+                       }
+                       deb_decode("not found in table\n");
+               }
+       }
+       return 0;
+}
+
+EXPORT_SYMBOL(af9005_rc_keys);
+EXPORT_SYMBOL(af9005_rc_keys_size);
+EXPORT_SYMBOL(af9005_rc_decode);
+
+MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
+MODULE_DESCRIPTION
+    ("Standard remote control decoder for Afatech 9005 DVB-T USB1.1 stick");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9005-script.h b/drivers/media/dvb/dvb-usb/af9005-script.h
new file mode 100644 (file)
index 0000000..6eeaae5
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+File automatically generated by createinit.py using data
+extracted from AF05BDA.sys (windows driver):
+
+dd if=AF05BDA.sys of=initsequence bs=1 skip=88316 count=1110
+python createinit.py > af9005-script.h
+
+*/
+
+typedef struct {
+       u16 reg;
+       u8 pos;
+       u8 len;
+       u8 val;
+} RegDesc;
+
+RegDesc script[] = {
+       {0xa180, 0x0, 0x8, 0xa},
+       {0xa181, 0x0, 0x8, 0xd7},
+       {0xa182, 0x0, 0x8, 0xa3},
+       {0xa0a0, 0x0, 0x8, 0x0},
+       {0xa0a1, 0x0, 0x5, 0x0},
+       {0xa0a1, 0x5, 0x1, 0x1},
+       {0xa0c0, 0x0, 0x4, 0x1},
+       {0xa20e, 0x4, 0x4, 0xa},
+       {0xa20f, 0x0, 0x8, 0x40},
+       {0xa210, 0x0, 0x8, 0x8},
+       {0xa32a, 0x0, 0x4, 0xa},
+       {0xa32c, 0x0, 0x8, 0x20},
+       {0xa32b, 0x0, 0x8, 0x15},
+       {0xa1a0, 0x1, 0x1, 0x1},
+       {0xa000, 0x0, 0x1, 0x1},
+       {0xa000, 0x1, 0x1, 0x0},
+       {0xa001, 0x1, 0x1, 0x1},
+       {0xa001, 0x0, 0x1, 0x0},
+       {0xa001, 0x5, 0x1, 0x0},
+       {0xa00e, 0x0, 0x5, 0x10},
+       {0xa00f, 0x0, 0x3, 0x4},
+       {0xa00f, 0x3, 0x3, 0x5},
+       {0xa010, 0x0, 0x3, 0x4},
+       {0xa010, 0x3, 0x3, 0x5},
+       {0xa016, 0x4, 0x4, 0x3},
+       {0xa01f, 0x0, 0x6, 0xa},
+       {0xa020, 0x0, 0x6, 0xa},
+       {0xa2bc, 0x0, 0x1, 0x1},
+       {0xa2bc, 0x5, 0x1, 0x1},
+       {0xa015, 0x0, 0x8, 0x50},
+       {0xa016, 0x0, 0x1, 0x0},
+       {0xa02a, 0x0, 0x8, 0x50},
+       {0xa029, 0x0, 0x8, 0x4b},
+       {0xa614, 0x0, 0x8, 0x46},
+       {0xa002, 0x0, 0x5, 0x19},
+       {0xa003, 0x0, 0x5, 0x1a},
+       {0xa004, 0x0, 0x5, 0x19},
+       {0xa005, 0x0, 0x5, 0x1a},
+       {0xa008, 0x0, 0x8, 0x69},
+       {0xa009, 0x0, 0x2, 0x2},
+       {0xae1b, 0x0, 0x8, 0x69},
+       {0xae1c, 0x0, 0x8, 0x2},
+       {0xae1d, 0x0, 0x8, 0x2a},
+       {0xa022, 0x0, 0x8, 0xaa},
+       {0xa006, 0x0, 0x8, 0xc8},
+       {0xa007, 0x0, 0x2, 0x0},
+       {0xa00c, 0x0, 0x8, 0xba},
+       {0xa00d, 0x0, 0x2, 0x2},
+       {0xa608, 0x0, 0x8, 0xba},
+       {0xa60e, 0x0, 0x2, 0x2},
+       {0xa609, 0x0, 0x8, 0x80},
+       {0xa60e, 0x2, 0x2, 0x3},
+       {0xa00a, 0x0, 0x8, 0xb6},
+       {0xa00b, 0x0, 0x2, 0x0},
+       {0xa011, 0x0, 0x8, 0xb9},
+       {0xa012, 0x0, 0x2, 0x0},
+       {0xa013, 0x0, 0x8, 0xbd},
+       {0xa014, 0x0, 0x2, 0x2},
+       {0xa366, 0x0, 0x1, 0x1},
+       {0xa2bc, 0x3, 0x1, 0x0},
+       {0xa2bd, 0x0, 0x8, 0xa},
+       {0xa2be, 0x0, 0x8, 0x14},
+       {0xa2bf, 0x0, 0x8, 0x8},
+       {0xa60a, 0x0, 0x8, 0xbd},
+       {0xa60e, 0x4, 0x2, 0x2},
+       {0xa60b, 0x0, 0x8, 0x86},
+       {0xa60e, 0x6, 0x2, 0x3},
+       {0xa001, 0x2, 0x2, 0x1},
+       {0xa1c7, 0x0, 0x8, 0xf5},
+       {0xa03d, 0x0, 0x8, 0xb1},
+       {0xa616, 0x0, 0x8, 0xff},
+       {0xa617, 0x0, 0x8, 0xad},
+       {0xa618, 0x0, 0x8, 0xad},
+       {0xa61e, 0x3, 0x1, 0x1},
+       {0xae1a, 0x0, 0x8, 0x0},
+       {0xae19, 0x0, 0x8, 0xc8},
+       {0xae18, 0x0, 0x8, 0x61},
+       {0xa140, 0x0, 0x8, 0x0},
+       {0xa141, 0x0, 0x8, 0xc8},
+       {0xa142, 0x0, 0x7, 0x61},
+       {0xa023, 0x0, 0x8, 0xff},
+       {0xa021, 0x0, 0x8, 0xad},
+       {0xa026, 0x0, 0x1, 0x0},
+       {0xa024, 0x0, 0x8, 0xff},
+       {0xa025, 0x0, 0x8, 0xff},
+       {0xa1c8, 0x0, 0x8, 0xf},
+       {0xa2bc, 0x1, 0x1, 0x0},
+       {0xa60c, 0x0, 0x4, 0x5},
+       {0xa60c, 0x4, 0x4, 0x6},
+       {0xa60d, 0x0, 0x8, 0xa},
+       {0xa371, 0x0, 0x1, 0x1},
+       {0xa366, 0x1, 0x3, 0x7},
+       {0xa338, 0x0, 0x8, 0x10},
+       {0xa339, 0x0, 0x6, 0x7},
+       {0xa33a, 0x0, 0x6, 0x1f},
+       {0xa33b, 0x0, 0x8, 0xf6},
+       {0xa33c, 0x3, 0x5, 0x4},
+       {0xa33d, 0x4, 0x4, 0x0},
+       {0xa33d, 0x1, 0x1, 0x1},
+       {0xa33d, 0x2, 0x1, 0x1},
+       {0xa33d, 0x3, 0x1, 0x1},
+       {0xa16d, 0x0, 0x4, 0xf},
+       {0xa161, 0x0, 0x5, 0x5},
+       {0xa162, 0x0, 0x4, 0x5},
+       {0xa165, 0x0, 0x8, 0xff},
+       {0xa166, 0x0, 0x8, 0x9c},
+       {0xa2c3, 0x0, 0x4, 0x5},
+       {0xa61a, 0x0, 0x6, 0xf},
+       {0xb200, 0x0, 0x8, 0xa1},
+       {0xb201, 0x0, 0x8, 0x7},
+       {0xa093, 0x0, 0x1, 0x0},
+       {0xa093, 0x1, 0x5, 0xf},
+       {0xa094, 0x0, 0x8, 0xff},
+       {0xa095, 0x0, 0x8, 0xf},
+       {0xa080, 0x2, 0x5, 0x3},
+       {0xa081, 0x0, 0x4, 0x0},
+       {0xa081, 0x4, 0x4, 0x9},
+       {0xa082, 0x0, 0x5, 0x1f},
+       {0xa08d, 0x0, 0x8, 0x1},
+       {0xa083, 0x0, 0x8, 0x32},
+       {0xa084, 0x0, 0x1, 0x0},
+       {0xa08e, 0x0, 0x8, 0x3},
+       {0xa085, 0x0, 0x8, 0x32},
+       {0xa086, 0x0, 0x3, 0x0},
+       {0xa087, 0x0, 0x8, 0x6e},
+       {0xa088, 0x0, 0x5, 0x15},
+       {0xa089, 0x0, 0x8, 0x0},
+       {0xa08a, 0x0, 0x5, 0x19},
+       {0xa08b, 0x0, 0x8, 0x92},
+       {0xa08c, 0x0, 0x5, 0x1c},
+       {0xa120, 0x0, 0x8, 0x0},
+       {0xa121, 0x0, 0x5, 0x10},
+       {0xa122, 0x0, 0x8, 0x0},
+       {0xa123, 0x0, 0x7, 0x40},
+       {0xa123, 0x7, 0x1, 0x0},
+       {0xa124, 0x0, 0x8, 0x13},
+       {0xa125, 0x0, 0x7, 0x10},
+       {0xa1c0, 0x0, 0x8, 0x0},
+       {0xa1c1, 0x0, 0x5, 0x4},
+       {0xa1c2, 0x0, 0x8, 0x0},
+       {0xa1c3, 0x0, 0x5, 0x10},
+       {0xa1c3, 0x5, 0x3, 0x0},
+       {0xa1c4, 0x0, 0x6, 0x0},
+       {0xa1c5, 0x0, 0x7, 0x10},
+       {0xa100, 0x0, 0x8, 0x0},
+       {0xa101, 0x0, 0x5, 0x10},
+       {0xa102, 0x0, 0x8, 0x0},
+       {0xa103, 0x0, 0x7, 0x40},
+       {0xa103, 0x7, 0x1, 0x0},
+       {0xa104, 0x0, 0x8, 0x18},
+       {0xa105, 0x0, 0x7, 0xa},
+       {0xa106, 0x0, 0x8, 0x20},
+       {0xa107, 0x0, 0x8, 0x40},
+       {0xa108, 0x0, 0x4, 0x0},
+       {0xa38c, 0x0, 0x8, 0xfc},
+       {0xa38d, 0x0, 0x8, 0x0},
+       {0xa38e, 0x0, 0x8, 0x7e},
+       {0xa38f, 0x0, 0x8, 0x0},
+       {0xa390, 0x0, 0x8, 0x2f},
+       {0xa60f, 0x5, 0x1, 0x1},
+       {0xa170, 0x0, 0x8, 0xdc},
+       {0xa171, 0x0, 0x2, 0x0},
+       {0xa2ae, 0x0, 0x1, 0x1},
+       {0xa2ae, 0x1, 0x1, 0x1},
+       {0xa392, 0x0, 0x1, 0x1},
+       {0xa391, 0x2, 0x1, 0x0},
+       {0xabc1, 0x0, 0x8, 0xff},
+       {0xabc2, 0x0, 0x8, 0x0},
+       {0xabc8, 0x0, 0x8, 0x8},
+       {0xabca, 0x0, 0x8, 0x10},
+       {0xabcb, 0x0, 0x1, 0x0},
+       {0xabc3, 0x5, 0x3, 0x7},
+       {0xabc0, 0x6, 0x1, 0x0},
+       {0xabc0, 0x4, 0x2, 0x0},
+       {0xa344, 0x4, 0x4, 0x1},
+       {0xabc0, 0x7, 0x1, 0x1},
+       {0xabc0, 0x2, 0x1, 0x1},
+       {0xa345, 0x0, 0x8, 0x66},
+       {0xa346, 0x0, 0x8, 0x66},
+       {0xa347, 0x0, 0x4, 0x0},
+       {0xa343, 0x0, 0x4, 0xa},
+       {0xa347, 0x4, 0x4, 0x2},
+       {0xa348, 0x0, 0x4, 0xc},
+       {0xa348, 0x4, 0x4, 0x7},
+       {0xa349, 0x0, 0x6, 0x2},
+};
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
new file mode 100644 (file)
index 0000000..7db6eee
--- /dev/null
@@ -0,0 +1,1141 @@
+/* DVB USB compliant Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/REDME.dvb-usb for more information
+ */
+#include "af9005.h"
+
+/* debug */
+int dvb_usb_af9005_debug;
+module_param_named(debug, dvb_usb_af9005_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+                "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))."
+                DVB_USB_DEBUG_STATUS);
+/* enable obnoxious led */
+int dvb_usb_af9005_led = 1;
+module_param_named(led, dvb_usb_af9005_led, bool, 0644);
+MODULE_PARM_DESC(led, "enable led (default: 1).");
+
+/* eeprom dump */
+int dvb_usb_af9005_dump_eeprom = 0;
+module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0);
+MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom.");
+
+/* remote control decoder */
+int (*rc_decode) (struct dvb_usb_device * d, u8 * data, int len, u32 * event,
+                 int *state);
+void *rc_keys;
+int *rc_keys_size;
+
+u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
+
+struct af9005_device_state {
+       u8 sequence;
+       int led_state;
+};
+
+int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen,
+                         u8 * rbuf, u16 rlen, int delay_ms)
+{
+       int actlen, ret = -ENOMEM;
+
+       if (wbuf == NULL || wlen == 0)
+               return -EINVAL;
+
+       if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+               return ret;
+
+       deb_xfer(">>> ");
+       debug_dump(wbuf, wlen, deb_xfer);
+
+       ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev,
+                                                   2), wbuf, wlen,
+                          &actlen, 2000);
+
+       if (ret)
+               err("bulk message failed: %d (%d/%d)", ret, wlen, actlen);
+       else
+               ret = actlen != wlen ? -1 : 0;
+
+       /* an answer is expected, and no error before */
+       if (!ret && rbuf && rlen) {
+               if (delay_ms)
+                       msleep(delay_ms);
+
+               ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
+                                                           0x01), rbuf,
+                                  rlen, &actlen, 2000);
+
+               if (ret)
+                       err("recv bulk message failed: %d", ret);
+               else {
+                       deb_xfer("<<< ");
+                       debug_dump(rbuf, actlen, deb_xfer);
+               }
+       }
+
+       mutex_unlock(&d->usb_mutex);
+       return ret;
+}
+
+int af9005_usb_generic_write(struct dvb_usb_device *d, u8 * buf, u16 len)
+{
+       return af9005_usb_generic_rw(d, buf, len, NULL, 0, 0);
+}
+
+int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
+                             int readwrite, int type, u8 * values, int len)
+{
+       struct af9005_device_state *st = d->priv;
+       u8 obuf[16] = { 0 };
+       u8 ibuf[17] = { 0 };
+       u8 command;
+       int i;
+       int ret;
+
+       if (len < 1) {
+               err("generic read/write, less than 1 byte. Makes no sense.");
+               return -EINVAL;
+       }
+       if (len > 8) {
+               err("generic read/write, more than 8 bytes. Not supported.");
+               return -EINVAL;
+       }
+
+       obuf[0] = 14;           /* rest of buffer length low */
+       obuf[1] = 0;            /* rest of buffer length high */
+
+       obuf[2] = AF9005_REGISTER_RW;   /* register operation */
+       obuf[3] = 12;           /* rest of buffer length */
+
+       obuf[4] = st->sequence++;       /* sequence number */
+
+       obuf[5] = (u8) (reg >> 8);      /* register address */
+       obuf[6] = (u8) (reg & 0xff);
+
+       if (type == AF9005_OFDM_REG) {
+               command = AF9005_CMD_OFDM_REG;
+       } else {
+               command = AF9005_CMD_TUNER;
+       }
+
+       if (len > 1)
+               command |=
+                   AF9005_CMD_BURST | AF9005_CMD_AUTOINC | (len - 1) << 3;
+       command |= readwrite;
+       if (readwrite == AF9005_CMD_WRITE)
+               for (i = 0; i < len; i++)
+                       obuf[8 + i] = values[i];
+       else if (type == AF9005_TUNER_REG)
+               /* read command for tuner, the first byte contains the i2c address */
+               obuf[8] = values[0];
+       obuf[7] = command;
+
+       ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
+       if (ret)
+               return ret;
+
+       /* sanity check */
+       if (ibuf[2] != AF9005_REGISTER_RW_ACK) {
+               err("generic read/write, wrong reply code.");
+               return -EIO;
+       }
+       if (ibuf[3] != 0x0d) {
+               err("generic read/write, wrong length in reply.");
+               return -EIO;
+       }
+       if (ibuf[4] != obuf[4]) {
+               err("generic read/write, wrong sequence in reply.");
+               return -EIO;
+       }
+       /*
+          Windows driver doesn't check these fields, in fact sometimes
+          the register in the reply is different that what has been sent
+
+          if (ibuf[5] != obuf[5] || ibuf[6] != obuf[6]) {
+          err("generic read/write, wrong register in reply.");
+          return -EIO;
+          }
+          if (ibuf[7] != command) {
+          err("generic read/write wrong command in reply.");
+          return -EIO;
+          }
+        */
+       if (ibuf[16] != 0x01) {
+               err("generic read/write wrong status code in reply.");
+               return -EIO;
+       }
+       if (readwrite == AF9005_CMD_READ)
+               for (i = 0; i < len; i++)
+                       values[i] = ibuf[8 + i];
+
+       return 0;
+
+}
+
+int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 * value)
+{
+       int ret;
+       deb_reg("read register %x ", reg);
+       ret = af9005_generic_read_write(d, reg,
+                                       AF9005_CMD_READ, AF9005_OFDM_REG,
+                                       value, 1);
+       if (ret)
+               deb_reg("failed\n");
+       else
+               deb_reg("value %x\n", *value);
+       return ret;
+}
+
+int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+                              u8 * values, int len)
+{
+       int ret;
+       deb_reg("read %d registers %x ", len, reg);
+       ret = af9005_generic_read_write(d, reg,
+                                       AF9005_CMD_READ, AF9005_OFDM_REG,
+                                       values, len);
+       if (ret)
+               deb_reg("failed\n");
+       else
+               debug_dump(values, len, deb_reg);
+       return ret;
+}
+
+int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 value)
+{
+       int ret;
+       u8 temp = value;
+       deb_reg("write register %x value %x ", reg, value);
+       ret = af9005_generic_read_write(d, reg,
+                                       AF9005_CMD_WRITE, AF9005_OFDM_REG,
+                                       &temp, 1);
+       if (ret)
+               deb_reg("failed\n");
+       else
+               deb_reg("ok\n");
+       return ret;
+}
+
+int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+                               u8 * values, int len)
+{
+       int ret;
+       deb_reg("write %d registers %x values ", len, reg);
+       debug_dump(values, len, deb_reg);
+
+       ret = af9005_generic_read_write(d, reg,
+                                       AF9005_CMD_WRITE, AF9005_OFDM_REG,
+                                       values, len);
+       if (ret)
+               deb_reg("failed\n");
+       else
+               deb_reg("ok\n");
+       return ret;
+}
+
+int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
+                             u8 len, u8 * value)
+{
+       u8 temp;
+       int ret;
+       deb_reg("read bits %x %x %x", reg, pos, len);
+       ret = af9005_read_ofdm_register(d, reg, &temp);
+       if (ret) {
+               deb_reg(" failed\n");
+               return ret;
+       }
+       *value = (temp >> pos) & regmask[len - 1];
+       deb_reg(" value %x\n", *value);
+       return 0;
+
+}
+
+int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
+                              u8 len, u8 value)
+{
+       u8 temp, mask;
+       int ret;
+       deb_reg("write bits %x %x %x value %x\n", reg, pos, len, value);
+       if (pos == 0 && len == 8)
+               return af9005_write_ofdm_register(d, reg, value);
+       ret = af9005_read_ofdm_register(d, reg, &temp);
+       if (ret)
+               return ret;
+       mask = regmask[len - 1] << pos;
+       temp = (temp & ~mask) | ((value << pos) & mask);
+       return af9005_write_ofdm_register(d, reg, temp);
+
+}
+
+static int af9005_usb_read_tuner_registers(struct dvb_usb_device *d,
+                                          u16 reg, u8 * values, int len)
+{
+       return af9005_generic_read_write(d, reg,
+                                        AF9005_CMD_READ, AF9005_TUNER_REG,
+                                        values, len);
+}
+
+static int af9005_usb_write_tuner_registers(struct dvb_usb_device *d,
+                                           u16 reg, u8 * values, int len)
+{
+       return af9005_generic_read_write(d, reg,
+                                        AF9005_CMD_WRITE,
+                                        AF9005_TUNER_REG, values, len);
+}
+
+int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,
+                                u8 * values, int len)
+{
+       /* don't let the name of this function mislead you: it's just used
+          as an interface from the firmware to the i2c bus. The actual
+          i2c addresses are contained in the data */
+       int ret, i, done = 0, fail = 0;
+       u8 temp;
+       ret = af9005_usb_write_tuner_registers(d, reg, values, len);
+       if (ret)
+               return ret;
+       if (reg != 0xffff) {
+               /* check if write done (0xa40d bit 1) or fail (0xa40d bit 2) */
+               for (i = 0; i < 200; i++) {
+                       ret =
+                           af9005_read_ofdm_register(d,
+                                                     xd_I2C_i2c_m_status_wdat_done,
+                                                     &temp);
+                       if (ret)
+                               return ret;
+                       done = temp & (regmask[i2c_m_status_wdat_done_len - 1]
+                                      << i2c_m_status_wdat_done_pos);
+                       if (done)
+                               break;
+                       fail = temp & (regmask[i2c_m_status_wdat_fail_len - 1]
+                                      << i2c_m_status_wdat_fail_pos);
+                       if (fail)
+                               break;
+                       msleep(50);
+               }
+               if (i == 200)
+                       return -ETIMEDOUT;
+               if (fail) {
+                       /* clear write fail bit */
+                       af9005_write_register_bits(d,
+                                                  xd_I2C_i2c_m_status_wdat_fail,
+                                                  i2c_m_status_wdat_fail_pos,
+                                                  i2c_m_status_wdat_fail_len,
+                                                  1);
+                       return -EIO;
+               }
+               /* clear write done bit */
+               ret =
+                   af9005_write_register_bits(d,
+                                              xd_I2C_i2c_m_status_wdat_fail,
+                                              i2c_m_status_wdat_done_pos,
+                                              i2c_m_status_wdat_done_len, 1);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, u8 addr,
+                               u8 * values, int len)
+{
+       /* don't let the name of this function mislead you: it's just used
+          as an interface from the firmware to the i2c bus. The actual
+          i2c addresses are contained in the data */
+       int ret, i;
+       u8 temp, buf[2];
+
+       buf[0] = addr;          /* tuner i2c address */
+       buf[1] = values[0];     /* tuner register */
+
+       values[0] = addr + 0x01;        /* i2c read address */
+
+       if (reg == APO_REG_I2C_RW_SILICON_TUNER) {
+               /* write tuner i2c address to tuner, 0c00c0 undocumented, found by sniffing */
+               ret = af9005_write_tuner_registers(d, 0x00c0, buf, 2);
+               if (ret)
+                       return ret;
+       }
+
+       /* send read command to ofsm */
+       ret = af9005_usb_read_tuner_registers(d, reg, values, 1);
+       if (ret)
+               return ret;
+
+       /* check if read done */
+       for (i = 0; i < 200; i++) {
+               ret = af9005_read_ofdm_register(d, 0xa408, &temp);
+               if (ret)
+                       return ret;
+               if (temp & 0x01)
+                       break;
+               msleep(50);
+       }
+       if (i == 200)
+               return -ETIMEDOUT;
+
+       /* clear read done bit (by writing 1) */
+       ret = af9005_write_ofdm_register(d, xd_I2C_i2c_m_data8, 1);
+       if (ret)
+               return ret;
+
+       /* get read data (available from 0xa400) */
+       for (i = 0; i < len; i++) {
+               ret = af9005_read_ofdm_register(d, 0xa400 + i, &temp);
+               if (ret)
+                       return ret;
+               values[i] = temp;
+       }
+       return 0;
+}
+
+static int af9005_i2c_write(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
+                           u8 * data, int len)
+{
+       int ret, i;
+       u8 buf[3];
+       deb_i2c("i2c_write i2caddr %x, reg %x, len %d data ", i2caddr,
+               reg, len);
+       debug_dump(data, len, deb_i2c);
+
+       for (i = 0; i < len; i++) {
+               buf[0] = i2caddr;
+               buf[1] = reg + (u8) i;
+               buf[2] = data[i];
+               ret =
+                   af9005_write_tuner_registers(d,
+                                                APO_REG_I2C_RW_SILICON_TUNER,
+                                                buf, 3);
+               if (ret) {
+                       deb_i2c("i2c_write failed\n");
+                       return ret;
+               }
+       }
+       deb_i2c("i2c_write ok\n");
+       return 0;
+}
+
+static int af9005_i2c_read(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
+                          u8 * data, int len)
+{
+       int ret, i;
+       u8 temp;
+       deb_i2c("i2c_read i2caddr %x, reg %x, len %d\n ", i2caddr, reg, len);
+       for (i = 0; i < len; i++) {
+               temp = reg + i;
+               ret =
+                   af9005_read_tuner_registers(d,
+                                               APO_REG_I2C_RW_SILICON_TUNER,
+                                               i2caddr, &temp, 1);
+               if (ret) {
+                       deb_i2c("i2c_read failed\n");
+                       return ret;
+               }
+               data[i] = temp;
+       }
+       deb_i2c("i2c data read: ");
+       debug_dump(data, len, deb_i2c);
+       return 0;
+}
+
+static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+                          int num)
+{
+       /* only implements what the mt2060 module does, don't know how
+          to make it really generic */
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int ret;
+       u8 reg, addr;
+       u8 *value;
+
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       if (num > 2)
+               warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+       if (num == 2) {
+               /* reads a single register */
+               reg = *msg[0].buf;
+               addr = msg[0].addr;
+               value = msg[1].buf;
+               ret = af9005_i2c_read(d, addr, reg, value, 1);
+               if (ret == 0)
+                       ret = 2;
+       } else {
+               /* write one or more registers */
+               reg = msg[0].buf[0];
+               addr = msg[0].addr;
+               value = &msg[0].buf[1];
+               ret = af9005_i2c_write(d, addr, reg, value, msg[0].len - 1);
+               if (ret == 0)
+                       ret = 1;
+       }
+
+       mutex_unlock(&d->i2c_mutex);
+       return ret;
+}
+
+static u32 af9005_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm af9005_i2c_algo = {
+       .master_xfer = af9005_i2c_xfer,
+       .functionality = af9005_i2c_func,
+};
+
+int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,
+                       int wlen, u8 * rbuf, int rlen)
+{
+       struct af9005_device_state *st = d->priv;
+
+       int ret, i, packet_len;
+       u8 buf[64];
+       u8 ibuf[64];
+
+       if (wlen < 0) {
+               err("send command, wlen less than 0 bytes. Makes no sense.");
+               return -EINVAL;
+       }
+       if (wlen > 54) {
+               err("send command, wlen more than 54 bytes. Not supported.");
+               return -EINVAL;
+       }
+       if (rlen > 54) {
+               err("send command, rlen more than 54 bytes. Not supported.");
+               return -EINVAL;
+       }
+       packet_len = wlen + 5;
+       buf[0] = (u8) (packet_len & 0xff);
+       buf[1] = (u8) ((packet_len & 0xff00) >> 8);
+
+       buf[2] = 0x26;          /* packet type */
+       buf[3] = wlen + 3;
+       buf[4] = st->sequence++;
+       buf[5] = command;
+       buf[6] = wlen;
+       for (i = 0; i < wlen; i++)
+               buf[7 + i] = wbuf[i];
+       ret = af9005_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);
+       if (ret)
+               return ret;
+       if (ibuf[2] != 0x27) {
+               err("send command, wrong reply code.");
+               return -EIO;
+       }
+       if (ibuf[4] != buf[4]) {
+               err("send command, wrong sequence in reply.");
+               return -EIO;
+       }
+       if (ibuf[5] != 0x01) {
+               err("send command, wrong status code in reply.");
+               return -EIO;
+       }
+       if (ibuf[6] != rlen) {
+               err("send command, invalid data length in reply.");
+               return -EIO;
+       }
+       for (i = 0; i < rlen; i++)
+               rbuf[i] = ibuf[i + 7];
+       return 0;
+}
+
+int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values,
+                      int len)
+{
+       struct af9005_device_state *st = d->priv;
+       u8 obuf[16], ibuf[14];
+       int ret, i;
+
+       memset(obuf, 0, sizeof(obuf));
+       memset(ibuf, 0, sizeof(ibuf));
+
+       obuf[0] = 14;           /* length of rest of packet low */
+       obuf[1] = 0;            /* length of rest of packer high */
+
+       obuf[2] = 0x2a;         /* read/write eeprom */
+
+       obuf[3] = 12;           /* size */
+
+       obuf[4] = st->sequence++;
+
+       obuf[5] = 0;            /* read */
+
+       obuf[6] = len;
+       obuf[7] = address;
+       ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
+       if (ret)
+               return ret;
+       if (ibuf[2] != 0x2b) {
+               err("Read eeprom, invalid reply code");
+               return -EIO;
+       }
+       if (ibuf[3] != 10) {
+               err("Read eeprom, invalid reply length");
+               return -EIO;
+       }
+       if (ibuf[4] != obuf[4]) {
+               err("Read eeprom, wrong sequence in reply ");
+               return -EIO;
+       }
+       if (ibuf[5] != 1) {
+               err("Read eeprom, wrong status in reply ");
+               return -EIO;
+       }
+       for (i = 0; i < len; i++) {
+               values[i] = ibuf[6 + i];
+       }
+       return 0;
+}
+
+static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply)
+{
+       u8 buf[FW_BULKOUT_SIZE + 2];
+       u16 checksum;
+       int act_len, i, ret;
+       memset(buf, 0, sizeof(buf));
+       buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
+       buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
+       switch (type) {
+       case FW_CONFIG:
+               buf[2] = 0x11;
+               buf[3] = 0x04;
+               buf[4] = 0x00;  /* sequence number, original driver doesn't increment it here */
+               buf[5] = 0x03;
+               checksum = buf[4] + buf[5];
+               buf[6] = (u8) ((checksum >> 8) & 0xff);
+               buf[7] = (u8) (checksum & 0xff);
+               break;
+       case FW_CONFIRM:
+               buf[2] = 0x11;
+               buf[3] = 0x04;
+               buf[4] = 0x00;  /* sequence number, original driver doesn't increment it here */
+               buf[5] = 0x01;
+               checksum = buf[4] + buf[5];
+               buf[6] = (u8) ((checksum >> 8) & 0xff);
+               buf[7] = (u8) (checksum & 0xff);
+               break;
+       case FW_BOOT:
+               buf[2] = 0x10;
+               buf[3] = 0x08;
+               buf[4] = 0x00;  /* sequence number, original driver doesn't increment it here */
+               buf[5] = 0x97;
+               buf[6] = 0xaa;
+               buf[7] = 0x55;
+               buf[8] = 0xa5;
+               buf[9] = 0x5a;
+               checksum = 0;
+               for (i = 4; i <= 9; i++)
+                       checksum += buf[i];
+               buf[10] = (u8) ((checksum >> 8) & 0xff);
+               buf[11] = (u8) (checksum & 0xff);
+               break;
+       default:
+               err("boot packet invalid boot packet type");
+               return -EINVAL;
+       }
+       deb_fw(">>> ");
+       debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
+
+       ret = usb_bulk_msg(udev,
+                          usb_sndbulkpipe(udev, 0x02),
+                          buf, FW_BULKOUT_SIZE + 2, &act_len, 2000);
+       if (ret)
+               err("boot packet bulk message failed: %d (%d/%d)", ret,
+                   FW_BULKOUT_SIZE + 2, act_len);
+       else
+               ret = act_len != FW_BULKOUT_SIZE + 2 ? -1 : 0;
+       if (ret)
+               return ret;
+       memset(buf, 0, 9);
+       ret = usb_bulk_msg(udev,
+                          usb_rcvbulkpipe(udev, 0x01), buf, 9, &act_len, 2000);
+       if (ret) {
+               err("boot packet recv bulk message failed: %d", ret);
+               return ret;
+       }
+       deb_fw("<<< ");
+       debug_dump(buf, act_len, deb_fw);
+       checksum = 0;
+       switch (type) {
+       case FW_CONFIG:
+               if (buf[2] != 0x11) {
+                       err("boot bad config header.");
+                       return -EIO;
+               }
+               if (buf[3] != 0x05) {
+                       err("boot bad config size.");
+                       return -EIO;
+               }
+               if (buf[4] != 0x00) {
+                       err("boot bad config sequence.");
+                       return -EIO;
+               }
+               if (buf[5] != 0x04) {
+                       err("boot bad config subtype.");
+                       return -EIO;
+               }
+               for (i = 4; i <= 6; i++)
+                       checksum += buf[i];
+               if (buf[7] * 256 + buf[8] != checksum) {
+                       err("boot bad config checksum.");
+                       return -EIO;
+               }
+               *reply = buf[6];
+               break;
+       case FW_CONFIRM:
+               if (buf[2] != 0x11) {
+                       err("boot bad confirm header.");
+                       return -EIO;
+               }
+               if (buf[3] != 0x05) {
+                       err("boot bad confirm size.");
+                       return -EIO;
+               }
+               if (buf[4] != 0x00) {
+                       err("boot bad confirm sequence.");
+                       return -EIO;
+               }
+               if (buf[5] != 0x02) {
+                       err("boot bad confirm subtype.");
+                       return -EIO;
+               }
+               for (i = 4; i <= 6; i++)
+                       checksum += buf[i];
+               if (buf[7] * 256 + buf[8] != checksum) {
+                       err("boot bad confirm checksum.");
+                       return -EIO;
+               }
+               *reply = buf[6];
+               break;
+       case FW_BOOT:
+               if (buf[2] != 0x10) {
+                       err("boot bad boot header.");
+                       return -EIO;
+               }
+               if (buf[3] != 0x05) {
+                       err("boot bad boot size.");
+                       return -EIO;
+               }
+               if (buf[4] != 0x00) {
+                       err("boot bad boot sequence.");
+                       return -EIO;
+               }
+               if (buf[5] != 0x01) {
+                       err("boot bad boot pattern 01.");
+                       return -EIO;
+               }
+               if (buf[6] != 0x10) {
+                       err("boot bad boot pattern 10.");
+                       return -EIO;
+               }
+               for (i = 4; i <= 6; i++)
+                       checksum += buf[i];
+               if (buf[7] * 256 + buf[8] != checksum) {
+                       err("boot bad boot checksum.");
+                       return -EIO;
+               }
+               break;
+
+       }
+
+       return 0;
+}
+
+int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw)
+{
+       int i, packets, ret, act_len;
+
+       u8 buf[FW_BULKOUT_SIZE + 2];
+       u8 reply;
+
+       ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+       if (ret)
+               return ret;
+       if (reply != 0x01) {
+               err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply);
+               return -EIO;
+       }
+       packets = fw->size / FW_BULKOUT_SIZE;
+       buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
+       buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
+       for (i = 0; i < packets; i++) {
+               memcpy(&buf[2], fw->data + i * FW_BULKOUT_SIZE,
+                      FW_BULKOUT_SIZE);
+               deb_fw(">>> ");
+               debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
+               ret = usb_bulk_msg(udev,
+                                  usb_sndbulkpipe(udev, 0x02),
+                                  buf, FW_BULKOUT_SIZE + 2, &act_len, 1000);
+               if (ret) {
+                       err("firmware download failed at packet %d with code %d", i, ret);
+                       return ret;
+               }
+       }
+       ret = af9005_boot_packet(udev, FW_CONFIRM, &reply);
+       if (ret)
+               return ret;
+       if (reply != (u8) (packets & 0xff)) {
+               err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply);
+               return -EIO;
+       }
+       ret = af9005_boot_packet(udev, FW_BOOT, &reply);
+       if (ret)
+               return ret;
+       ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+       if (ret)
+               return ret;
+       if (reply != 0x02) {
+               err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply);
+               return -EIO;
+       }
+
+       return 0;
+
+}
+
+int af9005_led_control(struct dvb_usb_device *d, int onoff)
+{
+       struct af9005_device_state *st = d->priv;
+       int temp, ret;
+
+       if (onoff && dvb_usb_af9005_led)
+               temp = 1;
+       else
+               temp = 0;
+       if (st->led_state != temp) {
+               ret =
+                   af9005_write_register_bits(d, xd_p_reg_top_locken1,
+                                              reg_top_locken1_pos,
+                                              reg_top_locken1_len, temp);
+               if (ret)
+                       return ret;
+               ret =
+                   af9005_write_register_bits(d, xd_p_reg_top_lock1,
+                                              reg_top_lock1_pos,
+                                              reg_top_lock1_len, temp);
+               if (ret)
+                       return ret;
+               st->led_state = temp;
+       }
+       return 0;
+}
+
+static int af9005_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       u8 buf[8];
+       int i;
+
+       /* without these calls the first commands after downloading
+          the firmware fail. I put these calls here to simulate
+          what it is done in dvb-usb-init.c.
+        */
+       struct usb_device *udev = adap->dev->udev;
+       usb_clear_halt(udev, usb_sndbulkpipe(udev, 2));
+       usb_clear_halt(udev, usb_rcvbulkpipe(udev, 1));
+       if (dvb_usb_af9005_dump_eeprom) {
+               printk("EEPROM DUMP\n");
+               for (i = 0; i < 255; i += 8) {
+                       af9005_read_eeprom(adap->dev, i, buf, 8);
+                       printk("ADDR %x ", i);
+                       debug_dump(buf, 8, printk);
+               }
+       }
+       adap->fe = af9005_fe_attach(adap->dev);
+       return 0;
+}
+
+static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state)
+{
+       struct af9005_device_state *st = d->priv;
+       int ret, len;
+
+       u8 obuf[5];
+       u8 ibuf[256];
+
+       *state = REMOTE_NO_KEY_PRESSED;
+       if (rc_decode == NULL) {
+               /* it shouldn't never come here */
+               return 0;
+       }
+       /* deb_info("rc_query\n"); */
+       obuf[0] = 3;            /* rest of packet length low */
+       obuf[1] = 0;            /* rest of packet lentgh high */
+       obuf[2] = 0x40;         /* read remote */
+       obuf[3] = 1;            /* rest of packet length */
+       obuf[4] = st->sequence++;       /* sequence number */
+       ret = af9005_usb_generic_rw(d, obuf, 5, ibuf, 256, 0);
+       if (ret) {
+               err("rc query failed");
+               return ret;
+       }
+       if (ibuf[2] != 0x41) {
+               err("rc query bad header.");
+               return -EIO;
+       }
+       if (ibuf[4] != obuf[4]) {
+               err("rc query bad sequence.");
+               return -EIO;
+       }
+       len = ibuf[5];
+       if (len > 246) {
+               err("rc query invalid length");
+               return -EIO;
+       }
+       if (len > 0) {
+               deb_rc("rc data (%d) ", len);
+               debug_dump((ibuf + 6), len, deb_rc);
+               ret = rc_decode(d, &ibuf[6], len, event, state);
+               if (ret) {
+                       err("rc_decode failed");
+                       return ret;
+               } else {
+                       deb_rc("rc_decode state %x event %x\n", *state, *event);
+                       if (*state == REMOTE_KEY_REPEAT)
+                               *event = d->last_event;
+               }
+       }
+       return 0;
+}
+
+static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+
+       return 0;
+}
+
+static int af9005_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
+{
+       int ret;
+       deb_info("pid filter control  onoff %d\n", onoff);
+       if (onoff) {
+               ret =
+                   af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
+               if (ret)
+                       return ret;
+               ret =
+                   af9005_write_register_bits(adap->dev,
+                                              XD_MP2IF_DMX_CTRL, 1, 1, 1);
+               if (ret)
+                       return ret;
+               ret =
+                   af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
+       } else
+               ret =
+                   af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 0);
+       if (ret)
+               return ret;
+       deb_info("pid filter control ok\n");
+       return 0;
+}
+
+static int af9005_pid_filter(struct dvb_usb_adapter *adap, int index,
+                            u16 pid, int onoff)
+{
+       u8 cmd = index & 0x1f;
+       int ret;
+       deb_info("set pid filter, index %d, pid %x, onoff %d\n", index,
+                pid, onoff);
+       if (onoff) {
+               /* cannot use it as pid_filter_ctrl since it has to be done
+                  before setting the first pid */
+               if (adap->feedcount == 1) {
+                       deb_info("first pid set, enable pid table\n");
+                       ret = af9005_pid_filter_control(adap, onoff);
+                       if (ret)
+                               return ret;
+               }
+               ret =
+                   af9005_write_ofdm_register(adap->dev,
+                                              XD_MP2IF_PID_DATA_L,
+                                              (u8) (pid & 0xff));
+               if (ret)
+                       return ret;
+               ret =
+                   af9005_write_ofdm_register(adap->dev,
+                                              XD_MP2IF_PID_DATA_H,
+                                              (u8) (pid >> 8));
+               if (ret)
+                       return ret;
+               cmd |= 0x20 | 0x40;
+       } else {
+               if (adap->feedcount == 0) {
+                       deb_info("last pid unset, disable pid table\n");
+                       ret = af9005_pid_filter_control(adap, onoff);
+                       if (ret)
+                               return ret;
+               }
+       }
+       ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_IDX, cmd);
+       if (ret)
+               return ret;
+       deb_info("set pid ok\n");
+       return 0;
+}
+
+static int af9005_identify_state(struct usb_device *udev,
+                                struct dvb_usb_device_properties *props,
+                                struct dvb_usb_device_description **desc,
+                                int *cold)
+{
+       int ret;
+       u8 reply;
+       ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+       if (ret)
+               return ret;
+       deb_info("result of FW_CONFIG in identify state %d\n", reply);
+       if (reply == 0x01)
+               *cold = 1;
+       else if (reply == 0x02)
+               *cold = 0;
+       else
+               return -EIO;
+       deb_info("Identify state cold = %d\n", *cold);
+       return 0;
+}
+
+static struct dvb_usb_device_properties af9005_properties;
+
+static int af9005_usb_probe(struct usb_interface *intf,
+                           const struct usb_device_id *id)
+{
+       return dvb_usb_device_init(intf, &af9005_properties, THIS_MODULE, NULL);
+}
+
+static struct usb_device_id af9005_usb_table[] = {
+       {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)},
+       {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)},
+       {0},
+};
+
+MODULE_DEVICE_TABLE(usb, af9005_usb_table);
+
+static struct dvb_usb_device_properties af9005_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl = DEVICE_SPECIFIC,
+       .firmware = "af9005.fw",
+       .download_firmware = af9005_download_firmware,
+       .no_reconnect = 1,
+
+       .size_of_priv = sizeof(struct af9005_device_state),
+
+       .num_adapters = 1,
+       .adapter = {
+                   {
+                    .caps =
+                    DVB_USB_ADAP_HAS_PID_FILTER |
+                    DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                    .pid_filter_count = 32,
+                    .pid_filter = af9005_pid_filter,
+                    /* .pid_filter_ctrl = af9005_pid_filter_control, */
+                    .frontend_attach = af9005_frontend_attach,
+                    /* .tuner_attach     = af9005_tuner_attach, */
+                    /* parameter for the MPEG2-data transfer */
+                    .stream = {
+                               .type = USB_BULK,
+                               .count = 10,
+                               .endpoint = 0x04,
+                               .u = {
+                                     .bulk = {
+                                              .buffersize = 4096,      /* actual size seen is 3948 */
+                                              }
+                                     }
+                               },
+                    }
+                   },
+       .power_ctrl = af9005_power_ctrl,
+       .identify_state = af9005_identify_state,
+
+       .i2c_algo = &af9005_i2c_algo,
+
+       .rc_interval = 200,
+       .rc_key_map = NULL,
+       .rc_key_map_size = 0,
+       .rc_query = af9005_rc_query,
+
+       .num_device_descs = 2,
+       .devices = {
+                   {.name = "Afatech DVB-T USB1.1 stick",
+                    .cold_ids = {&af9005_usb_table[0], NULL},
+                    .warm_ids = {NULL},
+                    },
+                   {.name = "TerraTec Cinergy T USB XE",
+                    .cold_ids = {&af9005_usb_table[1], NULL},
+                    .warm_ids = {NULL},
+                    },
+                   {NULL},
+                   }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver af9005_usb_driver = {
+       .name = "dvb_usb_af9005",
+       .probe = af9005_usb_probe,
+       .disconnect = dvb_usb_device_exit,
+       .id_table = af9005_usb_table,
+};
+
+/* module stuff */
+static int __init af9005_usb_module_init(void)
+{
+       int result;
+       if ((result = usb_register(&af9005_usb_driver))) {
+               err("usb_register failed. (%d)", result);
+               return result;
+       }
+       rc_decode = symbol_request(af9005_rc_decode);
+       rc_keys = symbol_request(af9005_rc_keys);
+       rc_keys_size = symbol_request(af9005_rc_keys_size);
+       if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) {
+               err("af9005_rc_decode function not found, disabling remote");
+               af9005_properties.rc_query = NULL;
+       } else {
+               af9005_properties.rc_key_map = rc_keys;
+               af9005_properties.rc_key_map_size = *rc_keys_size;
+       }
+
+       return 0;
+}
+
+static void __exit af9005_usb_module_exit(void)
+{
+       /* release rc decode symbols */
+       if (rc_decode != NULL)
+               symbol_put(af9005_rc_decode);
+       if (rc_keys != NULL)
+               symbol_put(af9005_rc_keys);
+       if (rc_keys_size != NULL)
+               symbol_put(af9005_rc_keys_size);
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&af9005_usb_driver);
+}
+
+module_init(af9005_usb_module_init);
+module_exit(af9005_usb_module_exit);
+
+MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
+MODULE_DESCRIPTION("Driver for Afatech 9005 DVB-T USB1.1 stick");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/dvb/dvb-usb/af9005.h
new file mode 100644 (file)
index 0000000..0bc48a0
--- /dev/null
@@ -0,0 +1,3496 @@
+/* Common header-file of the Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_AF9005_H_
+#define _DVB_USB_AF9005_H_
+
+#define DVB_USB_LOG_PREFIX "af9005"
+#include "dvb-usb.h"
+
+extern int dvb_usb_af9005_debug;
+#define deb_info(args...) dprintk(dvb_usb_af9005_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_af9005_debug,0x02,args)
+#define deb_rc(args...)   dprintk(dvb_usb_af9005_debug,0x04,args)
+#define deb_reg(args...)  dprintk(dvb_usb_af9005_debug,0x08,args)
+#define deb_i2c(args...)  dprintk(dvb_usb_af9005_debug,0x10,args)
+#define deb_fw(args...)   dprintk(dvb_usb_af9005_debug,0x20,args)
+
+extern int dvb_usb_af9005_led;
+
+/* firmware */
+#define FW_BULKOUT_SIZE 250
+enum {
+       FW_CONFIG,
+       FW_CONFIRM,
+       FW_BOOT
+};
+
+/* af9005 commands */
+#define AF9005_OFDM_REG  0
+#define AF9005_TUNER_REG 1
+
+#define AF9005_REGISTER_RW     0x20
+#define AF9005_REGISTER_RW_ACK 0x21
+
+#define AF9005_CMD_OFDM_REG 0x00
+#define AF9005_CMD_TUNER    0x80
+#define AF9005_CMD_BURST    0x02
+#define AF9005_CMD_AUTOINC  0x04
+#define AF9005_CMD_READ     0x00
+#define AF9005_CMD_WRITE    0x01
+
+/* af9005 registers */
+#define APO_REG_RESET                                  0xAEFF
+
+#define APO_REG_I2C_RW_CAN_TUNER            0xF000
+#define APO_REG_I2C_RW_SILICON_TUNER        0xF001
+#define APO_REG_GPIO_RW_SILICON_TUNER       0xFFFE     /*  also for OFSM */
+#define APO_REG_TRIGGER_OFSM                0xFFFF     /*  also for OFSM */
+
+/***********************************************************************
+ *  Apollo Registers from VLSI                                        *
+ ***********************************************************************/
+#define xd_p_reg_aagc_inverted_agc     0xA000
+#define        reg_aagc_inverted_agc_pos 0
+#define        reg_aagc_inverted_agc_len 1
+#define        reg_aagc_inverted_agc_lsb 0
+#define xd_p_reg_aagc_sign_only        0xA000
+#define        reg_aagc_sign_only_pos 1
+#define        reg_aagc_sign_only_len 1
+#define        reg_aagc_sign_only_lsb 0
+#define xd_p_reg_aagc_slow_adc_en      0xA000
+#define        reg_aagc_slow_adc_en_pos 2
+#define        reg_aagc_slow_adc_en_len 1
+#define        reg_aagc_slow_adc_en_lsb 0
+#define xd_p_reg_aagc_slow_adc_scale   0xA000
+#define        reg_aagc_slow_adc_scale_pos 3
+#define        reg_aagc_slow_adc_scale_len 5
+#define        reg_aagc_slow_adc_scale_lsb 0
+#define xd_p_reg_aagc_check_slow_adc_lock      0xA001
+#define        reg_aagc_check_slow_adc_lock_pos 0
+#define        reg_aagc_check_slow_adc_lock_len 1
+#define        reg_aagc_check_slow_adc_lock_lsb 0
+#define xd_p_reg_aagc_init_control     0xA001
+#define        reg_aagc_init_control_pos 1
+#define        reg_aagc_init_control_len 1
+#define        reg_aagc_init_control_lsb 0
+#define xd_p_reg_aagc_total_gain_sel   0xA001
+#define        reg_aagc_total_gain_sel_pos 2
+#define        reg_aagc_total_gain_sel_len 2
+#define        reg_aagc_total_gain_sel_lsb 0
+#define xd_p_reg_aagc_out_inv  0xA001
+#define        reg_aagc_out_inv_pos 5
+#define        reg_aagc_out_inv_len 1
+#define        reg_aagc_out_inv_lsb 0
+#define xd_p_reg_aagc_int_en   0xA001
+#define        reg_aagc_int_en_pos 6
+#define        reg_aagc_int_en_len 1
+#define        reg_aagc_int_en_lsb 0
+#define xd_p_reg_aagc_lock_change_flag 0xA001
+#define        reg_aagc_lock_change_flag_pos 7
+#define        reg_aagc_lock_change_flag_len 1
+#define        reg_aagc_lock_change_flag_lsb 0
+#define xd_p_reg_aagc_rf_loop_bw_scale_acquire 0xA002
+#define        reg_aagc_rf_loop_bw_scale_acquire_pos 0
+#define        reg_aagc_rf_loop_bw_scale_acquire_len 5
+#define        reg_aagc_rf_loop_bw_scale_acquire_lsb 0
+#define xd_p_reg_aagc_rf_loop_bw_scale_track   0xA003
+#define        reg_aagc_rf_loop_bw_scale_track_pos 0
+#define        reg_aagc_rf_loop_bw_scale_track_len 5
+#define        reg_aagc_rf_loop_bw_scale_track_lsb 0
+#define xd_p_reg_aagc_if_loop_bw_scale_acquire 0xA004
+#define        reg_aagc_if_loop_bw_scale_acquire_pos 0
+#define        reg_aagc_if_loop_bw_scale_acquire_len 5
+#define        reg_aagc_if_loop_bw_scale_acquire_lsb 0
+#define xd_p_reg_aagc_if_loop_bw_scale_track   0xA005
+#define        reg_aagc_if_loop_bw_scale_track_pos 0
+#define        reg_aagc_if_loop_bw_scale_track_len 5
+#define        reg_aagc_if_loop_bw_scale_track_lsb 0
+#define xd_p_reg_aagc_max_rf_agc_7_0   0xA006
+#define        reg_aagc_max_rf_agc_7_0_pos 0
+#define        reg_aagc_max_rf_agc_7_0_len 8
+#define        reg_aagc_max_rf_agc_7_0_lsb 0
+#define xd_p_reg_aagc_max_rf_agc_9_8   0xA007
+#define        reg_aagc_max_rf_agc_9_8_pos 0
+#define        reg_aagc_max_rf_agc_9_8_len 2
+#define        reg_aagc_max_rf_agc_9_8_lsb 8
+#define xd_p_reg_aagc_min_rf_agc_7_0   0xA008
+#define        reg_aagc_min_rf_agc_7_0_pos 0
+#define        reg_aagc_min_rf_agc_7_0_len 8
+#define        reg_aagc_min_rf_agc_7_0_lsb 0
+#define xd_p_reg_aagc_min_rf_agc_9_8   0xA009
+#define        reg_aagc_min_rf_agc_9_8_pos 0
+#define        reg_aagc_min_rf_agc_9_8_len 2
+#define        reg_aagc_min_rf_agc_9_8_lsb 8
+#define xd_p_reg_aagc_max_if_agc_7_0   0xA00A
+#define        reg_aagc_max_if_agc_7_0_pos 0
+#define        reg_aagc_max_if_agc_7_0_len 8
+#define        reg_aagc_max_if_agc_7_0_lsb 0
+#define xd_p_reg_aagc_max_if_agc_9_8   0xA00B
+#define        reg_aagc_max_if_agc_9_8_pos 0
+#define        reg_aagc_max_if_agc_9_8_len 2
+#define        reg_aagc_max_if_agc_9_8_lsb 8
+#define xd_p_reg_aagc_min_if_agc_7_0   0xA00C
+#define        reg_aagc_min_if_agc_7_0_pos 0
+#define        reg_aagc_min_if_agc_7_0_len 8
+#define        reg_aagc_min_if_agc_7_0_lsb 0
+#define xd_p_reg_aagc_min_if_agc_9_8   0xA00D
+#define        reg_aagc_min_if_agc_9_8_pos 0
+#define        reg_aagc_min_if_agc_9_8_len 2
+#define        reg_aagc_min_if_agc_9_8_lsb 8
+#define xd_p_reg_aagc_lock_sample_scale        0xA00E
+#define        reg_aagc_lock_sample_scale_pos 0
+#define        reg_aagc_lock_sample_scale_len 5
+#define        reg_aagc_lock_sample_scale_lsb 0
+#define xd_p_reg_aagc_rf_agc_lock_scale_acquire        0xA00F
+#define        reg_aagc_rf_agc_lock_scale_acquire_pos 0
+#define        reg_aagc_rf_agc_lock_scale_acquire_len 3
+#define        reg_aagc_rf_agc_lock_scale_acquire_lsb 0
+#define xd_p_reg_aagc_rf_agc_lock_scale_track  0xA00F
+#define        reg_aagc_rf_agc_lock_scale_track_pos 3
+#define        reg_aagc_rf_agc_lock_scale_track_len 3
+#define        reg_aagc_rf_agc_lock_scale_track_lsb 0
+#define xd_p_reg_aagc_if_agc_lock_scale_acquire        0xA010
+#define        reg_aagc_if_agc_lock_scale_acquire_pos 0
+#define        reg_aagc_if_agc_lock_scale_acquire_len 3
+#define        reg_aagc_if_agc_lock_scale_acquire_lsb 0
+#define xd_p_reg_aagc_if_agc_lock_scale_track  0xA010
+#define        reg_aagc_if_agc_lock_scale_track_pos 3
+#define        reg_aagc_if_agc_lock_scale_track_len 3
+#define        reg_aagc_if_agc_lock_scale_track_lsb 0
+#define xd_p_reg_aagc_rf_top_numerator_7_0     0xA011
+#define        reg_aagc_rf_top_numerator_7_0_pos 0
+#define        reg_aagc_rf_top_numerator_7_0_len 8
+#define        reg_aagc_rf_top_numerator_7_0_lsb 0
+#define xd_p_reg_aagc_rf_top_numerator_9_8     0xA012
+#define        reg_aagc_rf_top_numerator_9_8_pos 0
+#define        reg_aagc_rf_top_numerator_9_8_len 2
+#define        reg_aagc_rf_top_numerator_9_8_lsb 8
+#define xd_p_reg_aagc_if_top_numerator_7_0     0xA013
+#define        reg_aagc_if_top_numerator_7_0_pos 0
+#define        reg_aagc_if_top_numerator_7_0_len 8
+#define        reg_aagc_if_top_numerator_7_0_lsb 0
+#define xd_p_reg_aagc_if_top_numerator_9_8     0xA014
+#define        reg_aagc_if_top_numerator_9_8_pos 0
+#define        reg_aagc_if_top_numerator_9_8_len 2
+#define        reg_aagc_if_top_numerator_9_8_lsb 8
+#define xd_p_reg_aagc_adc_out_desired_7_0      0xA015
+#define        reg_aagc_adc_out_desired_7_0_pos 0
+#define        reg_aagc_adc_out_desired_7_0_len 8
+#define        reg_aagc_adc_out_desired_7_0_lsb 0
+#define xd_p_reg_aagc_adc_out_desired_8        0xA016
+#define        reg_aagc_adc_out_desired_8_pos 0
+#define        reg_aagc_adc_out_desired_8_len 1
+#define        reg_aagc_adc_out_desired_8_lsb 0
+#define xd_p_reg_aagc_fixed_gain       0xA016
+#define        reg_aagc_fixed_gain_pos 3
+#define        reg_aagc_fixed_gain_len 1
+#define        reg_aagc_fixed_gain_lsb 0
+#define xd_p_reg_aagc_lock_count_th    0xA016
+#define        reg_aagc_lock_count_th_pos 4
+#define        reg_aagc_lock_count_th_len 4
+#define        reg_aagc_lock_count_th_lsb 0
+#define xd_p_reg_aagc_fixed_rf_agc_control_7_0 0xA017
+#define        reg_aagc_fixed_rf_agc_control_7_0_pos 0
+#define        reg_aagc_fixed_rf_agc_control_7_0_len 8
+#define        reg_aagc_fixed_rf_agc_control_7_0_lsb 0
+#define xd_p_reg_aagc_fixed_rf_agc_control_15_8        0xA018
+#define        reg_aagc_fixed_rf_agc_control_15_8_pos 0
+#define        reg_aagc_fixed_rf_agc_control_15_8_len 8
+#define        reg_aagc_fixed_rf_agc_control_15_8_lsb 8
+#define xd_p_reg_aagc_fixed_rf_agc_control_23_16       0xA019
+#define        reg_aagc_fixed_rf_agc_control_23_16_pos 0
+#define        reg_aagc_fixed_rf_agc_control_23_16_len 8
+#define        reg_aagc_fixed_rf_agc_control_23_16_lsb 16
+#define xd_p_reg_aagc_fixed_rf_agc_control_30_24       0xA01A
+#define        reg_aagc_fixed_rf_agc_control_30_24_pos 0
+#define        reg_aagc_fixed_rf_agc_control_30_24_len 7
+#define        reg_aagc_fixed_rf_agc_control_30_24_lsb 24
+#define xd_p_reg_aagc_fixed_if_agc_control_7_0 0xA01B
+#define        reg_aagc_fixed_if_agc_control_7_0_pos 0
+#define        reg_aagc_fixed_if_agc_control_7_0_len 8
+#define        reg_aagc_fixed_if_agc_control_7_0_lsb 0
+#define xd_p_reg_aagc_fixed_if_agc_control_15_8        0xA01C
+#define        reg_aagc_fixed_if_agc_control_15_8_pos 0
+#define        reg_aagc_fixed_if_agc_control_15_8_len 8
+#define        reg_aagc_fixed_if_agc_control_15_8_lsb 8
+#define xd_p_reg_aagc_fixed_if_agc_control_23_16       0xA01D
+#define        reg_aagc_fixed_if_agc_control_23_16_pos 0
+#define        reg_aagc_fixed_if_agc_control_23_16_len 8
+#define        reg_aagc_fixed_if_agc_control_23_16_lsb 16
+#define xd_p_reg_aagc_fixed_if_agc_control_30_24       0xA01E
+#define        reg_aagc_fixed_if_agc_control_30_24_pos 0
+#define        reg_aagc_fixed_if_agc_control_30_24_len 7
+#define        reg_aagc_fixed_if_agc_control_30_24_lsb 24
+#define xd_p_reg_aagc_rf_agc_unlock_numerator  0xA01F
+#define        reg_aagc_rf_agc_unlock_numerator_pos 0
+#define        reg_aagc_rf_agc_unlock_numerator_len 6
+#define        reg_aagc_rf_agc_unlock_numerator_lsb 0
+#define xd_p_reg_aagc_if_agc_unlock_numerator  0xA020
+#define        reg_aagc_if_agc_unlock_numerator_pos 0
+#define        reg_aagc_if_agc_unlock_numerator_len 6
+#define        reg_aagc_if_agc_unlock_numerator_lsb 0
+#define xd_p_reg_unplug_th     0xA021
+#define        reg_unplug_th_pos 0
+#define        reg_unplug_th_len 8
+#define        reg_aagc_rf_x0_lsb 0
+#define xd_p_reg_weak_signal_rfagc_thr 0xA022
+#define        reg_weak_signal_rfagc_thr_pos 0
+#define        reg_weak_signal_rfagc_thr_len 8
+#define        reg_weak_signal_rfagc_thr_lsb 0
+#define xd_p_reg_unplug_rf_gain_th 0xA023
+#define        reg_unplug_rf_gain_th_pos 0
+#define        reg_unplug_rf_gain_th_len 8
+#define        reg_unplug_rf_gain_th_lsb 0
+#define xd_p_reg_unplug_dtop_rf_gain_th 0xA024
+#define        reg_unplug_dtop_rf_gain_th_pos 0
+#define        reg_unplug_dtop_rf_gain_th_len 8
+#define        reg_unplug_dtop_rf_gain_th_lsb 0
+#define xd_p_reg_unplug_dtop_if_gain_th 0xA025
+#define        reg_unplug_dtop_if_gain_th_pos 0
+#define        reg_unplug_dtop_if_gain_th_len 8
+#define        reg_unplug_dtop_if_gain_th_lsb 0
+#define xd_p_reg_top_recover_at_unplug_en 0xA026
+#define        reg_top_recover_at_unplug_en_pos 0
+#define        reg_top_recover_at_unplug_en_len 1
+#define        reg_top_recover_at_unplug_en_lsb 0
+#define xd_p_reg_aagc_rf_x6    0xA027
+#define        reg_aagc_rf_x6_pos 0
+#define        reg_aagc_rf_x6_len 8
+#define        reg_aagc_rf_x6_lsb 0
+#define xd_p_reg_aagc_rf_x7    0xA028
+#define        reg_aagc_rf_x7_pos 0
+#define        reg_aagc_rf_x7_len 8
+#define        reg_aagc_rf_x7_lsb 0
+#define xd_p_reg_aagc_rf_x8    0xA029
+#define        reg_aagc_rf_x8_pos 0
+#define        reg_aagc_rf_x8_len 8
+#define        reg_aagc_rf_x8_lsb 0
+#define xd_p_reg_aagc_rf_x9    0xA02A
+#define        reg_aagc_rf_x9_pos 0
+#define        reg_aagc_rf_x9_len 8
+#define        reg_aagc_rf_x9_lsb 0
+#define xd_p_reg_aagc_rf_x10   0xA02B
+#define        reg_aagc_rf_x10_pos 0
+#define        reg_aagc_rf_x10_len 8
+#define        reg_aagc_rf_x10_lsb 0
+#define xd_p_reg_aagc_rf_x11   0xA02C
+#define        reg_aagc_rf_x11_pos 0
+#define        reg_aagc_rf_x11_len 8
+#define        reg_aagc_rf_x11_lsb 0
+#define xd_p_reg_aagc_rf_x12   0xA02D
+#define        reg_aagc_rf_x12_pos 0
+#define        reg_aagc_rf_x12_len 8
+#define        reg_aagc_rf_x12_lsb 0
+#define xd_p_reg_aagc_rf_x13   0xA02E
+#define        reg_aagc_rf_x13_pos 0
+#define        reg_aagc_rf_x13_len 8
+#define        reg_aagc_rf_x13_lsb 0
+#define xd_p_reg_aagc_if_x0    0xA02F
+#define        reg_aagc_if_x0_pos 0
+#define        reg_aagc_if_x0_len 8
+#define        reg_aagc_if_x0_lsb 0
+#define xd_p_reg_aagc_if_x1    0xA030
+#define        reg_aagc_if_x1_pos 0
+#define        reg_aagc_if_x1_len 8
+#define        reg_aagc_if_x1_lsb 0
+#define xd_p_reg_aagc_if_x2    0xA031
+#define        reg_aagc_if_x2_pos 0
+#define        reg_aagc_if_x2_len 8
+#define        reg_aagc_if_x2_lsb 0
+#define xd_p_reg_aagc_if_x3    0xA032
+#define        reg_aagc_if_x3_pos 0
+#define        reg_aagc_if_x3_len 8
+#define        reg_aagc_if_x3_lsb 0
+#define xd_p_reg_aagc_if_x4    0xA033
+#define        reg_aagc_if_x4_pos 0
+#define        reg_aagc_if_x4_len 8
+#define        reg_aagc_if_x4_lsb 0
+#define xd_p_reg_aagc_if_x5    0xA034
+#define        reg_aagc_if_x5_pos 0
+#define        reg_aagc_if_x5_len 8
+#define        reg_aagc_if_x5_lsb 0
+#define xd_p_reg_aagc_if_x6    0xA035
+#define        reg_aagc_if_x6_pos 0
+#define        reg_aagc_if_x6_len 8
+#define        reg_aagc_if_x6_lsb 0
+#define xd_p_reg_aagc_if_x7    0xA036
+#define        reg_aagc_if_x7_pos 0
+#define        reg_aagc_if_x7_len 8
+#define        reg_aagc_if_x7_lsb 0
+#define xd_p_reg_aagc_if_x8    0xA037
+#define        reg_aagc_if_x8_pos 0
+#define        reg_aagc_if_x8_len 8
+#define        reg_aagc_if_x8_lsb 0
+#define xd_p_reg_aagc_if_x9    0xA038
+#define        reg_aagc_if_x9_pos 0
+#define        reg_aagc_if_x9_len 8
+#define        reg_aagc_if_x9_lsb 0
+#define xd_p_reg_aagc_if_x10   0xA039
+#define        reg_aagc_if_x10_pos 0
+#define        reg_aagc_if_x10_len 8
+#define        reg_aagc_if_x10_lsb 0
+#define xd_p_reg_aagc_if_x11   0xA03A
+#define        reg_aagc_if_x11_pos 0
+#define        reg_aagc_if_x11_len 8
+#define        reg_aagc_if_x11_lsb 0
+#define xd_p_reg_aagc_if_x12   0xA03B
+#define        reg_aagc_if_x12_pos 0
+#define        reg_aagc_if_x12_len 8
+#define        reg_aagc_if_x12_lsb 0
+#define xd_p_reg_aagc_if_x13   0xA03C
+#define        reg_aagc_if_x13_pos 0
+#define        reg_aagc_if_x13_len 8
+#define        reg_aagc_if_x13_lsb 0
+#define xd_p_reg_aagc_min_rf_ctl_8bit_for_dca  0xA03D
+#define        reg_aagc_min_rf_ctl_8bit_for_dca_pos 0
+#define        reg_aagc_min_rf_ctl_8bit_for_dca_len 8
+#define        reg_aagc_min_rf_ctl_8bit_for_dca_lsb 0
+#define xd_p_reg_aagc_min_if_ctl_8bit_for_dca  0xA03E
+#define        reg_aagc_min_if_ctl_8bit_for_dca_pos 0
+#define        reg_aagc_min_if_ctl_8bit_for_dca_len 8
+#define        reg_aagc_min_if_ctl_8bit_for_dca_lsb 0
+#define xd_r_reg_aagc_total_gain_7_0   0xA070
+#define        reg_aagc_total_gain_7_0_pos 0
+#define        reg_aagc_total_gain_7_0_len 8
+#define        reg_aagc_total_gain_7_0_lsb 0
+#define xd_r_reg_aagc_total_gain_15_8  0xA071
+#define        reg_aagc_total_gain_15_8_pos 0
+#define        reg_aagc_total_gain_15_8_len 8
+#define        reg_aagc_total_gain_15_8_lsb 8
+#define xd_p_reg_aagc_in_sat_cnt_7_0   0xA074
+#define        reg_aagc_in_sat_cnt_7_0_pos 0
+#define        reg_aagc_in_sat_cnt_7_0_len 8
+#define        reg_aagc_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_aagc_in_sat_cnt_15_8  0xA075
+#define        reg_aagc_in_sat_cnt_15_8_pos 0
+#define        reg_aagc_in_sat_cnt_15_8_len 8
+#define        reg_aagc_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_aagc_in_sat_cnt_23_16 0xA076
+#define        reg_aagc_in_sat_cnt_23_16_pos 0
+#define        reg_aagc_in_sat_cnt_23_16_len 8
+#define        reg_aagc_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_aagc_in_sat_cnt_31_24 0xA077
+#define        reg_aagc_in_sat_cnt_31_24_pos 0
+#define        reg_aagc_in_sat_cnt_31_24_len 8
+#define        reg_aagc_in_sat_cnt_31_24_lsb 24
+#define xd_r_reg_aagc_digital_rf_volt_7_0      0xA078
+#define        reg_aagc_digital_rf_volt_7_0_pos 0
+#define        reg_aagc_digital_rf_volt_7_0_len 8
+#define        reg_aagc_digital_rf_volt_7_0_lsb 0
+#define xd_r_reg_aagc_digital_rf_volt_9_8      0xA079
+#define        reg_aagc_digital_rf_volt_9_8_pos 0
+#define        reg_aagc_digital_rf_volt_9_8_len 2
+#define        reg_aagc_digital_rf_volt_9_8_lsb 8
+#define xd_r_reg_aagc_digital_if_volt_7_0      0xA07A
+#define        reg_aagc_digital_if_volt_7_0_pos 0
+#define        reg_aagc_digital_if_volt_7_0_len 8
+#define        reg_aagc_digital_if_volt_7_0_lsb 0
+#define xd_r_reg_aagc_digital_if_volt_9_8      0xA07B
+#define        reg_aagc_digital_if_volt_9_8_pos 0
+#define        reg_aagc_digital_if_volt_9_8_len 2
+#define        reg_aagc_digital_if_volt_9_8_lsb 8
+#define xd_r_reg_aagc_rf_gain  0xA07C
+#define        reg_aagc_rf_gain_pos 0
+#define        reg_aagc_rf_gain_len 8
+#define        reg_aagc_rf_gain_lsb 0
+#define xd_r_reg_aagc_if_gain  0xA07D
+#define        reg_aagc_if_gain_pos 0
+#define        reg_aagc_if_gain_len 8
+#define        reg_aagc_if_gain_lsb 0
+#define xd_p_tinr_imp_indicator        0xA080
+#define        tinr_imp_indicator_pos 0
+#define        tinr_imp_indicator_len 2
+#define        tinr_imp_indicator_lsb 0
+#define xd_p_reg_tinr_fifo_size        0xA080
+#define        reg_tinr_fifo_size_pos 2
+#define        reg_tinr_fifo_size_len 5
+#define        reg_tinr_fifo_size_lsb 0
+#define xd_p_reg_tinr_saturation_cnt_th        0xA081
+#define        reg_tinr_saturation_cnt_th_pos 0
+#define        reg_tinr_saturation_cnt_th_len 4
+#define        reg_tinr_saturation_cnt_th_lsb 0
+#define xd_p_reg_tinr_saturation_th_3_0        0xA081
+#define        reg_tinr_saturation_th_3_0_pos 4
+#define        reg_tinr_saturation_th_3_0_len 4
+#define        reg_tinr_saturation_th_3_0_lsb 0
+#define xd_p_reg_tinr_saturation_th_8_4        0xA082
+#define        reg_tinr_saturation_th_8_4_pos 0
+#define        reg_tinr_saturation_th_8_4_len 5
+#define        reg_tinr_saturation_th_8_4_lsb 4
+#define xd_p_reg_tinr_imp_duration_th_2k_7_0   0xA083
+#define        reg_tinr_imp_duration_th_2k_7_0_pos 0
+#define        reg_tinr_imp_duration_th_2k_7_0_len 8
+#define        reg_tinr_imp_duration_th_2k_7_0_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_2k_8     0xA084
+#define        reg_tinr_imp_duration_th_2k_8_pos 0
+#define        reg_tinr_imp_duration_th_2k_8_len 1
+#define        reg_tinr_imp_duration_th_2k_8_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_8k_7_0   0xA085
+#define        reg_tinr_imp_duration_th_8k_7_0_pos 0
+#define        reg_tinr_imp_duration_th_8k_7_0_len 8
+#define        reg_tinr_imp_duration_th_8k_7_0_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_8k_10_8  0xA086
+#define        reg_tinr_imp_duration_th_8k_10_8_pos 0
+#define        reg_tinr_imp_duration_th_8k_10_8_len 3
+#define        reg_tinr_imp_duration_th_8k_10_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_6m_7_0        0xA087
+#define        reg_tinr_freq_ratio_6m_7_0_pos 0
+#define        reg_tinr_freq_ratio_6m_7_0_len 8
+#define        reg_tinr_freq_ratio_6m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_6m_12_8       0xA088
+#define        reg_tinr_freq_ratio_6m_12_8_pos 0
+#define        reg_tinr_freq_ratio_6m_12_8_len 5
+#define        reg_tinr_freq_ratio_6m_12_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_7m_7_0        0xA089
+#define        reg_tinr_freq_ratio_7m_7_0_pos 0
+#define        reg_tinr_freq_ratio_7m_7_0_len 8
+#define        reg_tinr_freq_ratio_7m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_7m_12_8       0xA08A
+#define        reg_tinr_freq_ratio_7m_12_8_pos 0
+#define        reg_tinr_freq_ratio_7m_12_8_len 5
+#define        reg_tinr_freq_ratio_7m_12_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_8m_7_0        0xA08B
+#define        reg_tinr_freq_ratio_8m_7_0_pos 0
+#define        reg_tinr_freq_ratio_8m_7_0_len 8
+#define        reg_tinr_freq_ratio_8m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_8m_12_8       0xA08C
+#define        reg_tinr_freq_ratio_8m_12_8_pos 0
+#define        reg_tinr_freq_ratio_8m_12_8_len 5
+#define        reg_tinr_freq_ratio_8m_12_8_lsb 8
+#define xd_p_reg_tinr_imp_duration_th_low_2k   0xA08D
+#define        reg_tinr_imp_duration_th_low_2k_pos 0
+#define        reg_tinr_imp_duration_th_low_2k_len 8
+#define        reg_tinr_imp_duration_th_low_2k_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_low_8k   0xA08E
+#define        reg_tinr_imp_duration_th_low_8k_pos 0
+#define        reg_tinr_imp_duration_th_low_8k_len 8
+#define        reg_tinr_imp_duration_th_low_8k_lsb 0
+#define xd_r_reg_tinr_counter_7_0      0xA090
+#define        reg_tinr_counter_7_0_pos 0
+#define        reg_tinr_counter_7_0_len 8
+#define        reg_tinr_counter_7_0_lsb 0
+#define xd_r_reg_tinr_counter_15_8     0xA091
+#define        reg_tinr_counter_15_8_pos 0
+#define        reg_tinr_counter_15_8_len 8
+#define        reg_tinr_counter_15_8_lsb 8
+#define xd_p_reg_tinr_adative_tinr_en  0xA093
+#define        reg_tinr_adative_tinr_en_pos 0
+#define        reg_tinr_adative_tinr_en_len 1
+#define        reg_tinr_adative_tinr_en_lsb 0
+#define xd_p_reg_tinr_peak_fifo_size   0xA093
+#define        reg_tinr_peak_fifo_size_pos 1
+#define        reg_tinr_peak_fifo_size_len 5
+#define        reg_tinr_peak_fifo_size_lsb 0
+#define xd_p_reg_tinr_counter_rst      0xA093
+#define        reg_tinr_counter_rst_pos 6
+#define        reg_tinr_counter_rst_len 1
+#define        reg_tinr_counter_rst_lsb 0
+#define xd_p_reg_tinr_search_period_7_0        0xA094
+#define        reg_tinr_search_period_7_0_pos 0
+#define        reg_tinr_search_period_7_0_len 8
+#define        reg_tinr_search_period_7_0_lsb 0
+#define xd_p_reg_tinr_search_period_15_8       0xA095
+#define        reg_tinr_search_period_15_8_pos 0
+#define        reg_tinr_search_period_15_8_len 8
+#define        reg_tinr_search_period_15_8_lsb 8
+#define xd_p_reg_ccifs_fcw_7_0 0xA0A0
+#define        reg_ccifs_fcw_7_0_pos 0
+#define        reg_ccifs_fcw_7_0_len 8
+#define        reg_ccifs_fcw_7_0_lsb 0
+#define xd_p_reg_ccifs_fcw_12_8        0xA0A1
+#define        reg_ccifs_fcw_12_8_pos 0
+#define        reg_ccifs_fcw_12_8_len 5
+#define        reg_ccifs_fcw_12_8_lsb 8
+#define xd_p_reg_ccifs_spec_inv        0xA0A1
+#define        reg_ccifs_spec_inv_pos 5
+#define        reg_ccifs_spec_inv_len 1
+#define        reg_ccifs_spec_inv_lsb 0
+#define xd_p_reg_gp_trigger    0xA0A2
+#define        reg_gp_trigger_pos 0
+#define        reg_gp_trigger_len 1
+#define        reg_gp_trigger_lsb 0
+#define xd_p_reg_trigger_sel   0xA0A2
+#define        reg_trigger_sel_pos 1
+#define        reg_trigger_sel_len 2
+#define        reg_trigger_sel_lsb 0
+#define xd_p_reg_debug_ofdm    0xA0A2
+#define        reg_debug_ofdm_pos 3
+#define        reg_debug_ofdm_len 2
+#define        reg_debug_ofdm_lsb 0
+#define xd_p_reg_trigger_module_sel    0xA0A3
+#define        reg_trigger_module_sel_pos 0
+#define        reg_trigger_module_sel_len 6
+#define        reg_trigger_module_sel_lsb 0
+#define xd_p_reg_trigger_set_sel       0xA0A4
+#define        reg_trigger_set_sel_pos 0
+#define        reg_trigger_set_sel_len 6
+#define        reg_trigger_set_sel_lsb 0
+#define xd_p_reg_fw_int_mask_n 0xA0A4
+#define        reg_fw_int_mask_n_pos 6
+#define        reg_fw_int_mask_n_len 1
+#define        reg_fw_int_mask_n_lsb 0
+#define xd_p_reg_debug_group   0xA0A5
+#define        reg_debug_group_pos 0
+#define        reg_debug_group_len 4
+#define        reg_debug_group_lsb 0
+#define xd_p_reg_odbg_clk_sel  0xA0A5
+#define        reg_odbg_clk_sel_pos 4
+#define        reg_odbg_clk_sel_len 2
+#define        reg_odbg_clk_sel_lsb 0
+#define xd_p_reg_ccif_sc       0xA0C0
+#define        reg_ccif_sc_pos 0
+#define        reg_ccif_sc_len 4
+#define        reg_ccif_sc_lsb 0
+#define xd_r_reg_ccif_saturate 0xA0C1
+#define        reg_ccif_saturate_pos 0
+#define        reg_ccif_saturate_len 2
+#define        reg_ccif_saturate_lsb 0
+#define xd_r_reg_antif_saturate        0xA0C1
+#define        reg_antif_saturate_pos 2
+#define        reg_antif_saturate_len 4
+#define        reg_antif_saturate_lsb 0
+#define xd_r_reg_acif_saturate 0xA0C2
+#define        reg_acif_saturate_pos 0
+#define        reg_acif_saturate_len 8
+#define        reg_acif_saturate_lsb 0
+#define xd_p_reg_tmr_timer0_threshold_7_0      0xA0C8
+#define        reg_tmr_timer0_threshold_7_0_pos 0
+#define        reg_tmr_timer0_threshold_7_0_len 8
+#define        reg_tmr_timer0_threshold_7_0_lsb 0
+#define xd_p_reg_tmr_timer0_threshold_15_8     0xA0C9
+#define        reg_tmr_timer0_threshold_15_8_pos 0
+#define        reg_tmr_timer0_threshold_15_8_len 8
+#define        reg_tmr_timer0_threshold_15_8_lsb 8
+#define xd_p_reg_tmr_timer0_enable     0xA0CA
+#define        reg_tmr_timer0_enable_pos 0
+#define        reg_tmr_timer0_enable_len 1
+#define        reg_tmr_timer0_enable_lsb 0
+#define xd_p_reg_tmr_timer0_clk_sel    0xA0CA
+#define        reg_tmr_timer0_clk_sel_pos 1
+#define        reg_tmr_timer0_clk_sel_len 1
+#define        reg_tmr_timer0_clk_sel_lsb 0
+#define xd_p_reg_tmr_timer0_int        0xA0CA
+#define        reg_tmr_timer0_int_pos 2
+#define        reg_tmr_timer0_int_len 1
+#define        reg_tmr_timer0_int_lsb 0
+#define xd_p_reg_tmr_timer0_rst        0xA0CA
+#define        reg_tmr_timer0_rst_pos 3
+#define        reg_tmr_timer0_rst_len 1
+#define        reg_tmr_timer0_rst_lsb 0
+#define xd_r_reg_tmr_timer0_count_7_0  0xA0CB
+#define        reg_tmr_timer0_count_7_0_pos 0
+#define        reg_tmr_timer0_count_7_0_len 8
+#define        reg_tmr_timer0_count_7_0_lsb 0
+#define xd_r_reg_tmr_timer0_count_15_8 0xA0CC
+#define        reg_tmr_timer0_count_15_8_pos 0
+#define        reg_tmr_timer0_count_15_8_len 8
+#define        reg_tmr_timer0_count_15_8_lsb 8
+#define xd_p_reg_suspend       0xA0CD
+#define        reg_suspend_pos 0
+#define        reg_suspend_len 1
+#define        reg_suspend_lsb 0
+#define xd_p_reg_suspend_rdy   0xA0CD
+#define        reg_suspend_rdy_pos 1
+#define        reg_suspend_rdy_len 1
+#define        reg_suspend_rdy_lsb 0
+#define xd_p_reg_resume        0xA0CD
+#define        reg_resume_pos 2
+#define        reg_resume_len 1
+#define        reg_resume_lsb 0
+#define xd_p_reg_resume_rdy    0xA0CD
+#define        reg_resume_rdy_pos 3
+#define        reg_resume_rdy_len 1
+#define        reg_resume_rdy_lsb 0
+#define xd_p_reg_fmf   0xA0CE
+#define        reg_fmf_pos 0
+#define        reg_fmf_len 8
+#define        reg_fmf_lsb 0
+#define xd_p_ccid_accumulate_num_2k_7_0        0xA100
+#define        ccid_accumulate_num_2k_7_0_pos 0
+#define        ccid_accumulate_num_2k_7_0_len 8
+#define        ccid_accumulate_num_2k_7_0_lsb 0
+#define xd_p_ccid_accumulate_num_2k_12_8       0xA101
+#define        ccid_accumulate_num_2k_12_8_pos 0
+#define        ccid_accumulate_num_2k_12_8_len 5
+#define        ccid_accumulate_num_2k_12_8_lsb 8
+#define xd_p_ccid_accumulate_num_8k_7_0        0xA102
+#define        ccid_accumulate_num_8k_7_0_pos 0
+#define        ccid_accumulate_num_8k_7_0_len 8
+#define        ccid_accumulate_num_8k_7_0_lsb 0
+#define xd_p_ccid_accumulate_num_8k_14_8       0xA103
+#define        ccid_accumulate_num_8k_14_8_pos 0
+#define        ccid_accumulate_num_8k_14_8_len 7
+#define        ccid_accumulate_num_8k_14_8_lsb 8
+#define xd_p_ccid_desired_level_0      0xA103
+#define        ccid_desired_level_0_pos 7
+#define        ccid_desired_level_0_len 1
+#define        ccid_desired_level_0_lsb 0
+#define xd_p_ccid_desired_level_8_1    0xA104
+#define        ccid_desired_level_8_1_pos 0
+#define        ccid_desired_level_8_1_len 8
+#define        ccid_desired_level_8_1_lsb 1
+#define xd_p_ccid_apply_delay  0xA105
+#define        ccid_apply_delay_pos 0
+#define        ccid_apply_delay_len 7
+#define        ccid_apply_delay_lsb 0
+#define xd_p_ccid_CCID_Threshold1      0xA106
+#define        ccid_CCID_Threshold1_pos 0
+#define        ccid_CCID_Threshold1_len 8
+#define        ccid_CCID_Threshold1_lsb 0
+#define xd_p_ccid_CCID_Threshold2      0xA107
+#define        ccid_CCID_Threshold2_pos 0
+#define        ccid_CCID_Threshold2_len 8
+#define        ccid_CCID_Threshold2_lsb 0
+#define xd_p_reg_ccid_gain_scale       0xA108
+#define        reg_ccid_gain_scale_pos 0
+#define        reg_ccid_gain_scale_len 4
+#define        reg_ccid_gain_scale_lsb 0
+#define xd_p_reg_ccid2_passband_gain_set       0xA108
+#define        reg_ccid2_passband_gain_set_pos 4
+#define        reg_ccid2_passband_gain_set_len 4
+#define        reg_ccid2_passband_gain_set_lsb 0
+#define xd_r_ccid_multiplier_7_0       0xA109
+#define        ccid_multiplier_7_0_pos 0
+#define        ccid_multiplier_7_0_len 8
+#define        ccid_multiplier_7_0_lsb 0
+#define xd_r_ccid_multiplier_15_8      0xA10A
+#define        ccid_multiplier_15_8_pos 0
+#define        ccid_multiplier_15_8_len 8
+#define        ccid_multiplier_15_8_lsb 8
+#define xd_r_ccid_right_shift_bits     0xA10B
+#define        ccid_right_shift_bits_pos 0
+#define        ccid_right_shift_bits_len 4
+#define        ccid_right_shift_bits_lsb 0
+#define xd_r_reg_ccid_sx_7_0   0xA10C
+#define        reg_ccid_sx_7_0_pos 0
+#define        reg_ccid_sx_7_0_len 8
+#define        reg_ccid_sx_7_0_lsb 0
+#define xd_r_reg_ccid_sx_15_8  0xA10D
+#define        reg_ccid_sx_15_8_pos 0
+#define        reg_ccid_sx_15_8_len 8
+#define        reg_ccid_sx_15_8_lsb 8
+#define xd_r_reg_ccid_sx_21_16 0xA10E
+#define        reg_ccid_sx_21_16_pos 0
+#define        reg_ccid_sx_21_16_len 6
+#define        reg_ccid_sx_21_16_lsb 16
+#define xd_r_reg_ccid_sy_7_0   0xA110
+#define        reg_ccid_sy_7_0_pos 0
+#define        reg_ccid_sy_7_0_len 8
+#define        reg_ccid_sy_7_0_lsb 0
+#define xd_r_reg_ccid_sy_15_8  0xA111
+#define        reg_ccid_sy_15_8_pos 0
+#define        reg_ccid_sy_15_8_len 8
+#define        reg_ccid_sy_15_8_lsb 8
+#define xd_r_reg_ccid_sy_23_16 0xA112
+#define        reg_ccid_sy_23_16_pos 0
+#define        reg_ccid_sy_23_16_len 8
+#define        reg_ccid_sy_23_16_lsb 16
+#define xd_r_reg_ccid2_sz_7_0  0xA114
+#define        reg_ccid2_sz_7_0_pos 0
+#define        reg_ccid2_sz_7_0_len 8
+#define        reg_ccid2_sz_7_0_lsb 0
+#define xd_r_reg_ccid2_sz_15_8 0xA115
+#define        reg_ccid2_sz_15_8_pos 0
+#define        reg_ccid2_sz_15_8_len 8
+#define        reg_ccid2_sz_15_8_lsb 8
+#define xd_r_reg_ccid2_sz_23_16        0xA116
+#define        reg_ccid2_sz_23_16_pos 0
+#define        reg_ccid2_sz_23_16_len 8
+#define        reg_ccid2_sz_23_16_lsb 16
+#define xd_r_reg_ccid2_sz_25_24        0xA117
+#define        reg_ccid2_sz_25_24_pos 0
+#define        reg_ccid2_sz_25_24_len 2
+#define        reg_ccid2_sz_25_24_lsb 24
+#define xd_r_reg_ccid2_sy_7_0  0xA118
+#define        reg_ccid2_sy_7_0_pos 0
+#define        reg_ccid2_sy_7_0_len 8
+#define        reg_ccid2_sy_7_0_lsb 0
+#define xd_r_reg_ccid2_sy_15_8 0xA119
+#define        reg_ccid2_sy_15_8_pos 0
+#define        reg_ccid2_sy_15_8_len 8
+#define        reg_ccid2_sy_15_8_lsb 8
+#define xd_r_reg_ccid2_sy_23_16        0xA11A
+#define        reg_ccid2_sy_23_16_pos 0
+#define        reg_ccid2_sy_23_16_len 8
+#define        reg_ccid2_sy_23_16_lsb 16
+#define xd_r_reg_ccid2_sy_25_24        0xA11B
+#define        reg_ccid2_sy_25_24_pos 0
+#define        reg_ccid2_sy_25_24_len 2
+#define        reg_ccid2_sy_25_24_lsb 24
+#define xd_p_dagc1_accumulate_num_2k_7_0       0xA120
+#define        dagc1_accumulate_num_2k_7_0_pos 0
+#define        dagc1_accumulate_num_2k_7_0_len 8
+#define        dagc1_accumulate_num_2k_7_0_lsb 0
+#define xd_p_dagc1_accumulate_num_2k_12_8      0xA121
+#define        dagc1_accumulate_num_2k_12_8_pos 0
+#define        dagc1_accumulate_num_2k_12_8_len 5
+#define        dagc1_accumulate_num_2k_12_8_lsb 8
+#define xd_p_dagc1_accumulate_num_8k_7_0       0xA122
+#define        dagc1_accumulate_num_8k_7_0_pos 0
+#define        dagc1_accumulate_num_8k_7_0_len 8
+#define        dagc1_accumulate_num_8k_7_0_lsb 0
+#define xd_p_dagc1_accumulate_num_8k_14_8      0xA123
+#define        dagc1_accumulate_num_8k_14_8_pos 0
+#define        dagc1_accumulate_num_8k_14_8_len 7
+#define        dagc1_accumulate_num_8k_14_8_lsb 8
+#define xd_p_dagc1_desired_level_0     0xA123
+#define        dagc1_desired_level_0_pos 7
+#define        dagc1_desired_level_0_len 1
+#define        dagc1_desired_level_0_lsb 0
+#define xd_p_dagc1_desired_level_8_1   0xA124
+#define        dagc1_desired_level_8_1_pos 0
+#define        dagc1_desired_level_8_1_len 8
+#define        dagc1_desired_level_8_1_lsb 1
+#define xd_p_dagc1_apply_delay 0xA125
+#define        dagc1_apply_delay_pos 0
+#define        dagc1_apply_delay_len 7
+#define        dagc1_apply_delay_lsb 0
+#define xd_p_dagc1_bypass_scale_ctl    0xA126
+#define        dagc1_bypass_scale_ctl_pos 0
+#define        dagc1_bypass_scale_ctl_len 2
+#define        dagc1_bypass_scale_ctl_lsb 0
+#define xd_p_reg_dagc1_in_sat_cnt_7_0  0xA127
+#define        reg_dagc1_in_sat_cnt_7_0_pos 0
+#define        reg_dagc1_in_sat_cnt_7_0_len 8
+#define        reg_dagc1_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc1_in_sat_cnt_15_8 0xA128
+#define        reg_dagc1_in_sat_cnt_15_8_pos 0
+#define        reg_dagc1_in_sat_cnt_15_8_len 8
+#define        reg_dagc1_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc1_in_sat_cnt_23_16        0xA129
+#define        reg_dagc1_in_sat_cnt_23_16_pos 0
+#define        reg_dagc1_in_sat_cnt_23_16_len 8
+#define        reg_dagc1_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc1_in_sat_cnt_31_24        0xA12A
+#define        reg_dagc1_in_sat_cnt_31_24_pos 0
+#define        reg_dagc1_in_sat_cnt_31_24_len 8
+#define        reg_dagc1_in_sat_cnt_31_24_lsb 24
+#define xd_p_reg_dagc1_out_sat_cnt_7_0 0xA12B
+#define        reg_dagc1_out_sat_cnt_7_0_pos 0
+#define        reg_dagc1_out_sat_cnt_7_0_len 8
+#define        reg_dagc1_out_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc1_out_sat_cnt_15_8        0xA12C
+#define        reg_dagc1_out_sat_cnt_15_8_pos 0
+#define        reg_dagc1_out_sat_cnt_15_8_len 8
+#define        reg_dagc1_out_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc1_out_sat_cnt_23_16       0xA12D
+#define        reg_dagc1_out_sat_cnt_23_16_pos 0
+#define        reg_dagc1_out_sat_cnt_23_16_len 8
+#define        reg_dagc1_out_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc1_out_sat_cnt_31_24       0xA12E
+#define        reg_dagc1_out_sat_cnt_31_24_pos 0
+#define        reg_dagc1_out_sat_cnt_31_24_len 8
+#define        reg_dagc1_out_sat_cnt_31_24_lsb 24
+#define xd_r_dagc1_multiplier_7_0      0xA136
+#define        dagc1_multiplier_7_0_pos 0
+#define        dagc1_multiplier_7_0_len 8
+#define        dagc1_multiplier_7_0_lsb 0
+#define xd_r_dagc1_multiplier_15_8     0xA137
+#define        dagc1_multiplier_15_8_pos 0
+#define        dagc1_multiplier_15_8_len 8
+#define        dagc1_multiplier_15_8_lsb 8
+#define xd_r_dagc1_right_shift_bits    0xA138
+#define        dagc1_right_shift_bits_pos 0
+#define        dagc1_right_shift_bits_len 4
+#define        dagc1_right_shift_bits_lsb 0
+#define xd_p_reg_bfs_fcw_7_0   0xA140
+#define        reg_bfs_fcw_7_0_pos 0
+#define        reg_bfs_fcw_7_0_len 8
+#define        reg_bfs_fcw_7_0_lsb 0
+#define xd_p_reg_bfs_fcw_15_8  0xA141
+#define        reg_bfs_fcw_15_8_pos 0
+#define        reg_bfs_fcw_15_8_len 8
+#define        reg_bfs_fcw_15_8_lsb 8
+#define xd_p_reg_bfs_fcw_22_16 0xA142
+#define        reg_bfs_fcw_22_16_pos 0
+#define        reg_bfs_fcw_22_16_len 7
+#define        reg_bfs_fcw_22_16_lsb 16
+#define xd_p_reg_antif_sf_7_0  0xA144
+#define        reg_antif_sf_7_0_pos 0
+#define        reg_antif_sf_7_0_len 8
+#define        reg_antif_sf_7_0_lsb 0
+#define xd_p_reg_antif_sf_11_8 0xA145
+#define        reg_antif_sf_11_8_pos 0
+#define        reg_antif_sf_11_8_len 4
+#define        reg_antif_sf_11_8_lsb 8
+#define xd_r_bfs_fcw_q_7_0     0xA150
+#define        bfs_fcw_q_7_0_pos 0
+#define        bfs_fcw_q_7_0_len 8
+#define        bfs_fcw_q_7_0_lsb 0
+#define xd_r_bfs_fcw_q_15_8    0xA151
+#define        bfs_fcw_q_15_8_pos 0
+#define        bfs_fcw_q_15_8_len 8
+#define        bfs_fcw_q_15_8_lsb 8
+#define xd_r_bfs_fcw_q_22_16   0xA152
+#define        bfs_fcw_q_22_16_pos 0
+#define        bfs_fcw_q_22_16_len 7
+#define        bfs_fcw_q_22_16_lsb 16
+#define xd_p_reg_dca_enu       0xA160
+#define        reg_dca_enu_pos 0
+#define        reg_dca_enu_len 1
+#define        reg_dca_enu_lsb 0
+#define xd_p_reg_dca_enl       0xA160
+#define        reg_dca_enl_pos 1
+#define        reg_dca_enl_len 1
+#define        reg_dca_enl_lsb 0
+#define xd_p_reg_dca_lower_chip        0xA160
+#define        reg_dca_lower_chip_pos 2
+#define        reg_dca_lower_chip_len 1
+#define        reg_dca_lower_chip_lsb 0
+#define xd_p_reg_dca_upper_chip        0xA160
+#define        reg_dca_upper_chip_pos 3
+#define        reg_dca_upper_chip_len 1
+#define        reg_dca_upper_chip_lsb 0
+#define xd_p_reg_dca_platch    0xA160
+#define        reg_dca_platch_pos 4
+#define        reg_dca_platch_len 1
+#define        reg_dca_platch_lsb 0
+#define xd_p_reg_dca_th        0xA161
+#define        reg_dca_th_pos 0
+#define        reg_dca_th_len 5
+#define        reg_dca_th_lsb 0
+#define xd_p_reg_dca_scale     0xA162
+#define        reg_dca_scale_pos 0
+#define        reg_dca_scale_len 4
+#define        reg_dca_scale_lsb 0
+#define xd_p_reg_dca_tone_7_0  0xA163
+#define        reg_dca_tone_7_0_pos 0
+#define        reg_dca_tone_7_0_len 8
+#define        reg_dca_tone_7_0_lsb 0
+#define xd_p_reg_dca_tone_12_8 0xA164
+#define        reg_dca_tone_12_8_pos 0
+#define        reg_dca_tone_12_8_len 5
+#define        reg_dca_tone_12_8_lsb 8
+#define xd_p_reg_dca_time_7_0  0xA165
+#define        reg_dca_time_7_0_pos 0
+#define        reg_dca_time_7_0_len 8
+#define        reg_dca_time_7_0_lsb 0
+#define xd_p_reg_dca_time_15_8 0xA166
+#define        reg_dca_time_15_8_pos 0
+#define        reg_dca_time_15_8_len 8
+#define        reg_dca_time_15_8_lsb 8
+#define xd_r_dcasm     0xA167
+#define        dcasm_pos 0
+#define        dcasm_len 3
+#define        dcasm_lsb 0
+#define xd_p_reg_qnt_valuew_7_0        0xA168
+#define        reg_qnt_valuew_7_0_pos 0
+#define        reg_qnt_valuew_7_0_len 8
+#define        reg_qnt_valuew_7_0_lsb 0
+#define xd_p_reg_qnt_valuew_10_8       0xA169
+#define        reg_qnt_valuew_10_8_pos 0
+#define        reg_qnt_valuew_10_8_len 3
+#define        reg_qnt_valuew_10_8_lsb 8
+#define xd_p_dca_sbx_gain_diff_7_0     0xA16A
+#define        dca_sbx_gain_diff_7_0_pos 0
+#define        dca_sbx_gain_diff_7_0_len 8
+#define        dca_sbx_gain_diff_7_0_lsb 0
+#define xd_p_dca_sbx_gain_diff_9_8     0xA16B
+#define        dca_sbx_gain_diff_9_8_pos 0
+#define        dca_sbx_gain_diff_9_8_len 2
+#define        dca_sbx_gain_diff_9_8_lsb 8
+#define xd_p_reg_dca_stand_alone       0xA16C
+#define        reg_dca_stand_alone_pos 0
+#define        reg_dca_stand_alone_len 1
+#define        reg_dca_stand_alone_lsb 0
+#define xd_p_reg_dca_upper_out_en      0xA16C
+#define        reg_dca_upper_out_en_pos 1
+#define        reg_dca_upper_out_en_len 1
+#define        reg_dca_upper_out_en_lsb 0
+#define xd_p_reg_dca_rc_en     0xA16C
+#define        reg_dca_rc_en_pos 2
+#define        reg_dca_rc_en_len 1
+#define        reg_dca_rc_en_lsb 0
+#define xd_p_reg_dca_retrain_send      0xA16C
+#define        reg_dca_retrain_send_pos 3
+#define        reg_dca_retrain_send_len 1
+#define        reg_dca_retrain_send_lsb 0
+#define xd_p_reg_dca_retrain_rec       0xA16C
+#define        reg_dca_retrain_rec_pos 4
+#define        reg_dca_retrain_rec_len 1
+#define        reg_dca_retrain_rec_lsb 0
+#define xd_p_reg_dca_api_tpsrdy        0xA16C
+#define        reg_dca_api_tpsrdy_pos 5
+#define        reg_dca_api_tpsrdy_len 1
+#define        reg_dca_api_tpsrdy_lsb 0
+#define xd_p_reg_dca_symbol_gap        0xA16D
+#define        reg_dca_symbol_gap_pos 0
+#define        reg_dca_symbol_gap_len 4
+#define        reg_dca_symbol_gap_lsb 0
+#define xd_p_reg_qnt_nfvaluew_7_0      0xA16E
+#define        reg_qnt_nfvaluew_7_0_pos 0
+#define        reg_qnt_nfvaluew_7_0_len 8
+#define        reg_qnt_nfvaluew_7_0_lsb 0
+#define xd_p_reg_qnt_nfvaluew_10_8     0xA16F
+#define        reg_qnt_nfvaluew_10_8_pos 0
+#define        reg_qnt_nfvaluew_10_8_len 3
+#define        reg_qnt_nfvaluew_10_8_lsb 8
+#define xd_p_reg_qnt_flatness_thr_7_0  0xA170
+#define        reg_qnt_flatness_thr_7_0_pos 0
+#define        reg_qnt_flatness_thr_7_0_len 8
+#define        reg_qnt_flatness_thr_7_0_lsb 0
+#define xd_p_reg_qnt_flatness_thr_9_8  0xA171
+#define        reg_qnt_flatness_thr_9_8_pos 0
+#define        reg_qnt_flatness_thr_9_8_len 2
+#define        reg_qnt_flatness_thr_9_8_lsb 8
+#define xd_p_reg_dca_tone_idx_5_0      0xA171
+#define        reg_dca_tone_idx_5_0_pos 2
+#define        reg_dca_tone_idx_5_0_len 6
+#define        reg_dca_tone_idx_5_0_lsb 0
+#define xd_p_reg_dca_tone_idx_12_6     0xA172
+#define        reg_dca_tone_idx_12_6_pos 0
+#define        reg_dca_tone_idx_12_6_len 7
+#define        reg_dca_tone_idx_12_6_lsb 6
+#define xd_p_reg_dca_data_vld  0xA173
+#define        reg_dca_data_vld_pos 0
+#define        reg_dca_data_vld_len 1
+#define        reg_dca_data_vld_lsb 0
+#define xd_p_reg_dca_read_update       0xA173
+#define        reg_dca_read_update_pos 1
+#define        reg_dca_read_update_len 1
+#define        reg_dca_read_update_lsb 0
+#define xd_r_reg_dca_data_re_5_0       0xA173
+#define        reg_dca_data_re_5_0_pos 2
+#define        reg_dca_data_re_5_0_len 6
+#define        reg_dca_data_re_5_0_lsb 0
+#define xd_r_reg_dca_data_re_10_6      0xA174
+#define        reg_dca_data_re_10_6_pos 0
+#define        reg_dca_data_re_10_6_len 5
+#define        reg_dca_data_re_10_6_lsb 6
+#define xd_r_reg_dca_data_im_7_0       0xA175
+#define        reg_dca_data_im_7_0_pos 0
+#define        reg_dca_data_im_7_0_len 8
+#define        reg_dca_data_im_7_0_lsb 0
+#define xd_r_reg_dca_data_im_10_8      0xA176
+#define        reg_dca_data_im_10_8_pos 0
+#define        reg_dca_data_im_10_8_len 3
+#define        reg_dca_data_im_10_8_lsb 8
+#define xd_r_reg_dca_data_h2_7_0       0xA178
+#define        reg_dca_data_h2_7_0_pos 0
+#define        reg_dca_data_h2_7_0_len 8
+#define        reg_dca_data_h2_7_0_lsb 0
+#define xd_r_reg_dca_data_h2_9_8       0xA179
+#define        reg_dca_data_h2_9_8_pos 0
+#define        reg_dca_data_h2_9_8_len 2
+#define        reg_dca_data_h2_9_8_lsb 8
+#define xd_p_reg_f_adc_7_0     0xA180
+#define        reg_f_adc_7_0_pos 0
+#define        reg_f_adc_7_0_len 8
+#define        reg_f_adc_7_0_lsb 0
+#define xd_p_reg_f_adc_15_8    0xA181
+#define        reg_f_adc_15_8_pos 0
+#define        reg_f_adc_15_8_len 8
+#define        reg_f_adc_15_8_lsb 8
+#define xd_p_reg_f_adc_23_16   0xA182
+#define        reg_f_adc_23_16_pos 0
+#define        reg_f_adc_23_16_len 8
+#define        reg_f_adc_23_16_lsb 16
+#define xd_r_intp_mu_7_0       0xA190
+#define        intp_mu_7_0_pos 0
+#define        intp_mu_7_0_len 8
+#define        intp_mu_7_0_lsb 0
+#define xd_r_intp_mu_15_8      0xA191
+#define        intp_mu_15_8_pos 0
+#define        intp_mu_15_8_len 8
+#define        intp_mu_15_8_lsb 8
+#define xd_r_intp_mu_19_16     0xA192
+#define        intp_mu_19_16_pos 0
+#define        intp_mu_19_16_len 4
+#define        intp_mu_19_16_lsb 16
+#define xd_p_reg_agc_rst       0xA1A0
+#define        reg_agc_rst_pos 0
+#define        reg_agc_rst_len 1
+#define        reg_agc_rst_lsb 0
+#define xd_p_rf_agc_en 0xA1A0
+#define        rf_agc_en_pos 1
+#define        rf_agc_en_len 1
+#define        rf_agc_en_lsb 0
+#define xd_p_rf_agc_dis        0xA1A0
+#define        rf_agc_dis_pos 2
+#define        rf_agc_dis_len 1
+#define        rf_agc_dis_lsb 0
+#define xd_p_if_agc_rst        0xA1A0
+#define        if_agc_rst_pos 3
+#define        if_agc_rst_len 1
+#define        if_agc_rst_lsb 0
+#define xd_p_if_agc_en 0xA1A0
+#define        if_agc_en_pos 4
+#define        if_agc_en_len 1
+#define        if_agc_en_lsb 0
+#define xd_p_if_agc_dis        0xA1A0
+#define        if_agc_dis_pos 5
+#define        if_agc_dis_len 1
+#define        if_agc_dis_lsb 0
+#define xd_p_agc_lock  0xA1A0
+#define        agc_lock_pos 6
+#define        agc_lock_len 1
+#define        agc_lock_lsb 0
+#define xd_p_reg_tinr_rst      0xA1A1
+#define        reg_tinr_rst_pos 0
+#define        reg_tinr_rst_len 1
+#define        reg_tinr_rst_lsb 0
+#define xd_p_reg_tinr_en       0xA1A1
+#define        reg_tinr_en_pos 1
+#define        reg_tinr_en_len 1
+#define        reg_tinr_en_lsb 0
+#define xd_p_reg_ccifs_en      0xA1A2
+#define        reg_ccifs_en_pos 0
+#define        reg_ccifs_en_len 1
+#define        reg_ccifs_en_lsb 0
+#define xd_p_reg_ccifs_dis     0xA1A2
+#define        reg_ccifs_dis_pos 1
+#define        reg_ccifs_dis_len 1
+#define        reg_ccifs_dis_lsb 0
+#define xd_p_reg_ccifs_rst     0xA1A2
+#define        reg_ccifs_rst_pos 2
+#define        reg_ccifs_rst_len 1
+#define        reg_ccifs_rst_lsb 0
+#define xd_p_reg_ccifs_byp     0xA1A2
+#define        reg_ccifs_byp_pos 3
+#define        reg_ccifs_byp_len 1
+#define        reg_ccifs_byp_lsb 0
+#define xd_p_reg_ccif_en       0xA1A3
+#define        reg_ccif_en_pos 0
+#define        reg_ccif_en_len 1
+#define        reg_ccif_en_lsb 0
+#define xd_p_reg_ccif_dis      0xA1A3
+#define        reg_ccif_dis_pos 1
+#define        reg_ccif_dis_len 1
+#define        reg_ccif_dis_lsb 0
+#define xd_p_reg_ccif_rst      0xA1A3
+#define        reg_ccif_rst_pos 2
+#define        reg_ccif_rst_len 1
+#define        reg_ccif_rst_lsb 0
+#define xd_p_reg_ccif_byp      0xA1A3
+#define        reg_ccif_byp_pos 3
+#define        reg_ccif_byp_len 1
+#define        reg_ccif_byp_lsb 0
+#define xd_p_dagc1_rst 0xA1A4
+#define        dagc1_rst_pos 0
+#define        dagc1_rst_len 1
+#define        dagc1_rst_lsb 0
+#define xd_p_dagc1_en  0xA1A4
+#define        dagc1_en_pos 1
+#define        dagc1_en_len 1
+#define        dagc1_en_lsb 0
+#define xd_p_dagc1_mode        0xA1A4
+#define        dagc1_mode_pos 2
+#define        dagc1_mode_len 2
+#define        dagc1_mode_lsb 0
+#define xd_p_dagc1_done        0xA1A4
+#define        dagc1_done_pos 4
+#define        dagc1_done_len 1
+#define        dagc1_done_lsb 0
+#define xd_p_ccid_rst  0xA1A5
+#define        ccid_rst_pos 0
+#define        ccid_rst_len 1
+#define        ccid_rst_lsb 0
+#define xd_p_ccid_en   0xA1A5
+#define        ccid_en_pos 1
+#define        ccid_en_len 1
+#define        ccid_en_lsb 0
+#define xd_p_ccid_mode 0xA1A5
+#define        ccid_mode_pos 2
+#define        ccid_mode_len 2
+#define        ccid_mode_lsb 0
+#define xd_p_ccid_done 0xA1A5
+#define        ccid_done_pos 4
+#define        ccid_done_len 1
+#define        ccid_done_lsb 0
+#define xd_r_ccid_deted        0xA1A5
+#define        ccid_deted_pos 5
+#define        ccid_deted_len 1
+#define        ccid_deted_lsb 0
+#define xd_p_ccid2_en  0xA1A5
+#define        ccid2_en_pos 6
+#define        ccid2_en_len 1
+#define        ccid2_en_lsb 0
+#define xd_p_ccid2_done        0xA1A5
+#define        ccid2_done_pos 7
+#define        ccid2_done_len 1
+#define        ccid2_done_lsb 0
+#define xd_p_reg_bfs_en        0xA1A6
+#define        reg_bfs_en_pos 0
+#define        reg_bfs_en_len 1
+#define        reg_bfs_en_lsb 0
+#define xd_p_reg_bfs_dis       0xA1A6
+#define        reg_bfs_dis_pos 1
+#define        reg_bfs_dis_len 1
+#define        reg_bfs_dis_lsb 0
+#define xd_p_reg_bfs_rst       0xA1A6
+#define        reg_bfs_rst_pos 2
+#define        reg_bfs_rst_len 1
+#define        reg_bfs_rst_lsb 0
+#define xd_p_reg_bfs_byp       0xA1A6
+#define        reg_bfs_byp_pos 3
+#define        reg_bfs_byp_len 1
+#define        reg_bfs_byp_lsb 0
+#define xd_p_reg_antif_en      0xA1A7
+#define        reg_antif_en_pos 0
+#define        reg_antif_en_len 1
+#define        reg_antif_en_lsb 0
+#define xd_p_reg_antif_dis     0xA1A7
+#define        reg_antif_dis_pos 1
+#define        reg_antif_dis_len 1
+#define        reg_antif_dis_lsb 0
+#define xd_p_reg_antif_rst     0xA1A7
+#define        reg_antif_rst_pos 2
+#define        reg_antif_rst_len 1
+#define        reg_antif_rst_lsb 0
+#define xd_p_reg_antif_byp     0xA1A7
+#define        reg_antif_byp_pos 3
+#define        reg_antif_byp_len 1
+#define        reg_antif_byp_lsb 0
+#define xd_p_intp_en   0xA1A8
+#define        intp_en_pos 0
+#define        intp_en_len 1
+#define        intp_en_lsb 0
+#define xd_p_intp_dis  0xA1A8
+#define        intp_dis_pos 1
+#define        intp_dis_len 1
+#define        intp_dis_lsb 0
+#define xd_p_intp_rst  0xA1A8
+#define        intp_rst_pos 2
+#define        intp_rst_len 1
+#define        intp_rst_lsb 0
+#define xd_p_intp_byp  0xA1A8
+#define        intp_byp_pos 3
+#define        intp_byp_len 1
+#define        intp_byp_lsb 0
+#define xd_p_reg_acif_en       0xA1A9
+#define        reg_acif_en_pos 0
+#define        reg_acif_en_len 1
+#define        reg_acif_en_lsb 0
+#define xd_p_reg_acif_dis      0xA1A9
+#define        reg_acif_dis_pos 1
+#define        reg_acif_dis_len 1
+#define        reg_acif_dis_lsb 0
+#define xd_p_reg_acif_rst      0xA1A9
+#define        reg_acif_rst_pos 2
+#define        reg_acif_rst_len 1
+#define        reg_acif_rst_lsb 0
+#define xd_p_reg_acif_byp      0xA1A9
+#define        reg_acif_byp_pos 3
+#define        reg_acif_byp_len 1
+#define        reg_acif_byp_lsb 0
+#define xd_p_reg_acif_sync_mode        0xA1A9
+#define        reg_acif_sync_mode_pos 4
+#define        reg_acif_sync_mode_len 1
+#define        reg_acif_sync_mode_lsb 0
+#define xd_p_dagc2_rst 0xA1AA
+#define        dagc2_rst_pos 0
+#define        dagc2_rst_len 1
+#define        dagc2_rst_lsb 0
+#define xd_p_dagc2_en  0xA1AA
+#define        dagc2_en_pos 1
+#define        dagc2_en_len 1
+#define        dagc2_en_lsb 0
+#define xd_p_dagc2_mode        0xA1AA
+#define        dagc2_mode_pos 2
+#define        dagc2_mode_len 2
+#define        dagc2_mode_lsb 0
+#define xd_p_dagc2_done        0xA1AA
+#define        dagc2_done_pos 4
+#define        dagc2_done_len 1
+#define        dagc2_done_lsb 0
+#define xd_p_reg_dca_en        0xA1AB
+#define        reg_dca_en_pos 0
+#define        reg_dca_en_len 1
+#define        reg_dca_en_lsb 0
+#define xd_p_dagc2_accumulate_num_2k_7_0       0xA1C0
+#define        dagc2_accumulate_num_2k_7_0_pos 0
+#define        dagc2_accumulate_num_2k_7_0_len 8
+#define        dagc2_accumulate_num_2k_7_0_lsb 0
+#define xd_p_dagc2_accumulate_num_2k_12_8      0xA1C1
+#define        dagc2_accumulate_num_2k_12_8_pos 0
+#define        dagc2_accumulate_num_2k_12_8_len 5
+#define        dagc2_accumulate_num_2k_12_8_lsb 8
+#define xd_p_dagc2_accumulate_num_8k_7_0       0xA1C2
+#define        dagc2_accumulate_num_8k_7_0_pos 0
+#define        dagc2_accumulate_num_8k_7_0_len 8
+#define        dagc2_accumulate_num_8k_7_0_lsb 0
+#define xd_p_dagc2_accumulate_num_8k_12_8      0xA1C3
+#define        dagc2_accumulate_num_8k_12_8_pos 0
+#define        dagc2_accumulate_num_8k_12_8_len 5
+#define        dagc2_accumulate_num_8k_12_8_lsb 8
+#define xd_p_dagc2_desired_level_2_0   0xA1C3
+#define        dagc2_desired_level_2_0_pos 5
+#define        dagc2_desired_level_2_0_len 3
+#define        dagc2_desired_level_2_0_lsb 0
+#define xd_p_dagc2_desired_level_8_3   0xA1C4
+#define        dagc2_desired_level_8_3_pos 0
+#define        dagc2_desired_level_8_3_len 6
+#define        dagc2_desired_level_8_3_lsb 3
+#define xd_p_dagc2_apply_delay 0xA1C5
+#define        dagc2_apply_delay_pos 0
+#define        dagc2_apply_delay_len 7
+#define        dagc2_apply_delay_lsb 0
+#define xd_p_dagc2_bypass_scale_ctl    0xA1C6
+#define        dagc2_bypass_scale_ctl_pos 0
+#define        dagc2_bypass_scale_ctl_len 3
+#define        dagc2_bypass_scale_ctl_lsb 0
+#define xd_p_dagc2_programmable_shift1 0xA1C7
+#define        dagc2_programmable_shift1_pos 0
+#define        dagc2_programmable_shift1_len 8
+#define        dagc2_programmable_shift1_lsb 0
+#define xd_p_dagc2_programmable_shift2 0xA1C8
+#define        dagc2_programmable_shift2_pos 0
+#define        dagc2_programmable_shift2_len 8
+#define        dagc2_programmable_shift2_lsb 0
+#define xd_p_reg_dagc2_in_sat_cnt_7_0  0xA1C9
+#define        reg_dagc2_in_sat_cnt_7_0_pos 0
+#define        reg_dagc2_in_sat_cnt_7_0_len 8
+#define        reg_dagc2_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc2_in_sat_cnt_15_8 0xA1CA
+#define        reg_dagc2_in_sat_cnt_15_8_pos 0
+#define        reg_dagc2_in_sat_cnt_15_8_len 8
+#define        reg_dagc2_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc2_in_sat_cnt_23_16        0xA1CB
+#define        reg_dagc2_in_sat_cnt_23_16_pos 0
+#define        reg_dagc2_in_sat_cnt_23_16_len 8
+#define        reg_dagc2_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc2_in_sat_cnt_31_24        0xA1CC
+#define        reg_dagc2_in_sat_cnt_31_24_pos 0
+#define        reg_dagc2_in_sat_cnt_31_24_len 8
+#define        reg_dagc2_in_sat_cnt_31_24_lsb 24
+#define xd_p_reg_dagc2_out_sat_cnt_7_0 0xA1CD
+#define        reg_dagc2_out_sat_cnt_7_0_pos 0
+#define        reg_dagc2_out_sat_cnt_7_0_len 8
+#define        reg_dagc2_out_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc2_out_sat_cnt_15_8        0xA1CE
+#define        reg_dagc2_out_sat_cnt_15_8_pos 0
+#define        reg_dagc2_out_sat_cnt_15_8_len 8
+#define        reg_dagc2_out_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc2_out_sat_cnt_23_16       0xA1CF
+#define        reg_dagc2_out_sat_cnt_23_16_pos 0
+#define        reg_dagc2_out_sat_cnt_23_16_len 8
+#define        reg_dagc2_out_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc2_out_sat_cnt_31_24       0xA1D0
+#define        reg_dagc2_out_sat_cnt_31_24_pos 0
+#define        reg_dagc2_out_sat_cnt_31_24_len 8
+#define        reg_dagc2_out_sat_cnt_31_24_lsb 24
+#define xd_r_dagc2_multiplier_7_0      0xA1D6
+#define        dagc2_multiplier_7_0_pos 0
+#define        dagc2_multiplier_7_0_len 8
+#define        dagc2_multiplier_7_0_lsb 0
+#define xd_r_dagc2_multiplier_15_8     0xA1D7
+#define        dagc2_multiplier_15_8_pos 0
+#define        dagc2_multiplier_15_8_len 8
+#define        dagc2_multiplier_15_8_lsb 8
+#define xd_r_dagc2_right_shift_bits    0xA1D8
+#define        dagc2_right_shift_bits_pos 0
+#define        dagc2_right_shift_bits_len 4
+#define        dagc2_right_shift_bits_lsb 0
+#define xd_p_cfoe_NS_coeff1_7_0        0xA200
+#define        cfoe_NS_coeff1_7_0_pos 0
+#define        cfoe_NS_coeff1_7_0_len 8
+#define        cfoe_NS_coeff1_7_0_lsb 0
+#define xd_p_cfoe_NS_coeff1_15_8       0xA201
+#define        cfoe_NS_coeff1_15_8_pos 0
+#define        cfoe_NS_coeff1_15_8_len 8
+#define        cfoe_NS_coeff1_15_8_lsb 8
+#define xd_p_cfoe_NS_coeff1_23_16      0xA202
+#define        cfoe_NS_coeff1_23_16_pos 0
+#define        cfoe_NS_coeff1_23_16_len 8
+#define        cfoe_NS_coeff1_23_16_lsb 16
+#define xd_p_cfoe_NS_coeff1_25_24      0xA203
+#define        cfoe_NS_coeff1_25_24_pos 0
+#define        cfoe_NS_coeff1_25_24_len 2
+#define        cfoe_NS_coeff1_25_24_lsb 24
+#define xd_p_cfoe_NS_coeff2_5_0        0xA203
+#define        cfoe_NS_coeff2_5_0_pos 2
+#define        cfoe_NS_coeff2_5_0_len 6
+#define        cfoe_NS_coeff2_5_0_lsb 0
+#define xd_p_cfoe_NS_coeff2_13_6       0xA204
+#define        cfoe_NS_coeff2_13_6_pos 0
+#define        cfoe_NS_coeff2_13_6_len 8
+#define        cfoe_NS_coeff2_13_6_lsb 6
+#define xd_p_cfoe_NS_coeff2_21_14      0xA205
+#define        cfoe_NS_coeff2_21_14_pos 0
+#define        cfoe_NS_coeff2_21_14_len 8
+#define        cfoe_NS_coeff2_21_14_lsb 14
+#define xd_p_cfoe_NS_coeff2_24_22      0xA206
+#define        cfoe_NS_coeff2_24_22_pos 0
+#define        cfoe_NS_coeff2_24_22_len 3
+#define        cfoe_NS_coeff2_24_22_lsb 22
+#define xd_p_cfoe_lf_c1_4_0    0xA206
+#define        cfoe_lf_c1_4_0_pos 3
+#define        cfoe_lf_c1_4_0_len 5
+#define        cfoe_lf_c1_4_0_lsb 0
+#define xd_p_cfoe_lf_c1_12_5   0xA207
+#define        cfoe_lf_c1_12_5_pos 0
+#define        cfoe_lf_c1_12_5_len 8
+#define        cfoe_lf_c1_12_5_lsb 5
+#define xd_p_cfoe_lf_c1_20_13  0xA208
+#define        cfoe_lf_c1_20_13_pos 0
+#define        cfoe_lf_c1_20_13_len 8
+#define        cfoe_lf_c1_20_13_lsb 13
+#define xd_p_cfoe_lf_c1_25_21  0xA209
+#define        cfoe_lf_c1_25_21_pos 0
+#define        cfoe_lf_c1_25_21_len 5
+#define        cfoe_lf_c1_25_21_lsb 21
+#define xd_p_cfoe_lf_c2_2_0    0xA209
+#define        cfoe_lf_c2_2_0_pos 5
+#define        cfoe_lf_c2_2_0_len 3
+#define        cfoe_lf_c2_2_0_lsb 0
+#define xd_p_cfoe_lf_c2_10_3   0xA20A
+#define        cfoe_lf_c2_10_3_pos 0
+#define        cfoe_lf_c2_10_3_len 8
+#define        cfoe_lf_c2_10_3_lsb 3
+#define xd_p_cfoe_lf_c2_18_11  0xA20B
+#define        cfoe_lf_c2_18_11_pos 0
+#define        cfoe_lf_c2_18_11_len 8
+#define        cfoe_lf_c2_18_11_lsb 11
+#define xd_p_cfoe_lf_c2_25_19  0xA20C
+#define        cfoe_lf_c2_25_19_pos 0
+#define        cfoe_lf_c2_25_19_len 7
+#define        cfoe_lf_c2_25_19_lsb 19
+#define xd_p_cfoe_ifod_7_0     0xA20D
+#define        cfoe_ifod_7_0_pos 0
+#define        cfoe_ifod_7_0_len 8
+#define        cfoe_ifod_7_0_lsb 0
+#define xd_p_cfoe_ifod_10_8    0xA20E
+#define        cfoe_ifod_10_8_pos 0
+#define        cfoe_ifod_10_8_len 3
+#define        cfoe_ifod_10_8_lsb 8
+#define xd_p_cfoe_Divg_ctr_th  0xA20E
+#define        cfoe_Divg_ctr_th_pos 4
+#define        cfoe_Divg_ctr_th_len 4
+#define        cfoe_Divg_ctr_th_lsb 0
+#define xd_p_cfoe_FOT_divg_th  0xA20F
+#define        cfoe_FOT_divg_th_pos 0
+#define        cfoe_FOT_divg_th_len 8
+#define        cfoe_FOT_divg_th_lsb 0
+#define xd_p_cfoe_FOT_cnvg_th  0xA210
+#define        cfoe_FOT_cnvg_th_pos 0
+#define        cfoe_FOT_cnvg_th_len 8
+#define        cfoe_FOT_cnvg_th_lsb 0
+#define xd_p_reg_cfoe_offset_7_0       0xA211
+#define        reg_cfoe_offset_7_0_pos 0
+#define        reg_cfoe_offset_7_0_len 8
+#define        reg_cfoe_offset_7_0_lsb 0
+#define xd_p_reg_cfoe_offset_9_8       0xA212
+#define        reg_cfoe_offset_9_8_pos 0
+#define        reg_cfoe_offset_9_8_len 2
+#define        reg_cfoe_offset_9_8_lsb 8
+#define xd_p_reg_cfoe_ifoe_sign_corr   0xA212
+#define        reg_cfoe_ifoe_sign_corr_pos 2
+#define        reg_cfoe_ifoe_sign_corr_len 1
+#define        reg_cfoe_ifoe_sign_corr_lsb 0
+#define xd_r_cfoe_fot_LF_output_7_0    0xA218
+#define        cfoe_fot_LF_output_7_0_pos 0
+#define        cfoe_fot_LF_output_7_0_len 8
+#define        cfoe_fot_LF_output_7_0_lsb 0
+#define xd_r_cfoe_fot_LF_output_15_8   0xA219
+#define        cfoe_fot_LF_output_15_8_pos 0
+#define        cfoe_fot_LF_output_15_8_len 8
+#define        cfoe_fot_LF_output_15_8_lsb 8
+#define xd_r_cfoe_ifo_metric_7_0       0xA21A
+#define        cfoe_ifo_metric_7_0_pos 0
+#define        cfoe_ifo_metric_7_0_len 8
+#define        cfoe_ifo_metric_7_0_lsb 0
+#define xd_r_cfoe_ifo_metric_15_8      0xA21B
+#define        cfoe_ifo_metric_15_8_pos 0
+#define        cfoe_ifo_metric_15_8_len 8
+#define        cfoe_ifo_metric_15_8_lsb 8
+#define xd_r_cfoe_ifo_metric_23_16     0xA21C
+#define        cfoe_ifo_metric_23_16_pos 0
+#define        cfoe_ifo_metric_23_16_len 8
+#define        cfoe_ifo_metric_23_16_lsb 16
+#define xd_p_ste_Nu    0xA220
+#define        ste_Nu_pos 0
+#define        ste_Nu_len 2
+#define        ste_Nu_lsb 0
+#define xd_p_ste_GI    0xA220
+#define        ste_GI_pos 2
+#define        ste_GI_len 3
+#define        ste_GI_lsb 0
+#define xd_p_ste_symbol_num    0xA221
+#define        ste_symbol_num_pos 0
+#define        ste_symbol_num_len 2
+#define        ste_symbol_num_lsb 0
+#define xd_p_ste_sample_num    0xA221
+#define        ste_sample_num_pos 2
+#define        ste_sample_num_len 2
+#define        ste_sample_num_lsb 0
+#define xd_p_reg_ste_buf_en    0xA221
+#define        reg_ste_buf_en_pos 7
+#define        reg_ste_buf_en_len 1
+#define        reg_ste_buf_en_lsb 0
+#define xd_p_ste_FFT_offset_7_0        0xA222
+#define        ste_FFT_offset_7_0_pos 0
+#define        ste_FFT_offset_7_0_len 8
+#define        ste_FFT_offset_7_0_lsb 0
+#define xd_p_ste_FFT_offset_11_8       0xA223
+#define        ste_FFT_offset_11_8_pos 0
+#define        ste_FFT_offset_11_8_len 4
+#define        ste_FFT_offset_11_8_lsb 8
+#define xd_p_reg_ste_tstmod    0xA223
+#define        reg_ste_tstmod_pos 5
+#define        reg_ste_tstmod_len 1
+#define        reg_ste_tstmod_lsb 0
+#define xd_p_ste_adv_start_7_0 0xA224
+#define        ste_adv_start_7_0_pos 0
+#define        ste_adv_start_7_0_len 8
+#define        ste_adv_start_7_0_lsb 0
+#define xd_p_ste_adv_start_10_8        0xA225
+#define        ste_adv_start_10_8_pos 0
+#define        ste_adv_start_10_8_len 3
+#define        ste_adv_start_10_8_lsb 8
+#define xd_p_ste_adv_stop      0xA226
+#define        ste_adv_stop_pos 0
+#define        ste_adv_stop_len 8
+#define        ste_adv_stop_lsb 0
+#define xd_r_ste_P_value_7_0   0xA228
+#define        ste_P_value_7_0_pos 0
+#define        ste_P_value_7_0_len 8
+#define        ste_P_value_7_0_lsb 0
+#define xd_r_ste_P_value_10_8  0xA229
+#define        ste_P_value_10_8_pos 0
+#define        ste_P_value_10_8_len 3
+#define        ste_P_value_10_8_lsb 8
+#define xd_r_ste_M_value_7_0   0xA22A
+#define        ste_M_value_7_0_pos 0
+#define        ste_M_value_7_0_len 8
+#define        ste_M_value_7_0_lsb 0
+#define xd_r_ste_M_value_10_8  0xA22B
+#define        ste_M_value_10_8_pos 0
+#define        ste_M_value_10_8_len 3
+#define        ste_M_value_10_8_lsb 8
+#define xd_r_ste_H1    0xA22C
+#define        ste_H1_pos 0
+#define        ste_H1_len 7
+#define        ste_H1_lsb 0
+#define xd_r_ste_H2    0xA22D
+#define        ste_H2_pos 0
+#define        ste_H2_len 7
+#define        ste_H2_lsb 0
+#define xd_r_ste_H3    0xA22E
+#define        ste_H3_pos 0
+#define        ste_H3_len 7
+#define        ste_H3_lsb 0
+#define xd_r_ste_H4    0xA22F
+#define        ste_H4_pos 0
+#define        ste_H4_len 7
+#define        ste_H4_lsb 0
+#define xd_r_ste_Corr_value_I_7_0      0xA230
+#define        ste_Corr_value_I_7_0_pos 0
+#define        ste_Corr_value_I_7_0_len 8
+#define        ste_Corr_value_I_7_0_lsb 0
+#define xd_r_ste_Corr_value_I_15_8     0xA231
+#define        ste_Corr_value_I_15_8_pos 0
+#define        ste_Corr_value_I_15_8_len 8
+#define        ste_Corr_value_I_15_8_lsb 8
+#define xd_r_ste_Corr_value_I_23_16    0xA232
+#define        ste_Corr_value_I_23_16_pos 0
+#define        ste_Corr_value_I_23_16_len 8
+#define        ste_Corr_value_I_23_16_lsb 16
+#define xd_r_ste_Corr_value_I_27_24    0xA233
+#define        ste_Corr_value_I_27_24_pos 0
+#define        ste_Corr_value_I_27_24_len 4
+#define        ste_Corr_value_I_27_24_lsb 24
+#define xd_r_ste_Corr_value_Q_7_0      0xA234
+#define        ste_Corr_value_Q_7_0_pos 0
+#define        ste_Corr_value_Q_7_0_len 8
+#define        ste_Corr_value_Q_7_0_lsb 0
+#define xd_r_ste_Corr_value_Q_15_8     0xA235
+#define        ste_Corr_value_Q_15_8_pos 0
+#define        ste_Corr_value_Q_15_8_len 8
+#define        ste_Corr_value_Q_15_8_lsb 8
+#define xd_r_ste_Corr_value_Q_23_16    0xA236
+#define        ste_Corr_value_Q_23_16_pos 0
+#define        ste_Corr_value_Q_23_16_len 8
+#define        ste_Corr_value_Q_23_16_lsb 16
+#define xd_r_ste_Corr_value_Q_27_24    0xA237
+#define        ste_Corr_value_Q_27_24_pos 0
+#define        ste_Corr_value_Q_27_24_len 4
+#define        ste_Corr_value_Q_27_24_lsb 24
+#define xd_r_ste_J_num_7_0     0xA238
+#define        ste_J_num_7_0_pos 0
+#define        ste_J_num_7_0_len 8
+#define        ste_J_num_7_0_lsb 0
+#define xd_r_ste_J_num_15_8    0xA239
+#define        ste_J_num_15_8_pos 0
+#define        ste_J_num_15_8_len 8
+#define        ste_J_num_15_8_lsb 8
+#define xd_r_ste_J_num_23_16   0xA23A
+#define        ste_J_num_23_16_pos 0
+#define        ste_J_num_23_16_len 8
+#define        ste_J_num_23_16_lsb 16
+#define xd_r_ste_J_num_31_24   0xA23B
+#define        ste_J_num_31_24_pos 0
+#define        ste_J_num_31_24_len 8
+#define        ste_J_num_31_24_lsb 24
+#define xd_r_ste_J_den_7_0     0xA23C
+#define        ste_J_den_7_0_pos 0
+#define        ste_J_den_7_0_len 8
+#define        ste_J_den_7_0_lsb 0
+#define xd_r_ste_J_den_15_8    0xA23D
+#define        ste_J_den_15_8_pos 0
+#define        ste_J_den_15_8_len 8
+#define        ste_J_den_15_8_lsb 8
+#define xd_r_ste_J_den_18_16   0xA23E
+#define        ste_J_den_18_16_pos 0
+#define        ste_J_den_18_16_len 3
+#define        ste_J_den_18_16_lsb 16
+#define xd_r_ste_Beacon_Indicator      0xA23E
+#define        ste_Beacon_Indicator_pos 4
+#define        ste_Beacon_Indicator_len 1
+#define        ste_Beacon_Indicator_lsb 0
+#define xd_r_tpsd_Frame_Num    0xA250
+#define        tpsd_Frame_Num_pos 0
+#define        tpsd_Frame_Num_len 2
+#define        tpsd_Frame_Num_lsb 0
+#define xd_r_tpsd_Constel      0xA250
+#define        tpsd_Constel_pos 2
+#define        tpsd_Constel_len 2
+#define        tpsd_Constel_lsb 0
+#define xd_r_tpsd_GI   0xA250
+#define        tpsd_GI_pos 4
+#define        tpsd_GI_len 2
+#define        tpsd_GI_lsb 0
+#define xd_r_tpsd_Mode 0xA250
+#define        tpsd_Mode_pos 6
+#define        tpsd_Mode_len 2
+#define        tpsd_Mode_lsb 0
+#define xd_r_tpsd_CR_HP        0xA251
+#define        tpsd_CR_HP_pos 0
+#define        tpsd_CR_HP_len 3
+#define        tpsd_CR_HP_lsb 0
+#define xd_r_tpsd_CR_LP        0xA251
+#define        tpsd_CR_LP_pos 3
+#define        tpsd_CR_LP_len 3
+#define        tpsd_CR_LP_lsb 0
+#define xd_r_tpsd_Hie  0xA252
+#define        tpsd_Hie_pos 0
+#define        tpsd_Hie_len 3
+#define        tpsd_Hie_lsb 0
+#define xd_r_tpsd_Res_Bits     0xA252
+#define        tpsd_Res_Bits_pos 3
+#define        tpsd_Res_Bits_len 5
+#define        tpsd_Res_Bits_lsb 0
+#define xd_r_tpsd_Res_Bits_0   0xA253
+#define        tpsd_Res_Bits_0_pos 0
+#define        tpsd_Res_Bits_0_len 1
+#define        tpsd_Res_Bits_0_lsb 0
+#define xd_r_tpsd_LengthInd    0xA253
+#define        tpsd_LengthInd_pos 1
+#define        tpsd_LengthInd_len 6
+#define        tpsd_LengthInd_lsb 0
+#define xd_r_tpsd_Cell_Id_7_0  0xA254
+#define        tpsd_Cell_Id_7_0_pos 0
+#define        tpsd_Cell_Id_7_0_len 8
+#define        tpsd_Cell_Id_7_0_lsb 0
+#define xd_r_tpsd_Cell_Id_15_8 0xA255
+#define        tpsd_Cell_Id_15_8_pos 0
+#define        tpsd_Cell_Id_15_8_len 8
+#define        tpsd_Cell_Id_15_8_lsb 0
+#define xd_p_reg_fft_mask_tone0_7_0    0xA260
+#define        reg_fft_mask_tone0_7_0_pos 0
+#define        reg_fft_mask_tone0_7_0_len 8
+#define        reg_fft_mask_tone0_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone0_12_8   0xA261
+#define        reg_fft_mask_tone0_12_8_pos 0
+#define        reg_fft_mask_tone0_12_8_len 5
+#define        reg_fft_mask_tone0_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone1_7_0    0xA262
+#define        reg_fft_mask_tone1_7_0_pos 0
+#define        reg_fft_mask_tone1_7_0_len 8
+#define        reg_fft_mask_tone1_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone1_12_8   0xA263
+#define        reg_fft_mask_tone1_12_8_pos 0
+#define        reg_fft_mask_tone1_12_8_len 5
+#define        reg_fft_mask_tone1_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone2_7_0    0xA264
+#define        reg_fft_mask_tone2_7_0_pos 0
+#define        reg_fft_mask_tone2_7_0_len 8
+#define        reg_fft_mask_tone2_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone2_12_8   0xA265
+#define        reg_fft_mask_tone2_12_8_pos 0
+#define        reg_fft_mask_tone2_12_8_len 5
+#define        reg_fft_mask_tone2_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone3_7_0    0xA266
+#define        reg_fft_mask_tone3_7_0_pos 0
+#define        reg_fft_mask_tone3_7_0_len 8
+#define        reg_fft_mask_tone3_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone3_12_8   0xA267
+#define        reg_fft_mask_tone3_12_8_pos 0
+#define        reg_fft_mask_tone3_12_8_len 5
+#define        reg_fft_mask_tone3_12_8_lsb 8
+#define xd_p_reg_fft_mask_from0_7_0    0xA268
+#define        reg_fft_mask_from0_7_0_pos 0
+#define        reg_fft_mask_from0_7_0_len 8
+#define        reg_fft_mask_from0_7_0_lsb 0
+#define xd_p_reg_fft_mask_from0_12_8   0xA269
+#define        reg_fft_mask_from0_12_8_pos 0
+#define        reg_fft_mask_from0_12_8_len 5
+#define        reg_fft_mask_from0_12_8_lsb 8
+#define xd_p_reg_fft_mask_to0_7_0      0xA26A
+#define        reg_fft_mask_to0_7_0_pos 0
+#define        reg_fft_mask_to0_7_0_len 8
+#define        reg_fft_mask_to0_7_0_lsb 0
+#define xd_p_reg_fft_mask_to0_12_8     0xA26B
+#define        reg_fft_mask_to0_12_8_pos 0
+#define        reg_fft_mask_to0_12_8_len 5
+#define        reg_fft_mask_to0_12_8_lsb 8
+#define xd_p_reg_fft_mask_from1_7_0    0xA26C
+#define        reg_fft_mask_from1_7_0_pos 0
+#define        reg_fft_mask_from1_7_0_len 8
+#define        reg_fft_mask_from1_7_0_lsb 0
+#define xd_p_reg_fft_mask_from1_12_8   0xA26D
+#define        reg_fft_mask_from1_12_8_pos 0
+#define        reg_fft_mask_from1_12_8_len 5
+#define        reg_fft_mask_from1_12_8_lsb 8
+#define xd_p_reg_fft_mask_to1_7_0      0xA26E
+#define        reg_fft_mask_to1_7_0_pos 0
+#define        reg_fft_mask_to1_7_0_len 8
+#define        reg_fft_mask_to1_7_0_lsb 0
+#define xd_p_reg_fft_mask_to1_12_8     0xA26F
+#define        reg_fft_mask_to1_12_8_pos 0
+#define        reg_fft_mask_to1_12_8_len 5
+#define        reg_fft_mask_to1_12_8_lsb 8
+#define xd_p_reg_cge_idx0_7_0  0xA280
+#define        reg_cge_idx0_7_0_pos 0
+#define        reg_cge_idx0_7_0_len 8
+#define        reg_cge_idx0_7_0_lsb 0
+#define xd_p_reg_cge_idx0_12_8 0xA281
+#define        reg_cge_idx0_12_8_pos 0
+#define        reg_cge_idx0_12_8_len 5
+#define        reg_cge_idx0_12_8_lsb 8
+#define xd_p_reg_cge_idx1_7_0  0xA282
+#define        reg_cge_idx1_7_0_pos 0
+#define        reg_cge_idx1_7_0_len 8
+#define        reg_cge_idx1_7_0_lsb 0
+#define xd_p_reg_cge_idx1_12_8 0xA283
+#define        reg_cge_idx1_12_8_pos 0
+#define        reg_cge_idx1_12_8_len 5
+#define        reg_cge_idx1_12_8_lsb 8
+#define xd_p_reg_cge_idx2_7_0  0xA284
+#define        reg_cge_idx2_7_0_pos 0
+#define        reg_cge_idx2_7_0_len 8
+#define        reg_cge_idx2_7_0_lsb 0
+#define xd_p_reg_cge_idx2_12_8 0xA285
+#define        reg_cge_idx2_12_8_pos 0
+#define        reg_cge_idx2_12_8_len 5
+#define        reg_cge_idx2_12_8_lsb 8
+#define xd_p_reg_cge_idx3_7_0  0xA286
+#define        reg_cge_idx3_7_0_pos 0
+#define        reg_cge_idx3_7_0_len 8
+#define        reg_cge_idx3_7_0_lsb 0
+#define xd_p_reg_cge_idx3_12_8 0xA287
+#define        reg_cge_idx3_12_8_pos 0
+#define        reg_cge_idx3_12_8_len 5
+#define        reg_cge_idx3_12_8_lsb 8
+#define xd_p_reg_cge_idx4_7_0  0xA288
+#define        reg_cge_idx4_7_0_pos 0
+#define        reg_cge_idx4_7_0_len 8
+#define        reg_cge_idx4_7_0_lsb 0
+#define xd_p_reg_cge_idx4_12_8 0xA289
+#define        reg_cge_idx4_12_8_pos 0
+#define        reg_cge_idx4_12_8_len 5
+#define        reg_cge_idx4_12_8_lsb 8
+#define xd_p_reg_cge_idx5_7_0  0xA28A
+#define        reg_cge_idx5_7_0_pos 0
+#define        reg_cge_idx5_7_0_len 8
+#define        reg_cge_idx5_7_0_lsb 0
+#define xd_p_reg_cge_idx5_12_8 0xA28B
+#define        reg_cge_idx5_12_8_pos 0
+#define        reg_cge_idx5_12_8_len 5
+#define        reg_cge_idx5_12_8_lsb 8
+#define xd_p_reg_cge_idx6_7_0  0xA28C
+#define        reg_cge_idx6_7_0_pos 0
+#define        reg_cge_idx6_7_0_len 8
+#define        reg_cge_idx6_7_0_lsb 0
+#define xd_p_reg_cge_idx6_12_8 0xA28D
+#define        reg_cge_idx6_12_8_pos 0
+#define        reg_cge_idx6_12_8_len 5
+#define        reg_cge_idx6_12_8_lsb 8
+#define xd_p_reg_cge_idx7_7_0  0xA28E
+#define        reg_cge_idx7_7_0_pos 0
+#define        reg_cge_idx7_7_0_len 8
+#define        reg_cge_idx7_7_0_lsb 0
+#define xd_p_reg_cge_idx7_12_8 0xA28F
+#define        reg_cge_idx7_12_8_pos 0
+#define        reg_cge_idx7_12_8_len 5
+#define        reg_cge_idx7_12_8_lsb 8
+#define xd_p_reg_cge_idx8_7_0  0xA290
+#define        reg_cge_idx8_7_0_pos 0
+#define        reg_cge_idx8_7_0_len 8
+#define        reg_cge_idx8_7_0_lsb 0
+#define xd_p_reg_cge_idx8_12_8 0xA291
+#define        reg_cge_idx8_12_8_pos 0
+#define        reg_cge_idx8_12_8_len 5
+#define        reg_cge_idx8_12_8_lsb 8
+#define xd_p_reg_cge_idx9_7_0  0xA292
+#define        reg_cge_idx9_7_0_pos 0
+#define        reg_cge_idx9_7_0_len 8
+#define        reg_cge_idx9_7_0_lsb 0
+#define xd_p_reg_cge_idx9_12_8 0xA293
+#define        reg_cge_idx9_12_8_pos 0
+#define        reg_cge_idx9_12_8_len 5
+#define        reg_cge_idx9_12_8_lsb 8
+#define xd_p_reg_cge_idx10_7_0 0xA294
+#define        reg_cge_idx10_7_0_pos 0
+#define        reg_cge_idx10_7_0_len 8
+#define        reg_cge_idx10_7_0_lsb 0
+#define xd_p_reg_cge_idx10_12_8        0xA295
+#define        reg_cge_idx10_12_8_pos 0
+#define        reg_cge_idx10_12_8_len 5
+#define        reg_cge_idx10_12_8_lsb 8
+#define xd_p_reg_cge_idx11_7_0 0xA296
+#define        reg_cge_idx11_7_0_pos 0
+#define        reg_cge_idx11_7_0_len 8
+#define        reg_cge_idx11_7_0_lsb 0
+#define xd_p_reg_cge_idx11_12_8        0xA297
+#define        reg_cge_idx11_12_8_pos 0
+#define        reg_cge_idx11_12_8_len 5
+#define        reg_cge_idx11_12_8_lsb 8
+#define xd_p_reg_cge_idx12_7_0 0xA298
+#define        reg_cge_idx12_7_0_pos 0
+#define        reg_cge_idx12_7_0_len 8
+#define        reg_cge_idx12_7_0_lsb 0
+#define xd_p_reg_cge_idx12_12_8        0xA299
+#define        reg_cge_idx12_12_8_pos 0
+#define        reg_cge_idx12_12_8_len 5
+#define        reg_cge_idx12_12_8_lsb 8
+#define xd_p_reg_cge_idx13_7_0 0xA29A
+#define        reg_cge_idx13_7_0_pos 0
+#define        reg_cge_idx13_7_0_len 8
+#define        reg_cge_idx13_7_0_lsb 0
+#define xd_p_reg_cge_idx13_12_8        0xA29B
+#define        reg_cge_idx13_12_8_pos 0
+#define        reg_cge_idx13_12_8_len 5
+#define        reg_cge_idx13_12_8_lsb 8
+#define xd_p_reg_cge_idx14_7_0 0xA29C
+#define        reg_cge_idx14_7_0_pos 0
+#define        reg_cge_idx14_7_0_len 8
+#define        reg_cge_idx14_7_0_lsb 0
+#define xd_p_reg_cge_idx14_12_8        0xA29D
+#define        reg_cge_idx14_12_8_pos 0
+#define        reg_cge_idx14_12_8_len 5
+#define        reg_cge_idx14_12_8_lsb 8
+#define xd_p_reg_cge_idx15_7_0 0xA29E
+#define        reg_cge_idx15_7_0_pos 0
+#define        reg_cge_idx15_7_0_len 8
+#define        reg_cge_idx15_7_0_lsb 0
+#define xd_p_reg_cge_idx15_12_8        0xA29F
+#define        reg_cge_idx15_12_8_pos 0
+#define        reg_cge_idx15_12_8_len 5
+#define        reg_cge_idx15_12_8_lsb 8
+#define xd_r_reg_fft_crc       0xA2A8
+#define        reg_fft_crc_pos 0
+#define        reg_fft_crc_len 8
+#define        reg_fft_crc_lsb 0
+#define xd_p_fd_fft_shift_max  0xA2A9
+#define        fd_fft_shift_max_pos 0
+#define        fd_fft_shift_max_len 4
+#define        fd_fft_shift_max_lsb 0
+#define xd_r_fd_fft_shift      0xA2A9
+#define        fd_fft_shift_pos 4
+#define        fd_fft_shift_len 4
+#define        fd_fft_shift_lsb 0
+#define xd_r_fd_fft_frame_num  0xA2AA
+#define        fd_fft_frame_num_pos 0
+#define        fd_fft_frame_num_len 2
+#define        fd_fft_frame_num_lsb 0
+#define xd_r_fd_fft_symbol_count       0xA2AB
+#define        fd_fft_symbol_count_pos 0
+#define        fd_fft_symbol_count_len 7
+#define        fd_fft_symbol_count_lsb 0
+#define xd_r_reg_fft_idx_max_7_0       0xA2AC
+#define        reg_fft_idx_max_7_0_pos 0
+#define        reg_fft_idx_max_7_0_len 8
+#define        reg_fft_idx_max_7_0_lsb 0
+#define xd_r_reg_fft_idx_max_12_8      0xA2AD
+#define        reg_fft_idx_max_12_8_pos 0
+#define        reg_fft_idx_max_12_8_len 5
+#define        reg_fft_idx_max_12_8_lsb 8
+#define xd_p_reg_cge_program   0xA2AE
+#define        reg_cge_program_pos 0
+#define        reg_cge_program_len 1
+#define        reg_cge_program_lsb 0
+#define xd_p_reg_cge_fixed     0xA2AE
+#define        reg_cge_fixed_pos 1
+#define        reg_cge_fixed_len 1
+#define        reg_cge_fixed_lsb 0
+#define xd_p_reg_fft_rotate_en 0xA2AE
+#define        reg_fft_rotate_en_pos 2
+#define        reg_fft_rotate_en_len 1
+#define        reg_fft_rotate_en_lsb 0
+#define xd_p_reg_fft_rotate_base_4_0   0xA2AE
+#define        reg_fft_rotate_base_4_0_pos 3
+#define        reg_fft_rotate_base_4_0_len 5
+#define        reg_fft_rotate_base_4_0_lsb 0
+#define xd_p_reg_fft_rotate_base_12_5  0xA2AF
+#define        reg_fft_rotate_base_12_5_pos 0
+#define        reg_fft_rotate_base_12_5_len 8
+#define        reg_fft_rotate_base_12_5_lsb 5
+#define xd_p_reg_gp_trigger_fd 0xA2B8
+#define        reg_gp_trigger_fd_pos 0
+#define        reg_gp_trigger_fd_len 1
+#define        reg_gp_trigger_fd_lsb 0
+#define xd_p_reg_trigger_sel_fd        0xA2B8
+#define        reg_trigger_sel_fd_pos 1
+#define        reg_trigger_sel_fd_len 2
+#define        reg_trigger_sel_fd_lsb 0
+#define xd_p_reg_trigger_module_sel_fd 0xA2B9
+#define        reg_trigger_module_sel_fd_pos 0
+#define        reg_trigger_module_sel_fd_len 6
+#define        reg_trigger_module_sel_fd_lsb 0
+#define xd_p_reg_trigger_set_sel_fd    0xA2BA
+#define        reg_trigger_set_sel_fd_pos 0
+#define        reg_trigger_set_sel_fd_len 6
+#define        reg_trigger_set_sel_fd_lsb 0
+#define xd_p_reg_fd_noname_7_0 0xA2BC
+#define        reg_fd_noname_7_0_pos 0
+#define        reg_fd_noname_7_0_len 8
+#define        reg_fd_noname_7_0_lsb 0
+#define xd_p_reg_fd_noname_15_8        0xA2BD
+#define        reg_fd_noname_15_8_pos 0
+#define        reg_fd_noname_15_8_len 8
+#define        reg_fd_noname_15_8_lsb 8
+#define xd_p_reg_fd_noname_23_16       0xA2BE
+#define        reg_fd_noname_23_16_pos 0
+#define        reg_fd_noname_23_16_len 8
+#define        reg_fd_noname_23_16_lsb 16
+#define xd_p_reg_fd_noname_31_24       0xA2BF
+#define        reg_fd_noname_31_24_pos 0
+#define        reg_fd_noname_31_24_len 8
+#define        reg_fd_noname_31_24_lsb 24
+#define xd_r_fd_fpcc_cp_corr_signn     0xA2C0
+#define        fd_fpcc_cp_corr_signn_pos 0
+#define        fd_fpcc_cp_corr_signn_len 8
+#define        fd_fpcc_cp_corr_signn_lsb 0
+#define xd_p_reg_feq_s1        0xA2C1
+#define        reg_feq_s1_pos 0
+#define        reg_feq_s1_len 5
+#define        reg_feq_s1_lsb 0
+#define xd_p_fd_fpcc_cp_corr_tone_th   0xA2C2
+#define        fd_fpcc_cp_corr_tone_th_pos 0
+#define        fd_fpcc_cp_corr_tone_th_len 6
+#define        fd_fpcc_cp_corr_tone_th_lsb 0
+#define xd_p_fd_fpcc_cp_corr_symbol_log_th     0xA2C3
+#define        fd_fpcc_cp_corr_symbol_log_th_pos 0
+#define        fd_fpcc_cp_corr_symbol_log_th_len 4
+#define        fd_fpcc_cp_corr_symbol_log_th_lsb 0
+#define xd_p_fd_fpcc_cp_corr_int       0xA2C4
+#define        fd_fpcc_cp_corr_int_pos 0
+#define        fd_fpcc_cp_corr_int_len 1
+#define        fd_fpcc_cp_corr_int_lsb 0
+#define xd_p_reg_sfoe_ns_7_0   0xA320
+#define        reg_sfoe_ns_7_0_pos 0
+#define        reg_sfoe_ns_7_0_len 8
+#define        reg_sfoe_ns_7_0_lsb 0
+#define xd_p_reg_sfoe_ns_14_8  0xA321
+#define        reg_sfoe_ns_14_8_pos 0
+#define        reg_sfoe_ns_14_8_len 7
+#define        reg_sfoe_ns_14_8_lsb 8
+#define xd_p_reg_sfoe_c1_7_0   0xA322
+#define        reg_sfoe_c1_7_0_pos 0
+#define        reg_sfoe_c1_7_0_len 8
+#define        reg_sfoe_c1_7_0_lsb 0
+#define xd_p_reg_sfoe_c1_15_8  0xA323
+#define        reg_sfoe_c1_15_8_pos 0
+#define        reg_sfoe_c1_15_8_len 8
+#define        reg_sfoe_c1_15_8_lsb 8
+#define xd_p_reg_sfoe_c1_17_16 0xA324
+#define        reg_sfoe_c1_17_16_pos 0
+#define        reg_sfoe_c1_17_16_len 2
+#define        reg_sfoe_c1_17_16_lsb 16
+#define xd_p_reg_sfoe_c2_7_0   0xA325
+#define        reg_sfoe_c2_7_0_pos 0
+#define        reg_sfoe_c2_7_0_len 8
+#define        reg_sfoe_c2_7_0_lsb 0
+#define xd_p_reg_sfoe_c2_15_8  0xA326
+#define        reg_sfoe_c2_15_8_pos 0
+#define        reg_sfoe_c2_15_8_len 8
+#define        reg_sfoe_c2_15_8_lsb 8
+#define xd_p_reg_sfoe_c2_17_16 0xA327
+#define        reg_sfoe_c2_17_16_pos 0
+#define        reg_sfoe_c2_17_16_len 2
+#define        reg_sfoe_c2_17_16_lsb 16
+#define xd_r_reg_sfoe_out_9_2  0xA328
+#define        reg_sfoe_out_9_2_pos 0
+#define        reg_sfoe_out_9_2_len 8
+#define        reg_sfoe_out_9_2_lsb 0
+#define xd_r_reg_sfoe_out_1_0  0xA329
+#define        reg_sfoe_out_1_0_pos 0
+#define        reg_sfoe_out_1_0_len 2
+#define        reg_sfoe_out_1_0_lsb 0
+#define xd_p_reg_sfoe_lm_counter_th    0xA32A
+#define        reg_sfoe_lm_counter_th_pos 0
+#define        reg_sfoe_lm_counter_th_len 4
+#define        reg_sfoe_lm_counter_th_lsb 0
+#define xd_p_reg_sfoe_convg_th 0xA32B
+#define        reg_sfoe_convg_th_pos 0
+#define        reg_sfoe_convg_th_len 8
+#define        reg_sfoe_convg_th_lsb 0
+#define xd_p_reg_sfoe_divg_th  0xA32C
+#define        reg_sfoe_divg_th_pos 0
+#define        reg_sfoe_divg_th_len 8
+#define        reg_sfoe_divg_th_lsb 0
+#define xd_p_fd_tpsd_en        0xA330
+#define        fd_tpsd_en_pos 0
+#define        fd_tpsd_en_len 1
+#define        fd_tpsd_en_lsb 0
+#define xd_p_fd_tpsd_dis       0xA330
+#define        fd_tpsd_dis_pos 1
+#define        fd_tpsd_dis_len 1
+#define        fd_tpsd_dis_lsb 0
+#define xd_p_fd_tpsd_rst       0xA330
+#define        fd_tpsd_rst_pos 2
+#define        fd_tpsd_rst_len 1
+#define        fd_tpsd_rst_lsb 0
+#define xd_p_fd_tpsd_lock      0xA330
+#define        fd_tpsd_lock_pos 3
+#define        fd_tpsd_lock_len 1
+#define        fd_tpsd_lock_lsb 0
+#define xd_r_fd_tpsd_s19       0xA330
+#define        fd_tpsd_s19_pos 4
+#define        fd_tpsd_s19_len 1
+#define        fd_tpsd_s19_lsb 0
+#define xd_r_fd_tpsd_s17       0xA330
+#define        fd_tpsd_s17_pos 5
+#define        fd_tpsd_s17_len 1
+#define        fd_tpsd_s17_lsb 0
+#define xd_p_fd_sfr_ste_en     0xA331
+#define        fd_sfr_ste_en_pos 0
+#define        fd_sfr_ste_en_len 1
+#define        fd_sfr_ste_en_lsb 0
+#define xd_p_fd_sfr_ste_dis    0xA331
+#define        fd_sfr_ste_dis_pos 1
+#define        fd_sfr_ste_dis_len 1
+#define        fd_sfr_ste_dis_lsb 0
+#define xd_p_fd_sfr_ste_rst    0xA331
+#define        fd_sfr_ste_rst_pos 2
+#define        fd_sfr_ste_rst_len 1
+#define        fd_sfr_ste_rst_lsb 0
+#define xd_p_fd_sfr_ste_mode   0xA331
+#define        fd_sfr_ste_mode_pos 3
+#define        fd_sfr_ste_mode_len 1
+#define        fd_sfr_ste_mode_lsb 0
+#define xd_p_fd_sfr_ste_done   0xA331
+#define        fd_sfr_ste_done_pos 4
+#define        fd_sfr_ste_done_len 1
+#define        fd_sfr_ste_done_lsb 0
+#define xd_p_reg_cfoe_ffoe_en  0xA332
+#define        reg_cfoe_ffoe_en_pos 0
+#define        reg_cfoe_ffoe_en_len 1
+#define        reg_cfoe_ffoe_en_lsb 0
+#define xd_p_reg_cfoe_ffoe_dis 0xA332
+#define        reg_cfoe_ffoe_dis_pos 1
+#define        reg_cfoe_ffoe_dis_len 1
+#define        reg_cfoe_ffoe_dis_lsb 0
+#define xd_p_reg_cfoe_ffoe_rst 0xA332
+#define        reg_cfoe_ffoe_rst_pos 2
+#define        reg_cfoe_ffoe_rst_len 1
+#define        reg_cfoe_ffoe_rst_lsb 0
+#define xd_p_reg_cfoe_ifoe_en  0xA332
+#define        reg_cfoe_ifoe_en_pos 3
+#define        reg_cfoe_ifoe_en_len 1
+#define        reg_cfoe_ifoe_en_lsb 0
+#define xd_p_reg_cfoe_ifoe_dis 0xA332
+#define        reg_cfoe_ifoe_dis_pos 4
+#define        reg_cfoe_ifoe_dis_len 1
+#define        reg_cfoe_ifoe_dis_lsb 0
+#define xd_p_reg_cfoe_ifoe_rst 0xA332
+#define        reg_cfoe_ifoe_rst_pos 5
+#define        reg_cfoe_ifoe_rst_len 1
+#define        reg_cfoe_ifoe_rst_lsb 0
+#define xd_p_reg_cfoe_fot_en   0xA332
+#define        reg_cfoe_fot_en_pos 6
+#define        reg_cfoe_fot_en_len 1
+#define        reg_cfoe_fot_en_lsb 0
+#define xd_p_reg_cfoe_fot_lm_en        0xA332
+#define        reg_cfoe_fot_lm_en_pos 7
+#define        reg_cfoe_fot_lm_en_len 1
+#define        reg_cfoe_fot_lm_en_lsb 0
+#define xd_p_reg_cfoe_fot_rst  0xA333
+#define        reg_cfoe_fot_rst_pos 0
+#define        reg_cfoe_fot_rst_len 1
+#define        reg_cfoe_fot_rst_lsb 0
+#define xd_r_fd_cfoe_ffoe_done 0xA333
+#define        fd_cfoe_ffoe_done_pos 1
+#define        fd_cfoe_ffoe_done_len 1
+#define        fd_cfoe_ffoe_done_lsb 0
+#define xd_p_fd_cfoe_metric_vld        0xA333
+#define        fd_cfoe_metric_vld_pos 2
+#define        fd_cfoe_metric_vld_len 1
+#define        fd_cfoe_metric_vld_lsb 0
+#define xd_p_reg_cfoe_ifod_vld 0xA333
+#define        reg_cfoe_ifod_vld_pos 3
+#define        reg_cfoe_ifod_vld_len 1
+#define        reg_cfoe_ifod_vld_lsb 0
+#define xd_r_fd_cfoe_ifoe_done 0xA333
+#define        fd_cfoe_ifoe_done_pos 4
+#define        fd_cfoe_ifoe_done_len 1
+#define        fd_cfoe_ifoe_done_lsb 0
+#define xd_r_fd_cfoe_fot_valid 0xA333
+#define        fd_cfoe_fot_valid_pos 5
+#define        fd_cfoe_fot_valid_len 1
+#define        fd_cfoe_fot_valid_lsb 0
+#define xd_p_reg_cfoe_divg_int 0xA333
+#define        reg_cfoe_divg_int_pos 6
+#define        reg_cfoe_divg_int_len 1
+#define        reg_cfoe_divg_int_lsb 0
+#define xd_r_reg_cfoe_divg_flag        0xA333
+#define        reg_cfoe_divg_flag_pos 7
+#define        reg_cfoe_divg_flag_len 1
+#define        reg_cfoe_divg_flag_lsb 0
+#define xd_p_reg_sfoe_en       0xA334
+#define        reg_sfoe_en_pos 0
+#define        reg_sfoe_en_len 1
+#define        reg_sfoe_en_lsb 0
+#define xd_p_reg_sfoe_dis      0xA334
+#define        reg_sfoe_dis_pos 1
+#define        reg_sfoe_dis_len 1
+#define        reg_sfoe_dis_lsb 0
+#define xd_p_reg_sfoe_rst      0xA334
+#define        reg_sfoe_rst_pos 2
+#define        reg_sfoe_rst_len 1
+#define        reg_sfoe_rst_lsb 0
+#define xd_p_reg_sfoe_vld_int  0xA334
+#define        reg_sfoe_vld_int_pos 3
+#define        reg_sfoe_vld_int_len 1
+#define        reg_sfoe_vld_int_lsb 0
+#define xd_p_reg_sfoe_lm_en    0xA334
+#define        reg_sfoe_lm_en_pos 4
+#define        reg_sfoe_lm_en_len 1
+#define        reg_sfoe_lm_en_lsb 0
+#define xd_p_reg_sfoe_divg_int 0xA334
+#define        reg_sfoe_divg_int_pos 5
+#define        reg_sfoe_divg_int_len 1
+#define        reg_sfoe_divg_int_lsb 0
+#define xd_r_reg_sfoe_divg_flag        0xA334
+#define        reg_sfoe_divg_flag_pos 6
+#define        reg_sfoe_divg_flag_len 1
+#define        reg_sfoe_divg_flag_lsb 0
+#define xd_p_reg_fft_rst       0xA335
+#define        reg_fft_rst_pos 0
+#define        reg_fft_rst_len 1
+#define        reg_fft_rst_lsb 0
+#define xd_p_reg_fft_fast_beacon       0xA335
+#define        reg_fft_fast_beacon_pos 1
+#define        reg_fft_fast_beacon_len 1
+#define        reg_fft_fast_beacon_lsb 0
+#define xd_p_reg_fft_fast_valid        0xA335
+#define        reg_fft_fast_valid_pos 2
+#define        reg_fft_fast_valid_len 1
+#define        reg_fft_fast_valid_lsb 0
+#define xd_p_reg_fft_mask_en   0xA335
+#define        reg_fft_mask_en_pos 3
+#define        reg_fft_mask_en_len 1
+#define        reg_fft_mask_en_lsb 0
+#define xd_p_reg_fft_crc_en    0xA335
+#define        reg_fft_crc_en_pos 4
+#define        reg_fft_crc_en_len 1
+#define        reg_fft_crc_en_lsb 0
+#define xd_p_reg_finr_en       0xA336
+#define        reg_finr_en_pos 0
+#define        reg_finr_en_len 1
+#define        reg_finr_en_lsb 0
+#define xd_p_fd_fste_en        0xA337
+#define        fd_fste_en_pos 1
+#define        fd_fste_en_len 1
+#define        fd_fste_en_lsb 0
+#define xd_p_fd_sqi_tps_level_shift    0xA338
+#define        fd_sqi_tps_level_shift_pos 0
+#define        fd_sqi_tps_level_shift_len 8
+#define        fd_sqi_tps_level_shift_lsb 0
+#define xd_p_fd_pilot_ma_len   0xA339
+#define        fd_pilot_ma_len_pos 0
+#define        fd_pilot_ma_len_len 6
+#define        fd_pilot_ma_len_lsb 0
+#define xd_p_fd_tps_ma_len     0xA33A
+#define        fd_tps_ma_len_pos 0
+#define        fd_tps_ma_len_len 6
+#define        fd_tps_ma_len_lsb 0
+#define xd_p_fd_sqi_s3 0xA33B
+#define        fd_sqi_s3_pos 0
+#define        fd_sqi_s3_len 8
+#define        fd_sqi_s3_lsb 0
+#define xd_p_fd_sqi_dummy_reg_0        0xA33C
+#define        fd_sqi_dummy_reg_0_pos 0
+#define        fd_sqi_dummy_reg_0_len 1
+#define        fd_sqi_dummy_reg_0_lsb 0
+#define xd_p_fd_sqi_debug_sel  0xA33C
+#define        fd_sqi_debug_sel_pos 1
+#define        fd_sqi_debug_sel_len 2
+#define        fd_sqi_debug_sel_lsb 0
+#define xd_p_fd_sqi_s2 0xA33C
+#define        fd_sqi_s2_pos 3
+#define        fd_sqi_s2_len 5
+#define        fd_sqi_s2_lsb 0
+#define xd_p_fd_sqi_dummy_reg_1        0xA33D
+#define        fd_sqi_dummy_reg_1_pos 0
+#define        fd_sqi_dummy_reg_1_len 1
+#define        fd_sqi_dummy_reg_1_lsb 0
+#define xd_p_fd_inr_ignore     0xA33D
+#define        fd_inr_ignore_pos 1
+#define        fd_inr_ignore_len 1
+#define        fd_inr_ignore_lsb 0
+#define xd_p_fd_pilot_ignore   0xA33D
+#define        fd_pilot_ignore_pos 2
+#define        fd_pilot_ignore_len 1
+#define        fd_pilot_ignore_lsb 0
+#define xd_p_fd_etps_ignore    0xA33D
+#define        fd_etps_ignore_pos 3
+#define        fd_etps_ignore_len 1
+#define        fd_etps_ignore_lsb 0
+#define xd_p_fd_sqi_s1 0xA33D
+#define        fd_sqi_s1_pos 4
+#define        fd_sqi_s1_len 4
+#define        fd_sqi_s1_lsb 0
+#define xd_p_reg_fste_ehw_7_0  0xA33E
+#define        reg_fste_ehw_7_0_pos 0
+#define        reg_fste_ehw_7_0_len 8
+#define        reg_fste_ehw_7_0_lsb 0
+#define xd_p_reg_fste_ehw_9_8  0xA33F
+#define        reg_fste_ehw_9_8_pos 0
+#define        reg_fste_ehw_9_8_len 2
+#define        reg_fste_ehw_9_8_lsb 8
+#define xd_p_reg_fste_i_adj_vld        0xA33F
+#define        reg_fste_i_adj_vld_pos 2
+#define        reg_fste_i_adj_vld_len 1
+#define        reg_fste_i_adj_vld_lsb 0
+#define xd_p_reg_fste_phase_ini_7_0    0xA340
+#define        reg_fste_phase_ini_7_0_pos 0
+#define        reg_fste_phase_ini_7_0_len 8
+#define        reg_fste_phase_ini_7_0_lsb 0
+#define xd_p_reg_fste_phase_ini_11_8   0xA341
+#define        reg_fste_phase_ini_11_8_pos 0
+#define        reg_fste_phase_ini_11_8_len 4
+#define        reg_fste_phase_ini_11_8_lsb 8
+#define xd_p_reg_fste_phase_inc_3_0    0xA341
+#define        reg_fste_phase_inc_3_0_pos 4
+#define        reg_fste_phase_inc_3_0_len 4
+#define        reg_fste_phase_inc_3_0_lsb 0
+#define xd_p_reg_fste_phase_inc_11_4   0xA342
+#define        reg_fste_phase_inc_11_4_pos 0
+#define        reg_fste_phase_inc_11_4_len 8
+#define        reg_fste_phase_inc_11_4_lsb 4
+#define xd_p_reg_fste_acum_cost_cnt_max        0xA343
+#define        reg_fste_acum_cost_cnt_max_pos 0
+#define        reg_fste_acum_cost_cnt_max_len 4
+#define        reg_fste_acum_cost_cnt_max_lsb 0
+#define xd_p_reg_fste_step_size_std    0xA343
+#define        reg_fste_step_size_std_pos 4
+#define        reg_fste_step_size_std_len 4
+#define        reg_fste_step_size_std_lsb 0
+#define xd_p_reg_fste_step_size_max    0xA344
+#define        reg_fste_step_size_max_pos 0
+#define        reg_fste_step_size_max_len 4
+#define        reg_fste_step_size_max_lsb 0
+#define xd_p_reg_fste_step_size_min    0xA344
+#define        reg_fste_step_size_min_pos 4
+#define        reg_fste_step_size_min_len 4
+#define        reg_fste_step_size_min_lsb 0
+#define xd_p_reg_fste_frac_step_size_7_0       0xA345
+#define        reg_fste_frac_step_size_7_0_pos 0
+#define        reg_fste_frac_step_size_7_0_len 8
+#define        reg_fste_frac_step_size_7_0_lsb 0
+#define xd_p_reg_fste_frac_step_size_15_8      0xA346
+#define        reg_fste_frac_step_size_15_8_pos 0
+#define        reg_fste_frac_step_size_15_8_len 8
+#define        reg_fste_frac_step_size_15_8_lsb 8
+#define xd_p_reg_fste_frac_step_size_19_16     0xA347
+#define        reg_fste_frac_step_size_19_16_pos 0
+#define        reg_fste_frac_step_size_19_16_len 4
+#define        reg_fste_frac_step_size_19_16_lsb 16
+#define xd_p_reg_fste_rpd_dir_cnt_max  0xA347
+#define        reg_fste_rpd_dir_cnt_max_pos 4
+#define        reg_fste_rpd_dir_cnt_max_len 4
+#define        reg_fste_rpd_dir_cnt_max_lsb 0
+#define xd_p_reg_fste_ehs      0xA348
+#define        reg_fste_ehs_pos 0
+#define        reg_fste_ehs_len 4
+#define        reg_fste_ehs_lsb 0
+#define xd_p_reg_fste_frac_cost_cnt_max_3_0    0xA348
+#define        reg_fste_frac_cost_cnt_max_3_0_pos 4
+#define        reg_fste_frac_cost_cnt_max_3_0_len 4
+#define        reg_fste_frac_cost_cnt_max_3_0_lsb 0
+#define xd_p_reg_fste_frac_cost_cnt_max_9_4    0xA349
+#define        reg_fste_frac_cost_cnt_max_9_4_pos 0
+#define        reg_fste_frac_cost_cnt_max_9_4_len 6
+#define        reg_fste_frac_cost_cnt_max_9_4_lsb 4
+#define xd_p_reg_fste_w0_7_0   0xA34A
+#define        reg_fste_w0_7_0_pos 0
+#define        reg_fste_w0_7_0_len 8
+#define        reg_fste_w0_7_0_lsb 0
+#define xd_p_reg_fste_w0_11_8  0xA34B
+#define        reg_fste_w0_11_8_pos 0
+#define        reg_fste_w0_11_8_len 4
+#define        reg_fste_w0_11_8_lsb 8
+#define xd_p_reg_fste_w1_3_0   0xA34B
+#define        reg_fste_w1_3_0_pos 4
+#define        reg_fste_w1_3_0_len 4
+#define        reg_fste_w1_3_0_lsb 0
+#define xd_p_reg_fste_w1_11_4  0xA34C
+#define        reg_fste_w1_11_4_pos 0
+#define        reg_fste_w1_11_4_len 8
+#define        reg_fste_w1_11_4_lsb 4
+#define xd_p_reg_fste_w2_7_0   0xA34D
+#define        reg_fste_w2_7_0_pos 0
+#define        reg_fste_w2_7_0_len 8
+#define        reg_fste_w2_7_0_lsb 0
+#define xd_p_reg_fste_w2_11_8  0xA34E
+#define        reg_fste_w2_11_8_pos 0
+#define        reg_fste_w2_11_8_len 4
+#define        reg_fste_w2_11_8_lsb 8
+#define xd_p_reg_fste_w3_3_0   0xA34E
+#define        reg_fste_w3_3_0_pos 4
+#define        reg_fste_w3_3_0_len 4
+#define        reg_fste_w3_3_0_lsb 0
+#define xd_p_reg_fste_w3_11_4  0xA34F
+#define        reg_fste_w3_11_4_pos 0
+#define        reg_fste_w3_11_4_len 8
+#define        reg_fste_w3_11_4_lsb 4
+#define xd_p_reg_fste_w4_7_0   0xA350
+#define        reg_fste_w4_7_0_pos 0
+#define        reg_fste_w4_7_0_len 8
+#define        reg_fste_w4_7_0_lsb 0
+#define xd_p_reg_fste_w4_11_8  0xA351
+#define        reg_fste_w4_11_8_pos 0
+#define        reg_fste_w4_11_8_len 4
+#define        reg_fste_w4_11_8_lsb 8
+#define xd_p_reg_fste_w5_3_0   0xA351
+#define        reg_fste_w5_3_0_pos 4
+#define        reg_fste_w5_3_0_len 4
+#define        reg_fste_w5_3_0_lsb 0
+#define xd_p_reg_fste_w5_11_4  0xA352
+#define        reg_fste_w5_11_4_pos 0
+#define        reg_fste_w5_11_4_len 8
+#define        reg_fste_w5_11_4_lsb 4
+#define xd_p_reg_fste_w6_7_0   0xA353
+#define        reg_fste_w6_7_0_pos 0
+#define        reg_fste_w6_7_0_len 8
+#define        reg_fste_w6_7_0_lsb 0
+#define xd_p_reg_fste_w6_11_8  0xA354
+#define        reg_fste_w6_11_8_pos 0
+#define        reg_fste_w6_11_8_len 4
+#define        reg_fste_w6_11_8_lsb 8
+#define xd_p_reg_fste_w7_3_0   0xA354
+#define        reg_fste_w7_3_0_pos 4
+#define        reg_fste_w7_3_0_len 4
+#define        reg_fste_w7_3_0_lsb 0
+#define xd_p_reg_fste_w7_11_4  0xA355
+#define        reg_fste_w7_11_4_pos 0
+#define        reg_fste_w7_11_4_len 8
+#define        reg_fste_w7_11_4_lsb 4
+#define xd_p_reg_fste_w8_7_0   0xA356
+#define        reg_fste_w8_7_0_pos 0
+#define        reg_fste_w8_7_0_len 8
+#define        reg_fste_w8_7_0_lsb 0
+#define xd_p_reg_fste_w8_11_8  0xA357
+#define        reg_fste_w8_11_8_pos 0
+#define        reg_fste_w8_11_8_len 4
+#define        reg_fste_w8_11_8_lsb 8
+#define xd_p_reg_fste_w9_3_0   0xA357
+#define        reg_fste_w9_3_0_pos 4
+#define        reg_fste_w9_3_0_len 4
+#define        reg_fste_w9_3_0_lsb 0
+#define xd_p_reg_fste_w9_11_4  0xA358
+#define        reg_fste_w9_11_4_pos 0
+#define        reg_fste_w9_11_4_len 8
+#define        reg_fste_w9_11_4_lsb 4
+#define xd_p_reg_fste_wa_7_0   0xA359
+#define        reg_fste_wa_7_0_pos 0
+#define        reg_fste_wa_7_0_len 8
+#define        reg_fste_wa_7_0_lsb 0
+#define xd_p_reg_fste_wa_11_8  0xA35A
+#define        reg_fste_wa_11_8_pos 0
+#define        reg_fste_wa_11_8_len 4
+#define        reg_fste_wa_11_8_lsb 8
+#define xd_p_reg_fste_wb_3_0   0xA35A
+#define        reg_fste_wb_3_0_pos 4
+#define        reg_fste_wb_3_0_len 4
+#define        reg_fste_wb_3_0_lsb 0
+#define xd_p_reg_fste_wb_11_4  0xA35B
+#define        reg_fste_wb_11_4_pos 0
+#define        reg_fste_wb_11_4_len 8
+#define        reg_fste_wb_11_4_lsb 4
+#define xd_r_fd_fste_i_adj     0xA35C
+#define        fd_fste_i_adj_pos 0
+#define        fd_fste_i_adj_len 5
+#define        fd_fste_i_adj_lsb 0
+#define xd_r_fd_fste_f_adj_7_0 0xA35D
+#define        fd_fste_f_adj_7_0_pos 0
+#define        fd_fste_f_adj_7_0_len 8
+#define        fd_fste_f_adj_7_0_lsb 0
+#define xd_r_fd_fste_f_adj_15_8        0xA35E
+#define        fd_fste_f_adj_15_8_pos 0
+#define        fd_fste_f_adj_15_8_len 8
+#define        fd_fste_f_adj_15_8_lsb 8
+#define xd_r_fd_fste_f_adj_19_16       0xA35F
+#define        fd_fste_f_adj_19_16_pos 0
+#define        fd_fste_f_adj_19_16_len 4
+#define        fd_fste_f_adj_19_16_lsb 16
+#define xd_p_reg_feq_Leak_Bypass       0xA366
+#define        reg_feq_Leak_Bypass_pos 0
+#define        reg_feq_Leak_Bypass_len 1
+#define        reg_feq_Leak_Bypass_lsb 0
+#define xd_p_reg_feq_Leak_Mneg1        0xA366
+#define        reg_feq_Leak_Mneg1_pos 1
+#define        reg_feq_Leak_Mneg1_len 3
+#define        reg_feq_Leak_Mneg1_lsb 0
+#define xd_p_reg_feq_Leak_B_ShiftQ     0xA366
+#define        reg_feq_Leak_B_ShiftQ_pos 4
+#define        reg_feq_Leak_B_ShiftQ_len 4
+#define        reg_feq_Leak_B_ShiftQ_lsb 0
+#define xd_p_reg_feq_Leak_B_Float0     0xA367
+#define        reg_feq_Leak_B_Float0_pos 0
+#define        reg_feq_Leak_B_Float0_len 8
+#define        reg_feq_Leak_B_Float0_lsb 0
+#define xd_p_reg_feq_Leak_B_Float1     0xA368
+#define        reg_feq_Leak_B_Float1_pos 0
+#define        reg_feq_Leak_B_Float1_len 8
+#define        reg_feq_Leak_B_Float1_lsb 0
+#define xd_p_reg_feq_Leak_B_Float2     0xA369
+#define        reg_feq_Leak_B_Float2_pos 0
+#define        reg_feq_Leak_B_Float2_len 8
+#define        reg_feq_Leak_B_Float2_lsb 0
+#define xd_p_reg_feq_Leak_B_Float3     0xA36A
+#define        reg_feq_Leak_B_Float3_pos 0
+#define        reg_feq_Leak_B_Float3_len 8
+#define        reg_feq_Leak_B_Float3_lsb 0
+#define xd_p_reg_feq_Leak_B_Float4     0xA36B
+#define        reg_feq_Leak_B_Float4_pos 0
+#define        reg_feq_Leak_B_Float4_len 8
+#define        reg_feq_Leak_B_Float4_lsb 0
+#define xd_p_reg_feq_Leak_B_Float5     0xA36C
+#define        reg_feq_Leak_B_Float5_pos 0
+#define        reg_feq_Leak_B_Float5_len 8
+#define        reg_feq_Leak_B_Float5_lsb 0
+#define xd_p_reg_feq_Leak_B_Float6     0xA36D
+#define        reg_feq_Leak_B_Float6_pos 0
+#define        reg_feq_Leak_B_Float6_len 8
+#define        reg_feq_Leak_B_Float6_lsb 0
+#define xd_p_reg_feq_Leak_B_Float7     0xA36E
+#define        reg_feq_Leak_B_Float7_pos 0
+#define        reg_feq_Leak_B_Float7_len 8
+#define        reg_feq_Leak_B_Float7_lsb 0
+#define xd_r_reg_feq_data_h2_7_0       0xA36F
+#define        reg_feq_data_h2_7_0_pos 0
+#define        reg_feq_data_h2_7_0_len 8
+#define        reg_feq_data_h2_7_0_lsb 0
+#define xd_r_reg_feq_data_h2_9_8       0xA370
+#define        reg_feq_data_h2_9_8_pos 0
+#define        reg_feq_data_h2_9_8_len 2
+#define        reg_feq_data_h2_9_8_lsb 8
+#define xd_p_reg_feq_leak_use_slice_tps        0xA371
+#define        reg_feq_leak_use_slice_tps_pos 0
+#define        reg_feq_leak_use_slice_tps_len 1
+#define        reg_feq_leak_use_slice_tps_lsb 0
+#define xd_p_reg_feq_read_update       0xA371
+#define        reg_feq_read_update_pos 1
+#define        reg_feq_read_update_len 1
+#define        reg_feq_read_update_lsb 0
+#define xd_p_reg_feq_data_vld  0xA371
+#define        reg_feq_data_vld_pos 2
+#define        reg_feq_data_vld_len 1
+#define        reg_feq_data_vld_lsb 0
+#define xd_p_reg_feq_tone_idx_4_0      0xA371
+#define        reg_feq_tone_idx_4_0_pos 3
+#define        reg_feq_tone_idx_4_0_len 5
+#define        reg_feq_tone_idx_4_0_lsb 0
+#define xd_p_reg_feq_tone_idx_12_5     0xA372
+#define        reg_feq_tone_idx_12_5_pos 0
+#define        reg_feq_tone_idx_12_5_len 8
+#define        reg_feq_tone_idx_12_5_lsb 5
+#define xd_r_reg_feq_data_re_7_0       0xA373
+#define        reg_feq_data_re_7_0_pos 0
+#define        reg_feq_data_re_7_0_len 8
+#define        reg_feq_data_re_7_0_lsb 0
+#define xd_r_reg_feq_data_re_10_8      0xA374
+#define        reg_feq_data_re_10_8_pos 0
+#define        reg_feq_data_re_10_8_len 3
+#define        reg_feq_data_re_10_8_lsb 8
+#define xd_r_reg_feq_data_im_7_0       0xA375
+#define        reg_feq_data_im_7_0_pos 0
+#define        reg_feq_data_im_7_0_len 8
+#define        reg_feq_data_im_7_0_lsb 0
+#define xd_r_reg_feq_data_im_10_8      0xA376
+#define        reg_feq_data_im_10_8_pos 0
+#define        reg_feq_data_im_10_8_len 3
+#define        reg_feq_data_im_10_8_lsb 8
+#define xd_r_reg_feq_y_re      0xA377
+#define        reg_feq_y_re_pos 0
+#define        reg_feq_y_re_len 8
+#define        reg_feq_y_re_lsb 0
+#define xd_r_reg_feq_y_im      0xA378
+#define        reg_feq_y_im_pos 0
+#define        reg_feq_y_im_len 8
+#define        reg_feq_y_im_lsb 0
+#define xd_r_reg_feq_h_re_7_0  0xA379
+#define        reg_feq_h_re_7_0_pos 0
+#define        reg_feq_h_re_7_0_len 8
+#define        reg_feq_h_re_7_0_lsb 0
+#define xd_r_reg_feq_h_re_8    0xA37A
+#define        reg_feq_h_re_8_pos 0
+#define        reg_feq_h_re_8_len 1
+#define        reg_feq_h_re_8_lsb 0
+#define xd_r_reg_feq_h_im_7_0  0xA37B
+#define        reg_feq_h_im_7_0_pos 0
+#define        reg_feq_h_im_7_0_len 8
+#define        reg_feq_h_im_7_0_lsb 0
+#define xd_r_reg_feq_h_im_8    0xA37C
+#define        reg_feq_h_im_8_pos 0
+#define        reg_feq_h_im_8_len 1
+#define        reg_feq_h_im_8_lsb 0
+#define xd_p_fec_super_frm_unit_7_0    0xA380
+#define        fec_super_frm_unit_7_0_pos 0
+#define        fec_super_frm_unit_7_0_len 8
+#define        fec_super_frm_unit_7_0_lsb 0
+#define xd_p_fec_super_frm_unit_15_8   0xA381
+#define        fec_super_frm_unit_15_8_pos 0
+#define        fec_super_frm_unit_15_8_len 8
+#define        fec_super_frm_unit_15_8_lsb 8
+#define xd_r_fec_vtb_err_bit_cnt_7_0   0xA382
+#define        fec_vtb_err_bit_cnt_7_0_pos 0
+#define        fec_vtb_err_bit_cnt_7_0_len 8
+#define        fec_vtb_err_bit_cnt_7_0_lsb 0
+#define xd_r_fec_vtb_err_bit_cnt_15_8  0xA383
+#define        fec_vtb_err_bit_cnt_15_8_pos 0
+#define        fec_vtb_err_bit_cnt_15_8_len 8
+#define        fec_vtb_err_bit_cnt_15_8_lsb 8
+#define xd_r_fec_vtb_err_bit_cnt_23_16 0xA384
+#define        fec_vtb_err_bit_cnt_23_16_pos 0
+#define        fec_vtb_err_bit_cnt_23_16_len 8
+#define        fec_vtb_err_bit_cnt_23_16_lsb 16
+#define xd_p_fec_rsd_packet_unit_7_0   0xA385
+#define        fec_rsd_packet_unit_7_0_pos 0
+#define        fec_rsd_packet_unit_7_0_len 8
+#define        fec_rsd_packet_unit_7_0_lsb 0
+#define xd_p_fec_rsd_packet_unit_15_8  0xA386
+#define        fec_rsd_packet_unit_15_8_pos 0
+#define        fec_rsd_packet_unit_15_8_len 8
+#define        fec_rsd_packet_unit_15_8_lsb 8
+#define xd_r_fec_rsd_bit_err_cnt_7_0   0xA387
+#define        fec_rsd_bit_err_cnt_7_0_pos 0
+#define        fec_rsd_bit_err_cnt_7_0_len 8
+#define        fec_rsd_bit_err_cnt_7_0_lsb 0
+#define xd_r_fec_rsd_bit_err_cnt_15_8  0xA388
+#define        fec_rsd_bit_err_cnt_15_8_pos 0
+#define        fec_rsd_bit_err_cnt_15_8_len 8
+#define        fec_rsd_bit_err_cnt_15_8_lsb 8
+#define xd_r_fec_rsd_bit_err_cnt_23_16 0xA389
+#define        fec_rsd_bit_err_cnt_23_16_pos 0
+#define        fec_rsd_bit_err_cnt_23_16_len 8
+#define        fec_rsd_bit_err_cnt_23_16_lsb 16
+#define xd_r_fec_rsd_abort_packet_cnt_7_0      0xA38A
+#define        fec_rsd_abort_packet_cnt_7_0_pos 0
+#define        fec_rsd_abort_packet_cnt_7_0_len 8
+#define        fec_rsd_abort_packet_cnt_7_0_lsb 0
+#define xd_r_fec_rsd_abort_packet_cnt_15_8     0xA38B
+#define        fec_rsd_abort_packet_cnt_15_8_pos 0
+#define        fec_rsd_abort_packet_cnt_15_8_len 8
+#define        fec_rsd_abort_packet_cnt_15_8_lsb 8
+#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_7_0      0xA38C
+#define        fec_RSD_PKT_NUM_PER_UNIT_7_0_pos 0
+#define        fec_RSD_PKT_NUM_PER_UNIT_7_0_len 8
+#define        fec_RSD_PKT_NUM_PER_UNIT_7_0_lsb 0
+#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_15_8     0xA38D
+#define        fec_RSD_PKT_NUM_PER_UNIT_15_8_pos 0
+#define        fec_RSD_PKT_NUM_PER_UNIT_15_8_len 8
+#define        fec_RSD_PKT_NUM_PER_UNIT_15_8_lsb 8
+#define xd_p_fec_RS_TH_1_7_0   0xA38E
+#define        fec_RS_TH_1_7_0_pos 0
+#define        fec_RS_TH_1_7_0_len 8
+#define        fec_RS_TH_1_7_0_lsb 0
+#define xd_p_fec_RS_TH_1_15_8  0xA38F
+#define        fec_RS_TH_1_15_8_pos 0
+#define        fec_RS_TH_1_15_8_len 8
+#define        fec_RS_TH_1_15_8_lsb 8
+#define xd_p_fec_RS_TH_2       0xA390
+#define        fec_RS_TH_2_pos 0
+#define        fec_RS_TH_2_len 8
+#define        fec_RS_TH_2_lsb 0
+#define xd_p_fec_mon_en        0xA391
+#define        fec_mon_en_pos 0
+#define        fec_mon_en_len 1
+#define        fec_mon_en_lsb 0
+#define xd_p_reg_b8to47        0xA391
+#define        reg_b8to47_pos 1
+#define        reg_b8to47_len 1
+#define        reg_b8to47_lsb 0
+#define xd_p_reg_rsd_sync_rep  0xA391
+#define        reg_rsd_sync_rep_pos 2
+#define        reg_rsd_sync_rep_len 1
+#define        reg_rsd_sync_rep_lsb 0
+#define xd_p_fec_rsd_retrain_rst       0xA391
+#define        fec_rsd_retrain_rst_pos 3
+#define        fec_rsd_retrain_rst_len 1
+#define        fec_rsd_retrain_rst_lsb 0
+#define xd_r_fec_rsd_ber_rdy   0xA391
+#define        fec_rsd_ber_rdy_pos 4
+#define        fec_rsd_ber_rdy_len 1
+#define        fec_rsd_ber_rdy_lsb 0
+#define xd_p_fec_rsd_ber_rst   0xA391
+#define        fec_rsd_ber_rst_pos 5
+#define        fec_rsd_ber_rst_len 1
+#define        fec_rsd_ber_rst_lsb 0
+#define xd_r_fec_vtb_ber_rdy   0xA391
+#define        fec_vtb_ber_rdy_pos 6
+#define        fec_vtb_ber_rdy_len 1
+#define        fec_vtb_ber_rdy_lsb 0
+#define xd_p_fec_vtb_ber_rst   0xA391
+#define        fec_vtb_ber_rst_pos 7
+#define        fec_vtb_ber_rst_len 1
+#define        fec_vtb_ber_rst_lsb 0
+#define xd_p_reg_vtb_clk40en   0xA392
+#define        reg_vtb_clk40en_pos 0
+#define        reg_vtb_clk40en_len 1
+#define        reg_vtb_clk40en_lsb 0
+#define xd_p_fec_vtb_rsd_mon_en        0xA392
+#define        fec_vtb_rsd_mon_en_pos 1
+#define        fec_vtb_rsd_mon_en_len 1
+#define        fec_vtb_rsd_mon_en_lsb 0
+#define xd_p_reg_fec_data_en   0xA392
+#define        reg_fec_data_en_pos 2
+#define        reg_fec_data_en_len 1
+#define        reg_fec_data_en_lsb 0
+#define xd_p_fec_dummy_reg_2   0xA392
+#define        fec_dummy_reg_2_pos 3
+#define        fec_dummy_reg_2_len 3
+#define        fec_dummy_reg_2_lsb 0
+#define xd_p_reg_sync_chk      0xA392
+#define        reg_sync_chk_pos 6
+#define        reg_sync_chk_len 1
+#define        reg_sync_chk_lsb 0
+#define xd_p_fec_rsd_bypass    0xA392
+#define        fec_rsd_bypass_pos 7
+#define        fec_rsd_bypass_len 1
+#define        fec_rsd_bypass_lsb 0
+#define xd_p_fec_sw_rst        0xA393
+#define        fec_sw_rst_pos 0
+#define        fec_sw_rst_len 1
+#define        fec_sw_rst_lsb 0
+#define xd_r_fec_vtb_pm_crc    0xA394
+#define        fec_vtb_pm_crc_pos 0
+#define        fec_vtb_pm_crc_len 8
+#define        fec_vtb_pm_crc_lsb 0
+#define xd_r_fec_vtb_tb_7_crc  0xA395
+#define        fec_vtb_tb_7_crc_pos 0
+#define        fec_vtb_tb_7_crc_len 8
+#define        fec_vtb_tb_7_crc_lsb 0
+#define xd_r_fec_vtb_tb_6_crc  0xA396
+#define        fec_vtb_tb_6_crc_pos 0
+#define        fec_vtb_tb_6_crc_len 8
+#define        fec_vtb_tb_6_crc_lsb 0
+#define xd_r_fec_vtb_tb_5_crc  0xA397
+#define        fec_vtb_tb_5_crc_pos 0
+#define        fec_vtb_tb_5_crc_len 8
+#define        fec_vtb_tb_5_crc_lsb 0
+#define xd_r_fec_vtb_tb_4_crc  0xA398
+#define        fec_vtb_tb_4_crc_pos 0
+#define        fec_vtb_tb_4_crc_len 8
+#define        fec_vtb_tb_4_crc_lsb 0
+#define xd_r_fec_vtb_tb_3_crc  0xA399
+#define        fec_vtb_tb_3_crc_pos 0
+#define        fec_vtb_tb_3_crc_len 8
+#define        fec_vtb_tb_3_crc_lsb 0
+#define xd_r_fec_vtb_tb_2_crc  0xA39A
+#define        fec_vtb_tb_2_crc_pos 0
+#define        fec_vtb_tb_2_crc_len 8
+#define        fec_vtb_tb_2_crc_lsb 0
+#define xd_r_fec_vtb_tb_1_crc  0xA39B
+#define        fec_vtb_tb_1_crc_pos 0
+#define        fec_vtb_tb_1_crc_len 8
+#define        fec_vtb_tb_1_crc_lsb 0
+#define xd_r_fec_vtb_tb_0_crc  0xA39C
+#define        fec_vtb_tb_0_crc_pos 0
+#define        fec_vtb_tb_0_crc_len 8
+#define        fec_vtb_tb_0_crc_lsb 0
+#define xd_r_fec_rsd_bank0_crc 0xA39D
+#define        fec_rsd_bank0_crc_pos 0
+#define        fec_rsd_bank0_crc_len 8
+#define        fec_rsd_bank0_crc_lsb 0
+#define xd_r_fec_rsd_bank1_crc 0xA39E
+#define        fec_rsd_bank1_crc_pos 0
+#define        fec_rsd_bank1_crc_len 8
+#define        fec_rsd_bank1_crc_lsb 0
+#define xd_r_fec_idi_vtb_crc   0xA39F
+#define        fec_idi_vtb_crc_pos 0
+#define        fec_idi_vtb_crc_len 8
+#define        fec_idi_vtb_crc_lsb 0
+#define xd_g_reg_tpsd_txmod    0xA3C0
+#define        reg_tpsd_txmod_pos 0
+#define        reg_tpsd_txmod_len 2
+#define        reg_tpsd_txmod_lsb 0
+#define xd_g_reg_tpsd_gi       0xA3C0
+#define        reg_tpsd_gi_pos 2
+#define        reg_tpsd_gi_len 2
+#define        reg_tpsd_gi_lsb 0
+#define xd_g_reg_tpsd_hier     0xA3C0
+#define        reg_tpsd_hier_pos 4
+#define        reg_tpsd_hier_len 3
+#define        reg_tpsd_hier_lsb 0
+#define xd_g_reg_bw    0xA3C1
+#define        reg_bw_pos 2
+#define        reg_bw_len 2
+#define        reg_bw_lsb 0
+#define xd_g_reg_dec_pri       0xA3C1
+#define        reg_dec_pri_pos 4
+#define        reg_dec_pri_len 1
+#define        reg_dec_pri_lsb 0
+#define xd_g_reg_tpsd_const    0xA3C1
+#define        reg_tpsd_const_pos 6
+#define        reg_tpsd_const_len 2
+#define        reg_tpsd_const_lsb 0
+#define xd_g_reg_tpsd_hpcr     0xA3C2
+#define        reg_tpsd_hpcr_pos 0
+#define        reg_tpsd_hpcr_len 3
+#define        reg_tpsd_hpcr_lsb 0
+#define xd_g_reg_tpsd_lpcr     0xA3C2
+#define        reg_tpsd_lpcr_pos 3
+#define        reg_tpsd_lpcr_len 3
+#define        reg_tpsd_lpcr_lsb 0
+#define xd_g_reg_ofsm_clk      0xA3D0
+#define        reg_ofsm_clk_pos 0
+#define        reg_ofsm_clk_len 3
+#define        reg_ofsm_clk_lsb 0
+#define xd_g_reg_fclk_cfg      0xA3D1
+#define        reg_fclk_cfg_pos 0
+#define        reg_fclk_cfg_len 1
+#define        reg_fclk_cfg_lsb 0
+#define xd_g_reg_fclk_idi      0xA3D1
+#define        reg_fclk_idi_pos 1
+#define        reg_fclk_idi_len 1
+#define        reg_fclk_idi_lsb 0
+#define xd_g_reg_fclk_odi      0xA3D1
+#define        reg_fclk_odi_pos 2
+#define        reg_fclk_odi_len 1
+#define        reg_fclk_odi_lsb 0
+#define xd_g_reg_fclk_rsd      0xA3D1
+#define        reg_fclk_rsd_pos 3
+#define        reg_fclk_rsd_len 1
+#define        reg_fclk_rsd_lsb 0
+#define xd_g_reg_fclk_vtb      0xA3D1
+#define        reg_fclk_vtb_pos 4
+#define        reg_fclk_vtb_len 1
+#define        reg_fclk_vtb_lsb 0
+#define xd_g_reg_fclk_cste     0xA3D1
+#define        reg_fclk_cste_pos 5
+#define        reg_fclk_cste_len 1
+#define        reg_fclk_cste_lsb 0
+#define xd_g_reg_fclk_mp2if    0xA3D1
+#define        reg_fclk_mp2if_pos 6
+#define        reg_fclk_mp2if_len 1
+#define        reg_fclk_mp2if_lsb 0
+#define xd_I2C_i2c_m_slave_addr        0xA400
+#define        i2c_m_slave_addr_pos 0
+#define        i2c_m_slave_addr_len 8
+#define        i2c_m_slave_addr_lsb 0
+#define xd_I2C_i2c_m_data1     0xA401
+#define        i2c_m_data1_pos 0
+#define        i2c_m_data1_len 8
+#define        i2c_m_data1_lsb 0
+#define xd_I2C_i2c_m_data2     0xA402
+#define        i2c_m_data2_pos 0
+#define        i2c_m_data2_len 8
+#define        i2c_m_data2_lsb 0
+#define xd_I2C_i2c_m_data3     0xA403
+#define        i2c_m_data3_pos 0
+#define        i2c_m_data3_len 8
+#define        i2c_m_data3_lsb 0
+#define xd_I2C_i2c_m_data4     0xA404
+#define        i2c_m_data4_pos 0
+#define        i2c_m_data4_len 8
+#define        i2c_m_data4_lsb 0
+#define xd_I2C_i2c_m_data5     0xA405
+#define        i2c_m_data5_pos 0
+#define        i2c_m_data5_len 8
+#define        i2c_m_data5_lsb 0
+#define xd_I2C_i2c_m_data6     0xA406
+#define        i2c_m_data6_pos 0
+#define        i2c_m_data6_len 8
+#define        i2c_m_data6_lsb 0
+#define xd_I2C_i2c_m_data7     0xA407
+#define        i2c_m_data7_pos 0
+#define        i2c_m_data7_len 8
+#define        i2c_m_data7_lsb 0
+#define xd_I2C_i2c_m_data8     0xA408
+#define        i2c_m_data8_pos 0
+#define        i2c_m_data8_len 8
+#define        i2c_m_data8_lsb 0
+#define xd_I2C_i2c_m_data9     0xA409
+#define        i2c_m_data9_pos 0
+#define        i2c_m_data9_len 8
+#define        i2c_m_data9_lsb 0
+#define xd_I2C_i2c_m_data10    0xA40A
+#define        i2c_m_data10_pos 0
+#define        i2c_m_data10_len 8
+#define        i2c_m_data10_lsb 0
+#define xd_I2C_i2c_m_data11    0xA40B
+#define        i2c_m_data11_pos 0
+#define        i2c_m_data11_len 8
+#define        i2c_m_data11_lsb 0
+#define xd_I2C_i2c_m_cmd_rw    0xA40C
+#define        i2c_m_cmd_rw_pos 0
+#define        i2c_m_cmd_rw_len 1
+#define        i2c_m_cmd_rw_lsb 0
+#define xd_I2C_i2c_m_cmd_rwlen 0xA40C
+#define        i2c_m_cmd_rwlen_pos 3
+#define        i2c_m_cmd_rwlen_len 4
+#define        i2c_m_cmd_rwlen_lsb 0
+#define xd_I2C_i2c_m_status_cmd_exe    0xA40D
+#define        i2c_m_status_cmd_exe_pos 0
+#define        i2c_m_status_cmd_exe_len 1
+#define        i2c_m_status_cmd_exe_lsb 0
+#define xd_I2C_i2c_m_status_wdat_done  0xA40D
+#define        i2c_m_status_wdat_done_pos 1
+#define        i2c_m_status_wdat_done_len 1
+#define        i2c_m_status_wdat_done_lsb 0
+#define xd_I2C_i2c_m_status_wdat_fail  0xA40D
+#define        i2c_m_status_wdat_fail_pos 2
+#define        i2c_m_status_wdat_fail_len 1
+#define        i2c_m_status_wdat_fail_lsb 0
+#define xd_I2C_i2c_m_period    0xA40E
+#define        i2c_m_period_pos 0
+#define        i2c_m_period_len 8
+#define        i2c_m_period_lsb 0
+#define xd_I2C_i2c_m_reg_msb_lsb       0xA40F
+#define        i2c_m_reg_msb_lsb_pos 0
+#define        i2c_m_reg_msb_lsb_len 1
+#define        i2c_m_reg_msb_lsb_lsb 0
+#define xd_I2C_reg_ofdm_rst    0xA40F
+#define        reg_ofdm_rst_pos 1
+#define        reg_ofdm_rst_len 1
+#define        reg_ofdm_rst_lsb 0
+#define xd_I2C_reg_sample_period_on_tuner      0xA40F
+#define        reg_sample_period_on_tuner_pos 2
+#define        reg_sample_period_on_tuner_len 1
+#define        reg_sample_period_on_tuner_lsb 0
+#define xd_I2C_reg_rst_i2c     0xA40F
+#define        reg_rst_i2c_pos 3
+#define        reg_rst_i2c_len 1
+#define        reg_rst_i2c_lsb 0
+#define xd_I2C_reg_ofdm_rst_en 0xA40F
+#define        reg_ofdm_rst_en_pos 4
+#define        reg_ofdm_rst_en_len 1
+#define        reg_ofdm_rst_en_lsb 0
+#define xd_I2C_reg_tuner_sda_sync_on   0xA40F
+#define        reg_tuner_sda_sync_on_pos 5
+#define        reg_tuner_sda_sync_on_len 1
+#define        reg_tuner_sda_sync_on_lsb 0
+#define xd_p_mp2if_data_access_disable_ofsm    0xA500
+#define        mp2if_data_access_disable_ofsm_pos 0
+#define        mp2if_data_access_disable_ofsm_len 1
+#define        mp2if_data_access_disable_ofsm_lsb 0
+#define xd_p_reg_mp2_sw_rst_ofsm       0xA500
+#define        reg_mp2_sw_rst_ofsm_pos 1
+#define        reg_mp2_sw_rst_ofsm_len 1
+#define        reg_mp2_sw_rst_ofsm_lsb 0
+#define xd_p_reg_mp2if_clk_en_ofsm     0xA500
+#define        reg_mp2if_clk_en_ofsm_pos 2
+#define        reg_mp2if_clk_en_ofsm_len 1
+#define        reg_mp2if_clk_en_ofsm_lsb 0
+#define xd_r_mp2if_sync_byte_locked    0xA500
+#define        mp2if_sync_byte_locked_pos 3
+#define        mp2if_sync_byte_locked_len 1
+#define        mp2if_sync_byte_locked_lsb 0
+#define xd_r_mp2if_ts_not_188  0xA500
+#define        mp2if_ts_not_188_pos 4
+#define        mp2if_ts_not_188_len 1
+#define        mp2if_ts_not_188_lsb 0
+#define xd_r_mp2if_psb_empty   0xA500
+#define        mp2if_psb_empty_pos 5
+#define        mp2if_psb_empty_len 1
+#define        mp2if_psb_empty_lsb 0
+#define xd_r_mp2if_psb_overflow        0xA500
+#define        mp2if_psb_overflow_pos 6
+#define        mp2if_psb_overflow_len 1
+#define        mp2if_psb_overflow_lsb 0
+#define xd_p_mp2if_keep_sf_sync_byte_ofsm      0xA500
+#define        mp2if_keep_sf_sync_byte_ofsm_pos 7
+#define        mp2if_keep_sf_sync_byte_ofsm_len 1
+#define        mp2if_keep_sf_sync_byte_ofsm_lsb 0
+#define xd_r_mp2if_psb_mp2if_num_pkt   0xA501
+#define        mp2if_psb_mp2if_num_pkt_pos 0
+#define        mp2if_psb_mp2if_num_pkt_len 6
+#define        mp2if_psb_mp2if_num_pkt_lsb 0
+#define xd_p_reg_mpeg_full_speed_ofsm  0xA501
+#define        reg_mpeg_full_speed_ofsm_pos 6
+#define        reg_mpeg_full_speed_ofsm_len 1
+#define        reg_mpeg_full_speed_ofsm_lsb 0
+#define xd_p_mp2if_mpeg_ser_mode_ofsm  0xA501
+#define        mp2if_mpeg_ser_mode_ofsm_pos 7
+#define        mp2if_mpeg_ser_mode_ofsm_len 1
+#define        mp2if_mpeg_ser_mode_ofsm_lsb 0
+#define xd_p_reg_sw_mon51      0xA600
+#define        reg_sw_mon51_pos 0
+#define        reg_sw_mon51_len 8
+#define        reg_sw_mon51_lsb 0
+#define xd_p_reg_top_pcsel     0xA601
+#define        reg_top_pcsel_pos 0
+#define        reg_top_pcsel_len 1
+#define        reg_top_pcsel_lsb 0
+#define xd_p_reg_top_rs232     0xA601
+#define        reg_top_rs232_pos 1
+#define        reg_top_rs232_len 1
+#define        reg_top_rs232_lsb 0
+#define xd_p_reg_top_pcout     0xA601
+#define        reg_top_pcout_pos 2
+#define        reg_top_pcout_len 1
+#define        reg_top_pcout_lsb 0
+#define xd_p_reg_top_debug     0xA601
+#define        reg_top_debug_pos 3
+#define        reg_top_debug_len 1
+#define        reg_top_debug_lsb 0
+#define xd_p_reg_top_adcdly    0xA601
+#define        reg_top_adcdly_pos 4
+#define        reg_top_adcdly_len 2
+#define        reg_top_adcdly_lsb 0
+#define xd_p_reg_top_pwrdw     0xA601
+#define        reg_top_pwrdw_pos 6
+#define        reg_top_pwrdw_len 1
+#define        reg_top_pwrdw_lsb 0
+#define xd_p_reg_top_pwrdw_inv 0xA601
+#define        reg_top_pwrdw_inv_pos 7
+#define        reg_top_pwrdw_inv_len 1
+#define        reg_top_pwrdw_inv_lsb 0
+#define xd_p_reg_top_int_inv   0xA602
+#define        reg_top_int_inv_pos 0
+#define        reg_top_int_inv_len 1
+#define        reg_top_int_inv_lsb 0
+#define xd_p_reg_top_dio_sel   0xA602
+#define        reg_top_dio_sel_pos 1
+#define        reg_top_dio_sel_len 1
+#define        reg_top_dio_sel_lsb 0
+#define xd_p_reg_top_gpioon0   0xA603
+#define        reg_top_gpioon0_pos 0
+#define        reg_top_gpioon0_len 1
+#define        reg_top_gpioon0_lsb 0
+#define xd_p_reg_top_gpioon1   0xA603
+#define        reg_top_gpioon1_pos 1
+#define        reg_top_gpioon1_len 1
+#define        reg_top_gpioon1_lsb 0
+#define xd_p_reg_top_gpioon2   0xA603
+#define        reg_top_gpioon2_pos 2
+#define        reg_top_gpioon2_len 1
+#define        reg_top_gpioon2_lsb 0
+#define xd_p_reg_top_gpioon3   0xA603
+#define        reg_top_gpioon3_pos 3
+#define        reg_top_gpioon3_len 1
+#define        reg_top_gpioon3_lsb 0
+#define xd_p_reg_top_lockon1   0xA603
+#define        reg_top_lockon1_pos 4
+#define        reg_top_lockon1_len 1
+#define        reg_top_lockon1_lsb 0
+#define xd_p_reg_top_lockon2   0xA603
+#define        reg_top_lockon2_pos 5
+#define        reg_top_lockon2_len 1
+#define        reg_top_lockon2_lsb 0
+#define xd_p_reg_top_gpioo0    0xA604
+#define        reg_top_gpioo0_pos 0
+#define        reg_top_gpioo0_len 1
+#define        reg_top_gpioo0_lsb 0
+#define xd_p_reg_top_gpioo1    0xA604
+#define        reg_top_gpioo1_pos 1
+#define        reg_top_gpioo1_len 1
+#define        reg_top_gpioo1_lsb 0
+#define xd_p_reg_top_gpioo2    0xA604
+#define        reg_top_gpioo2_pos 2
+#define        reg_top_gpioo2_len 1
+#define        reg_top_gpioo2_lsb 0
+#define xd_p_reg_top_gpioo3    0xA604
+#define        reg_top_gpioo3_pos 3
+#define        reg_top_gpioo3_len 1
+#define        reg_top_gpioo3_lsb 0
+#define xd_p_reg_top_lock1     0xA604
+#define        reg_top_lock1_pos 4
+#define        reg_top_lock1_len 1
+#define        reg_top_lock1_lsb 0
+#define xd_p_reg_top_lock2     0xA604
+#define        reg_top_lock2_pos 5
+#define        reg_top_lock2_len 1
+#define        reg_top_lock2_lsb 0
+#define xd_p_reg_top_gpioen0   0xA605
+#define        reg_top_gpioen0_pos 0
+#define        reg_top_gpioen0_len 1
+#define        reg_top_gpioen0_lsb 0
+#define xd_p_reg_top_gpioen1   0xA605
+#define        reg_top_gpioen1_pos 1
+#define        reg_top_gpioen1_len 1
+#define        reg_top_gpioen1_lsb 0
+#define xd_p_reg_top_gpioen2   0xA605
+#define        reg_top_gpioen2_pos 2
+#define        reg_top_gpioen2_len 1
+#define        reg_top_gpioen2_lsb 0
+#define xd_p_reg_top_gpioen3   0xA605
+#define        reg_top_gpioen3_pos 3
+#define        reg_top_gpioen3_len 1
+#define        reg_top_gpioen3_lsb 0
+#define xd_p_reg_top_locken1   0xA605
+#define        reg_top_locken1_pos 4
+#define        reg_top_locken1_len 1
+#define        reg_top_locken1_lsb 0
+#define xd_p_reg_top_locken2   0xA605
+#define        reg_top_locken2_pos 5
+#define        reg_top_locken2_len 1
+#define        reg_top_locken2_lsb 0
+#define xd_r_reg_top_gpioi0    0xA606
+#define        reg_top_gpioi0_pos 0
+#define        reg_top_gpioi0_len 1
+#define        reg_top_gpioi0_lsb 0
+#define xd_r_reg_top_gpioi1    0xA606
+#define        reg_top_gpioi1_pos 1
+#define        reg_top_gpioi1_len 1
+#define        reg_top_gpioi1_lsb 0
+#define xd_r_reg_top_gpioi2    0xA606
+#define        reg_top_gpioi2_pos 2
+#define        reg_top_gpioi2_len 1
+#define        reg_top_gpioi2_lsb 0
+#define xd_r_reg_top_gpioi3    0xA606
+#define        reg_top_gpioi3_pos 3
+#define        reg_top_gpioi3_len 1
+#define        reg_top_gpioi3_lsb 0
+#define xd_r_reg_top_locki1    0xA606
+#define        reg_top_locki1_pos 4
+#define        reg_top_locki1_len 1
+#define        reg_top_locki1_lsb 0
+#define xd_r_reg_top_locki2    0xA606
+#define        reg_top_locki2_pos 5
+#define        reg_top_locki2_len 1
+#define        reg_top_locki2_lsb 0
+#define xd_p_reg_dummy_7_0     0xA608
+#define        reg_dummy_7_0_pos 0
+#define        reg_dummy_7_0_len 8
+#define        reg_dummy_7_0_lsb 0
+#define xd_p_reg_dummy_15_8    0xA609
+#define        reg_dummy_15_8_pos 0
+#define        reg_dummy_15_8_len 8
+#define        reg_dummy_15_8_lsb 8
+#define xd_p_reg_dummy_23_16   0xA60A
+#define        reg_dummy_23_16_pos 0
+#define        reg_dummy_23_16_len 8
+#define        reg_dummy_23_16_lsb 16
+#define xd_p_reg_dummy_31_24   0xA60B
+#define        reg_dummy_31_24_pos 0
+#define        reg_dummy_31_24_len 8
+#define        reg_dummy_31_24_lsb 24
+#define xd_p_reg_dummy_39_32   0xA60C
+#define        reg_dummy_39_32_pos 0
+#define        reg_dummy_39_32_len 8
+#define        reg_dummy_39_32_lsb 32
+#define xd_p_reg_dummy_47_40   0xA60D
+#define        reg_dummy_47_40_pos 0
+#define        reg_dummy_47_40_len 8
+#define        reg_dummy_47_40_lsb 40
+#define xd_p_reg_dummy_55_48   0xA60E
+#define        reg_dummy_55_48_pos 0
+#define        reg_dummy_55_48_len 8
+#define        reg_dummy_55_48_lsb 48
+#define xd_p_reg_dummy_63_56   0xA60F
+#define        reg_dummy_63_56_pos 0
+#define        reg_dummy_63_56_len 8
+#define        reg_dummy_63_56_lsb 56
+#define xd_p_reg_dummy_71_64   0xA610
+#define        reg_dummy_71_64_pos 0
+#define        reg_dummy_71_64_len 8
+#define        reg_dummy_71_64_lsb 64
+#define xd_p_reg_dummy_79_72   0xA611
+#define        reg_dummy_79_72_pos 0
+#define        reg_dummy_79_72_len 8
+#define        reg_dummy_79_72_lsb 72
+#define xd_p_reg_dummy_87_80   0xA612
+#define        reg_dummy_87_80_pos 0
+#define        reg_dummy_87_80_len 8
+#define        reg_dummy_87_80_lsb 80
+#define xd_p_reg_dummy_95_88   0xA613
+#define        reg_dummy_95_88_pos 0
+#define        reg_dummy_95_88_len 8
+#define        reg_dummy_95_88_lsb 88
+#define xd_p_reg_dummy_103_96  0xA614
+#define        reg_dummy_103_96_pos 0
+#define        reg_dummy_103_96_len 8
+#define        reg_dummy_103_96_lsb 96
+
+#define xd_p_reg_unplug_flag   0xA615
+#define        reg_unplug_flag_pos 0
+#define        reg_unplug_flag_len 1
+#define        reg_unplug_flag_lsb 104
+
+#define xd_p_reg_api_dca_stes_request   0xA615
+#define reg_api_dca_stes_request_pos 1
+#define reg_api_dca_stes_request_len 1
+#define reg_api_dca_stes_request_lsb 0
+
+#define xd_p_reg_back_to_dca_flag      0xA615
+#define        reg_back_to_dca_flag_pos 2
+#define        reg_back_to_dca_flag_len 1
+#define        reg_back_to_dca_flag_lsb 106
+
+#define xd_p_reg_api_retrain_request    0xA615
+#define reg_api_retrain_request_pos 3
+#define reg_api_retrain_request_len 1
+#define reg_api_retrain_request_lsb 0
+
+#define xd_p_reg_Dyn_Top_Try_flag      0xA615
+#define        reg_Dyn_Top_Try_flag_pos 3
+#define        reg_Dyn_Top_Try_flag_len 1
+#define        reg_Dyn_Top_Try_flag_lsb 107
+
+#define xd_p_reg_API_retrain_freeze_flag       0xA615
+#define        reg_API_retrain_freeze_flag_pos 4
+#define        reg_API_retrain_freeze_flag_len 1
+#define        reg_API_retrain_freeze_flag_lsb 108
+
+#define xd_p_reg_dummy_111_104 0xA615
+#define        reg_dummy_111_104_pos 0
+#define        reg_dummy_111_104_len 8
+#define        reg_dummy_111_104_lsb 104
+#define xd_p_reg_dummy_119_112 0xA616
+#define        reg_dummy_119_112_pos 0
+#define        reg_dummy_119_112_len 8
+#define        reg_dummy_119_112_lsb 112
+#define xd_p_reg_dummy_127_120 0xA617
+#define        reg_dummy_127_120_pos 0
+#define        reg_dummy_127_120_len 8
+#define        reg_dummy_127_120_lsb 120
+#define xd_p_reg_dummy_135_128 0xA618
+#define        reg_dummy_135_128_pos 0
+#define        reg_dummy_135_128_len 8
+#define        reg_dummy_135_128_lsb 128
+
+#define xd_p_reg_dummy_143_136 0xA619
+#define        reg_dummy_143_136_pos 0
+#define        reg_dummy_143_136_len 8
+#define        reg_dummy_143_136_lsb 136
+
+#define xd_p_reg_CCIR_dis      0xA619
+#define        reg_CCIR_dis_pos 0
+#define        reg_CCIR_dis_len 1
+#define        reg_CCIR_dis_lsb 0
+
+#define xd_p_reg_dummy_151_144 0xA61A
+#define        reg_dummy_151_144_pos 0
+#define        reg_dummy_151_144_len 8
+#define        reg_dummy_151_144_lsb 144
+
+#define xd_p_reg_dummy_159_152 0xA61B
+#define        reg_dummy_159_152_pos 0
+#define        reg_dummy_159_152_len 8
+#define        reg_dummy_159_152_lsb 152
+
+#define xd_p_reg_dummy_167_160 0xA61C
+#define        reg_dummy_167_160_pos 0
+#define        reg_dummy_167_160_len 8
+#define        reg_dummy_167_160_lsb 160
+
+#define xd_p_reg_dummy_175_168 0xA61D
+#define        reg_dummy_175_168_pos 0
+#define        reg_dummy_175_168_len 8
+#define        reg_dummy_175_168_lsb 168
+
+#define xd_p_reg_dummy_183_176 0xA61E
+#define        reg_dummy_183_176_pos 0
+#define        reg_dummy_183_176_len 8
+#define        reg_dummy_183_176_lsb 176
+
+#define xd_p_reg_ofsm_read_rbc_en  0xA61E
+#define reg_ofsm_read_rbc_en_pos 2
+#define reg_ofsm_read_rbc_en_len 1
+#define reg_ofsm_read_rbc_en_lsb 0
+
+#define xd_p_reg_ce_filter_selection_dis  0xA61E
+#define reg_ce_filter_selection_dis_pos 1
+#define reg_ce_filter_selection_dis_len 1
+#define reg_ce_filter_selection_dis_lsb 0
+
+#define xd_p_reg_OFSM_version_control_7_0  0xA611
+#define reg_OFSM_version_control_7_0_pos 0
+#define reg_OFSM_version_control_7_0_len 8
+#define reg_OFSM_version_control_7_0_lsb 0
+
+#define xd_p_reg_OFSM_version_control_15_8  0xA61F
+#define reg_OFSM_version_control_15_8_pos 0
+#define reg_OFSM_version_control_15_8_len 8
+#define reg_OFSM_version_control_15_8_lsb 0
+
+#define xd_p_reg_OFSM_version_control_23_16  0xA620
+#define reg_OFSM_version_control_23_16_pos 0
+#define reg_OFSM_version_control_23_16_len 8
+#define reg_OFSM_version_control_23_16_lsb 0
+
+#define xd_p_reg_dummy_191_184 0xA61F
+#define        reg_dummy_191_184_pos 0
+#define        reg_dummy_191_184_len 8
+#define        reg_dummy_191_184_lsb 184
+
+#define xd_p_reg_dummy_199_192 0xA620
+#define        reg_dummy_199_192_pos 0
+#define        reg_dummy_199_192_len 8
+#define        reg_dummy_199_192_lsb 192
+
+#define xd_p_reg_ce_en 0xABC0
+#define        reg_ce_en_pos 0
+#define        reg_ce_en_len 1
+#define        reg_ce_en_lsb 0
+#define xd_p_reg_ce_fctrl_en   0xABC0
+#define        reg_ce_fctrl_en_pos 1
+#define        reg_ce_fctrl_en_len 1
+#define        reg_ce_fctrl_en_lsb 0
+#define xd_p_reg_ce_fste_tdi   0xABC0
+#define        reg_ce_fste_tdi_pos 2
+#define        reg_ce_fste_tdi_len 1
+#define        reg_ce_fste_tdi_lsb 0
+#define xd_p_reg_ce_dynamic    0xABC0
+#define        reg_ce_dynamic_pos 3
+#define        reg_ce_dynamic_len 1
+#define        reg_ce_dynamic_lsb 0
+#define xd_p_reg_ce_conf       0xABC0
+#define        reg_ce_conf_pos 4
+#define        reg_ce_conf_len 2
+#define        reg_ce_conf_lsb 0
+#define xd_p_reg_ce_dyn12      0xABC0
+#define        reg_ce_dyn12_pos 6
+#define        reg_ce_dyn12_len 1
+#define        reg_ce_dyn12_lsb 0
+#define xd_p_reg_ce_derot_en   0xABC0
+#define        reg_ce_derot_en_pos 7
+#define        reg_ce_derot_en_len 1
+#define        reg_ce_derot_en_lsb 0
+#define xd_p_reg_ce_dynamic_th_7_0     0xABC1
+#define        reg_ce_dynamic_th_7_0_pos 0
+#define        reg_ce_dynamic_th_7_0_len 8
+#define        reg_ce_dynamic_th_7_0_lsb 0
+#define xd_p_reg_ce_dynamic_th_15_8    0xABC2
+#define        reg_ce_dynamic_th_15_8_pos 0
+#define        reg_ce_dynamic_th_15_8_len 8
+#define        reg_ce_dynamic_th_15_8_lsb 8
+#define xd_p_reg_ce_s1 0xABC3
+#define        reg_ce_s1_pos 0
+#define        reg_ce_s1_len 5
+#define        reg_ce_s1_lsb 0
+#define xd_p_reg_ce_var_forced_value   0xABC3
+#define        reg_ce_var_forced_value_pos 5
+#define        reg_ce_var_forced_value_len 3
+#define        reg_ce_var_forced_value_lsb 0
+#define xd_p_reg_ce_data_im_7_0        0xABC4
+#define        reg_ce_data_im_7_0_pos 0
+#define        reg_ce_data_im_7_0_len 8
+#define        reg_ce_data_im_7_0_lsb 0
+#define xd_p_reg_ce_data_im_8  0xABC5
+#define        reg_ce_data_im_8_pos 0
+#define        reg_ce_data_im_8_len 1
+#define        reg_ce_data_im_8_lsb 0
+#define xd_p_reg_ce_data_re_6_0        0xABC5
+#define        reg_ce_data_re_6_0_pos 1
+#define        reg_ce_data_re_6_0_len 7
+#define        reg_ce_data_re_6_0_lsb 0
+#define xd_p_reg_ce_data_re_8_7        0xABC6
+#define        reg_ce_data_re_8_7_pos 0
+#define        reg_ce_data_re_8_7_len 2
+#define        reg_ce_data_re_8_7_lsb 7
+#define xd_p_reg_ce_tone_5_0   0xABC6
+#define        reg_ce_tone_5_0_pos 2
+#define        reg_ce_tone_5_0_len 6
+#define        reg_ce_tone_5_0_lsb 0
+#define xd_p_reg_ce_tone_12_6  0xABC7
+#define        reg_ce_tone_12_6_pos 0
+#define        reg_ce_tone_12_6_len 7
+#define        reg_ce_tone_12_6_lsb 6
+#define xd_p_reg_ce_centroid_drift_th  0xABC8
+#define        reg_ce_centroid_drift_th_pos 0
+#define        reg_ce_centroid_drift_th_len 8
+#define        reg_ce_centroid_drift_th_lsb 0
+#define xd_p_reg_ce_centroid_count_max 0xABC9
+#define        reg_ce_centroid_count_max_pos 0
+#define        reg_ce_centroid_count_max_len 4
+#define        reg_ce_centroid_count_max_lsb 0
+#define xd_p_reg_ce_centroid_bias_inc_7_0      0xABCA
+#define        reg_ce_centroid_bias_inc_7_0_pos 0
+#define        reg_ce_centroid_bias_inc_7_0_len 8
+#define        reg_ce_centroid_bias_inc_7_0_lsb 0
+#define xd_p_reg_ce_centroid_bias_inc_8        0xABCB
+#define        reg_ce_centroid_bias_inc_8_pos 0
+#define        reg_ce_centroid_bias_inc_8_len 1
+#define        reg_ce_centroid_bias_inc_8_lsb 0
+#define xd_p_reg_ce_var_th0_7_0        0xABCC
+#define        reg_ce_var_th0_7_0_pos 0
+#define        reg_ce_var_th0_7_0_len 8
+#define        reg_ce_var_th0_7_0_lsb 0
+#define xd_p_reg_ce_var_th0_15_8       0xABCD
+#define        reg_ce_var_th0_15_8_pos 0
+#define        reg_ce_var_th0_15_8_len 8
+#define        reg_ce_var_th0_15_8_lsb 8
+#define xd_p_reg_ce_var_th1_7_0        0xABCE
+#define        reg_ce_var_th1_7_0_pos 0
+#define        reg_ce_var_th1_7_0_len 8
+#define        reg_ce_var_th1_7_0_lsb 0
+#define xd_p_reg_ce_var_th1_15_8       0xABCF
+#define        reg_ce_var_th1_15_8_pos 0
+#define        reg_ce_var_th1_15_8_len 8
+#define        reg_ce_var_th1_15_8_lsb 8
+#define xd_p_reg_ce_var_th2_7_0        0xABD0
+#define        reg_ce_var_th2_7_0_pos 0
+#define        reg_ce_var_th2_7_0_len 8
+#define        reg_ce_var_th2_7_0_lsb 0
+#define xd_p_reg_ce_var_th2_15_8       0xABD1
+#define        reg_ce_var_th2_15_8_pos 0
+#define        reg_ce_var_th2_15_8_len 8
+#define        reg_ce_var_th2_15_8_lsb 8
+#define xd_p_reg_ce_var_th3_7_0        0xABD2
+#define        reg_ce_var_th3_7_0_pos 0
+#define        reg_ce_var_th3_7_0_len 8
+#define        reg_ce_var_th3_7_0_lsb 0
+#define xd_p_reg_ce_var_th3_15_8       0xABD3
+#define        reg_ce_var_th3_15_8_pos 0
+#define        reg_ce_var_th3_15_8_len 8
+#define        reg_ce_var_th3_15_8_lsb 8
+#define xd_p_reg_ce_var_th4_7_0        0xABD4
+#define        reg_ce_var_th4_7_0_pos 0
+#define        reg_ce_var_th4_7_0_len 8
+#define        reg_ce_var_th4_7_0_lsb 0
+#define xd_p_reg_ce_var_th4_15_8       0xABD5
+#define        reg_ce_var_th4_15_8_pos 0
+#define        reg_ce_var_th4_15_8_len 8
+#define        reg_ce_var_th4_15_8_lsb 8
+#define xd_p_reg_ce_var_th5_7_0        0xABD6
+#define        reg_ce_var_th5_7_0_pos 0
+#define        reg_ce_var_th5_7_0_len 8
+#define        reg_ce_var_th5_7_0_lsb 0
+#define xd_p_reg_ce_var_th5_15_8       0xABD7
+#define        reg_ce_var_th5_15_8_pos 0
+#define        reg_ce_var_th5_15_8_len 8
+#define        reg_ce_var_th5_15_8_lsb 8
+#define xd_p_reg_ce_var_th6_7_0        0xABD8
+#define        reg_ce_var_th6_7_0_pos 0
+#define        reg_ce_var_th6_7_0_len 8
+#define        reg_ce_var_th6_7_0_lsb 0
+#define xd_p_reg_ce_var_th6_15_8       0xABD9
+#define        reg_ce_var_th6_15_8_pos 0
+#define        reg_ce_var_th6_15_8_len 8
+#define        reg_ce_var_th6_15_8_lsb 8
+#define xd_p_reg_ce_fctrl_reset        0xABDA
+#define        reg_ce_fctrl_reset_pos 0
+#define        reg_ce_fctrl_reset_len 1
+#define        reg_ce_fctrl_reset_lsb 0
+#define xd_p_reg_ce_cent_auto_clr_en   0xABDA
+#define        reg_ce_cent_auto_clr_en_pos 1
+#define        reg_ce_cent_auto_clr_en_len 1
+#define        reg_ce_cent_auto_clr_en_lsb 0
+#define xd_p_reg_ce_fctrl_auto_reset_en        0xABDA
+#define        reg_ce_fctrl_auto_reset_en_pos 2
+#define        reg_ce_fctrl_auto_reset_en_len 1
+#define        reg_ce_fctrl_auto_reset_en_lsb 0
+#define xd_p_reg_ce_var_forced_en      0xABDA
+#define        reg_ce_var_forced_en_pos 3
+#define        reg_ce_var_forced_en_len 1
+#define        reg_ce_var_forced_en_lsb 0
+#define xd_p_reg_ce_cent_forced_en     0xABDA
+#define        reg_ce_cent_forced_en_pos 4
+#define        reg_ce_cent_forced_en_len 1
+#define        reg_ce_cent_forced_en_lsb 0
+#define xd_p_reg_ce_var_max    0xABDA
+#define        reg_ce_var_max_pos 5
+#define        reg_ce_var_max_len 3
+#define        reg_ce_var_max_lsb 0
+#define xd_p_reg_ce_cent_forced_value_7_0      0xABDB
+#define        reg_ce_cent_forced_value_7_0_pos 0
+#define        reg_ce_cent_forced_value_7_0_len 8
+#define        reg_ce_cent_forced_value_7_0_lsb 0
+#define xd_p_reg_ce_cent_forced_value_11_8     0xABDC
+#define        reg_ce_cent_forced_value_11_8_pos 0
+#define        reg_ce_cent_forced_value_11_8_len 4
+#define        reg_ce_cent_forced_value_11_8_lsb 8
+#define xd_p_reg_ce_fctrl_rd   0xABDD
+#define        reg_ce_fctrl_rd_pos 0
+#define        reg_ce_fctrl_rd_len 1
+#define        reg_ce_fctrl_rd_lsb 0
+#define xd_p_reg_ce_centroid_max_6_0   0xABDD
+#define        reg_ce_centroid_max_6_0_pos 1
+#define        reg_ce_centroid_max_6_0_len 7
+#define        reg_ce_centroid_max_6_0_lsb 0
+#define xd_p_reg_ce_centroid_max_11_7  0xABDE
+#define        reg_ce_centroid_max_11_7_pos 0
+#define        reg_ce_centroid_max_11_7_len 5
+#define        reg_ce_centroid_max_11_7_lsb 7
+#define xd_p_reg_ce_var        0xABDF
+#define        reg_ce_var_pos 0
+#define        reg_ce_var_len 3
+#define        reg_ce_var_lsb 0
+#define xd_p_reg_ce_fctrl_rdy  0xABDF
+#define        reg_ce_fctrl_rdy_pos 3
+#define        reg_ce_fctrl_rdy_len 1
+#define        reg_ce_fctrl_rdy_lsb 0
+#define xd_p_reg_ce_centroid_out_3_0   0xABDF
+#define        reg_ce_centroid_out_3_0_pos 4
+#define        reg_ce_centroid_out_3_0_len 4
+#define        reg_ce_centroid_out_3_0_lsb 0
+#define xd_p_reg_ce_centroid_out_11_4  0xABE0
+#define        reg_ce_centroid_out_11_4_pos 0
+#define        reg_ce_centroid_out_11_4_len 8
+#define        reg_ce_centroid_out_11_4_lsb 4
+#define xd_p_reg_ce_bias_7_0   0xABE1
+#define        reg_ce_bias_7_0_pos 0
+#define        reg_ce_bias_7_0_len 8
+#define        reg_ce_bias_7_0_lsb 0
+#define xd_p_reg_ce_bias_11_8  0xABE2
+#define        reg_ce_bias_11_8_pos 0
+#define        reg_ce_bias_11_8_len 4
+#define        reg_ce_bias_11_8_lsb 8
+#define xd_p_reg_ce_m1_3_0     0xABE2
+#define        reg_ce_m1_3_0_pos 4
+#define        reg_ce_m1_3_0_len 4
+#define        reg_ce_m1_3_0_lsb 0
+#define xd_p_reg_ce_m1_11_4    0xABE3
+#define        reg_ce_m1_11_4_pos 0
+#define        reg_ce_m1_11_4_len 8
+#define        reg_ce_m1_11_4_lsb 4
+#define xd_p_reg_ce_rh0_7_0    0xABE4
+#define        reg_ce_rh0_7_0_pos 0
+#define        reg_ce_rh0_7_0_len 8
+#define        reg_ce_rh0_7_0_lsb 0
+#define xd_p_reg_ce_rh0_15_8   0xABE5
+#define        reg_ce_rh0_15_8_pos 0
+#define        reg_ce_rh0_15_8_len 8
+#define        reg_ce_rh0_15_8_lsb 8
+#define xd_p_reg_ce_rh0_23_16  0xABE6
+#define        reg_ce_rh0_23_16_pos 0
+#define        reg_ce_rh0_23_16_len 8
+#define        reg_ce_rh0_23_16_lsb 16
+#define xd_p_reg_ce_rh0_31_24  0xABE7
+#define        reg_ce_rh0_31_24_pos 0
+#define        reg_ce_rh0_31_24_len 8
+#define        reg_ce_rh0_31_24_lsb 24
+#define xd_p_reg_ce_rh3_real_7_0       0xABE8
+#define        reg_ce_rh3_real_7_0_pos 0
+#define        reg_ce_rh3_real_7_0_len 8
+#define        reg_ce_rh3_real_7_0_lsb 0
+#define xd_p_reg_ce_rh3_real_15_8      0xABE9
+#define        reg_ce_rh3_real_15_8_pos 0
+#define        reg_ce_rh3_real_15_8_len 8
+#define        reg_ce_rh3_real_15_8_lsb 8
+#define xd_p_reg_ce_rh3_real_23_16     0xABEA
+#define        reg_ce_rh3_real_23_16_pos 0
+#define        reg_ce_rh3_real_23_16_len 8
+#define        reg_ce_rh3_real_23_16_lsb 16
+#define xd_p_reg_ce_rh3_real_31_24     0xABEB
+#define        reg_ce_rh3_real_31_24_pos 0
+#define        reg_ce_rh3_real_31_24_len 8
+#define        reg_ce_rh3_real_31_24_lsb 24
+#define xd_p_reg_ce_rh3_imag_7_0       0xABEC
+#define        reg_ce_rh3_imag_7_0_pos 0
+#define        reg_ce_rh3_imag_7_0_len 8
+#define        reg_ce_rh3_imag_7_0_lsb 0
+#define xd_p_reg_ce_rh3_imag_15_8      0xABED
+#define        reg_ce_rh3_imag_15_8_pos 0
+#define        reg_ce_rh3_imag_15_8_len 8
+#define        reg_ce_rh3_imag_15_8_lsb 8
+#define xd_p_reg_ce_rh3_imag_23_16     0xABEE
+#define        reg_ce_rh3_imag_23_16_pos 0
+#define        reg_ce_rh3_imag_23_16_len 8
+#define        reg_ce_rh3_imag_23_16_lsb 16
+#define xd_p_reg_ce_rh3_imag_31_24     0xABEF
+#define        reg_ce_rh3_imag_31_24_pos 0
+#define        reg_ce_rh3_imag_31_24_len 8
+#define        reg_ce_rh3_imag_31_24_lsb 24
+#define xd_p_reg_feq_fix_eh2_7_0       0xABF0
+#define        reg_feq_fix_eh2_7_0_pos 0
+#define        reg_feq_fix_eh2_7_0_len 8
+#define        reg_feq_fix_eh2_7_0_lsb 0
+#define xd_p_reg_feq_fix_eh2_15_8      0xABF1
+#define        reg_feq_fix_eh2_15_8_pos 0
+#define        reg_feq_fix_eh2_15_8_len 8
+#define        reg_feq_fix_eh2_15_8_lsb 8
+#define xd_p_reg_feq_fix_eh2_23_16     0xABF2
+#define        reg_feq_fix_eh2_23_16_pos 0
+#define        reg_feq_fix_eh2_23_16_len 8
+#define        reg_feq_fix_eh2_23_16_lsb 16
+#define xd_p_reg_feq_fix_eh2_31_24     0xABF3
+#define        reg_feq_fix_eh2_31_24_pos 0
+#define        reg_feq_fix_eh2_31_24_len 8
+#define        reg_feq_fix_eh2_31_24_lsb 24
+#define xd_p_reg_ce_m2_central_7_0     0xABF4
+#define        reg_ce_m2_central_7_0_pos 0
+#define        reg_ce_m2_central_7_0_len 8
+#define        reg_ce_m2_central_7_0_lsb 0
+#define xd_p_reg_ce_m2_central_15_8    0xABF5
+#define        reg_ce_m2_central_15_8_pos 0
+#define        reg_ce_m2_central_15_8_len 8
+#define        reg_ce_m2_central_15_8_lsb 8
+#define xd_p_reg_ce_fftshift   0xABF6
+#define        reg_ce_fftshift_pos 0
+#define        reg_ce_fftshift_len 4
+#define        reg_ce_fftshift_lsb 0
+#define xd_p_reg_ce_fftshift1  0xABF6
+#define        reg_ce_fftshift1_pos 4
+#define        reg_ce_fftshift1_len 4
+#define        reg_ce_fftshift1_lsb 0
+#define xd_p_reg_ce_fftshift2  0xABF7
+#define        reg_ce_fftshift2_pos 0
+#define        reg_ce_fftshift2_len 4
+#define        reg_ce_fftshift2_lsb 0
+#define xd_p_reg_ce_top_mobile 0xABF7
+#define        reg_ce_top_mobile_pos 4
+#define        reg_ce_top_mobile_len 1
+#define        reg_ce_top_mobile_lsb 0
+#define xd_p_reg_strong_sginal_detected 0xA2BC
+#define reg_strong_sginal_detected_pos 2
+#define reg_strong_sginal_detected_len 1
+#define reg_strong_sginal_detected_lsb 0
+
+#define XD_MP2IF_BASE                           0xB000
+#define XD_MP2IF_CSR                        (0x00 + XD_MP2IF_BASE)
+#define XD_MP2IF_DMX_CTRL                       (0x03 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_IDX                        (0x04 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_DATA_L                     (0x05 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_DATA_H                     (0x06 + XD_MP2IF_BASE)
+#define XD_MP2IF_MISC                       (0x07 + XD_MP2IF_BASE)
+
+extern struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d);
+extern int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg,
+                                    u8 * value);
+extern int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+                                     u8 * values, int len);
+extern int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg,
+                                     u8 value);
+extern int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+                                      u8 * values, int len);
+extern int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg,
+                                      u8 addr, u8 * values, int len);
+extern int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,
+                                       u8 * values, int len);
+extern int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg,
+                                    u8 pos, u8 len, u8 * value);
+extern int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg,
+                                     u8 pos, u8 len, u8 value);
+extern int af9005_send_command(struct dvb_usb_device *d, u8 command,
+                              u8 * wbuf, int wlen, u8 * rbuf, int rlen);
+extern int af9005_read_eeprom(struct dvb_usb_device *d, u8 address,
+                             u8 * values, int len);
+extern int af9005_tuner_attach(struct dvb_usb_adapter *adap);
+extern int af9005_led_control(struct dvb_usb_device *d, int onoff);
+
+extern u8 regmask[8];
+
+/* remote control decoder */
+extern int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len,
+                           u32 * event, int *state);
+extern struct dvb_usb_rc_key af9005_rc_keys[];
+extern int af9005_rc_keys_size;
+
+#endif
index bac2ae3b4a1f86972934b946f4168c5da8d109db..04e31cf7d53030613aaab9269c4a29ee5232c26d 100644 (file)
@@ -354,41 +354,35 @@ static struct mt352_config cxusb_mt352_config = {
 /* Callbacks for DVB USB */
 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
-       adap->pll_addr = 0x61;
-       memcpy(adap->pll_init, bpll, 4);
-       adap->pll_desc = &dvb_pll_fmd1216me;
-
-       adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
-       adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
-
+       dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
+                  DVB_PLL_FMD1216ME);
        return 0;
 }
 
 static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap)
 {
        dvb_attach(dvb_pll_attach, adap->fe, 0x61,
-                  NULL, &dvb_pll_thomson_dtt7579);
+                  NULL, DVB_PLL_THOMSON_DTT7579);
        return 0;
 }
 
 static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, &dvb_pll_lg_z201);
+       dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_LG_Z201);
        return 0;
 }
 
 static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
 {
        dvb_attach(dvb_pll_attach, adap->fe, 0x60,
-                  NULL, &dvb_pll_thomson_dtt7579);
+                  NULL, DVB_PLL_THOMSON_DTT7579);
        return 0;
 }
 
 static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
 {
        dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
-                  &dvb_pll_lg_tdvs_h06xf);
+                  DVB_PLL_LG_TDVS_H06XF);
        return 0;
 }
 
index 5143e426d283cc539043e0234d108f8eb7d7915c..9a184da01c47385ae4772c3a2ce45774b4b7a807 100644 (file)
@@ -295,7 +295,7 @@ int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap)
        tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
        if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) {
                /* not found - use panasonic pll parameters */
-               if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, &dvb_pll_env57h1xd5) == NULL)
+               if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL)
                        return -ENOMEM;
        } else {
                st->mt2060_present = 1;
index 7a6ae8f482e0634f87f95f33d1707ce63681cb36..043cadae08594f62ed1dead95e77439e728a3a2d 100644 (file)
  */
 #include "dibusb.h"
 
+static int dib3000mb_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dibusb_state *st = adap->priv;
+
+       return st->ops.tuner_pass_ctrl(fe, enable, st->tuner_addr);
+}
+
 static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
 {
        struct dib3000_config demod_cfg;
@@ -21,21 +29,34 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
 
        demod_cfg.demod_address = 0x8;
 
-       if ((adap->fe = dib3000mb_attach(&demod_cfg,&adap->dev->i2c_adap,&st->ops)) == NULL)
+       if ((adap->fe = dvb_attach(dib3000mb_attach, &demod_cfg,
+                                  &adap->dev->i2c_adap, &st->ops)) == NULL)
                return -ENODEV;
 
-       adap->fe->ops.tuner_ops.init       = dvb_usb_tuner_init_i2c;
-       adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
-
-       adap->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
+       adap->fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl;
 
        return 0;
 }
 
 static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       adap->pll_addr = 0x61;
-       adap->pll_desc = &dvb_pll_tua6010xs;
+       struct dibusb_state *st = adap->priv;
+
+       st->tuner_addr = 0x61;
+
+       dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
+                  DVB_PLL_TUA6010XS);
+       return 0;
+}
+
+static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct dibusb_state *st = adap->priv;
+
+       st->tuner_addr = 0x60;
+
+       dvb_attach(dvb_pll_attach, adap->fe, 0x60, &adap->dev->i2c_adap,
+                  DVB_PLL_TDA665X);
        return 0;
 }
 
@@ -50,30 +71,28 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap)
                { .flags = 0,        .buf = b,  .len = 2 },
                { .flags = I2C_M_RD, .buf = b2, .len = 1 },
        };
+       struct dibusb_state *st = adap->priv;
 
        /* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */
-       msg[0].addr = msg[1].addr = 0x60;
+       msg[0].addr = msg[1].addr = st->tuner_addr = 0x60;
 
-       if (adap->tuner_pass_ctrl)
-               adap->tuner_pass_ctrl(adap->fe,1,msg[0].addr);
+       if (adap->fe->ops.i2c_gate_ctrl)
+               adap->fe->ops.i2c_gate_ctrl(adap->fe,1);
 
        if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) {
                err("tuner i2c write failed.");
                ret = -EREMOTEIO;
        }
 
-       if (adap->tuner_pass_ctrl)
-               adap->tuner_pass_ctrl(adap->fe,0,msg[0].addr);
+       if (adap->fe->ops.i2c_gate_ctrl)
+               adap->fe->ops.i2c_gate_ctrl(adap->fe,0);
 
        if (b2[0] == 0xfe) {
                info("This device has the Thomson Cable onboard. Which is default.");
-               dibusb_thomson_tuner_attach(adap);
+               ret = dibusb_thomson_tuner_attach(adap);
        } else {
-               u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
                info("This device has the Panasonic ENV77H11D5 onboard.");
-               adap->pll_addr = 0x60;
-               memcpy(adap->pll_init,bpll,4);
-               adap->pll_desc = &dvb_pll_tda665x;
+               ret = dibusb_panasonic_tuner_attach(adap);
        }
 
        return ret;
index b607810327426f17bdc7a961974971b815da5253..8e847aa73ba1af1e8db007c5f85d10abbf8a79a0 100644 (file)
@@ -99,6 +99,7 @@
 struct dibusb_state {
        struct dib_fe_xfer_ops ops;
        int mt2060_present;
+       u8 tuner_addr;
 };
 
 struct dibusb_device_state {
index b5acb11c0bc95bf0bcacedc1c4db84366553e8b1..bca1e09057395898478182fcc4cd4a909009f11a 100644 (file)
@@ -118,7 +118,8 @@ static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_f
 {
        struct dvb_usb_adapter *adap = fe->dvb->priv;
        u8 b[5];
-       dvb_usb_tuner_calc_regs(fe,fep,b, 5);
+
+       fe->ops.tuner_ops.calc_regs(fe, fep, b, sizeof(b));
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
        return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0);
@@ -130,12 +131,14 @@ static struct nxt6000_config digitv_nxt6000_config = {
 
 static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
 {
+       struct digitv_state *st = adap->dev->priv;
+
        if ((adap->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) {
-               adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+               st->is_nxt6000 = 0;
                return 0;
        }
        if ((adap->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) {
-               adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+               st->is_nxt6000 = 1;
                return 0;
        }
        return -EIO;
@@ -143,8 +146,14 @@ static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
 
 static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       adap->pll_addr = 0x60;
-       adap->pll_desc = &dvb_pll_tded4;
+       struct digitv_state *st = adap->dev->priv;
+
+       if (!dvb_attach(dvb_pll_attach, adap->fe, 0x60, NULL, DVB_PLL_TDED4))
+               return -ENODEV;
+
+       if (st->is_nxt6000)
+               adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+
        return 0;
 }
 
@@ -273,6 +282,8 @@ static struct dvb_usb_device_properties digitv_properties = {
        .usb_ctrl = CYPRESS_FX2,
        .firmware = "dvb-usb-digitv-02.fw",
 
+       .size_of_priv = sizeof(struct digitv_state),
+
        .num_adapters = 1,
        .adapter = {
                {
index 477ee428a70e9c81034677f6db7d90085fccd795..8b43e3db869171f8b0ea78569383d8aaf76a9242 100644 (file)
@@ -4,6 +4,10 @@
 #define DVB_USB_LOG_PREFIX "digitv"
 #include "dvb-usb.h"
 
+struct digitv_state {
+    int is_nxt6000;
+};
+
 extern int dvb_usb_digitv_debug;
 #define deb_rc(args...)   dprintk(dvb_usb_digitv_debug,0x01,args)
 
index 088b6dee3a7fbfa289e3ff9c11b77b34405fb478..23428cd307569d8ebdf5d252b0ceed4958356b9c 100644 (file)
@@ -46,82 +46,3 @@ int dvb_usb_i2c_exit(struct dvb_usb_device *d)
        d->state &= ~DVB_USB_STATE_I2C;
        return 0;
 }
-
-int dvb_usb_tuner_init_i2c(struct dvb_frontend *fe)
-{
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = adap->pll_init, .len = 4 };
-       int ret = 0;
-
-       /* if pll_desc is not used */
-       if (adap->pll_desc == NULL)
-               return 0;
-
-       if (adap->tuner_pass_ctrl)
-               adap->tuner_pass_ctrl(fe, 1, adap->pll_addr);
-
-       deb_pll("pll init: %x\n",adap->pll_addr);
-       deb_pll("pll-buf: %x %x %x %x\n",adap->pll_init[0], adap->pll_init[1],
-                       adap->pll_init[2], adap->pll_init[3]);
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if (i2c_transfer (&adap->dev->i2c_adap, &msg, 1) != 1) {
-               err("tuner i2c write failed for pll_init.");
-               ret = -EREMOTEIO;
-       }
-       msleep(1);
-
-       if (adap->tuner_pass_ctrl)
-               adap->tuner_pass_ctrl(fe,0,adap->pll_addr);
-       return ret;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_init_i2c);
-
-int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len)
-{
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-
-       if (buf_len != 5)
-               return -EINVAL;
-       if (adap->pll_desc == NULL)
-               return 0;
-
-       deb_pll("pll addr: %x, freq: %d %p\n",adap->pll_addr, fep->frequency, adap->pll_desc);
-
-       b[0] = adap->pll_addr;
-       dvb_pll_configure(adap->pll_desc, &b[1], fep->frequency, fep->u.ofdm.bandwidth);
-
-       deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]);
-
-       return 5;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_calc_regs);
-
-int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
-{
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       int ret = 0;
-       u8 b[5];
-       struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
-
-       dvb_usb_tuner_calc_regs(fe,fep,b,5);
-
-       if (adap->tuner_pass_ctrl)
-               adap->tuner_pass_ctrl(fe, 1, adap->pll_addr);
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-
-       if (i2c_transfer(&adap->dev->i2c_adap, &msg, 1) != 1) {
-               err("tuner i2c write failed for pll_set.");
-               ret = -EREMOTEIO;
-       }
-       msleep(1);
-
-       if (adap->tuner_pass_ctrl)
-               adap->tuner_pass_ctrl(fe, 0, adap->pll_addr);
-
-       return ret;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_set_params_i2c);
index 403081689de1bdc30b1d339d7775f36cb479e133..4dfab02a8a0d526394bb14f3a89af2a5bd04d273 100644 (file)
@@ -11,7 +11,9 @@
 
 /* Vendor IDs */
 #define USB_VID_ADSTECH                                0x06e1
+#define USB_VID_AFATECH                                0x15a4
 #define USB_VID_ALCOR_MICRO            0x058f
+#define USB_VID_ALINK                          0x05e3
 #define USB_VID_ANCHOR                         0x0547
 #define USB_VID_ANUBIS_ELECTRONIC              0x10fd
 #define USB_VID_AVERMEDIA                      0x07ca
@@ -35,6 +37,7 @@
 #define USB_VID_MSI                            0x0db0
 #define USB_VID_OPERA1                         0x695c
 #define USB_VID_PINNACLE                       0x2304
+#define USB_VID_TERRATEC                       0x0ccd
 #define USB_VID_VISIONPLUS                     0x13d3
 #define USB_VID_TWINHAN                                0x1822
 #define USB_VID_ULTIMA_ELECTRONIC              0x05d8
@@ -44,6 +47,8 @@
 /* Product IDs */
 #define USB_PID_ADSTECH_USB2_COLD                      0xa333
 #define USB_PID_ADSTECH_USB2_WARM                      0xa334
+#define USB_PID_AFATECH_AF9005                         0x9020
+#define USB_VID_ALINK_DTU                              0xf170
 #define USB_PID_AVERMEDIA_DVBT_USB_COLD                        0x0001
 #define USB_PID_AVERMEDIA_DVBT_USB_WARM                        0x0002
 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD               0xa800
@@ -69,6 +74,7 @@
 #define USB_PID_GRANDTEC_DVBT_USB_WARM                 0x0fa1
 #define USB_PID_KWORLD_VSTREAM_COLD                    0x17de
 #define USB_PID_KWORLD_VSTREAM_WARM                    0x17df
+#define USB_PID_TERRATEC_CINERGY_T_USB_XE              0x0055
 #define USB_PID_TWINHAN_VP7041_COLD                    0x3201
 #define USB_PID_TWINHAN_VP7041_WARM                    0x3202
 #define USB_PID_TWINHAN_VP7020_COLD                    0x3203
index 9200a30dd1b906ffad037d3351d441f56a668c2c..7b9f35bfb4f062fe132f78de4fd69736bf293b2f 100644 (file)
@@ -110,7 +110,7 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
        input_dev->name = "IR-receiver inside an USB DVB receiver";
        input_dev->phys = d->rc_phys;
        usb_to_input_id(d->udev, &input_dev->id);
-       input_dev->cdev.dev = &d->udev->dev;
+       input_dev->dev.parent = &d->udev->dev;
 
        /* set the bits for the keys */
        deb_rc("key map size: %d\n", d->props.rc_key_map_size);
index 6f824a569e14d5a2b4f9ca83f4e821d97a0437fe..d1b3c7b81fffebad0da13a96406903d276db1d01 100644 (file)
@@ -297,12 +297,6 @@ struct dvb_usb_adapter {
        int feedcount;
        int pid_filtering;
 
-       /* tuner programming information */
-       u8 pll_addr;
-       u8 pll_init[4];
-       struct dvb_pll_desc *pll_desc;
-       int (*tuner_pass_ctrl) (struct dvb_frontend *, int, u8);
-
        /* dvb */
        struct dvb_adapter   dvb_adap;
        struct dmxdev        dmxdev;
@@ -388,11 +382,6 @@ extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16);
 /* commonly used remote control parsing */
 extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
 
-/* commonly used pll init and set functions */
-extern int dvb_usb_tuner_init_i2c(struct dvb_frontend *);
-extern int dvb_usb_tuner_calc_regs(struct dvb_frontend *, struct dvb_frontend_parameters *, u8 *buf, int buf_len);
-extern int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
-
 /* commonly used firmware download types and function */
 struct hexline {
        u8 len;
index e0587e6635913a85a00bc28169cce11fe90c96af..f01d99c1c43c12ebef10a3729c1c5ff15b9a23ec 100644 (file)
@@ -157,6 +157,7 @@ static int gl861_probe(struct usb_interface *intf,
 
 static struct usb_device_id gl861_table [] = {
                { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) },
+               { USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) },
                { }             /* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, gl861_table);
@@ -187,12 +188,16 @@ static struct dvb_usb_device_properties gl861_properties = {
        }},
        .i2c_algo         = &gl861_i2c_algo,
 
-       .num_device_descs = 1,
+       .num_device_descs = 2,
        .devices = {
                {   "MSI Mega Sky 55801 DVB-T USB2.0",
                        { &gl861_table[0], NULL },
                        { NULL },
                },
+               {   "A-LINK DTU DVB-T USB2.0",
+                       { &gl861_table[1], NULL },
+                       { NULL },
+               },
        }
 };
 
index c546ddeda5d4fbd8d7e0f8a4dd8c40f131839cf0..a956bc503a4c7aa6480e06c21a6900c6328cee60 100644 (file)
@@ -22,6 +22,8 @@ static int dvb_usb_m920x_debug;
 module_param_named(debug,dvb_usb_m920x_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
 
+static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid);
+
 static inline int m920x_read(struct usb_device *udev, u8 request, u16 value,
                             u16 index, void *data, int size)
 {
@@ -57,7 +59,8 @@ static inline int m920x_write(struct usb_device *udev, u8 request,
 
 static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
 {
-       int ret = 0;
+       int ret = 0, i, epi, flags = 0;
+       int adap_enabled[M9206_MAX_ADAPTERS] = { 0 };
 
        /* Remote controller init. */
        if (d->props.rc_query) {
@@ -76,9 +79,51 @@ static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
                deb("Initialising remote control success\n");
        }
 
+       for (i = 0; i < d->props.num_adapters; i++)
+               flags |= d->adapter[i].props.caps;
+
+       /* Some devices(Dposh) might crash if we attempt touch at all. */
+       if (flags & DVB_USB_ADAP_HAS_PID_FILTER) {
+               for (i = 0; i < d->props.num_adapters; i++) {
+                       epi = d->adapter[i].props.stream.endpoint - 0x81;
+
+                       if (epi < 0 || epi >= M9206_MAX_ADAPTERS) {
+                               printk(KERN_INFO "m920x: Unexpected adapter endpoint!\n");
+                               return -EINVAL;
+                       }
+
+                       adap_enabled[epi] = 1;
+               }
+
+               for (i = 0; i < M9206_MAX_ADAPTERS; i++) {
+                       if (adap_enabled[i])
+                               continue;
+
+                       if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x0)) != 0)
+                               return ret;
+
+                       if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x02f5)) != 0)
+                               return ret;
+               }
+       }
+
        return ret;
 }
 
+static int m920x_init_ep(struct usb_interface *intf)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct usb_host_interface *alt;
+
+       if ((alt = usb_altnum_to_altsetting(intf, 1)) == NULL) {
+               deb("No alt found!\n");
+               return -ENODEV;
+       }
+
+       return usb_set_interface(udev, alt->desc.bInterfaceNumber,
+                                alt->desc.bAlternateSetting);
+}
+
 static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
        struct m920x_state *m = d->priv;
@@ -211,8 +256,7 @@ static struct i2c_algorithm m920x_i2c_algo = {
 };
 
 /* pid filter */
-static int m920x_set_filter(struct dvb_usb_adapter *adap,
-                           int type, int idx, int pid)
+static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid)
 {
        int ret = 0;
 
@@ -221,10 +265,10 @@ static int m920x_set_filter(struct dvb_usb_adapter *adap,
 
        pid |= 0x8000;
 
-       if ((ret = m920x_write(adap->dev->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
+       if ((ret = m920x_write(d->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
                return ret;
 
-       if ((ret = m920x_write(adap->dev->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
+       if ((ret = m920x_write(d->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
                return ret;
 
        return ret;
@@ -233,40 +277,35 @@ static int m920x_set_filter(struct dvb_usb_adapter *adap,
 static int m920x_update_filters(struct dvb_usb_adapter *adap)
 {
        struct m920x_state *m = adap->dev->priv;
-       int enabled = m->filtering_enabled;
+       int enabled = m->filtering_enabled[adap->id];
        int i, ret = 0, filter = 0;
+       int ep = adap->props.stream.endpoint;
 
        for (i = 0; i < M9206_MAX_FILTERS; i++)
-               if (m->filters[i] == 8192)
+               if (m->filters[adap->id][i] == 8192)
                        enabled = 0;
 
        /* Disable all filters */
-       if ((ret = m920x_set_filter(adap, 0x81, 1, enabled)) != 0)
+       if ((ret = m920x_set_filter(adap->dev, ep, 1, enabled)) != 0)
                return ret;
 
        for (i = 0; i < M9206_MAX_FILTERS; i++)
-               if ((ret = m920x_set_filter(adap, 0x81, i + 2, 0)) != 0)
+               if ((ret = m920x_set_filter(adap->dev, ep, i + 2, 0)) != 0)
                        return ret;
 
-       if ((ret = m920x_set_filter(adap, 0x82, 0, 0x0)) != 0)
-               return ret;
-
        /* Set */
        if (enabled) {
                for (i = 0; i < M9206_MAX_FILTERS; i++) {
-                       if (m->filters[i] == 0)
+                       if (m->filters[adap->id][i] == 0)
                                continue;
 
-                       if ((ret = m920x_set_filter(adap, 0x81, filter + 2, m->filters[i])) != 0)
+                       if ((ret = m920x_set_filter(adap->dev, ep, filter + 2, m->filters[adap->id][i])) != 0)
                                return ret;
 
                        filter++;
                }
        }
 
-       if ((ret = m920x_set_filter(adap, 0x82, 0, 0x02f5)) != 0)
-               return ret;
-
        return ret;
 }
 
@@ -274,7 +313,7 @@ static int m920x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
        struct m920x_state *m = adap->dev->priv;
 
-       m->filtering_enabled = onoff ? 1 : 0;
+       m->filtering_enabled[adap->id] = onoff ? 1 : 0;
 
        return m920x_update_filters(adap);
 }
@@ -283,7 +322,7 @@ static int m920x_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, in
 {
        struct m920x_state *m = adap->dev->priv;
 
-       m->filters[index] = onoff ? pid : 0;
+       m->filters[adap->id][index] = onoff ? pid : 0;
 
        return m920x_update_filters(adap);
 }
@@ -368,6 +407,7 @@ static int m920x_identify_state(struct usb_device *udev,
 /* demod configurations */
 static int m920x_mt352_demod_init(struct dvb_frontend *fe)
 {
+       int ret;
        u8 config[] = { CONFIG, 0x3d };
        u8 clock[] = { CLOCK_CTL, 0x30 };
        u8 reset[] = { RESET, 0x80 };
@@ -377,17 +417,25 @@ static int m920x_mt352_demod_init(struct dvb_frontend *fe)
        u8 unk1[] = { 0x93, 0x1a };
        u8 unk2[] = { 0xb5, 0x7a };
 
-       mt352_write(fe, config, ARRAY_SIZE(config));
-       mt352_write(fe, clock, ARRAY_SIZE(clock));
-       mt352_write(fe, reset, ARRAY_SIZE(reset));
-       mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl));
-       mt352_write(fe, agc, ARRAY_SIZE(agc));
-       mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc));
-       mt352_write(fe, unk1, ARRAY_SIZE(unk1));
-       mt352_write(fe, unk2, ARRAY_SIZE(unk2));
-
        deb("Demod init!\n");
 
+       if ((ret = mt352_write(fe, config, ARRAY_SIZE(config))) != 0)
+               return ret;
+       if ((ret = mt352_write(fe, clock, ARRAY_SIZE(clock))) != 0)
+               return ret;
+       if ((ret = mt352_write(fe, reset, ARRAY_SIZE(reset))) != 0)
+               return ret;
+       if ((ret = mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl))) != 0)
+               return ret;
+       if ((ret = mt352_write(fe, agc, ARRAY_SIZE(agc))) != 0)
+               return ret;
+       if ((ret = mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc))) != 0)
+               return ret;
+       if ((ret = mt352_write(fe, unk1, ARRAY_SIZE(unk1))) != 0)
+               return ret;
+       if ((ret = mt352_write(fe, unk2, ARRAY_SIZE(unk2))) != 0)
+               return ret;
+
        return 0;
 }
 
@@ -558,8 +606,7 @@ static struct dvb_usb_device_properties dposh_properties;
 static int m920x_probe(struct usb_interface *intf,
                       const struct usb_device_id *id)
 {
-       struct dvb_usb_device *d;
-       struct usb_host_interface *alt;
+       struct dvb_usb_device *d = NULL;
        int ret;
        struct m920x_inits *rc_init_seq = NULL;
        int bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber;
@@ -604,23 +651,13 @@ static int m920x_probe(struct usb_interface *intf,
                 * tvwalkertwin_properties already configured both
                 * tuners, so there is nothing for us to do here
                 */
-
-               return -ENODEV;
        }
 
  found:
-       alt = usb_altnum_to_altsetting(intf, 1);
-       if (alt == NULL) {
-               deb("No alt found!\n");
-               return -ENODEV;
-       }
-
-       ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
-                               alt->desc.bAlternateSetting);
-       if (ret < 0)
+       if ((ret = m920x_init_ep(intf)) < 0)
                return ret;
 
-       if ((ret = m920x_init(d, rc_init_seq)) != 0)
+       if (d && (ret = m920x_init(d, rc_init_seq)) != 0)
                return ret;
 
        return ret;
@@ -737,9 +774,9 @@ static struct dvb_usb_device_properties digivox_mini_ii_properties = {
  *
  * LifeView TV Walker Twin has 1 x M9206, 2 x TDA10046, 2 x TDA8275A
  * TDA10046 #0 is located at i2c address 0x08
- * TDA10046 #1 is located at i2c address 0x0b (presently disabled - not yet working)
+ * TDA10046 #1 is located at i2c address 0x0b
  * TDA8275A #0 is located at i2c address 0x60
- * TDA8275A #1 is located at i2c address 0x61 (presently disabled - not yet working)
+ * TDA8275A #1 is located at i2c address 0x61
  */
 static struct dvb_usb_device_properties tvwalkertwin_properties = {
        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
@@ -756,7 +793,7 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = {
        .size_of_priv     = sizeof(struct m920x_state),
 
        .identify_state   = m920x_identify_state,
-       .num_adapters = 1,
+       .num_adapters = 2,
        .adapter = {{
                .caps = DVB_USB_ADAP_HAS_PID_FILTER |
                        DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
index 2c8942d042226e51908089523517f18aac934c33..37532890accdd9cb16d37f5e7a5f6f9b3804ffdc 100644 (file)
@@ -18,6 +18,7 @@
 #define M9206_FW       0x30
 
 #define M9206_MAX_FILTERS 8
+#define M9206_MAX_ADAPTERS 2
 
 /*
 sequences found in logs:
@@ -60,8 +61,8 @@ response to a write, is unknown.
 */
 
 struct m920x_state {
-       u16 filters[M9206_MAX_FILTERS];
-       int filtering_enabled;
+       u16 filters[M9206_MAX_ADAPTERS][M9206_MAX_FILTERS];
+       int filtering_enabled[M9206_MAX_ADAPTERS];
        int rep_count;
 };
 
index 518d7ad217df23edab68316fda6510b11e7a3035..d7c04951ceab38a20cef7b548b21af912cc58157 100644 (file)
@@ -263,7 +263,7 @@ static int opera1_tuner_attach(struct dvb_usb_adapter *adap)
 {
        dvb_attach(
                dvb_pll_attach, adap->fe, 0xc0>>1,
-               &adap->dev->i2c_adap, &dvb_pll_opera1
+               &adap->dev->i2c_adap, DVB_PLL_OPERA1
        );
        return 0;
 }
@@ -435,9 +435,9 @@ static int opera1_xilinx_load_firmware(struct usb_device *dev,
 {
        const struct firmware *fw = NULL;
        u8 *b, *p;
-       int ret = 0, i;
+       int ret = 0, i,fpgasize=40;
        u8 testval;
-       info("start downloading fpga firmware");
+       info("start downloading fpga firmware %s",filename);
 
        if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) {
                err("did not find the firmware file. (%s) "
@@ -454,17 +454,20 @@ static int opera1_xilinx_load_firmware(struct usb_device *dev,
                        /* clear fpga ? */
                        opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1,
                                         OPERA_WRITE_MSG);
-                       for (i = 0; p[i] != 0 && i < fw->size;) {
+                       for (i = 0; i < fw->size;) {
+                               if ( (fw->size - i) <fpgasize){
+                                   fpgasize=fw->size-i;
+                               }
                                b = (u8 *) p + i;
                                if (opera1_xilinx_rw
-                                       (dev, OPERA_WRITE_FX2, 0x0, b + 1, b[0],
-                                               OPERA_WRITE_MSG) != b[0]
+                                       (dev, OPERA_WRITE_FX2, 0x0, b , fpgasize,
+                                               OPERA_WRITE_MSG) != fpgasize
                                        ) {
                                        err("error while transferring firmware");
                                        ret = -EINVAL;
                                        break;
                                }
-                               i = i + 1 + b[0];
+                               i = i + fpgasize;
                        }
                        /* restart the CPU */
                        if (ret || opera1_xilinx_rw
@@ -534,18 +537,16 @@ static struct dvb_usb_device_properties opera1_properties = {
 static int opera1_probe(struct usb_interface *intf,
                        const struct usb_device_id *id)
 {
-       struct dvb_usb_device *d;
        struct usb_device *udev = interface_to_usbdev(intf);
 
        if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM &&
                udev->descriptor.idVendor == USB_VID_OPERA1 &&
-               (d == NULL
-                       || opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga.fw") != 0)
-               ) {
+               opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0
+           ) {
                return -EINVAL;
        }
 
-       if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, &d) != 0)
+       if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, NULL) != 0)
                return -EINVAL;
        return 0;
 }
index f77b48f76582001958db7eb53ccad7249e9b190e..0dcab3d4e2362bcfd5f1862a236aa56f4b94b920 100644 (file)
@@ -65,9 +65,7 @@ static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap)
 
 static int umt_tuner_attach (struct dvb_usb_adapter *adap)
 {
-       adap->pll_addr = 0x61;
-       adap->pll_desc = &dvb_pll_tua6034;
-       adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+       dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_TUA6034);
        return 0;
 }
 
@@ -84,8 +82,8 @@ static int umt_probe(struct usb_interface *intf,
 
 /* do not change the order of the ID table */
 static struct usb_device_id umt_table [] = {
-/* 00 */       { USB_DEVICE(USB_VID_HANFTEK,           USB_PID_HANFTEK_UMT_010_COLD) },
-/* 01 */       { USB_DEVICE(USB_VID_HANFTEK,           USB_PID_HANFTEK_UMT_010_WARM) },
+/* 00 */       { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) },
+/* 01 */       { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) },
                        { }             /* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, umt_table);
index 27f386585d43140c93fdd9116d9783353e522b90..156b062e02c40d800b78f6c66fd3b3b7396d5da3 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the kernel DVB frontend device drivers.
 #
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
 
 obj-$(CONFIG_DVB_PLL) += dvb-pll.o
 obj-$(CONFIG_DVB_STV0299) += stv0299.o
index 335219ebce2d5a5568dc6d815ffe8aaf3ac185c6..1dc164d5488cd277b3059a19828f98655a7fa86a 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include "dvb_frontend.h"
-#include "dvb-pll.h"
 #include "cx22702.h"
 
 
index 732e94aaa364779f53920780f7b04a5dc7e0e5fa..0834c0677fef8f86ba807b272e21b782d6ebb394 100644 (file)
@@ -917,7 +917,7 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 static int cx24123_tune(struct dvb_frontend* fe,
                        struct dvb_frontend_parameters* params,
                        unsigned int mode_flags,
-                       int *delay,
+                       unsigned int *delay,
                        fe_status_t *status)
 {
        int retval = 0;
index 5f96ffda91ad230414b818fe06f4d639c7ed966d..0c0b94767bc1e1b8a64e8a75aa76415135b72fe3 100644 (file)
 
 #include "dvb-pll.h"
 
+struct dvb_pll_desc {
+       char *name;
+       u32  min;
+       u32  max;
+       u32  iffreq;
+       void (*set)(u8 *buf, const struct dvb_frontend_parameters *params);
+       u8   *initdata;
+       u8   *sleepdata;
+       int  count;
+       struct {
+               u32 limit;
+               u32 stepsize;
+               u8  config;
+               u8  cb;
+       } entries[12];
+};
+
 /* ----------------------------------------------------------- */
 /* descriptions                                                */
 
        0x50 = AGC Take over point = 103 dBuV */
 static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 };
 
-struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
+/*     0x04 = 166.67 kHz divider
+
+       0x80 = AGC Time constant 50ms Iagc = 9 uA
+       0x20 = AGC Take over point = 112 dBuV */
+static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 };
+
+static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
        .name  = "Thomson dtt7579",
        .min   = 177000000,
        .max   = 858000000,
@@ -52,9 +75,8 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
                {  999999999, 166667, 0xf4, 0x08 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_thomson_dtt7579);
 
-struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
        .name  = "Thomson dtt7610",
        .min   =  44000000,
        .max   = 958000000,
@@ -66,19 +88,19 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
                { 999999999, 62500, 0x8e, 0x3c },
        },
 };
-EXPORT_SYMBOL(dvb_pll_thomson_dtt7610);
 
-static void thomson_dtt759x_bw(u8 *buf, u32 freq, int bandwidth)
+static void thomson_dtt759x_bw(u8 *buf,
+                              const struct dvb_frontend_parameters *params)
 {
-       if (BANDWIDTH_7_MHZ == bandwidth)
+       if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth)
                buf[3] |= 0x10;
 }
 
-struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
        .name  = "Thomson dtt759x",
        .min   = 177000000,
        .max   = 896000000,
-       .setbw = thomson_dtt759x_bw,
+       .set   = thomson_dtt759x_bw,
        .iffreq= 36166667,
        .sleepdata = (u8[]){ 2, 0x84, 0x03 },
        .count = 5,
@@ -90,9 +112,8 @@ struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
                {  999999999, 166667, 0xfc, 0x08 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_thomson_dtt759x);
 
-struct dvb_pll_desc dvb_pll_lg_z201 = {
+static struct dvb_pll_desc dvb_pll_lg_z201 = {
        .name  = "LG z201",
        .min   = 174000000,
        .max   = 862000000,
@@ -107,9 +128,8 @@ struct dvb_pll_desc dvb_pll_lg_z201 = {
                {  999999999, 166667, 0xfc, 0x04 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_lg_z201);
 
-struct dvb_pll_desc dvb_pll_microtune_4042 = {
+static struct dvb_pll_desc dvb_pll_microtune_4042 = {
        .name  = "Microtune 4042 FI5",
        .min   =  57000000,
        .max   = 858000000,
@@ -121,9 +141,8 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = {
                { 999999999, 62500, 0x8e, 0x31 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_microtune_4042);
 
-struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
        /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
        .name  = "Thomson dtt761x",
        .min   =  57000000,
@@ -137,9 +156,8 @@ struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
                { 999999999, 62500, 0x8e, 0x3c },
        },
 };
-EXPORT_SYMBOL(dvb_pll_thomson_dtt761x);
 
-struct dvb_pll_desc dvb_pll_unknown_1 = {
+static struct dvb_pll_desc dvb_pll_unknown_1 = {
        .name  = "unknown 1", /* used by dntv live dvb-t */
        .min   = 174000000,
        .max   = 862000000,
@@ -157,12 +175,11 @@ struct dvb_pll_desc dvb_pll_unknown_1 = {
                {  999999999, 166667, 0xfc, 0x08 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_unknown_1);
 
 /* Infineon TUA6010XS
  * used in Thomson Cable Tuner
  */
-struct dvb_pll_desc dvb_pll_tua6010xs = {
+static struct dvb_pll_desc dvb_pll_tua6010xs = {
        .name  = "Infineon TUA6010XS",
        .min   =  44250000,
        .max   = 858000000,
@@ -174,10 +191,9 @@ struct dvb_pll_desc dvb_pll_tua6010xs = {
                {  999999999, 62500, 0x8e, 0x85 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_tua6010xs);
 
 /* Panasonic env57h1xd5 (some Philips PLL ?) */
-struct dvb_pll_desc dvb_pll_env57h1xd5 = {
+static struct dvb_pll_desc dvb_pll_env57h1xd5 = {
        .name  = "Panasonic ENV57H1XD5",
        .min   =  44250000,
        .max   = 858000000,
@@ -190,23 +206,23 @@ struct dvb_pll_desc dvb_pll_env57h1xd5 = {
                {  999999999, 166667, 0xc2, 0xa4 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_env57h1xd5);
 
 /* Philips TDA6650/TDA6651
  * used in Panasonic ENV77H11D5
  */
-static void tda665x_bw(u8 *buf, u32 freq, int bandwidth)
+static void tda665x_bw(u8 *buf, const struct dvb_frontend_parameters *params)
 {
-       if (bandwidth == BANDWIDTH_8_MHZ)
+       if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
                buf[3] |= 0x08;
 }
 
-struct dvb_pll_desc dvb_pll_tda665x = {
+static struct dvb_pll_desc dvb_pll_tda665x = {
        .name  = "Philips TDA6650/TDA6651",
        .min   =  44250000,
        .max   = 858000000,
-       .setbw = tda665x_bw,
+       .set   = tda665x_bw,
        .iffreq= 36166667,
+       .initdata = (u8[]){ 4, 0x0b, 0xf5, 0x85, 0xab },
        .count = 12,
        .entries = {
                {   93834000, 166667, 0xca, 0x61 /* 011 0 0 0  01 */ },
@@ -223,36 +239,34 @@ struct dvb_pll_desc dvb_pll_tda665x = {
                {  861000000, 166667, 0xca, 0xe4 /* 111 0 0 1  00 */ },
        }
 };
-EXPORT_SYMBOL(dvb_pll_tda665x);
 
 /* Infineon TUA6034
  * used in LG TDTP E102P
  */
-static void tua6034_bw(u8 *buf, u32 freq, int bandwidth)
+static void tua6034_bw(u8 *buf, const struct dvb_frontend_parameters *params)
 {
-       if (BANDWIDTH_7_MHZ != bandwidth)
+       if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth)
                buf[3] |= 0x08;
 }
 
-struct dvb_pll_desc dvb_pll_tua6034 = {
+static struct dvb_pll_desc dvb_pll_tua6034 = {
        .name  = "Infineon TUA6034",
        .min   =  44250000,
        .max   = 858000000,
        .iffreq= 36166667,
        .count = 3,
-       .setbw = tua6034_bw,
+       .set   = tua6034_bw,
        .entries = {
                {  174500000, 62500, 0xce, 0x01 },
                {  230000000, 62500, 0xce, 0x02 },
                {  999999999, 62500, 0xce, 0x04 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_tua6034);
 
 /* Infineon TUA6034
  * used in LG TDVS-H061F, LG TDVS-H062F and LG TDVS-H064F
  */
-struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
+static struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
        .name  = "LG TDVS-H06xF",
        .min   =  54000000,
        .max   = 863000000,
@@ -265,23 +279,25 @@ struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
                {  999999999, 62500, 0xce, 0x04 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf);
 
 /* Philips FMD1216ME
  * used in Medion Hybrid PCMCIA card and USB Box
  */
-static void fmd1216me_bw(u8 *buf, u32 freq, int bandwidth)
+static void fmd1216me_bw(u8 *buf, const struct dvb_frontend_parameters *params)
 {
-       if (bandwidth == BANDWIDTH_8_MHZ && freq >= 158870000)
+       if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
+           params->frequency >= 158870000)
                buf[3] |= 0x08;
 }
 
-struct dvb_pll_desc dvb_pll_fmd1216me = {
+static struct dvb_pll_desc dvb_pll_fmd1216me = {
        .name = "Philips FMD1216ME",
        .min = 50870000,
        .max = 858000000,
        .iffreq= 36125000,
-       .setbw = fmd1216me_bw,
+       .set   = fmd1216me_bw,
+       .initdata = tua603x_agc112,
+       .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
        .count = 7,
        .entries = {
                { 143870000, 166667, 0xbc, 0x41 },
@@ -293,23 +309,22 @@ struct dvb_pll_desc dvb_pll_fmd1216me = {
                { 999999999, 166667, 0xfc, 0x44 },
        }
 };
-EXPORT_SYMBOL(dvb_pll_fmd1216me);
 
 /* ALPS TDED4
  * used in Nebula-Cards and USB boxes
  */
-static void tded4_bw(u8 *buf, u32 freq, int bandwidth)
+static void tded4_bw(u8 *buf, const struct dvb_frontend_parameters *params)
 {
-       if (bandwidth == BANDWIDTH_8_MHZ)
+       if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
                buf[3] |= 0x04;
 }
 
-struct dvb_pll_desc dvb_pll_tded4 = {
+static struct dvb_pll_desc dvb_pll_tded4 = {
        .name = "ALPS TDED4",
        .min = 47000000,
        .max = 863000000,
        .iffreq= 36166667,
-       .setbw = tded4_bw,
+       .set   = tded4_bw,
        .count = 4,
        .entries = {
                { 153000000, 166667, 0x85, 0x01 },
@@ -318,12 +333,11 @@ struct dvb_pll_desc dvb_pll_tded4 = {
                { 999999999, 166667, 0x85, 0x88 },
        }
 };
-EXPORT_SYMBOL(dvb_pll_tded4);
 
 /* ALPS TDHU2
  * used in AverTVHD MCE A180
  */
-struct dvb_pll_desc dvb_pll_tdhu2 = {
+static struct dvb_pll_desc dvb_pll_tdhu2 = {
        .name = "ALPS TDHU2",
        .min = 54000000,
        .max = 864000000,
@@ -336,16 +350,29 @@ struct dvb_pll_desc dvb_pll_tdhu2 = {
                { 999999999, 62500, 0x85, 0x88 },
        }
 };
-EXPORT_SYMBOL(dvb_pll_tdhu2);
 
 /* Philips TUV1236D
  * used in ATI HDTV Wonder
  */
-struct dvb_pll_desc dvb_pll_tuv1236d = {
+static void tuv1236d_rf(u8 *buf, const struct dvb_frontend_parameters *params)
+{
+       switch (params->u.vsb.modulation) {
+               case QAM_64:
+               case QAM_256:
+                       buf[3] |= 0x08;
+                       break;
+               case VSB_8:
+               default:
+                       buf[3] &= ~0x08;
+       }
+}
+
+static struct dvb_pll_desc dvb_pll_tuv1236d = {
        .name  = "Philips TUV1236D",
        .min   =  54000000,
        .max   = 864000000,
        .iffreq= 44000000,
+       .set   = tuv1236d_rf,
        .count = 3,
        .entries = {
                { 157250000, 62500, 0xc6, 0x41 },
@@ -353,12 +380,11 @@ struct dvb_pll_desc dvb_pll_tuv1236d = {
                { 999999999, 62500, 0xc6, 0x44 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_tuv1236d);
 
 /* Samsung TBMV30111IN / TBMV30712IN1
  * used in Air2PC ATSC - 2nd generation (nxt2002)
  */
-struct dvb_pll_desc dvb_pll_samsung_tbmv = {
+static struct dvb_pll_desc dvb_pll_samsung_tbmv = {
        .name = "Samsung TBMV30111IN / TBMV30712IN1",
        .min = 54000000,
        .max = 860000000,
@@ -373,12 +399,11 @@ struct dvb_pll_desc dvb_pll_samsung_tbmv = {
                { 999999999, 166667, 0xfc, 0x02 },
        }
 };
-EXPORT_SYMBOL(dvb_pll_samsung_tbmv);
 
 /*
  * Philips SD1878 Tuner.
  */
-struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
+static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
        .name  = "Philips SD1878",
        .min   =  950000,
        .max   = 2150000,
@@ -391,19 +416,18 @@ struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
                { 2150000, 500, 0xc4, 0xc0},
        },
 };
-EXPORT_SYMBOL(dvb_pll_philips_sd1878_tda8261);
 
 /*
  * Philips TD1316 Tuner.
  */
-static void td1316_bw(u8 *buf, u32 freq, int bandwidth)
+static void td1316_bw(u8 *buf, const struct dvb_frontend_parameters *params)
 {
        u8 band;
 
        /* determine band */
-       if (freq < 161000000)
+       if (params->frequency < 161000000)
                band = 1;
-       else if (freq < 444000000)
+       else if (params->frequency < 444000000)
                band = 2;
        else
                band = 4;
@@ -411,16 +435,16 @@ static void td1316_bw(u8 *buf, u32 freq, int bandwidth)
        buf[3] |= band;
 
        /* setup PLL filter */
-       if (bandwidth == BANDWIDTH_8_MHZ)
+       if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
                buf[3] |= 1 << 3;
 }
 
-struct dvb_pll_desc dvb_pll_philips_td1316 = {
+static struct dvb_pll_desc dvb_pll_philips_td1316 = {
        .name  = "Philips TD1316",
        .min   =  87000000,
        .max   = 895000000,
        .iffreq= 36166667,
-       .setbw = td1316_bw,
+       .set   = td1316_bw,
        .count = 9,
        .entries = {
                {  93834000, 166667, 0xca, 0x60},
@@ -434,10 +458,9 @@ struct dvb_pll_desc dvb_pll_philips_td1316 = {
                { 858834000, 166667, 0xca, 0xe0},
        },
 };
-EXPORT_SYMBOL(dvb_pll_philips_td1316);
 
 /* FE6600 used on DViCO Hybrid */
-struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
+static struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
        .name = "Thomson FE6600",
        .min =  44250000,
        .max = 858000000,
@@ -450,19 +473,19 @@ struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
                { 999999999, 166667, 0xf4, 0x18 },
        }
 };
-EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
-static void opera1_bw(u8 *buf, u32 freq, int bandwidth)
+
+static void opera1_bw(u8 *buf, const struct dvb_frontend_parameters *params)
 {
-       if (bandwidth == BANDWIDTH_8_MHZ)
+       if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
                buf[2] |= 0x08;
 }
 
-struct dvb_pll_desc dvb_pll_opera1 = {
+static struct dvb_pll_desc dvb_pll_opera1 = {
        .name  = "Opera Tuner",
        .min   =  900000,
        .max   = 2250000,
        .iffreq= 0,
-       .setbw = opera1_bw,
+       .set   = opera1_bw,
        .count = 8,
        .entries = {
                { 1064000, 500, 0xe5, 0xc6 },
@@ -475,7 +498,54 @@ struct dvb_pll_desc dvb_pll_opera1 = {
                { 2250000, 500, 0xe5, 0xc4 },
        }
 };
-EXPORT_SYMBOL(dvb_pll_opera1);
+
+/* Philips FCV1236D
+ */
+struct dvb_pll_desc dvb_pll_fcv1236d = {
+/* Bit_0: RF Input select
+ * Bit_1: 0=digital, 1=analog
+ */
+       .name  = "Philips FCV1236D",
+       .min   =  53000000,
+       .max   = 803000000,
+       .iffreq= 44000000,
+       .count = 3,
+       .entries = {
+               { 159000000, 62500, 0x8e, 0xa0 },
+               { 453000000, 62500, 0x8e, 0x90 },
+               { 999999999, 62500, 0x8e, 0x30 },
+       },
+};
+
+/* ----------------------------------------------------------- */
+
+static struct dvb_pll_desc *pll_list[] = {
+       [DVB_PLL_UNDEFINED]              = NULL,
+       [DVB_PLL_THOMSON_DTT7579]        = &dvb_pll_thomson_dtt7579,
+       [DVB_PLL_THOMSON_DTT759X]        = &dvb_pll_thomson_dtt759x,
+       [DVB_PLL_THOMSON_DTT7610]        = &dvb_pll_thomson_dtt7610,
+       [DVB_PLL_LG_Z201]                = &dvb_pll_lg_z201,
+       [DVB_PLL_MICROTUNE_4042]         = &dvb_pll_microtune_4042,
+       [DVB_PLL_THOMSON_DTT761X]        = &dvb_pll_thomson_dtt761x,
+       [DVB_PLL_UNKNOWN_1]              = &dvb_pll_unknown_1,
+       [DVB_PLL_TUA6010XS]              = &dvb_pll_tua6010xs,
+       [DVB_PLL_ENV57H1XD5]             = &dvb_pll_env57h1xd5,
+       [DVB_PLL_TUA6034]                = &dvb_pll_tua6034,
+       [DVB_PLL_LG_TDVS_H06XF]          = &dvb_pll_lg_tdvs_h06xf,
+       [DVB_PLL_TDA665X]                = &dvb_pll_tda665x,
+       [DVB_PLL_FMD1216ME]              = &dvb_pll_fmd1216me,
+       [DVB_PLL_TDED4]                  = &dvb_pll_tded4,
+       [DVB_PLL_TUV1236D]               = &dvb_pll_tuv1236d,
+       [DVB_PLL_TDHU2]                  = &dvb_pll_tdhu2,
+       [DVB_PLL_SAMSUNG_TBMV]           = &dvb_pll_samsung_tbmv,
+       [DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
+       [DVB_PLL_PHILIPS_TD1316]         = &dvb_pll_philips_td1316,
+       [DVB_PLL_THOMSON_FE6600]         = &dvb_pll_thomson_fe6600,
+       [DVB_PLL_OPERA1]                 = &dvb_pll_opera1,
+       [DVB_PLL_FCV1236D]               = &dvb_pll_fcv1236d,
+};
+
+/* ----------------------------------------------------------- */
 
 struct dvb_pll_priv {
        /* i2c details */
@@ -497,35 +567,37 @@ static int debug = 0;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
-                     u32 freq, int bandwidth)
+static int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
+                            const struct dvb_frontend_parameters *params)
 {
        u32 div;
        int i;
 
-       if (freq != 0 && (freq < desc->min || freq > desc->max))
-           return -EINVAL;
+       if (params->frequency != 0 && (params->frequency < desc->min ||
+                                      params->frequency > desc->max))
+               return -EINVAL;
 
        for (i = 0; i < desc->count; i++) {
-               if (freq > desc->entries[i].limit)
+               if (params->frequency > desc->entries[i].limit)
                        continue;
                break;
        }
+
        if (debug)
-               printk("pll: %s: freq=%d bw=%d | i=%d/%d\n",
-                      desc->name, freq, bandwidth, i, desc->count);
+               printk("pll: %s: freq=%d | i=%d/%d\n", desc->name,
+                      params->frequency, i, desc->count);
        if (i == desc->count)
                return -EINVAL;
 
-       div = (freq + desc->iffreq + desc->entries[i].stepsize/2) /
-             desc->entries[i].stepsize;
+       div = (params->frequency + desc->iffreq +
+              desc->entries[i].stepsize/2) / desc->entries[i].stepsize;
        buf[0] = div >> 8;
        buf[1] = div & 0xff;
        buf[2] = desc->entries[i].config;
        buf[3] = desc->entries[i].cb;
 
-       if (desc->setbw)
-               desc->setbw(buf, freq, bandwidth);
+       if (desc->set)
+               desc->set(buf, params);
 
        if (debug)
                printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
@@ -534,7 +606,6 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
        // calculate the frequency we set it to
        return (div * desc->entries[i].stepsize) - desc->iffreq;
 }
-EXPORT_SYMBOL(dvb_pll_configure);
 
 static int dvb_pll_release(struct dvb_frontend *fe)
 {
@@ -578,18 +649,12 @@ static int dvb_pll_set_params(struct dvb_frontend *fe,
                { .addr = priv->pll_i2c_address, .flags = 0,
                  .buf = buf, .len = sizeof(buf) };
        int result;
-       u32 bandwidth = 0, frequency = 0;
+       u32 frequency = 0;
 
        if (priv->i2c == NULL)
                return -EINVAL;
 
-       // DVBT bandwidth only just now
-       if (fe->ops.info.type == FE_OFDM) {
-               bandwidth = params->u.ofdm.bandwidth;
-       }
-
-       if ((result = dvb_pll_configure(priv->pll_desc, buf,
-                                       params->frequency, bandwidth)) < 0)
+       if ((result = dvb_pll_configure(priv->pll_desc, buf, params)) < 0)
                return result;
        else
                frequency = result;
@@ -601,7 +666,7 @@ static int dvb_pll_set_params(struct dvb_frontend *fe,
        }
 
        priv->frequency = frequency;
-       priv->bandwidth = bandwidth;
+       priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
 
        return 0;
 }
@@ -612,18 +677,12 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe,
 {
        struct dvb_pll_priv *priv = fe->tuner_priv;
        int result;
-       u32 bandwidth = 0, frequency = 0;
+       u32 frequency = 0;
 
        if (buf_len < 5)
                return -EINVAL;
 
-       // DVBT bandwidth only just now
-       if (fe->ops.info.type == FE_OFDM) {
-               bandwidth = params->u.ofdm.bandwidth;
-       }
-
-       if ((result = dvb_pll_configure(priv->pll_desc, buf+1,
-                                       params->frequency, bandwidth)) < 0)
+       if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params)) < 0)
                return result;
        else
                frequency = result;
@@ -631,7 +690,7 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe,
        buf[0] = priv->pll_i2c_address;
 
        priv->frequency = frequency;
-       priv->bandwidth = bandwidth;
+       priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
 
        return 5;
 }
@@ -687,13 +746,18 @@ static struct dvb_tuner_ops dvb_pll_tuner_ops = {
 
 struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
                                    struct i2c_adapter *i2c,
-                                   struct dvb_pll_desc *desc)
+                                   unsigned int pll_desc_id)
 {
        u8 b1 [] = { 0 };
        struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD,
                               .buf = b1, .len = 1 };
        struct dvb_pll_priv *priv = NULL;
        int ret;
+       struct dvb_pll_desc *desc;
+
+       BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list));
+
+       desc = pll_list[pll_desc_id];
 
        if (i2c != NULL) {
                if (fe->ops.i2c_gate_ctrl)
index 5209f46f089395bc4f8293dd3b5f7dfee91bc0ea..e93a8104052bb12b9ff5257d902798a27396aac0 100644 (file)
@@ -8,50 +8,29 @@
 #include <linux/i2c.h>
 #include "dvb_frontend.h"
 
-struct dvb_pll_desc {
-       char *name;
-       u32  min;
-       u32  max;
-       u32  iffreq;
-       void (*setbw)(u8 *buf, u32 freq, int bandwidth);
-       u8   *initdata;
-       u8   *sleepdata;
-       int  count;
-       struct {
-               u32 limit;
-               u32 stepsize;
-               u8  config;
-               u8  cb;
-       } entries[12];
-};
-
-extern struct dvb_pll_desc dvb_pll_thomson_dtt7579;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt759x;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt7610;
-extern struct dvb_pll_desc dvb_pll_lg_z201;
-extern struct dvb_pll_desc dvb_pll_microtune_4042;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt761x;
-extern struct dvb_pll_desc dvb_pll_unknown_1;
-
-extern struct dvb_pll_desc dvb_pll_tua6010xs;
-extern struct dvb_pll_desc dvb_pll_env57h1xd5;
-extern struct dvb_pll_desc dvb_pll_tua6034;
-extern struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf;
-extern struct dvb_pll_desc dvb_pll_tda665x;
-extern struct dvb_pll_desc dvb_pll_fmd1216me;
-extern struct dvb_pll_desc dvb_pll_tded4;
-
-extern struct dvb_pll_desc dvb_pll_tuv1236d;
-extern struct dvb_pll_desc dvb_pll_tdhu2;
-extern struct dvb_pll_desc dvb_pll_samsung_tbmv;
-extern struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261;
-extern struct dvb_pll_desc dvb_pll_philips_td1316;
-
-extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
-extern struct dvb_pll_desc dvb_pll_opera1;
-
-extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
-                            u32 freq, int bandwidth);
+#define DVB_PLL_UNDEFINED               0
+#define DVB_PLL_THOMSON_DTT7579         1
+#define DVB_PLL_THOMSON_DTT759X         2
+#define DVB_PLL_THOMSON_DTT7610         3
+#define DVB_PLL_LG_Z201                 4
+#define DVB_PLL_MICROTUNE_4042          5
+#define DVB_PLL_THOMSON_DTT761X         6
+#define DVB_PLL_UNKNOWN_1               7
+#define DVB_PLL_TUA6010XS               8
+#define DVB_PLL_ENV57H1XD5              9
+#define DVB_PLL_TUA6034                10
+#define DVB_PLL_LG_TDVS_H06XF          11
+#define DVB_PLL_TDA665X                12
+#define DVB_PLL_FMD1216ME              13
+#define DVB_PLL_TDED4                  14
+#define DVB_PLL_TUV1236D               15
+#define DVB_PLL_TDHU2                  16
+#define DVB_PLL_SAMSUNG_TBMV           17
+#define DVB_PLL_PHILIPS_SD1878_TDA8261 18
+#define DVB_PLL_PHILIPS_TD1316         19
+#define DVB_PLL_THOMSON_FE6600         20
+#define DVB_PLL_OPERA1                 21
+#define DVB_PLL_FCV1236D               22
 
 /**
  * Attach a dvb-pll to the supplied frontend structure.
@@ -59,19 +38,19 @@ extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
  * @param fe Frontend to attach to.
  * @param pll_addr i2c address of the PLL (if used).
  * @param i2c i2c adapter to use (set to NULL if not used).
- * @param desc dvb_pll_desc to use.
+ * @param pll_desc_id dvb_pll_desc to use.
  * @return Frontend pointer on success, NULL on failure
  */
 #if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE))
 extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
                                           int pll_addr,
                                           struct i2c_adapter *i2c,
-                                          struct dvb_pll_desc *desc);
+                                          unsigned int pll_desc_id);
 #else
 static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
                                           int pll_addr,
                                           struct i2c_adapter *i2c,
-                                          struct dvb_pll_desc *desc)
+                                          unsigned int pll_desc_id)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
        return NULL;
index b809f83d95635762b3de7103c4224826acafa537..ddc84899cf862f3b8834f90977fe84396e7ac8b2 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/string.h>
 
 #include "dvb_frontend.h"
-#include "dvb-pll.h"
 #include "nxt200x.h"
 
 struct nxt200x_state {
@@ -546,11 +545,6 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
                nxt200x_writebytes(state, 0x17, buf, 1);
        }
 
-       /* get tuning information */
-       if (fe->ops.tuner_ops.calc_regs) {
-               fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
-       }
-
        /* set additional params */
        switch (p->u.vsb.modulation) {
                case QAM_64:
@@ -559,27 +553,24 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
                        /* This is just a guess since I am unable to test it */
                        if (state->config->set_ts_params)
                                state->config->set_ts_params(fe, 1);
-
-                       /* set input */
-                       if (state->config->set_pll_input)
-                               state->config->set_pll_input(buf+1, 1);
                        break;
                case VSB_8:
                        /* Set non-punctured clock for VSB */
                        if (state->config->set_ts_params)
                                state->config->set_ts_params(fe, 0);
-
-                       /* set input */
-                       if (state->config->set_pll_input)
-                               state->config->set_pll_input(buf+1, 0);
                        break;
                default:
                        return -EINVAL;
                        break;
        }
 
-       /* write frequency information */
-       nxt200x_writetuner(state, buf);
+       if (fe->ops.tuner_ops.calc_regs) {
+               /* get tuning information */
+               fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
+
+               /* write frequency information */
+               nxt200x_writetuner(state, buf);
+       }
 
        /* reset the agc now that tuning has been completed */
        nxt200x_agc_reset(state);
index 28bc5591b319942c32154e206c07d68b44bb86e4..bb0ef58d797277dbdc93c70bcc9c873ba4efd214 100644 (file)
@@ -38,9 +38,6 @@ struct nxt200x_config
        /* the demodulator's i2c address */
        u8 demod_address;
 
-       /* used to set pll input */
-       int (*set_pll_input)(u8* buf, int input);
-
        /* need to set device param for start_dma */
        int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
 };
index 4e0aca7c67aacef4e8b7591016438f9c860abbb0..3cc8b444b8f2d903b820c748b2db8e5821d313d8 100644 (file)
@@ -45,7 +45,6 @@
 
 #include "dvb_math.h"
 #include "dvb_frontend.h"
-#include "dvb-pll.h"
 #include "or51132.h"
 
 static int debug;
index 048d7cfe12d30fa139d846aeb7200530379d477c..f46d5a46683abd868bcc6d2827dce226e4a6e53b 100644 (file)
@@ -223,38 +223,13 @@ 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");
+               if (fe->ops.tuner_ops.set_params) {
+                       fe->ops.tuner_ops.set_params(fe, param);
+                       if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
                }
-               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);
index 18768d2f6d40116ea827ad6bd1344a0dea5928a9..6c607302c1b6c3d08b73015f9312786bcd019105 100644 (file)
@@ -249,7 +249,7 @@ static int stv0299_get_symbolrate (struct stv0299_state* state)
        dprintk ("%s\n", __FUNCTION__);
 
        stv0299_readregs (state, 0x1f, sfr, 3);
-       stv0299_readregs (state, 0x1a, &rtf, 1);
+       stv0299_readregs (state, 0x1a, (u8 *)&rtf, 1);
 
        srate = (sfr[0] << 8) | sfr[1];
        srate *= Mclk;
index da796e784be319e9a7ba1ddd5029c6a2b8f8cec6..4bb06f97938b8638cfca51a85bf21d17af14dbdc 100644 (file)
@@ -478,7 +478,7 @@ struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
        state->i2c = i2c;
        memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
        state->pwm = pwm;
-       for (i=0; i < sizeof(tda10023_inittab)/sizeof(*tda10023_inittab);i+=3) {
+       for (i=0; i < ARRAY_SIZE(tda10023_inittab);i+=3) {
                if (tda10023_inittab[i] == 0x00) {
                        state->reg0 = tda10023_inittab[i+2];
                        break;
index ce6a9aaf937e9e0a7c8713f015c1ccd0dcf91325..7ac128724df81100393c416af4cd872116e706bb 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_PLUTO2) += pluto2.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
index 7751628e14152d58e367234673f7420a7d16e3e8..6d53289b327693887881714e3ee79ad5a5602df2 100644 (file)
@@ -108,7 +108,7 @@ config DVB_BUDGET_AV
        tristate "Budget cards with analog video inputs"
        depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
        select VIDEO_SAA7146_VV
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_STV0299 if !DVB_FE_CUSTOMISE
        select DVB_TDA1004X if !DVB_FE_CUSTOMISE
        select DVB_TDA10021 if !DVB_FE_CUSTOMISE
index aa85ecdc6c8079965f8bd8db54288c064a2c2df5..2c1145236ee634b8f8108d33a8481dab2a9afbde 100644 (file)
@@ -11,7 +11,7 @@ obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o
 obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o
 obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 
 hostprogs-y    := fdump
 
index ef1108c0bf11005167eb6b6b225ac4a890465369..2cee9e3bd29f8c33cb4b73e1c1f7d156cf7b3d8d 100644 (file)
@@ -137,6 +137,15 @@ static void init_av7110_av(struct av7110 *av7110)
        if (ret < 0)
                printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret);
 
+       ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType,
+                           1, (u16) av7110->display_ar);
+       if (ret < 0)
+               printk("dvb-ttpci: unable to set aspect ratio\n");
+       ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
+                           1, av7110->display_panscan);
+       if (ret < 0)
+               printk("dvb-ttpci: unable to set pan scan\n");
+
        ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 2, wss_cfg_4_3);
        if (ret < 0)
                printk("dvb-ttpci: unable to configure 4:3 wss\n");
@@ -2639,12 +2648,12 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
        av7110->mixer.volume_left  = volume;
        av7110->mixer.volume_right = volume;
 
-       init_av7110_av(av7110);
-
        ret = av7110_register(av7110);
        if (ret < 0)
                goto err_arm_thread_stop_10;
 
+       init_av7110_av(av7110);
+
        /* 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... */
index 115002b0390ca40bbad0c57b52fe457a0ef529a5..0cb43952749891855ceefe5a7c6fd9c0fbffc0e1 100644 (file)
@@ -194,6 +194,7 @@ struct av7110 {
 
        int                     video_blank;
        struct video_status     videostate;
+       u16                     display_panscan;
        int                     display_ar;
        int                     trickmode;
 #define TRICK_NONE   0
index 58678c05aa53924dfd44ab4de78c3643abfac9b1..d75e7e48addcc821b0869a4b524bfb3265797c08 100644 (file)
@@ -391,7 +391,7 @@ static int get_video_format(struct av7110 *av7110, u8 *buf, int count)
  ****************************************************************************/
 
 static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf,
-                                        const char *buf, unsigned long count)
+                                        const u8 *buf, unsigned long count)
 {
        unsigned long todo = count;
        int free;
@@ -436,7 +436,7 @@ static void play_audio_cb(u8 *buf, int count, void *priv)
 #define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
                   dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
 
-static ssize_t dvb_play(struct av7110 *av7110, const u8 __user *buf,
+static ssize_t dvb_play(struct av7110 *av7110, const char __user *buf,
                        unsigned long count, int nonblock, int type)
 {
        unsigned long todo = count, n;
@@ -499,7 +499,7 @@ static ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf,
        return count - todo;
 }
 
-static ssize_t dvb_aplay(struct av7110 *av7110, const u8 __user *buf,
+static ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf,
                         unsigned long count, int nonblock, int type)
 {
        unsigned long todo = count, n;
@@ -959,7 +959,7 @@ static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x
 
 #define MIN_IFRAME 400000
 
-static int play_iframe(struct av7110 *av7110, u8 __user *buf, unsigned int len, int nonblock)
+static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock)
 {
        int i, n;
 
@@ -1082,19 +1082,18 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
        case VIDEO_SET_DISPLAY_FORMAT:
        {
                video_displayformat_t format = (video_displayformat_t) arg;
-               u16 val = 0;
 
                switch (format) {
                case VIDEO_PAN_SCAN:
-                       val = VID_PAN_SCAN_PREF;
+                       av7110->display_panscan = VID_PAN_SCAN_PREF;
                        break;
 
                case VIDEO_LETTER_BOX:
-                       val = VID_VC_AND_PS_PREF;
+                       av7110->display_panscan = VID_VC_AND_PS_PREF;
                        break;
 
                case VIDEO_CENTER_CUT_OUT:
-                       val = VID_CENTRE_CUT_PREF;
+                       av7110->display_panscan = VID_CENTRE_CUT_PREF;
                        break;
 
                default:
@@ -1104,7 +1103,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
                        break;
                av7110->videostate.display_format = format;
                ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
-                                   1, (u16) val);
+                                   1, av7110->display_panscan);
                break;
        }
 
@@ -1466,8 +1465,9 @@ int av7110_av_register(struct av7110 *av7110)
        av7110->videostate.play_state = VIDEO_STOPPED;
        av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX;
        av7110->videostate.video_format = VIDEO_FORMAT_4_3;
-       av7110->videostate.display_format = VIDEO_CENTER_CUT_OUT;
+       av7110->videostate.display_format = VIDEO_LETTER_BOX;
        av7110->display_ar = VIDEO_FORMAT_4_3;
+       av7110->display_panscan = VID_VC_AND_PS_PREF;
 
        init_waitqueue_head(&av7110->video_events.wait_queue);
        spin_lock_init(&av7110->video_events.lock);
index e1c1294bb7673ccfe9a1ec617767ef0feae6f289..c58e3fc509ed314f8c039d75870a94e1275f4679 100644 (file)
@@ -151,7 +151,7 @@ static ssize_t ci_ll_write(struct dvb_ringbuffer *cibuf, struct file *file,
 {
        int free;
        int non_blocking = file->f_flags & O_NONBLOCK;
-       char *page = (char *)__get_free_page(GFP_USER);
+       u8 *page = (u8 *)__get_free_page(GFP_USER);
        int res;
 
        if (!page)
@@ -208,7 +208,7 @@ static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file,
                return -EINVAL;
        DVB_RINGBUFFER_SKIP(cibuf, 2);
 
-       return dvb_ringbuffer_read(cibuf, buf, len, 1);
+       return dvb_ringbuffer_read(cibuf, (u8 *)buf, len, 1);
 }
 
 static int dvb_ca_open(struct inode *inode, struct file *file)
index 70aee4eb5da46f11d6ed703b08cfb2925fbd1965..515e8232e0203e0d31240c380752886a91ea817c 100644 (file)
@@ -158,7 +158,7 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
                }
                dprintk(4, "writing DRAM block %d\n", i);
                mwdebi(av7110, DEBISWAB, bootblock,
-                      ((char*)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
+                      ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
                bootblock ^= 0x1400;
                iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
                iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
@@ -173,10 +173,10 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
                }
                if (rest > 4)
                        mwdebi(av7110, DEBISWAB, bootblock,
-                              ((char*)data) + i * AV7110_BOOT_MAX_SIZE, rest);
+                              ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest);
                else
                        mwdebi(av7110, DEBISWAB, bootblock,
-                              ((char*)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
+                              ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
 
                iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
                iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
@@ -751,7 +751,7 @@ static int FlushText(struct av7110 *av7110)
        return 0;
 }
 
-static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
+static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf)
 {
        int i, ret;
        unsigned long start;
index 673d9b3f064c86391f886fadbdff203480cb5cf9..74d940f75da606517e9ed46098b63db8cbc59d59 100644 (file)
@@ -393,7 +393,7 @@ static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val,
 }
 
 /* buffer writes */
-static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, char *val, int count)
+static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, u8 *val, int count)
 {
        memcpy(av7110->debi_virt, val, count);
        av7110_debiwrite(av7110, config, addr, 0, count);
index a97f166bb5230e12bf5411c081aa8f9618b6ccdd..6322800ee12b9bef96519113c912af47e32d8105 100644 (file)
@@ -356,7 +356,7 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
                input_dev->id.vendor = av7110->dev->pci->vendor;
                input_dev->id.product = av7110->dev->pci->device;
        }
-       input_dev->cdev.dev = &av7110->dev->pci->dev;
+       input_dev->dev.parent = &av7110->dev->pci->dev;
        /* initial keymap */
        memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map);
        input_register_keys(&av7110->ir);
index fcd9994058d004077c1525814eb2e65167b25ac8..87afaebc07032721ba6a70e5f41e13bfc3b318a5 100644 (file)
@@ -333,7 +333,7 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                        return -EINVAL;
 
                memset(t, 0, sizeof(*t));
-               strcpy(t->name, "Television");
+               strcpy((char *)t->name, "Television");
 
                t->type = V4L2_TUNER_ANALOG_TV;
                t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
index 0e817d6f1ce524e017b57684c379700f31686d1c..0aee7a13a070f4fdcf87f24339030a10bf46a547 100644 (file)
@@ -828,29 +828,6 @@ static u8 philips_sd1878_inittab[] = {
        0xff, 0xff
 };
 
-static int philips_sd1878_tda8261_tuner_set_params(struct dvb_frontend *fe,
-                                                  struct dvb_frontend_parameters *params)
-{
-       u8              buf[4];
-       int             rc;
-       struct i2c_msg  tuner_msg = {.addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf)};
-       struct budget *budget = (struct budget *) fe->dvb->priv;
-
-       if((params->frequency < 950000) || (params->frequency > 2150000))
-               return -EINVAL;
-
-       rc=dvb_pll_configure(&dvb_pll_philips_sd1878_tda8261, buf,
-                            params->frequency, 0);
-       if(rc < 0) return rc;
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if(i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
-               return -EIO;
-
-    return 0;
-}
-
 static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe,
                u32 srate, u32 ratio)
 {
@@ -921,6 +898,7 @@ static u8 read_pwm(struct budget_av *budget_av)
 #define SUBID_DVBS_TV_STAR             0x0014
 #define SUBID_DVBS_TV_STAR_CI          0x0016
 #define SUBID_DVBS_EASYWATCH_1         0x001a
+#define SUBID_DVBS_EASYWATCH_2         0x001b
 #define SUBID_DVBS_EASYWATCH           0x001e
 
 #define SUBID_DVBC_EASYWATCH           0x002a
@@ -982,10 +960,13 @@ static void frontend_init(struct budget_av *budget_av)
        case SUBID_DVBS_TV_STAR_CI:
        case SUBID_DVBS_CYNERGY1200N:
        case SUBID_DVBS_EASYWATCH:
+       case SUBID_DVBS_EASYWATCH_2:
                fe = dvb_attach(stv0299_attach, &philips_sd1878_config,
                                &budget_av->budget.i2c_adap);
                if (fe) {
-                       fe->ops.tuner_ops.set_params = philips_sd1878_tda8261_tuner_set_params;
+                       dvb_attach(dvb_pll_attach, fe, 0x60,
+                                  &budget_av->budget.i2c_adap,
+                                  DVB_PLL_PHILIPS_SD1878_TDA8261);
                }
                break;
 
@@ -1264,6 +1245,7 @@ MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
 MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
 MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
 MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
+MAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S);
 MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP);
 MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3);
 MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
@@ -1287,6 +1269,7 @@ static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
        MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
        MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
+       MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b),
        MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a),
        MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c),
        MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
index 9d42f88ebb0ed048db14f3f5089da90668381816..873c3ba296f25688925172921bd8b4e79de3767e 100644 (file)
@@ -206,7 +206,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
                input_dev->id.vendor = saa->pci->vendor;
                input_dev->id.product = saa->pci->device;
        }
-       input_dev->cdev.dev = &saa->pci->dev;
+       input_dev->dev.parent = &saa->pci->dev;
 
        /* Select keymap and address */
        switch (budget_ci->budget.dev->pci->subsystem_device) {
index 6ab97f6b53fc2efc7e482aeba7e5bd05165bb191..fbe2b9514c21bdc98fd69294adfcb25368781210 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
index b41bf1f06a9fbf7e178d6ba5d576276feed5ca83..2d70a8269391e20e6e8a49638ab69e9b626fb7b1 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
index 194b102140ef5f03501631f803cf54f2b614299b..f8bf9fe37d36a57ce135f958704dcb20aaf073ac 100644 (file)
@@ -324,8 +324,8 @@ config RADIO_ZOLTRIX_PORT
          Enter the I/O port of your Zoltrix radio card.
 
 config USB_DSBR
-       tristate "D-Link USB FM radio support (EXPERIMENTAL)"
-       depends on USB && VIDEO_V4L2 && EXPERIMENTAL
+       tristate "D-Link/GemTek USB FM radio support"
+       depends on USB && VIDEO_V4L2
        ---help---
          Say Y here if you want to connect this type of radio to your
          computer's USB port. Note that the audio is not digital, and
index 5adc27c3ced9598021c42aefeb795fcfb6127441..ce940b1b787f346d442d58fedd978aaf07249bfa 100644 (file)
@@ -392,7 +392,6 @@ static struct video_device rtrack_radio=
        .owner          = THIS_MODULE,
        .name           = "RadioTrack radio",
        .type           = VID_TYPE_TUNER,
-       .hardware       = 0,
        .fops           = &rtrack_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index 9f1addae6928e0c6eb4dfe5190f870efd9ab51fd..9b1f7a99dac0ac4c6b71dcfb836ef5d4fc18bf68 100644 (file)
@@ -355,7 +355,6 @@ static struct video_device aztech_radio=
        .owner              = THIS_MODULE,
        .name               = "Aztech radio",
        .type               = VID_TYPE_TUNER,
-       .hardware           = 0,
        .fops               = &aztech_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index 5e6f17df204b458e0c3b634d40498e79a6ece678..4db05b2b1b6eb919735591090ca05ff302d238fa 100644 (file)
@@ -377,7 +377,6 @@ static struct video_device vdev_template = {
        .owner         = THIS_MODULE,
        .name          = "Gemtek PCI Radio",
        .type          = VID_TYPE_TUNER,
-       .hardware      = 0,
        .fops          = &gemtek_pci_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index b04b6a7fff7c2f3698c6e5ed4b69d2cbc2700d68..eab8c80a2e47db0665b61fdbbfec5ba8041f2cc2 100644 (file)
@@ -330,7 +330,6 @@ static struct video_device gemtek_radio=
        .owner          = THIS_MODULE,
        .name           = "GemTek radio",
        .type           = VID_TYPE_TUNER,
-       .hardware       = 0,
        .fops           = &gemtek_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index 9b493b3298cd28f3c56d92f5b687deba54c011d2..82aedfc95d4f3883b0e487402a53d21631baf494 100644 (file)
@@ -297,7 +297,6 @@ static struct video_device rtrack2_radio=
        .owner          = THIS_MODULE,
        .name           = "RadioTrack II radio",
        .type           = VID_TYPE_TUNER,
-       .hardware       = 0,
        .fops           = &rtrack2_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index dc33f19c0e2cc4ce9acc9988324b60e6442ec38f..395165367f377c6dfb4541f061fa88430b880619 100644 (file)
@@ -297,7 +297,6 @@ static struct video_device fmi_radio=
        .owner          = THIS_MODULE,
        .name           = "SF16FMx radio",
        .type           = VID_TYPE_TUNER,
-       .hardware       = 0,
        .fops           = &fmi_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index e6c125def5cb860dec082c66c91e067e9651a7b1..c432c44bd634bf2144395dc0bfe902ba886b205f 100644 (file)
@@ -442,7 +442,6 @@ static struct video_device fmr2_radio=
        .owner          = THIS_MODULE,
        .name           = "SF16FMR2 radio",
        . type          = VID_TYPE_TUNER,
-       .hardware       = 0,
        .fops           = &fmr2_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index e43acfd7e5332389ae22f24cc241e957bd9208a6..7e1911c3d54e2f5663219daa00f4f28ea7b444f7 100644 (file)
@@ -369,7 +369,6 @@ static struct video_device terratec_radio=
        .owner          = THIS_MODULE,
        .name           = "TerraTec ActiveRadio",
        .type           = VID_TYPE_TUNER,
-       .hardware       = 0,
        .fops           = &terratec_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index c27c629d99df9dea0480899d0f34758b2dcc852a..c11981fed827deb3572f828ce0dc6f7dc39058cf 100644 (file)
@@ -349,7 +349,6 @@ static struct video_device trust_radio=
        .owner          = THIS_MODULE,
        .name           = "Trust FM Radio",
        .type           = VID_TYPE_TUNER,
-       .hardware       = 0,
        .fops           = &trust_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index 8ff5a23a9f01adedb7aeb875c452398f566cc968..1366326474e5b664951ffe06944cfddccf140e9c 100644 (file)
@@ -349,7 +349,6 @@ static struct video_device typhoon_radio =
        .owner          = THIS_MODULE,
        .name           = "Typhoon Radio",
        .type           = VID_TYPE_TUNER,
-       .hardware       = 0,
        .fops           = &typhoon_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index 4d45a40016deec706dda8d011653aa27c73193d7..9dcbffd0aa151a711ccc1e43a70f1347b575925a 100644 (file)
@@ -489,6 +489,15 @@ config TUNER_3036
          Say Y here to include support for Philips SAB3036 compatible tuners.
          If in doubt, say N.
 
+config TUNER_TEA5761
+       bool "TEA 5761 radio tuner (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       depends on I2C
+       select VIDEO_TUNER
+       help
+         Say Y here to include support for Philips TEA5761 radio tuner.
+         If in doubt, say N.
+
 config VIDEO_VINO
        tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
        depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
index 9c2de501612f4c1c199702d0f96c80f077f06416..10b4d44690162c361737ab3008e8860c2608a67c 100644 (file)
@@ -7,6 +7,8 @@ zr36067-objs    :=      zoran_procfs.o zoran_device.o \
 tuner-objs     :=      tuner-core.o tuner-types.o tuner-simple.o \
                        mt20xx.o tda8290.o tea5767.o tda9887.o
 
+tuner-$(CONFIG_TUNER_TEA5761)  += tea5761.o
+
 msp3400-objs   :=      msp3400-driver.o msp3400-kthreads.o
 
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o
@@ -16,7 +18,7 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
 endif
 
 obj-$(CONFIG_VIDEO_BT848) += bt8xx/
-obj-$(CONFIG_VIDEO_BT848) += ir-kbd-i2c.o
+obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
 obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
 obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
 obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
@@ -59,7 +61,7 @@ obj-$(CONFIG_VIDEO_CPIA) += cpia.o
 obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
 obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
 obj-$(CONFIG_VIDEO_MEYE) += meye.o
-obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
+obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
 obj-$(CONFIG_VIDEO_CX88) += cx88/
 obj-$(CONFIG_VIDEO_IVTV) += ivtv/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
index 823cd6cc471ebdcd62ce231c097f3d0a95e8b4a1..cbab53fc6243a830a94aaecb6fd122c61198611b 100644 (file)
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
 
 MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
 MODULE_AUTHOR("Maxim Yevtyushkin");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(x) (x)->name
 
-#include <linux/video_encoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
index 05c7820fe53e952f38c05e08e979ca437ffc8526..0d0c554bfdf7bce39f3ca0736bf768d27047137f 100644 (file)
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
 
 MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
 MODULE_AUTHOR("Dave Perks");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(s) (s)->name
 
-#include <linux/video_encoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
index 59a43603b5cbdcb8f933e28eac5b3454486f0697..12d1b9248be599faa2d7bababc59c9d4816632b8 100644 (file)
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
+
 
 MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
 MODULE_AUTHOR("Mike Bernson & Dave Perks");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(s) (s)->name
 
-#include <linux/video_decoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
index 853b1a3d6a1d21c88ac4d9468228742dd1ec6c22..e1028a76c042046760d3a634552c92a9bd441006 100644 (file)
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/video_encoder.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
 
 MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
 MODULE_AUTHOR("Mike Bernson & Dave Perks");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(s) (s)->name
 
-#include <linux/video_encoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
index 6b31e50fb9513c6baa4a1ef2c86361e561446b5d..2aea09c720937962fa8613c2f887cfcd9a3723bc 100644 (file)
@@ -178,8 +178,8 @@ static struct CARD {
        /* this seems to happen as well ... */
        { 0xff1211bd, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV" },
 
-       { 0x3000121a, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
-       { 0x263710b4, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
+       { 0x3000121a, BTTV_BOARD_VOODOOTV_200,  "3Dfx VoodooTV 200" },
+       { 0x263710b4, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM" },
        { 0x3060121a, BTTV_BOARD_STB2,    "3Dfx VoodooTV 100/ STB OEM" },
 
        { 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
@@ -313,6 +313,7 @@ static struct CARD {
        { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE,    "Ultraview DVB-T Lite" },
        { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,    "DViCO FusionHDTV 5 Lite" },
        { 0x00261822, BTTV_BOARD_TWINHAN_DST,   "DNTV Live! Mini "},
+       { 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2,    "DViCO FusionHDTV 2" },
 
        { 0, -1, NULL }
 };
@@ -329,7 +330,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner          = 0,
                .svhs           = 2,
                .muxsel         = { 2, 3, 1, 0 },
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -344,7 +345,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 2, 0, 0, 0 },
                .gpiomute       = 10,
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -359,7 +360,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 1, 2, 3 },
                .gpiomute       = 4,
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -387,13 +388,13 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Intel Create and Share PCI/ Smart Video Recorder III",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 2,
                .gpiomask       = 0,
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 0 },
                .needs_tvaudio  = 0,
-               .tuner_type     = 4,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -408,7 +409,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 1, 0, 1 },
                .gpiomute       = 3,
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -423,7 +424,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0x0c, 0x04, 0x08, 0x04 },
                /*                0x04 for some cards ?? */
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .audio_hook     = avermedia_tvphone_audio,
@@ -433,13 +434,13 @@ struct tvcard bttv_tvcards[] = {
                .name           = "MATRIX-Vision MV-Delta",
                .video_inputs   = 5,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 3,
                .gpiomask       = 0,
                .muxsel         = { 2, 3, 1, 0, 0 },
                .gpiomux        = { 0 },
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -457,7 +458,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0xc00,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -488,7 +489,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 4,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -503,7 +504,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0x20001,0x10001, 0, 0 },
                .gpiomute       = 10,
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -519,7 +520,7 @@ struct tvcard bttv_tvcards[] = {
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 13, 14, 11, 7 },
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -553,7 +554,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 4,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -568,7 +569,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 0, 1, 0 },
                .gpiomute       = 10,
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -587,7 +588,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0x002000,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
        },
        [BTTV_BOARD_WINVIEW_601] = {
                .name           = "Leadtek WinView 601",
@@ -600,7 +601,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007 },
                .gpiomute       = 0xcfa007,
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .audio_hook     = winview_audio,
@@ -616,7 +617,7 @@ struct tvcard bttv_tvcards[] = {
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 1, 0, 0, 0 },
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -624,13 +625,13 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
                .video_inputs   = 4,
                .audio_inputs   = 1,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .gpiomask       = 0x8dff00,
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 0 },
                .no_msp34xx     = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -643,7 +644,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner          = 0,
                .svhs           = 2,
                .muxsel         = { 2, 3, 1, 1 },
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -674,7 +675,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0xc00,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -683,7 +684,7 @@ struct tvcard bttv_tvcards[] = {
                .video_inputs   = 3,
                .audio_inputs   = 1,
                .tuner          = 0,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 7,
                .muxsel         = { 2, 3, -1 },
                .digital_mode   = DIGITAL_MODE_CAMERA,
@@ -708,7 +709,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0xc00,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_remote     = 1,
@@ -740,7 +741,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 1, 2, 3 },
                .gpiomute       = 4,
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -813,13 +814,13 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Imagenation PXC200",
                .video_inputs   = 5,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1, /* was: 4 */
                .gpiomask       = 0,
                .muxsel         = { 2, 3, 1, 0, 0},
                .gpiomux        = { 0 },
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .muxsel_hook    = PXC200_muxsel,
@@ -836,7 +837,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 0x0800, 0x1000, 0x1000 },
                .gpiomute       = 0x1800,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -860,13 +861,13 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Intel Create and Share PCI/ Smart Video Recorder III",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 2,
                .gpiomask       = 0,
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 0 },
                .needs_tvaudio  = 0,
-               .tuner_type     = 4,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -911,7 +912,7 @@ struct tvcard bttv_tvcards[] = {
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
                .has_radio      = 1,
-               .tuner_type     = 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */
+               .tuner_type     = TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .audio_hook     = winfast2000_audio,
@@ -928,7 +929,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
                .gpiomute       = 0x1800,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -945,7 +946,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
                .gpiomute       = 0x1800,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_radio      = 1,
@@ -962,7 +963,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0x29,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -978,7 +979,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0x551c00,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = 1,
+               .tuner_type     = TUNER_PHILIPS_PAL_I,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_remote     = 1,
@@ -995,7 +996,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 1,
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1030,7 +1031,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 13, 4, 11, 7 },
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_radio      = 1,
@@ -1048,7 +1049,7 @@ struct tvcard bttv_tvcards[] = {
                .needs_tvaudio  = 1,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = 1,
+               .tuner_type     = TUNER_PHILIPS_PAL_I,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1063,7 +1064,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0xff9ff6, 0xff9ff6, 0xff1ff7, 0 },
                .gpiomute       = 0xff3ffc,
                .no_msp34xx     = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1074,14 +1075,14 @@ struct tvcard bttv_tvcards[] = {
                .video_inputs   = 2,
                .audio_inputs   = 1,
                .tuner          = 0,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 3,
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 1, 1, 0, 2 },
                .gpiomute       = 3,
                .no_msp34xx     = 1,
                .pll            = PLL_NONE,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1089,14 +1090,14 @@ struct tvcard bttv_tvcards[] = {
                .name           = "MATRIX-Vision MV-Delta 2",
                .video_inputs   = 5,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 3,
                .gpiomask       = 0,
                .muxsel         = { 2, 3, 1, 0, 0 },
                .gpiomux        = { 0 },
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1112,7 +1113,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0xbcb03f,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = 21,
+               .tuner_type     = TUNER_TEMIC_4039FR5_NTSC,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1129,7 +1130,7 @@ struct tvcard bttv_tvcards[] = {
                .needs_tvaudio  = 1,
                .no_msp34xx     = 1,
                .pll            = PLL_35,
-               .tuner_type     = 1,
+               .tuner_type     = TUNER_PHILIPS_PAL_I,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_radio      = 1,
@@ -1148,7 +1149,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 1,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1206,7 +1207,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 1, 2, 3 },
                .gpiomute       = 4,
                .pll            = PLL_28,
-               .tuner_type     = -1 /* TUNER_ALPS_TMDH2_NTSC */,
+               .tuner_type     = UNSET /* TUNER_ALPS_TMDH2_NTSC */,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1234,7 +1235,7 @@ struct tvcard bttv_tvcards[] = {
                                        1= FM stereo Radio from Tuner */
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1277,7 +1278,7 @@ struct tvcard bttv_tvcards[] = {
                                0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
                                0x0880: Tuner A2 stereo */
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1313,7 +1314,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
                .gpiomute       = 0x1800,
                .pll            = PLL_28,
-               .tuner_type     = 5,
+               .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1324,7 +1325,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "GrandTec 'Grand Video Capture' (Bt848)",
                .video_inputs   = 2,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .gpiomask       = 0,
                .muxsel         = { 3, 1 },
@@ -1332,7 +1333,7 @@ struct tvcard bttv_tvcards[] = {
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
                .pll            = PLL_35,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1365,7 +1366,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 2, 0, 0, 0 },
                .gpiomute       = 1,
                .pll            = PLL_28,
-               .tuner_type     = 0,
+               .tuner_type     = TUNER_TEMIC_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1377,7 +1378,7 @@ struct tvcard bttv_tvcards[] = {
                .video_inputs   = 2,
                .audio_inputs   = 2,
                .tuner          = 0,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 11,
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 2, 0, 0, 1 },
@@ -1392,7 +1393,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "AG Electronics GMV1",
                .video_inputs   = 2,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .gpiomask       = 0xF,
                .muxsel         = { 2, 2 },
@@ -1400,7 +1401,7 @@ struct tvcard bttv_tvcards[] = {
                .no_msp34xx     = 1,
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1447,7 +1448,7 @@ struct tvcard bttv_tvcards[] = {
                .video_inputs   = 2,
                .audio_inputs   = 1,
                .tuner          = 0,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 1,
                .muxsel         = { 2, 3, 0, 1 },
                .gpiomux        = { 0, 0, 1, 0 },
@@ -1476,7 +1477,7 @@ struct tvcard bttv_tvcards[] = {
                .no_tda9875     = 1,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = 5,
+               .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1517,13 +1518,35 @@ struct tvcard bttv_tvcards[] = {
 
        /* ---- card 0x44 ---------------------------------- */
        [BTTV_BOARD_VOODOOTV_FM] = {
-               .name           = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
+               .name           = "3Dfx VoodooTV FM (Euro)",
+               /* try "insmod msp3400 simple=0" if you have
+               * sound problems with this card. */
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = UNSET,
+               .gpiomask       = 0x4f8a00,
+               /* 0x100000: 1=MSP enabled (0=disable again)
+               * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
+               .gpiomux        = {0x947fff, 0x987fff,0x947fff,0x947fff },
+               .gpiomute       = 0x947fff,
+               /* tvtuner, radio,   external,internal, mute,  stereo
+               * tuner, Composit, SVid, Composit-on-Svid-adapter */
+               .muxsel         = { 2, 3 ,0 ,1 },
+               .tuner_type     = TUNER_MT2032,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_VOODOOTV_200] = {
+               .name           = "VoodooTV 200 (USA)",
                /* try "insmod msp3400 simple=0" if you have
                * sound problems with this card. */
                .video_inputs   = 4,
                .audio_inputs   = 1,
                .tuner          = 0,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 0x4f8a00,
                /* 0x100000: 1=MSP enabled (0=disable again)
                * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
@@ -1543,8 +1566,8 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Active Imaging AIMMS",
                .video_inputs   = 1,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
+               .tuner          = UNSET,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
@@ -1564,7 +1587,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 13,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = 25,
+               .tuner_type     = TUNER_LG_PAL_I_FM,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_remote     = 1,
@@ -1580,7 +1603,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Lifeview FlyVideo 98EZ (capture only) LR51",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 2,
                .muxsel         = { 2, 3, 1, 1 }, /* AV1, AV2, SVHS, CVid adapter on SVHS */
                .pll            = PLL_28,
@@ -1606,7 +1629,7 @@ struct tvcard bttv_tvcards[] = {
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .pll            = PLL_28,
-               .tuner_type     = 5,
+               .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .audio_hook     = pvbt878p9b_audio, /* Note: not all cards have stereo */
@@ -1626,13 +1649,13 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Sensoray 311",
                .video_inputs   = 5,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 4,
                .gpiomask       = 0,
                .muxsel         = { 2, 3, 1, 0, 0 },
                .gpiomux        = { 0 },
                .needs_tvaudio  = 0,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1641,15 +1664,15 @@ struct tvcard bttv_tvcards[] = {
                .name           = "RemoteVision MX (RV605)",
                .video_inputs   = 16,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .gpiomask       = 0x00,
                .gpiomask2      = 0x07ff,
                .muxsel         = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
                                0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .muxsel_hook    = rv605_muxsel,
@@ -1693,15 +1716,15 @@ struct tvcard bttv_tvcards[] = {
                .name           = "GrandTec Multi Capture Card (Bt878)",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .gpiomask       = 0,
                .muxsel         = { 2, 3, 1, 0 },
                .gpiomux        = { 0 },
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1724,7 +1747,7 @@ struct tvcard bttv_tvcards[] = {
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = 5,
+               .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
@@ -1744,10 +1767,10 @@ struct tvcard bttv_tvcards[] = {
                /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
                .name           = "DSP Design TCVIDEO",
                .video_inputs   = 4,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .muxsel         = { 2, 3, 1, 0 },
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1762,7 +1785,7 @@ struct tvcard bttv_tvcards[] = {
                .muxsel         = { 2, 0, 1, 1 },
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
 
@@ -1791,11 +1814,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
                .video_inputs   = 4,                  /* id-inputs-clock */
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 3,
                .muxsel         = { 3, 2, 0, 1 },
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
@@ -1806,11 +1829,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
                .video_inputs   = 3,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 2,
                .muxsel         = { 2, 3, 1 },
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
@@ -1823,11 +1846,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 101 (848)", /* 0x05-40C0-C1 */
                .video_inputs   = 2,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 3, 1 },
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
@@ -1838,11 +1861,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 101/151",       /* 0x1(4|5)-0004-C4 */
                .video_inputs   = 1,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .muxsel         = { 0 },
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
@@ -1853,11 +1876,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 101/151 w/ svid",  /* 0x(16|17|20)-00C4-C1 */
                .video_inputs   = 2,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 0, 1 },
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
@@ -1868,8 +1891,8 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 200/201/250/251",  /* 0x1(8|9|E|F)-0004-C4 */
                .video_inputs   = 1,
                .audio_inputs   = 1,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .muxsel         = { 0 },
                .pll            = PLL_28,
                .tuner_type     = UNSET,
@@ -1885,7 +1908,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 200/250",   /* 0x1(A|B)-00C4-C1 */
                .video_inputs   = 2,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 0, 1 },
                .pll            = PLL_28,
@@ -1900,7 +1923,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 210/220/230",   /* 0x1(A|B)-04C0-C1 */
                .video_inputs   = 2,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 2, 3 },
                .pll            = PLL_28,
@@ -1915,11 +1938,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 500",   /* 500 */
                .video_inputs   = 2,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 2, 3 },
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
@@ -1930,9 +1953,9 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 540",   /* 540 */
                .video_inputs   = 4,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
@@ -1945,7 +1968,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 2000",  /* 2000 */
                .video_inputs   = 2,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 2, 3 },
                .pll            = PLL_28,
@@ -1961,11 +1984,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "IDS Eagle",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
+               .tuner          = UNSET,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 0,
                .muxsel         = { 0, 1, 2, 3 },
                .muxsel_hook    = eagle_muxsel,
@@ -1978,8 +2001,8 @@ struct tvcard bttv_tvcards[] = {
                .video_inputs   = 2,
                .audio_inputs   = 0,
                .svhs           = 1,
-               .tuner          = -1,
-               .tuner_type     = -1,
+               .tuner          = UNSET,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
@@ -2020,13 +2043,13 @@ struct tvcard bttv_tvcards[] = {
                .video_inputs   = 3,
                .audio_inputs   = 1,
                .tuner          = 0,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 7,
                .muxsel         = { 2, 3, 1, 1},
                .gpiomux        = { 0, 1, 2, 3},
                .gpiomute       = 4,
                .needs_tvaudio  = 1,
-               .tuner_type     = 5,
+               .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
@@ -2035,7 +2058,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Euresys Picolo",
                .video_inputs   = 3,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 2,
                .gpiomask       = 0,
                .no_msp34xx     = 1,
@@ -2052,8 +2075,8 @@ struct tvcard bttv_tvcards[] = {
                .name           = "ProVideo PV150", /* 0x4f */
                .video_inputs   = 2,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .gpiomask       = 0,
                .muxsel         = { 2, 3 },
                .gpiomux        = { 0 },
@@ -2080,7 +2103,7 @@ struct tvcard bttv_tvcards[] = {
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = 2,
+               .tuner_type     = TUNER_PHILIPS_NTSC,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .audio_hook     = adtvk503_audio,
@@ -2098,7 +2121,7 @@ struct tvcard bttv_tvcards[] = {
                .needs_tvaudio  = 1,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = 5,
+               .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                /* Notes:
@@ -2121,7 +2144,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomask       = 0,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
-               .tuner_type     = 1,
+               .tuner_type     = TUNER_PHILIPS_PAL_I,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_radio      = 1,
@@ -2138,11 +2161,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "IVC-200",
                .video_inputs   = 1,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
+               .tuner          = UNSET,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 0xdf,
                .muxsel         = { 2 },
                .pll            = PLL_28,
@@ -2151,9 +2174,9 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Grand X-Guard / Trust 814PCI",
                .video_inputs   = 16,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
-               .tuner_type     = 4,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .gpiomask2      = 0xff,
@@ -2169,14 +2192,14 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_NEBULA_DIGITV] = {
                .name           = "Nebula Electronics DigiTV",
                .video_inputs   = 1,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .muxsel         = { 2, 3, 1, 0 },
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_dvb        = 1,
@@ -2189,15 +2212,15 @@ struct tvcard bttv_tvcards[] = {
                .name           = "ProVideo PV143",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .gpiomask       = 0,
                .muxsel         = { 2, 3, 1, 0 },
                .gpiomux        = { 0 },
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2206,14 +2229,14 @@ struct tvcard bttv_tvcards[] = {
                .name           = "PHYTEC VD-009-X1 MiniDIN (bt878)",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1, /* card has no tuner */
+               .tuner          = UNSET, /* card has no tuner */
                .svhs           = 3,
                .gpiomask       = 0x00,
                .muxsel         = { 2, 3, 1, 0 },
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2221,14 +2244,14 @@ struct tvcard bttv_tvcards[] = {
                .name           = "PHYTEC VD-009-X1 Combi (bt878)",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1, /* card has no tuner */
+               .tuner          = UNSET, /* card has no tuner */
                .svhs           = 3,
                .gpiomask       = 0x00,
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2238,7 +2261,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "PHYTEC VD-009 MiniDIN (bt878)",
                .video_inputs   = 10,
                .audio_inputs   = 0,
-               .tuner          = -1, /* card has no tuner */
+               .tuner          = UNSET, /* card has no tuner */
                .svhs           = 9,
                .gpiomask       = 0x00,
                .gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
@@ -2248,7 +2271,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2256,7 +2279,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "PHYTEC VD-009 Combi (bt878)",
                .video_inputs   = 10,
                .audio_inputs   = 0,
-               .tuner          = -1, /* card has no tuner */
+               .tuner          = UNSET, /* card has no tuner */
                .svhs           = 9,
                .gpiomask       = 0x00,
                .gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
@@ -2266,7 +2289,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2274,11 +2297,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "IVC-100",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
+               .tuner          = UNSET,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 0xdf,
                .muxsel         = { 2, 3, 1, 0 },
                .pll            = PLL_28,
@@ -2288,11 +2311,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "IVC-120G",
                .video_inputs   = 16,
                .audio_inputs   = 0,    /* card has no audio */
-               .tuner          = -1,   /* card has no tuner */
-               .tuner_type     = -1,
+               .tuner          = UNSET,   /* card has no tuner */
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,   /* card has no svhs */
+               .svhs           = UNSET,   /* card has no svhs */
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
@@ -2333,7 +2356,7 @@ struct tvcard bttv_tvcards[] = {
                .video_inputs   = 3,
                .audio_inputs   = 0,
                .svhs           = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .muxsel         = { 3, 1, 1, 3 }, /* Vid In, SVid In, Vid over SVid in connector */
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
@@ -2364,9 +2387,9 @@ struct tvcard bttv_tvcards[] = {
                .name           = "SIMUS GVC1100",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
-               .tuner_type     = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
@@ -2395,14 +2418,14 @@ struct tvcard bttv_tvcards[] = {
                .name           = "LMLBT4",
                .video_inputs   = 4, /* IN1,IN2,IN3,IN4 */
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .muxsel         = { 2, 3, 1, 0 },
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
                .needs_tvaudio  = 0,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2452,8 +2475,8 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Euresys Picolo Tetra",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .gpiomask       = 0,
                .gpiomask2      = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
                .no_msp34xx     = 1,
@@ -2464,7 +2487,7 @@ struct tvcard bttv_tvcards[] = {
                .pll            = PLL_28,
                .needs_tvaudio  = 0,
                .muxsel_hook    = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2490,7 +2513,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "AVerMedia AVerTV DVB-T 771",
                .video_inputs   = 2,
                .svhs           = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
@@ -2509,14 +2532,14 @@ struct tvcard bttv_tvcards[] = {
                /* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */
                .name           = "AverMedia AverTV DVB-T 761",
                .video_inputs   = 2,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 3, 1, 2, 0 }, /* Comp0, S-Video, ?, ? */
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_dvb        = 1,
@@ -2528,8 +2551,8 @@ struct tvcard bttv_tvcards[] = {
                .name             = "MATRIX Vision Sigma-SQ",
                .video_inputs     = 16,
                .audio_inputs     = 0,
-               .tuner            = -1,
-               .svhs             = -1,
+               .tuner            = UNSET,
+               .svhs             = UNSET,
                .gpiomask         = 0x0,
                .muxsel           = { 2, 2, 2, 2, 2, 2, 2, 2,
                                3, 3, 3, 3, 3, 3, 3, 3 },
@@ -2537,7 +2560,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux          = { 0 },
                .no_msp34xx       = 1,
                .pll              = PLL_28,
-               .tuner_type       = -1,
+               .tuner_type       = UNSET,
                .tuner_addr       = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2546,15 +2569,15 @@ struct tvcard bttv_tvcards[] = {
                .name             = "MATRIX Vision Sigma-SLC",
                .video_inputs     = 4,
                .audio_inputs     = 0,
-               .tuner            = -1,
-               .svhs             = -1,
+               .tuner            = UNSET,
+               .svhs             = UNSET,
                .gpiomask         = 0x0,
                .muxsel           = { 2, 2, 2, 2 },
                .muxsel_hook      = sigmaSLC_muxsel,
                .gpiomux          = { 0 },
                .no_msp34xx       = 1,
                .pll              = PLL_28,
-               .tuner_type       = -1,
+               .tuner_type       = UNSET,
                .tuner_addr       = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2566,7 +2589,7 @@ struct tvcard bttv_tvcards[] = {
                .video_inputs   = 2,
                .audio_inputs   = 1,
                .tuner          = 0,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 0xFF,
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 2, 0, 0, 0 },
@@ -2584,14 +2607,14 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_DVICO_DVBT_LITE] = {
                /* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
                .name           = "DViCO FusionHDTV DVB-T Lite",
-               .tuner          = -1,
+               .tuner          = UNSET,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
                .pll            = PLL_28,
                .no_video       = 1,
                .has_dvb        = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2634,14 +2657,14 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Tibet Systems 'Progress DVR' CS16",
                .video_inputs   = 16,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .muxsel         = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
                .pll            = PLL_28,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .muxsel_hook    = tibetCS16_muxsel,
@@ -2661,11 +2684,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Kodicom 4400R (master)",
                .video_inputs   = 16,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
+               .tuner          = UNSET,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,
+               .svhs           = UNSET,
                /* GPIO bits 0-9 used for analog switch:
                *   00 - 03:    camera selector
                *   04 - 06:    channel (controller) selector
@@ -2693,11 +2716,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Kodicom 4400R (slave)",
                .video_inputs   = 16,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
+               .tuner          = UNSET,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 0x010000,
                .no_gpioirq     = 1,
                .muxsel         = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
@@ -2717,7 +2740,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner          = 0,
                .svhs           = 2,
                .muxsel         = { 2, 3, 1, 0 },
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
@@ -2824,7 +2847,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 440",
                .video_inputs   = 1,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 2 },
                .pll            = PLL_28,
@@ -2848,7 +2871,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 1,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = 2,
+               .tuner_type     = TUNER_PHILIPS_NTSC,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2875,14 +2898,14 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Hauppauge ImpactVCB (bt878)",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .gpiomask       = 0x0f, /* old: 7 */
                .muxsel         = { 0, 1, 3, 2 }, /* Composite 0-3 */
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2914,10 +2937,10 @@ struct tvcard bttv_tvcards[] = {
                .name           = "SSAI Security Video Interface",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .muxsel         = { 0, 1, 2, 3 },
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2925,13 +2948,31 @@ struct tvcard bttv_tvcards[] = {
                .name           = "SSAI Ultrasound Video Interface",
                .video_inputs   = 2,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 2, 0, 1, 3 },
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
+       /* ---- card 0x94---------------------------------- */
+       [BTTV_BOARD_DVICO_FUSIONHDTV_2] = {
+               .name           = "DViCO FusionHDTV 2",
+               .tuner          = 0,
+               .tuner_type     = TUNER_PHILIPS_ATSC, /* FCV1236D */
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1 },
+               .gpiomask       = 0x00e00007,
+               .gpiomux        = { 0x00400005, 0, 0x00000001, 0 },
+               .gpiomute       = 0x00c00007,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
 };
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3040,7 +3081,7 @@ static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256])
 static void flyvideo_gpio(struct bttv *btv)
 {
        int gpio,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821;
-       int tuner=-1,ttype;
+       int tuner=UNSET,ttype;
 
        gpio_inout(0xffffff, 0);
        udelay(8);  /* without this we would see the 0x1800 mask */
@@ -3085,7 +3126,7 @@ static void flyvideo_gpio(struct bttv *btv)
         * gpio & 0x001000    output bit for audio routing */
 
        if(is_capture_only)
-               tuner=4; /* No tuner present */
+               tuner = TUNER_ABSENT; /* No tuner present */
 
        printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n",
               btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio);
@@ -3093,7 +3134,7 @@ static void flyvideo_gpio(struct bttv *btv)
                btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ",
                is_capture_only?"yes":"no ");
 
-       if(tuner!= -1) /* only set if known tuner autodetected, else let insmod option through */
+       if (tuner != UNSET) /* only set if known tuner autodetected, else let insmod option through */
                btv->tuner_type = tuner;
        btv->has_radio = has_radio;
 
@@ -3302,6 +3343,7 @@ void __devinit bttv_init_card1(struct bttv *btv)
        case BTTV_BOARD_HAUPPAUGE878:
                boot_msp34xx(btv,5);
                break;
+       case BTTV_BOARD_VOODOOTV_200:
        case BTTV_BOARD_VOODOOTV_FM:
                boot_msp34xx(btv,20);
                break;
@@ -3328,10 +3370,9 @@ void __devinit bttv_init_card1(struct bttv *btv)
 /* initialization part two -- after registering i2c bus */
 void __devinit bttv_init_card2(struct bttv *btv)
 {
-       int tda9887;
        int addr=ADDR_UNSET;
 
-       btv->tuner_type = -1;
+       btv->tuner_type = UNSET;
 
        if (BTTV_BOARD_UNKNOWN == btv->c.type) {
                bttv_readee(btv,eeprom_data,0xa0);
@@ -3479,7 +3520,15 @@ void __devinit bttv_init_card2(struct bttv *btv)
                        btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
        if (UNSET != tuner[btv->c.nr])
                btv->tuner_type = tuner[btv->c.nr];
-       printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type);
+
+       if (btv->tuner_type == TUNER_ABSENT ||
+           bttv_tvcards[btv->c.type].tuner == UNSET)
+               printk(KERN_INFO "bttv%d: tuner absent\n", btv->c.nr);
+       else if(btv->tuner_type == UNSET)
+               printk(KERN_WARNING "bttv%d: tuner type unset\n", btv->c.nr);
+       else
+               printk(KERN_INFO "bttv%d: tuner type=%d\n", btv->c.nr,
+                      btv->tuner_type);
 
        if (btv->tuner_type != UNSET) {
                struct tuner_setup tun_setup;
@@ -3521,6 +3570,9 @@ void __devinit bttv_init_card2(struct bttv *btv)
        if (!autoload)
                return;
 
+       if (bttv_tvcards[btv->c.type].tuner == UNSET)
+               return;  /* no tuner or related drivers to load */
+
        /* try to detect audio/fader chips */
        if (!bttv_tvcards[btv->c.type].no_msp34xx &&
            bttv_I2CRead(btv, I2C_ADDR_MSP3400, "MSP34xx") >=0)
@@ -3541,17 +3593,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
        if (bttv_tvcards[btv->c.type].needs_tvaudio)
                request_module("tvaudio");
 
-       /* tuner modules */
-       tda9887 = 0;
-       if (btv->tda9887_conf)
-               tda9887 = 1;
-       if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb &&
-           bttv_I2CRead(btv, I2C_ADDR_TDA9887, "TDA9887") >=0)
-               tda9887 = 1;
-       /* Hybrid DVB card, DOES have a tda9887 */
-       if (btv->c.type == BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE)
-               tda9887 = 1;
-       if (btv->tuner_type != UNSET)
+       if (btv->tuner_type != UNSET && btv->tuner_type != TUNER_ABSENT)
                request_module("tuner");
 }
 
@@ -3865,11 +3907,15 @@ void bttv_tda9880_setnorm(struct bttv *btv, int norm)
        if(norm==VIDEO_MODE_NTSC) {
                bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
                bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff;
+               bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
+               bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x957fff;
                dprintk("bttv_tda9880_setnorm to NTSC\n");
        }
        else {
                bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff;
                bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x947fff;
+               bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff;
+               bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x947fff;
                dprintk("bttv_tda9880_setnorm to PAL\n");
        }
        /* set GPIO according */
index b1fedb0f64310507d5260450e16816c55254411f..cb555f2c40f95802749ae5ac791d4f68eb7e7e5d 100644 (file)
@@ -1218,7 +1218,14 @@ audio_mux(struct bttv *btv, int input, int mute)
                        break;
                case TVAUDIO_INPUT_TUNER:
                default:
-                       route.input = MSP_INPUT_DEFAULT;
+                       /* This is the only card that uses TUNER2, and afaik,
+                          is the only difference between the VOODOOTV_FM
+                          and VOODOOTV_200 */
+                       if (btv->c.type == BTTV_BOARD_VOODOOTV_200)
+                               route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
+                                       MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER);
+                       else
+                               route.input = MSP_INPUT_DEFAULT;
                        break;
                }
                route.output = MSP_OUTPUT_DEFAULT;
@@ -1253,7 +1260,7 @@ i2c_vidiocschan(struct bttv *btv)
        v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id;
 
        bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std);
-       if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
+       if (btv->c.type == BTTV_BOARD_VOODOOTV_FM || btv->c.type == BTTV_BOARD_VOODOOTV_200)
                bttv_tda9880_setnorm(btv,btv->tvnorm);
 }
 
@@ -1323,6 +1330,7 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
 
        switch (btv->c.type) {
        case BTTV_BOARD_VOODOOTV_FM:
+       case BTTV_BOARD_VOODOOTV_200:
                bttv_tda9880_setnorm(btv,norm);
                break;
        }
@@ -2251,6 +2259,24 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
                printk(KERN_INFO "bttv%d: ==================  END STATUS CARD #%d  ==================\n", btv->c.nr, btv->c.nr);
                return 0;
        }
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       case VIDIOC_DBG_G_REGISTER:
+       case VIDIOC_DBG_S_REGISTER:
+       {
+               struct v4l2_register *reg = arg;
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+                       return -EINVAL;
+               /* bt848 has a 12-bit register space */
+               reg->reg &= 0xfff;
+               if (cmd == VIDIOC_DBG_G_REGISTER)
+                       reg->val = btread(reg->reg);
+               else
+                       btwrite(reg->val, reg->reg);
+               return 0;
+       }
+#endif
 
        default:
                return -ENOIOCTLCMD;
@@ -3561,6 +3587,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_G_FREQUENCY:
        case VIDIOC_S_FREQUENCY:
        case VIDIOC_LOG_STATUS:
+       case VIDIOC_DBG_G_REGISTER:
+       case VIDIOC_DBG_S_REGISTER:
                return bttv_common_ioctls(btv,cmd,arg);
 
        default:
@@ -3943,6 +3971,8 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOCGAUDIO:
        case VIDIOCSAUDIO:
        case VIDIOC_LOG_STATUS:
+       case VIDIOC_DBG_G_REGISTER:
+       case VIDIOC_DBG_S_REGISTER:
                return bttv_common_ioctls(btv,cmd,arg);
 
        default:
index 6f74c8042bc346ff3df0bbe8d59557144b89408d..94a13d0ee61484d994f142da2d49d188ccf28d61 100644 (file)
@@ -313,7 +313,7 @@ int bttv_input_init(struct bttv *btv)
                input_dev->id.vendor  = btv->c.pci->vendor;
                input_dev->id.product = btv->c.pci->device;
        }
-       input_dev->cdev.dev = &btv->c.pci->dev;
+       input_dev->dev.parent = &btv->c.pci->dev;
 
        btv->remote = ir;
        bttv_ir_start(btv, ir);
index f821ba69db990b78aa6199a20ac1284c65518a54..dcc847dc2486dbc1ac405da7e745be168bea89cb 100644 (file)
 #define BTTV_BOARD_MACHTV_MAGICTV          0x90
 #define BTTV_BOARD_SSAI_SECURITY          0x91
 #define BTTV_BOARD_SSAI_ULTRASOUND        0x92
+#define BTTV_BOARD_VOODOOTV_200                   0x93
+#define BTTV_BOARD_DVICO_FUSIONHDTV_2     0x94
 
 /* more card-specific defines */
 #define PT2254_L_CHANNEL 0x10
index 8f44f02029beb2592a32d407991f629590d0904b..bd85f6d0fbe3f32d03f28fe103a9698138877998 100644 (file)
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/videodev.h>
-#include <media/v4l2-common.h>
 #include <linux/pci.h>
 #include <linux/input.h>
 #include <linux/mutex.h>
 #include <asm/scatterlist.h>
 #include <asm/io.h>
+#include <media/v4l2-common.h>
 
 #include <linux/device.h>
 #include <media/video-buf.h>
index fd771c7a2fe24fa930768c612eee546c13f68072..55aab8d38880296336a0de8497fb19043fbac98a 100644 (file)
@@ -663,15 +663,13 @@ int cpia2_reset_camera(struct camera_data *cam)
                cpia2_send_command(cam, &cmd);
        }
 
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(100 * HZ / 1000);      /* wait for 100 msecs */
+       schedule_timeout_interruptible(msecs_to_jiffies(100));
 
        if (cam->params.pnp_id.device_type == DEVICE_STV_672)
                retval = apply_vp_patch(cam);
 
        /* wait for vp to go to sleep */
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(100 * HZ / 1000);      /* wait for 100 msecs */
+       schedule_timeout_interruptible(msecs_to_jiffies(100));
 
        /***
         * If this is a 676, apply VP5 fixes before we start streaming
@@ -720,8 +718,7 @@ int cpia2_reset_camera(struct camera_data *cam)
        set_default_user_mode(cam);
 
        /* Give VP time to wake up */
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(100 * HZ / 1000);      /* wait for 100 msecs */
+       schedule_timeout_interruptible(msecs_to_jiffies(100));
 
        set_all_properties(cam);
 
index 1bda7ad9de117b4bc290c8dfbe57b5d682229d62..92778cd1d7356a7a12bc81d1ab70b0dabfb4c4af 100644 (file)
@@ -105,7 +105,7 @@ static struct control_menu_info framerate_controls[] =
        { CPIA2_VP_FRAMERATE_25,   "25 fps"   },
        { CPIA2_VP_FRAMERATE_30,   "30 fps"   },
 };
-#define NUM_FRAMERATE_CONTROLS (sizeof(framerate_controls)/sizeof(framerate_controls[0]))
+#define NUM_FRAMERATE_CONTROLS (ARRAY_SIZE(framerate_controls))
 
 static struct control_menu_info flicker_controls[] =
 {
@@ -113,7 +113,7 @@ static struct control_menu_info flicker_controls[] =
        { FLICKER_50,    "50 Hz" },
        { FLICKER_60,    "60 Hz"  },
 };
-#define NUM_FLICKER_CONTROLS (sizeof(flicker_controls)/sizeof(flicker_controls[0]))
+#define NUM_FLICKER_CONTROLS (ARRAY_SIZE(flicker_controls))
 
 static struct control_menu_info lights_controls[] =
 {
@@ -122,7 +122,7 @@ static struct control_menu_info lights_controls[] =
        { 128, "Bottom"  },
        { 192, "Both"  },
 };
-#define NUM_LIGHTS_CONTROLS (sizeof(lights_controls)/sizeof(lights_controls[0]))
+#define NUM_LIGHTS_CONTROLS (ARRAY_SIZE(lights_controls))
 #define GPIO_LIGHTS_MASK 192
 
 static struct v4l2_queryctrl controls[] = {
@@ -235,7 +235,7 @@ static struct v4l2_queryctrl controls[] = {
                .default_value = 0,
        },
 };
-#define NUM_CONTROLS (sizeof(controls)/sizeof(controls[0]))
+#define NUM_CONTROLS (ARRAY_SIZE(controls))
 
 
 /******************************************************************************
index 0f9d96963618221fbf8ef43f8b298e00f92e0e95..f750a543c96145c30fba197ccbc4b130dc93d0ea 100644 (file)
@@ -47,7 +47,7 @@ config VIDEO_CX88_DVB
        tristate "DVB/ATSC Support for cx2388x based TV cards"
        depends on VIDEO_CX88 && DVB_CORE
        select VIDEO_BUF_DVB
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_MT352 if !DVB_FE_CUSTOMISE
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
        select DVB_OR51132 if !DVB_FE_CUSTOMISE
index a80b1cb1abe88999c0074e2f949f83b4ce510d32..f2fcdb92ecce97d584f3584609c0045c7af6b4be 100644 (file)
@@ -56,8 +56,7 @@ MODULE_PARM_DESC(debug,"enable debug messages [blackbird]");
 
 /* ------------------------------------------------------------------ */
 
-#define OLD_BLACKBIRD_FIRM_IMAGE_SIZE 262144
-#define     BLACKBIRD_FIRM_IMAGE_SIZE 376836
+#define BLACKBIRD_FIRM_IMAGE_SIZE 376836
 
 /* defines below are from ivtv-driver.h */
 
@@ -405,7 +404,7 @@ static int blackbird_find_mailbox(struct cx8802_dev *dev)
        u32 value;
        int i;
 
-       for (i = 0; i < dev->fw_size; i++) {
+       for (i = 0; i < BLACKBIRD_FIRM_IMAGE_SIZE; i++) {
                memory_read(dev->core, i, &value);
                if (value == signature[signaturecnt])
                        signaturecnt++;
@@ -453,15 +452,12 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
                return -1;
        }
 
-       if ((firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) &&
-           (firmware->size != OLD_BLACKBIRD_FIRM_IMAGE_SIZE)) {
-               dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d or %d)\n",
-                       firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE,
-                       OLD_BLACKBIRD_FIRM_IMAGE_SIZE);
+       if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) {
+               dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d)\n",
+                       firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE);
                release_firmware(firmware);
                return -1;
        }
-       dev->fw_size = firmware->size;
 
        if (0 != memcmp(firmware->data, magic, 8)) {
                dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\n");
index e61102dc8ad7fc154244ffe3044ec1df217d152e..6a136ddbccf852c8bb02a762a08778f36e43aed1 100644 (file)
@@ -1335,6 +1335,26 @@ struct cx88_board cx88_boards[] = {
                /* fixme: Add radio support */
                .mpeg           = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
        },
+       [CX88_BOARD_ADSTECH_PTV_390] = {
+               .name           = "ADS Tech Instant Video PCI",
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_DEBUG,
+                       .vmux   = 3,
+                       .gpio0  = 0x04ff,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x07fa,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x07fa,
+               }},
+       },
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
 
@@ -1641,6 +1661,10 @@ struct cx88_subid cx88_subids[] = {
                .subvendor = 0x1421,
                .subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */
                .card      = CX88_BOARD_KWORLD_DVBS_100,
+       },{
+               .subvendor = 0x1421,
+               .subdevice = 0x0390,
+               .card      = CX88_BOARD_ADSTECH_PTV_390,
        },
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
index dbfe4dc9cf8c184642ea984fc6b96755ba09341e..1773b40467dc176b808cbc15e8cbc18c803f46a6 100644 (file)
@@ -35,9 +35,7 @@
 
 #include "mt352.h"
 #include "mt352_priv.h"
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
-# include "cx88-vp3054-i2c.h"
-#endif
+#include "cx88-vp3054-i2c.h"
 #include "zl10353.h"
 #include "cx22702.h"
 #include "or51132.h"
@@ -199,7 +197,7 @@ static struct mt352_config dvico_fusionhdtv_dual = {
        .demod_init    = dvico_dual_demod_init,
 };
 
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
 static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
 {
        static u8 clock_config []  = { 0x89, 0x38, 0x38 };
@@ -223,64 +221,6 @@ static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
-{
-       struct cx8802_dev *dev= fe->dvb->priv;
-
-       /* this message is to set up ATC and ALC */
-       static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
-       struct i2c_msg msg =
-               { .addr = dev->core->pll_addr, .flags = 0,
-                 .buf = fmd1216_init, .len = sizeof(fmd1216_init) };
-       int err;
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
-               if (err < 0)
-                       return err;
-               else
-                       return -EREMOTEIO;
-       }
-
-       return 0;
-}
-
-static int dntv_live_dvbt_pro_tuner_set_params(struct dvb_frontend* fe,
-                                              struct dvb_frontend_parameters* params)
-{
-       struct cx8802_dev *dev= fe->dvb->priv;
-       u8 buf[4];
-       struct i2c_msg msg =
-               { .addr = dev->core->pll_addr, .flags = 0,
-                 .buf = buf, .len = 4 };
-       int err;
-
-       /* Switch PLL to DVB mode */
-       err = philips_fmd1216_pll_init(fe);
-       if (err)
-               return err;
-
-       /* Tune PLL */
-       dvb_pll_configure(dev->core->pll_desc, buf,
-                         params->frequency,
-                         params->u.ofdm.bandwidth);
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
-
-               printk(KERN_WARNING "cx88-dvb: %s error "
-                      "(addr %02x <- %02x, err = %i)\n",
-                      __FUNCTION__, dev->core->pll_addr, buf[0], err);
-               if (err < 0)
-                       return err;
-               else
-                       return -EREMOTEIO;
-       }
-
-       return 0;
-}
-
 static struct mt352_config dntv_live_dvbt_pro_config = {
        .demod_address = 0x0f,
        .no_tuner      = 1,
@@ -370,18 +310,8 @@ static int nxt200x_set_ts_param(struct dvb_frontend* fe, int is_punctured)
        return 0;
 }
 
-static int nxt200x_set_pll_input(u8* buf, int input)
-{
-       if (input)
-               buf[3] |= 0x08;
-       else
-               buf[3] &= ~0x08;
-       return 0;
-}
-
 static struct nxt200x_config ati_hdtvwonder = {
        .demod_address = 0x0a,
-       .set_pll_input = nxt200x_set_pll_input,
        .set_ts_params = nxt200x_set_ts_param,
 };
 
@@ -456,7 +386,7 @@ static int dvb_register(struct cx8802_dev *dev)
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
                                   &dev->core->i2c_adap,
-                                  &dvb_pll_thomson_dtt759x);
+                                  DVB_PLL_THOMSON_DTT759X);
                }
                break;
        case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
@@ -469,7 +399,7 @@ static int dvb_register(struct cx8802_dev *dev)
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
                                   &dev->core->i2c_adap,
-                                  &dvb_pll_thomson_dtt7579);
+                                  DVB_PLL_THOMSON_DTT7579);
                }
                break;
        case CX88_BOARD_WINFAST_DTV2000H:
@@ -482,7 +412,7 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  &dev->core->i2c_adap, &dvb_pll_fmd1216me);
+                                  &dev->core->i2c_adap, DVB_PLL_FMD1216ME);
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
@@ -491,7 +421,7 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
-                                  NULL, &dvb_pll_thomson_dtt7579);
+                                  NULL, DVB_PLL_THOMSON_DTT7579);
                        break;
                }
                /* ZL10353 replaces MT352 on later cards */
@@ -500,7 +430,7 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
-                                  NULL, &dvb_pll_thomson_dtt7579);
+                                  NULL, DVB_PLL_THOMSON_DTT7579);
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
@@ -511,7 +441,7 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, &dvb_pll_thomson_dtt7579);
+                                  NULL, DVB_PLL_THOMSON_DTT7579);
                        break;
                }
                /* ZL10353 replaces MT352 on later cards */
@@ -520,7 +450,7 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, &dvb_pll_thomson_dtt7579);
+                                  NULL, DVB_PLL_THOMSON_DTT7579);
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
@@ -529,7 +459,7 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, &dvb_pll_lg_z201);
+                                  NULL, DVB_PLL_LG_Z201);
                }
                break;
        case CX88_BOARD_KWORLD_DVB_T:
@@ -540,17 +470,16 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, &dvb_pll_unknown_1);
+                                  NULL, DVB_PLL_UNKNOWN_1);
                }
                break;
        case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
-               dev->core->pll_addr = 0x61;
-               dev->core->pll_desc = &dvb_pll_fmd1216me;
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
                dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
                        &((struct vp3054_i2c_state *)dev->card_priv)->adap);
                if (dev->dvb.frontend != NULL) {
-                       dev->dvb.frontend->ops.tuner_ops.set_params = dntv_live_dvbt_pro_tuner_set_params;
+                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+                                  &dev->core->i2c_adap, DVB_PLL_FMD1216ME);
                }
 #else
                printk("%s: built without vp3054 support\n", dev->core->name);
@@ -563,7 +492,7 @@ static int dvb_register(struct cx8802_dev *dev)
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
                                   &dev->core->i2c_adap,
-                                  &dvb_pll_thomson_fe6600);
+                                  DVB_PLL_THOMSON_FE6600);
                }
                break;
        case CX88_BOARD_PCHDTV_HD3000:
@@ -572,7 +501,7 @@ static int dvb_register(struct cx8802_dev *dev)
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
                                   &dev->core->i2c_adap,
-                                  &dvb_pll_thomson_dtt761x);
+                                  DVB_PLL_THOMSON_DTT761X);
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
@@ -594,7 +523,7 @@ static int dvb_register(struct cx8802_dev *dev)
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
                                   &dev->core->i2c_adap,
-                                  &dvb_pll_microtune_4042);
+                                  DVB_PLL_MICROTUNE_4042);
                }
                }
                break;
@@ -614,7 +543,7 @@ static int dvb_register(struct cx8802_dev *dev)
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
                                   &dev->core->i2c_adap,
-                                  &dvb_pll_thomson_dtt761x);
+                                  DVB_PLL_THOMSON_DTT761X);
                }
                }
                break;
@@ -634,7 +563,7 @@ static int dvb_register(struct cx8802_dev *dev)
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
                                   &dev->core->i2c_adap,
-                                  &dvb_pll_lg_tdvs_h06xf);
+                                  DVB_PLL_LG_TDVS_H06XF);
                }
                }
                break;
@@ -654,7 +583,7 @@ static int dvb_register(struct cx8802_dev *dev)
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
                                   &dev->core->i2c_adap,
-                                  &dvb_pll_lg_tdvs_h06xf);
+                                  DVB_PLL_LG_TDVS_H06XF);
                }
                }
                break;
@@ -664,7 +593,7 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, &dvb_pll_tuv1236d);
+                                  NULL, DVB_PLL_TUV1236D);
                }
                break;
        case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
@@ -705,10 +634,6 @@ static int dvb_register(struct cx8802_dev *dev)
                return -1;
        }
 
-       if (dev->core->pll_desc) {
-               dev->dvb.frontend->ops.info.frequency_min = dev->core->pll_desc->min;
-               dev->dvb.frontend->ops.info.frequency_max = dev->core->pll_desc->max;
-       }
        /* Ensure all frontends negotiate bus access */
        dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
 
@@ -778,11 +703,10 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
        if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB))
                goto fail_core;
 
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
+       /* If vp3054 isn't enabled, a stub will just return 0 */
        err = vp3054_i2c_probe(dev);
        if (0 != err)
                goto fail_core;
-#endif
 
        /* dvb stuff */
        printk("%s/2: cx2388x based dvb card\n", core->name);
@@ -807,9 +731,7 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv)
        /* dvb */
        videobuf_dvb_unregister(&dev->dvb);
 
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
        vp3054_i2c_remove(dev);
-#endif
 
        return 0;
 }
index 7919a1f9da06a19e7e5161e0fc8876bdeca09a4f..78bbcfab96700ba9019c20a383db1f5ab5dc5984 100644 (file)
@@ -160,7 +160,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
                i2c_clients_command(&core->i2c_adap, cmd, arg);
 }
 
-static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
+static const struct i2c_algo_bit_data cx8800_i2c_algo_template = {
        .setsda  = cx8800_bit_setsda,
        .setscl  = cx8800_bit_setscl,
        .getsda  = cx8800_bit_getsda,
@@ -171,18 +171,6 @@ static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_adapter cx8800_i2c_adap_template = {
-       .name              = "cx2388x",
-       .owner             = THIS_MODULE,
-       .id                = I2C_HW_B_CX2388x,
-       .client_register   = attach_inform,
-       .client_unregister = detach_inform,
-};
-
-static struct i2c_client cx8800_i2c_client_template = {
-       .name   = "cx88xx internal",
-};
-
 static char *i2c_devs[128] = {
        [ 0x1c >> 1 ] = "lgdt330x",
        [ 0x86 >> 1 ] = "tda9887/cx22702",
@@ -212,14 +200,9 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
        /* Prevents usage of invalid delay values */
        if (i2c_udelay<5)
                i2c_udelay=5;
-       cx8800_i2c_algo_template.udelay=i2c_udelay;
 
-       memcpy(&core->i2c_adap, &cx8800_i2c_adap_template,
-              sizeof(core->i2c_adap));
        memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
               sizeof(core->i2c_algo));
-       memcpy(&core->i2c_client, &cx8800_i2c_client_template,
-              sizeof(core->i2c_client));
 
        if (core->tuner_type != TUNER_ABSENT)
                core->i2c_adap.class |= I2C_CLASS_TV_ANALOG;
@@ -228,10 +211,16 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
 
        core->i2c_adap.dev.parent = &pci->dev;
        strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
+       core->i2c_adap.owner = THIS_MODULE;
+       core->i2c_adap.id = I2C_HW_B_CX2388x;
+       core->i2c_adap.client_register = attach_inform;
+       core->i2c_adap.client_unregister = detach_inform;
+       core->i2c_algo.udelay = i2c_udelay;
        core->i2c_algo.data = core;
        i2c_set_adapdata(&core->i2c_adap,core);
        core->i2c_adap.algo_data = &core->i2c_algo;
        core->i2c_client.adapter = &core->i2c_adap;
+       strlcpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE);
 
        cx8800_bit_setscl(core,1);
        cx8800_bit_setsda(core,1);
index 8136673fe9e8b5d8d3551748dd7bc50c2c020685..f5d4a565346e30cb43c2d7d41b5c07b9cee7a9ae 100644 (file)
@@ -74,7 +74,8 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
 
        /* read gpio value */
        gpio = cx_read(ir->gpio_addr);
-       if (core->board == CX88_BOARD_NPGTECH_REALTV_TOP10FM) {
+       switch (core->board) {
+       case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
                /* This board apparently uses a combination of 2 GPIO
                   to represent the keys. Additionally, the second GPIO
                   can be used for parity.
@@ -90,9 +91,14 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
                auxgpio = cx_read(MO_GP1_IO);
                /* Take out the parity part */
                gpio=(gpio & 0x7fd) + (auxgpio & 0xef);
-       } else
+               break;
+       case CX88_BOARD_WINFAST_DTV1000:
+               gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
                auxgpio = gpio;
-
+               break;
+       default:
+               auxgpio = gpio;
+       }
        if (ir->polling) {
                if (ir->last_gpio == auxgpio)
                        return;
@@ -148,20 +154,16 @@ static void ir_timer(unsigned long data)
 static void cx88_ir_work(struct work_struct *work)
 {
        struct cx88_IR *ir = container_of(work, struct cx88_IR, work);
-       unsigned long timeout;
 
        cx88_ir_handle_key(ir);
-       timeout = jiffies + (ir->polling * HZ / 1000);
-       mod_timer(&ir->timer, timeout);
+       mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
 }
 
 static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
 {
        if (ir->polling) {
+               setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
                INIT_WORK(&ir->work, cx88_ir_work);
-               init_timer(&ir->timer);
-               ir->timer.function = ir_timer;
-               ir->timer.data = (unsigned long)ir;
                schedule_work(&ir->work);
        }
        if (ir->sampling) {
@@ -222,7 +224,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
        case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
        case CX88_BOARD_HAUPPAUGE_HVR1100:
-       case CX88_BOARD_HAUPPAUGE_HVR1300:
        case CX88_BOARD_HAUPPAUGE_HVR3000:
                ir_codes = ir_codes_hauppauge_new;
                ir_type = IR_TYPE_RC5;
@@ -236,6 +237,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                ir->polling = 50; /* ms */
                break;
        case CX88_BOARD_WINFAST2000XP_EXPERT:
+       case CX88_BOARD_WINFAST_DTV1000:
                ir_codes = ir_codes_winfast;
                ir->gpio_addr = MO_GP0_IO;
                ir->mask_keycode = 0x8f8;
@@ -328,7 +330,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                input_dev->id.vendor = pci->vendor;
                input_dev->id.product = pci->device;
        }
-       input_dev->cdev.dev = &pci->dev;
+       input_dev->dev.parent = &pci->dev;
        /* record handles to ourself */
        ir->core = core;
        core->ir = ir;
@@ -442,7 +444,6 @@ void cx88_ir_irq(struct cx88_core *core)
        case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
        case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
        case CX88_BOARD_HAUPPAUGE_HVR1100:
-       case CX88_BOARD_HAUPPAUGE_HVR1300:
        case CX88_BOARD_HAUPPAUGE_HVR3000:
                ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
                ir_dprintk("biphase decoded: %x\n", ircode);
index 543b05ebc0e79ba74851f2a7c4b4180bde2d1e93..317a2a3f9cc1bdd59d923306febe9d901e3742f6 100644 (file)
@@ -336,7 +336,7 @@ static void cx8802_timeout(unsigned long data)
 {
        struct cx8802_dev *dev = (struct cx8802_dev*)data;
 
-       dprintk(0, "%s\n",__FUNCTION__);
+       dprintk(1, "%s\n",__FUNCTION__);
 
        if (debug)
                cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
index 82bc3a28aa22941ad7aa0617ece154c910e17880..cd0877636a322faaedf9446e4deeffb9485681e8 100644 (file)
@@ -94,7 +94,7 @@ static int vp3054_bit_getsda(void *data)
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_algo_bit_data vp3054_i2c_algo_template = {
+static const struct i2c_algo_bit_data vp3054_i2c_algo_template = {
        .setsda  = vp3054_bit_setsda,
        .setscl  = vp3054_bit_setscl,
        .getsda  = vp3054_bit_getsda,
@@ -105,12 +105,6 @@ static struct i2c_algo_bit_data vp3054_i2c_algo_template = {
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_adapter vp3054_i2c_adap_template = {
-       .name              = "cx2388x",
-       .owner             = THIS_MODULE,
-       .id                = I2C_HW_B_CX2388x,
-};
-
 int vp3054_i2c_probe(struct cx8802_dev *dev)
 {
        struct cx88_core *core = dev->core;
@@ -125,8 +119,6 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
                return -ENOMEM;
        vp3054_i2c = dev->card_priv;
 
-       memcpy(&vp3054_i2c->adap, &vp3054_i2c_adap_template,
-              sizeof(vp3054_i2c->adap));
        memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template,
               sizeof(vp3054_i2c->algo));
 
@@ -135,6 +127,8 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
        vp3054_i2c->adap.dev.parent = &dev->pci->dev;
        strlcpy(vp3054_i2c->adap.name, core->name,
                sizeof(vp3054_i2c->adap.name));
+       vp3054_i2c->adap.owner = THIS_MODULE;
+       vp3054_i2c->adap.id = I2C_HW_B_CX2388x;
        vp3054_i2c->algo.data = dev;
        i2c_set_adapdata(&vp3054_i2c->adap, dev);
        vp3054_i2c->adap.algo_data = &vp3054_i2c->algo;
index 637a7d2322389c79ac161981e1ce6fcd9b7ebf7c..be99c931dc3e24a2e686261a66a0e822677dbc5c 100644 (file)
@@ -30,5 +30,12 @@ struct vp3054_i2c_state {
 };
 
 /* ----------------------------------------------------------------------- */
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
 int  vp3054_i2c_probe(struct cx8802_dev *dev);
 void vp3054_i2c_remove(struct cx8802_dev *dev);
+#else
+static inline int  vp3054_i2c_probe(struct cx8802_dev *dev)
+{ return 0; }
+static inline void vp3054_i2c_remove(struct cx8802_dev *dev)
+{ }
+#endif
index 738d4f20c580da46fd1ba215d4c0ce9f563568c9..c4f656ec46b04b1faeaf09ddc7342135f0d4a371 100644 (file)
@@ -209,6 +209,7 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_NORWOOD_MICRO           54
 #define CX88_BOARD_TE_DTV_250_OEM_SWANN    55
 #define CX88_BOARD_HAUPPAUGE_HVR1300       56
+#define CX88_BOARD_ADSTECH_PTV_390         57
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
@@ -316,8 +317,6 @@ struct cx88_core {
 
        /* config info -- dvb */
 #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
-       struct dvb_pll_desc        *pll_desc;
-       unsigned int               pll_addr;
        int                        (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
 #endif
 
@@ -463,13 +462,10 @@ struct cx8802_dev {
        u32                        mailbox;
        int                        width;
        int                        height;
-       int                        fw_size;
 
 #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
        /* for dvb only */
        struct videobuf_dvb        dvb;
-       void*                      fe_handle;
-       int                        (*fe_release)(void *handle);
 
        void                       *card_priv;
 #endif
index 664676f440685cdc0f405ba97a84560e5f132811..dcc1a033544001b44e476614fce6799eb1121317 100644 (file)
@@ -1,6 +1,6 @@
 config USB_ET61X251
        tristate "USB ET61X[12]51 PC Camera Controller support"
-       depends on VIDEO_V4L1
+       depends on VIDEO_V4L2
        ---help---
          Say Y here if you want support for cameras based on Etoms ET61X151
          or ET61X251 PC Camera Controllers.
index 262f98e124099ad381db8c461ab8b1527c156e88..02c741d8f85a55a7e2b965922610c7b4ae09733c 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/mutex.h>
 #include <linux/stddef.h>
 #include <linux/string.h>
+#include <linux/kref.h>
 
 #include "et61x251_sensor.h"
 
@@ -134,7 +135,7 @@ struct et61x251_module_param {
 };
 
 static DEFINE_MUTEX(et61x251_sysfs_lock);
-static DECLARE_RWSEM(et61x251_disconnect);
+static DECLARE_RWSEM(et61x251_dev_lock);
 
 struct et61x251_device {
        struct video_device* v4ldev;
@@ -158,12 +159,14 @@ struct et61x251_device {
        struct et61x251_sysfs_attr sysfs;
        struct et61x251_module_param module_param;
 
+       struct kref kref;
        enum et61x251_dev_state state;
        u8 users;
 
-       struct mutex dev_mutex, fileop_mutex;
+       struct completion probe;
+       struct mutex open_mutex, fileop_mutex;
        spinlock_t queue_lock;
-       wait_queue_head_t open, wait_frame, wait_stream;
+       wait_queue_head_t wait_open, wait_frame, wait_stream;
 };
 
 /*****************************************************************************/
@@ -177,7 +180,7 @@ et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
 
 void
 et61x251_attach_sensor(struct et61x251_device* cam,
-                      struct et61x251_sensor* sensor)
+                      const struct et61x251_sensor* sensor)
 {
        memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
 }
@@ -195,8 +198,8 @@ do {                                                                          \
                else if ((level) == 2)                                        \
                        dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
                else if ((level) >= 3)                                        \
-                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
-                                __FUNCTION__, __LINE__ , ## args);           \
+                       dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n",   \
+                                __FILE__, __FUNCTION__, __LINE__ , ## args); \
        }                                                                     \
 } while (0)
 #      define KDBG(level, fmt, args...)                                      \
@@ -205,8 +208,8 @@ do {                                                                          \
                if ((level) == 1 || (level) == 2)                             \
                        pr_info("et61x251: " fmt "\n", ## args);              \
                else if ((level) == 3)                                        \
-                       pr_debug("et61x251: [%s:%d] " fmt "\n", __FUNCTION__, \
-                                __LINE__ , ## args);                         \
+                       pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__,   \
+                                __FUNCTION__, __LINE__ , ## args);           \
        }                                                                     \
 } while (0)
 #      define V4LDBG(level, name, cmd)                                       \
@@ -222,8 +225,8 @@ do {                                                                          \
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
-        __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__,   \
+        __LINE__ , ## args)
 
 #undef PDBGG
 #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
index a6525513cd1e12492248ade25f8274949003cfd8..585bd1fe0765540172114278baad8fd096416492 100644 (file)
 
 #define ET61X251_MODULE_NAME    "V4L2 driver for ET61X[12]51 "                \
                                "PC Camera Controllers"
-#define ET61X251_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
+#define ET61X251_MODULE_AUTHOR  "(C) 2006-2007 Luca Risolia"
 #define ET61X251_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
 #define ET61X251_MODULE_LICENSE "GPL"
-#define ET61X251_MODULE_VERSION "1:1.04"
-#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 4)
+#define ET61X251_MODULE_VERSION "1:1.09"
+#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 9)
 
 /*****************************************************************************/
 
@@ -245,7 +245,8 @@ int et61x251_read_reg(struct et61x251_device* cam, u16 index)
 
 
 static int
-et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor)
+et61x251_i2c_wait(struct et61x251_device* cam,
+                 const struct et61x251_sensor* sensor)
 {
        int i, r;
 
@@ -270,7 +271,7 @@ et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor)
 
 int
 et61x251_i2c_try_read(struct et61x251_device* cam,
-                     struct et61x251_sensor* sensor, u8 address)
+                     const struct et61x251_sensor* sensor, u8 address)
 {
        struct usb_device* udev = cam->usbdev;
        u8* data = cam->control_buffer;
@@ -303,7 +304,8 @@ et61x251_i2c_try_read(struct et61x251_device* cam,
 
 int
 et61x251_i2c_try_write(struct et61x251_device* cam,
-                      struct et61x251_sensor* sensor, u8 address, u8 value)
+                      const struct et61x251_sensor* sensor, u8 address,
+                      u8 value)
 {
        struct usb_device* udev = cam->usbdev;
        u8* data = cam->control_buffer;
@@ -615,7 +617,7 @@ static int et61x251_start_transfer(struct et61x251_device* cam)
        return 0;
 
 free_urbs:
-       for (i = 0; (i < ET61X251_URBS) &&  cam->urb[i]; i++)
+       for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++)
                usb_free_urb(cam->urb[i]);
 
 free_buffers:
@@ -682,7 +684,7 @@ static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)
 
        if (len < 4) {
                strncpy(str, buff, len);
-               str[len+1] = '\0';
+               str[len] = '\0';
        } else {
                strncpy(str, buff, 4);
                str[4] = '\0';
@@ -977,30 +979,30 @@ static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
 
 static int et61x251_create_sysfs(struct et61x251_device* cam)
 {
-       struct video_device *v4ldev = cam->v4ldev;
+       struct class_device *classdev = &(cam->v4ldev->class_dev);
        int err = 0;
 
-       if ((err = video_device_create_file(v4ldev, &class_device_attr_reg)))
+       if ((err = class_device_create_file(classdev, &class_device_attr_reg)))
                goto err_out;
-       if ((err = video_device_create_file(v4ldev, &class_device_attr_val)))
+       if ((err = class_device_create_file(classdev, &class_device_attr_val)))
                goto err_reg;
 
        if (cam->sensor.sysfs_ops) {
-               if ((err = video_device_create_file(v4ldev,
+               if ((err = class_device_create_file(classdev,
                                                  &class_device_attr_i2c_reg)))
                        goto err_val;
-               if ((err = video_device_create_file(v4ldev,
+               if ((err = class_device_create_file(classdev,
                                                  &class_device_attr_i2c_val)))
                        goto err_i2c_reg;
        }
 
 err_i2c_reg:
        if (cam->sensor.sysfs_ops)
-       video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
+               class_device_remove_file(classdev, &class_device_attr_i2c_reg);
 err_val:
-       video_device_remove_file(v4ldev, &class_device_attr_val);
+       class_device_remove_file(classdev, &class_device_attr_val);
 err_reg:
-       video_device_remove_file(v4ldev, &class_device_attr_reg);
+       class_device_remove_file(classdev, &class_device_attr_reg);
 err_out:
        return err;
 }
@@ -1103,7 +1105,8 @@ static int et61x251_init(struct et61x251_device* cam)
        int err = 0;
 
        if (!(cam->state & DEV_INITIALIZED)) {
-               init_waitqueue_head(&cam->open);
+               mutex_init(&cam->open_mutex);
+               init_waitqueue_head(&cam->wait_open);
                qctrl = s->qctrl;
                rect = &(s->cropcap.defrect);
                cam->compression.quality = ET61X251_COMPRESSION_QUALITY;
@@ -1177,64 +1180,80 @@ static int et61x251_init(struct et61x251_device* cam)
        return 0;
 }
 
+/*****************************************************************************/
 
-static void et61x251_release_resources(struct et61x251_device* cam)
+static void et61x251_release_resources(struct kref *kref)
 {
+       struct et61x251_device *cam;
+
        mutex_lock(&et61x251_sysfs_lock);
 
+       cam = container_of(kref, struct et61x251_device, kref);
+
        DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
        video_set_drvdata(cam->v4ldev, NULL);
        video_unregister_device(cam->v4ldev);
+       usb_put_dev(cam->usbdev);
+       kfree(cam->control_buffer);
+       kfree(cam);
 
        mutex_unlock(&et61x251_sysfs_lock);
-
-       kfree(cam->control_buffer);
 }
 
-/*****************************************************************************/
 
 static int et61x251_open(struct inode* inode, struct file* filp)
 {
        struct et61x251_device* cam;
        int err = 0;
 
-       /*
-          This is the only safe way to prevent race conditions with
-          disconnect
-       */
-       if (!down_read_trylock(&et61x251_disconnect))
+       if (!down_read_trylock(&et61x251_dev_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(video_devdata(filp));
 
-       if (mutex_lock_interruptible(&cam->dev_mutex)) {
-               up_read(&et61x251_disconnect);
+       if (wait_for_completion_interruptible(&cam->probe)) {
+               up_read(&et61x251_dev_lock);
                return -ERESTARTSYS;
        }
 
+       kref_get(&cam->kref);
+
+       if (mutex_lock_interruptible(&cam->open_mutex)) {
+               kref_put(&cam->kref, et61x251_release_resources);
+               up_read(&et61x251_dev_lock);
+               return -ERESTARTSYS;
+       }
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               err = -ENODEV;
+               goto out;
+       }
+
        if (cam->users) {
-               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+               DBG(2, "Device /dev/video%d is already in use",
+                      cam->v4ldev->minor);
+               DBG(3, "Simultaneous opens are not supported");
                if ((filp->f_flags & O_NONBLOCK) ||
                    (filp->f_flags & O_NDELAY)) {
                        err = -EWOULDBLOCK;
                        goto out;
                }
-               mutex_unlock(&cam->dev_mutex);
-               err = wait_event_interruptible_exclusive(cam->open,
-                                                 cam->state & DEV_DISCONNECTED
+               DBG(2, "A blocking open() has been requested. Wait for the "
+                      "device to be released...");
+               up_read(&et61x251_dev_lock);
+               err = wait_event_interruptible_exclusive(cam->wait_open,
+                                               (cam->state & DEV_DISCONNECTED)
                                                         || !cam->users);
-               if (err) {
-                       up_read(&et61x251_disconnect);
-                       return err;
-               }
+               down_read(&et61x251_dev_lock);
+               if (err)
+                       goto out;
                if (cam->state & DEV_DISCONNECTED) {
-                       up_read(&et61x251_disconnect);
-                       return -ENODEV;
+                       err = -ENODEV;
+                       goto out;
                }
-               mutex_lock(&cam->dev_mutex);
        }
 
-
        if (cam->state & DEV_MISCONFIGURED) {
                err = et61x251_init(cam);
                if (err) {
@@ -1259,36 +1278,32 @@ static int et61x251_open(struct inode* inode, struct file* filp)
        DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
 
 out:
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&et61x251_disconnect);
+       mutex_unlock(&cam->open_mutex);
+       if (err)
+               kref_put(&cam->kref, et61x251_release_resources);
+       up_read(&et61x251_dev_lock);
        return err;
 }
 
 
 static int et61x251_release(struct inode* inode, struct file* filp)
 {
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       struct et61x251_device* cam;
 
-       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+       down_write(&et61x251_dev_lock);
 
-       et61x251_stop_transfer(cam);
+       cam = video_get_drvdata(video_devdata(filp));
 
+       et61x251_stop_transfer(cam);
        et61x251_release_buffers(cam);
-
-       if (cam->state & DEV_DISCONNECTED) {
-               et61x251_release_resources(cam);
-               usb_put_dev(cam->usbdev);
-               mutex_unlock(&cam->dev_mutex);
-               kfree(cam);
-               return 0;
-       }
-
        cam->users--;
-       wake_up_interruptible_nr(&cam->open, 1);
+       wake_up_interruptible_nr(&cam->wait_open, 1);
 
        DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
 
-       mutex_unlock(&cam->dev_mutex);
+       kref_put(&cam->kref, et61x251_release_resources);
+
+       up_write(&et61x251_dev_lock);
 
        return 0;
 }
@@ -1324,7 +1339,7 @@ et61x251_read(struct file* filp, char __user * buf,
                DBG(3, "Close and open the device again to choose the read "
                       "method");
                mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
+               return -EBUSY;
        }
 
        if (cam->io == IO_NONE) {
@@ -1504,7 +1519,12 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
                return -EIO;
        }
 
-       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+       if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EACCES;
+       }
+
+       if (cam->io != IO_MMAP ||
            size != PAGE_ALIGN(cam->frame[0].buf.length)) {
                mutex_unlock(&cam->fileop_mutex);
                return -EINVAL;
@@ -1535,7 +1555,6 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
 
        vma->vm_ops = &et61x251_vm_ops;
        vma->vm_private_data = &cam->frame[i];
-
        et61x251_vm_open(vma);
 
        mutex_unlock(&cam->fileop_mutex);
@@ -1764,7 +1783,7 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
                        if (cam->frame[i].vma_use_count) {
                                DBG(3, "VIDIOC_S_CROP failed. "
                                       "Unmap the buffers first.");
-                               return -EINVAL;
+                               return -EBUSY;
                        }
 
        /* Preserve R,G or B origin */
@@ -1921,6 +1940,8 @@ et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg)
        if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
+       pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_ET61X251) ?
+                          0 : V4L2_COLORSPACE_SRGB;
        pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251)
                             ? 0 : (pfmt->width * pfmt->priv) / 8;
        pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
@@ -1996,6 +2017,8 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
            pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
                pix->pixelformat = pfmt->pixelformat;
        pix->priv = pfmt->priv; /* bpp */
+       pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) ?
+                         0 : V4L2_COLORSPACE_SRGB;
        pix->colorspace = pfmt->colorspace;
        pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
                            ? 0 : (pix->width * pix->priv) / 8;
@@ -2013,7 +2036,7 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
                        if (cam->frame[i].vma_use_count) {
                                DBG(3, "VIDIOC_S_FMT failed. "
                                       "Unmap the buffers first.");
-                               return -EINVAL;
+                               return -EBUSY;
                        }
 
        if (cam->stream == STREAM_ON)
@@ -2129,14 +2152,14 @@ et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg)
        if (cam->io == IO_READ) {
                DBG(3, "Close and open the device again to choose the mmap "
                       "I/O method");
-               return -EINVAL;
+               return -EBUSY;
        }
 
        for (i = 0; i < cam->nbuffers; i++)
                if (cam->frame[i].vma_use_count) {
                        DBG(3, "VIDIOC_REQBUFS failed. "
                               "Previous buffers are still mapped.");
-                       return -EINVAL;
+                       return -EBUSY;
                }
 
        if (cam->stream == STREAM_ON)
@@ -2284,9 +2307,6 @@ et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg)
        if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
                return -EINVAL;
 
-       if (list_empty(&cam->inqueue))
-               return -EINVAL;
-
        cam->stream = STREAM_ON;
 
        DBG(3, "Stream on");
@@ -2535,8 +2555,6 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                goto fail;
        }
 
-       mutex_init(&cam->dev_mutex);
-
        DBG(2, "ET61X[12]51 PC Camera Controller detected "
               "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
 
@@ -2568,7 +2586,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        cam->v4ldev->release = video_device_release;
        video_set_drvdata(cam->v4ldev, cam);
 
-       mutex_lock(&cam->dev_mutex);
+       init_completion(&cam->probe);
 
        err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
                                    video_nr[dev_nr]);
@@ -2578,7 +2596,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                        DBG(1, "Free /dev/videoX node not found");
                video_nr[dev_nr] = -1;
                dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               mutex_unlock(&cam->dev_mutex);
+               complete_all(&cam->probe);
                goto fail;
        }
 
@@ -2599,11 +2617,15 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                       "device controlling. Error #%d", err);
 #else
        DBG(2, "Optional device control through 'sysfs' interface disabled");
+       DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' "
+              "configuration option to enable it.");
 #endif
 
        usb_set_intfdata(intf, cam);
+       kref_init(&cam->kref);
+       usb_get_dev(cam->usbdev);
 
-       mutex_unlock(&cam->dev_mutex);
+       complete_all(&cam->probe);
 
        return 0;
 
@@ -2620,40 +2642,31 @@ fail:
 
 static void et61x251_usb_disconnect(struct usb_interface* intf)
 {
-       struct et61x251_device* cam = usb_get_intfdata(intf);
-
-       if (!cam)
-               return;
+       struct et61x251_device* cam;
 
-       down_write(&et61x251_disconnect);
+       down_write(&et61x251_dev_lock);
 
-       mutex_lock(&cam->dev_mutex);
+       cam = usb_get_intfdata(intf);
 
        DBG(2, "Disconnecting %s...", cam->v4ldev->name);
 
-       wake_up_interruptible_all(&cam->open);
-
        if (cam->users) {
                DBG(2, "Device /dev/video%d is open! Deregistration and "
-                      "memory deallocation are deferred on close.",
+                      "memory deallocation are deferred.",
                    cam->v4ldev->minor);
                cam->state |= DEV_MISCONFIGURED;
                et61x251_stop_transfer(cam);
                cam->state |= DEV_DISCONNECTED;
                wake_up_interruptible(&cam->wait_frame);
                wake_up(&cam->wait_stream);
-               usb_get_dev(cam->usbdev);
-       } else {
+       } else
                cam->state |= DEV_DISCONNECTED;
-               et61x251_release_resources(cam);
-       }
 
-       mutex_unlock(&cam->dev_mutex);
+       wake_up_interruptible_all(&cam->wait_open);
 
-       if (!cam->users)
-               kfree(cam);
+       kref_put(&cam->kref, et61x251_release_resources);
 
-       up_write(&et61x251_disconnect);
+       up_write(&et61x251_dev_lock);
 }
 
 
index 5fadb5de68bf65e85d16784b7eb484509bf19247..e1458633062351d337f569681dc5e92870844618 100644 (file)
@@ -22,7 +22,7 @@
 #define _ET61X251_SENSOR_H_
 
 #include <linux/usb.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <linux/device.h>
 #include <linux/stddef.h>
 #include <linux/errno.h>
@@ -47,7 +47,7 @@ et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id);
 
 extern void
 et61x251_attach_sensor(struct et61x251_device* cam,
-                      struct et61x251_sensor* sensor);
+                      const struct et61x251_sensor* sensor);
 
 /*****************************************************************************/
 
@@ -56,10 +56,10 @@ extern int et61x251_read_reg(struct et61x251_device*, u16 index);
 extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value);
 extern int et61x251_i2c_read(struct et61x251_device*, u8 address);
 extern int et61x251_i2c_try_write(struct et61x251_device*,
-                                 struct et61x251_sensor*, u8 address,
+                                 const struct et61x251_sensor*, u8 address,
                                  u8 value);
 extern int et61x251_i2c_try_read(struct et61x251_device*,
-                                struct et61x251_sensor*, u8 address);
+                                const struct et61x251_sensor*, u8 address);
 extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
                                  u8 data2, u8 data3, u8 data4, u8 data5,
                                  u8 data6, u8 data7, u8 data8, u8 address);
index b066434098426d57859b4f73615a49f4c157cb26..04b7fbb310a82d6d7737c57846d325f651f4f367 100644 (file)
@@ -69,7 +69,7 @@ static int tas5130d1b_set_ctrl(struct et61x251_device* cam,
 }
 
 
-static struct et61x251_sensor tas5130d1b = {
+static const struct et61x251_sensor tas5130d1b = {
        .name = "TAS5130D1B",
        .interface = ET61X251_I2C_3WIRES,
        .rsta = ET61X251_I2C_RSTA_STOP,
index ed92b6f7187a6eac7b3e5da338b20995abc2a0bb..2d709e064679249e5567097cfe2515aaec6719a1 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/i2c-id.h>
 #include <linux/workqueue.h>
 #include <asm/semaphore.h>
 
@@ -60,21 +61,22 @@ MODULE_PARM_DESC(hauppauge, "Specify Hauppauge remote: 0=black, 1=grey (defaults
 
 /* ----------------------------------------------------------------------- */
 
-static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
+                              int size, int offset)
 {
-       unsigned char buf[3];
+       unsigned char buf[6];
        int start, range, toggle, dev, code;
 
        /* poll IR chip */
-       if (3 != i2c_master_recv(&ir->c,buf,3))
+       if (size != i2c_master_recv(&ir->c,buf,size))
                return -EIO;
 
        /* split rc5 data block ... */
-       start  = (buf[0] >> 7) &    1;
-       range  = (buf[0] >> 6) &    1;
-       toggle = (buf[0] >> 5) &    1;
-       dev    =  buf[0]       & 0x1f;
-       code   = (buf[1] >> 2) & 0x3f;
+       start  = (buf[offset] >> 7) &    1;
+       range  = (buf[offset] >> 6) &    1;
+       toggle = (buf[offset] >> 5) &    1;
+       dev    =  buf[offset]       & 0x1f;
+       code   = (buf[offset+1] >> 2) & 0x3f;
 
        /* rc5 has two start bits
         * the first bit must be one
@@ -96,6 +98,16 @@ static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        return 1;
 }
 
+static inline int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+       return get_key_haup_common (ir, ir_key, ir_raw, 3, 0);
+}
+
+static inline int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+       return get_key_haup_common (ir, ir_key, ir_raw, 6, 3);
+}
+
 static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
        unsigned char b;
@@ -270,8 +282,9 @@ static void ir_timer(unsigned long data)
 static void ir_work(struct work_struct *work)
 {
        struct IR_i2c *ir = container_of(work, struct IR_i2c, work);
+
        ir_key_poll(ir);
-       mod_timer(&ir->timer, jiffies+HZ/10);
+       mod_timer(&ir->timer, jiffies + msecs_to_jiffies(100));
 }
 
 /* ----------------------------------------------------------------------- */
@@ -354,9 +367,21 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
        case 0x7a:
        case 0x47:
        case 0x71:
-               /* Handled by saa7134-input */
-               name        = "SAA713x remote";
-               ir_type     = IR_TYPE_OTHER;
+               if (adap->id == I2C_HW_B_CX2388x) {
+                       /* Handled by cx88-input */
+                       name        = "CX2388x remote";
+                       ir_type     = IR_TYPE_RC5;
+                       ir->get_key = get_key_haup_xvr;
+                       if (hauppauge == 1) {
+                               ir_codes    = ir_codes_hauppauge_new;
+                       } else {
+                               ir_codes    = ir_codes_rc5_tv;
+                       }
+               } else {
+                       /* Handled by saa7134-input */
+                       name        = "SAA713x remote";
+                       ir_type     = IR_TYPE_OTHER;
+               }
                break;
        default:
                /* shouldn't happen */
@@ -450,6 +475,7 @@ static int ir_probe(struct i2c_adapter *adap)
        static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
        static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 };
        static const int probe_em28XX[] = { 0x30, 0x47, -1 };
+       static const int probe_cx88[] = { 0x18, 0x71, -1 };
        const int *probe = NULL;
        struct i2c_client c;
        unsigned char buf;
@@ -468,6 +494,9 @@ static int ir_probe(struct i2c_adapter *adap)
        case I2C_HW_B_EM28XX:
                probe = probe_em28XX;
                break;
+       case I2C_HW_B_CX2388x:
+               probe = probe_cx88;
+               break;
        }
        if (NULL == probe)
                return 0;
index efc66355339ac7f8aa6d693c753c20afd006b594..4c93466a89e52402ce32fb17a18293a910691c01 100644 (file)
@@ -181,7 +181,7 @@ MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC");
 MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K");
 MODULE_PARM_DESC(debug,
                 "Debug level (bitmask). Default: errors only\n"
-                "\t\t\t(debug = 511 gives full debugging)");
+                "\t\t\t(debug = 1023 gives full debugging)");
 MODULE_PARM_DESC(ivtv_pci_latency,
                 "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
                 "\t\t\tDefault: Yes");
@@ -339,6 +339,7 @@ static void ivtv_process_eeprom(struct ivtv *itv)
                /* In a few cases the PCI subsystem IDs do not correctly
                   identify the card. A better method is to check the
                   model number from the eeprom instead. */
+               case 30012 ... 30039:  /* Low profile PVR250 */
                case 32000 ... 32999:
                case 48000 ... 48099:  /* 48??? range are PVR250s with a cx23415 */
                case 48400 ... 48599:
@@ -622,6 +623,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
        itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */
        itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */
 
+       mutex_init(&itv->serialize_lock);
        mutex_init(&itv->i2c_bus_lock);
        mutex_init(&itv->udma.lock);
 
@@ -1288,10 +1290,7 @@ static void ivtv_remove(struct pci_dev *pci_dev)
 
        IVTV_DEBUG_INFO(" Releasing irq.\n");
        free_irq(itv->dev->irq, (void *)itv);
-
-       if (itv->dev) {
-               ivtv_iounmap(itv);
-       }
+       ivtv_iounmap(itv);
 
        IVTV_DEBUG_INFO(" Releasing mem.\n");
        release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
@@ -1326,9 +1325,9 @@ static int module_start(void)
                return -1;
        }
 
-       if (ivtv_debug < 0 || ivtv_debug > 511) {
+       if (ivtv_debug < 0 || ivtv_debug > 1023) {
                ivtv_debug = 0;
-               printk(KERN_INFO "ivtv:  debug value must be >= 0 and <= 511!\n");
+               printk(KERN_INFO "ivtv:  debug value must be >= 0 and <= 1023!\n");
        }
 
        if (pci_register_driver(&ivtv_pci_driver)) {
index e6e56f175f3fe1a1da7b2b96849795256d851ce5..6c1a85f1ee1b966daea6ff93321a6ce37481ce10 100644 (file)
@@ -268,6 +268,8 @@ extern const u32 yuv_offset[4];
 #define IVTV_DBGFLG_IRQ   (1 << 6)
 #define IVTV_DBGFLG_DEC   (1 << 7)
 #define IVTV_DBGFLG_YUV   (1 << 8)
+/* Flag to turn on high volume debugging */
+#define IVTV_DBGFLG_HIGHVOL (1 << 9)
 
 /* NOTE: extra space before comma in 'itv->num , ## args' is required for
    gcc-2.95, otherwise it won't compile. */
@@ -286,6 +288,21 @@ extern const u32 yuv_offset[4];
 #define IVTV_DEBUG_DEC(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
 #define IVTV_DEBUG_YUV(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
 
+#define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \
+       do { \
+               if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \
+                       printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \
+       } while (0)
+#define IVTV_DEBUG_HI_WARN(fmt, args...)  IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warning", fmt , ## args)
+#define IVTV_DEBUG_HI_INFO(fmt, args...)  IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info",fmt , ## args)
+#define IVTV_DEBUG_HI_API(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_API, "api", fmt , ## args)
+#define IVTV_DEBUG_HI_DMA(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args)
+#define IVTV_DEBUG_HI_IOCTL(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define IVTV_DEBUG_HI_I2C(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args)
+#define IVTV_DEBUG_HI_IRQ(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args)
+#define IVTV_DEBUG_HI_DEC(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
+#define IVTV_DEBUG_HI_YUV(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
+
 #define IVTV_FB_DEBUG(x, type, fmt, args...) \
        do { \
                if ((x) & ivtv_debug) \
@@ -650,7 +667,6 @@ struct vbi_info {
        /* convenience pointer to sliced struct in vbi_in union */
        struct v4l2_sliced_vbi_format *sliced_in;
        u32 service_set_in;
-       u32 service_set_out;
        int insert_mpeg;
 
        /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
@@ -723,6 +739,7 @@ struct ivtv {
        int search_pack_header;
 
        spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
+       struct mutex serialize_lock;  /* lock used to serialize starting streams */
 
        /* User based DMA for OSD */
        struct ivtv_user_dma udma;
index 555d5e6369c319215ad7849f87dcf8b2ccd8a4d6..ee7e884e9c4f2606498eabe0686bcdf635baab95 100644 (file)
@@ -406,7 +406,7 @@ static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t co
        ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0;
        struct ivtv *itv = s->itv;
 
-       IVTV_DEBUG_INFO("read %zd from %s, got %zd\n", count, s->name, rc);
+       IVTV_DEBUG_HI_INFO("read %zd from %s, got %zd\n", count, s->name, rc);
        if (rc > 0)
                pos += rc;
        return rc;
@@ -497,7 +497,7 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_
        struct ivtv_stream *s = &itv->streams[id->type];
        int rc;
 
-       IVTV_DEBUG_IOCTL("read %zd bytes from %s\n", count, s->name);
+       IVTV_DEBUG_HI_IOCTL("read %zd bytes from %s\n", count, s->name);
 
        rc = ivtv_start_capture(id);
        if (rc)
@@ -535,7 +535,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
        int rc;
        DEFINE_WAIT(wait);
 
-       IVTV_DEBUG_IOCTL("write %zd bytes to %s\n", count, s->name);
+       IVTV_DEBUG_HI_IOCTL("write %zd bytes to %s\n", count, s->name);
 
        if (s->type != IVTV_DEC_STREAM_TYPE_MPG &&
            s->type != IVTV_DEC_STREAM_TYPE_YUV &&
@@ -643,7 +643,7 @@ retry:
           to transfer the rest. */
        if (count && !(filp->f_flags & O_NONBLOCK))
                goto retry;
-       IVTV_DEBUG_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
+       IVTV_DEBUG_HI_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
        return bytes_written;
 }
 
index d4c910b782af6bb186edb168f7f214a2f53e606d..2b6208a6a108dd5c9b0a66970491cfb2300a8094 100644 (file)
@@ -56,9 +56,7 @@ retry:
                volatile u32 __iomem *dst = (volatile u32 __iomem *)mem;
                const u32 *src = (const u32 *)fw->data;
 
-               /* temporarily allow 256 KB encoding firmwares as well for
-                  compatibility with blackbird cards */
-               if (fw->size != size && fw->size != 256 * 1024) {
+               if (fw->size != size) {
                        /* Due to race conditions in firmware loading (esp. with udev <0.95)
                           the wrong file was sometimes loaded. So we check filesizes to
                           see if at least the right-sized file was loaded. If not, then we
index bc8f8ca2961f4564c771260bde1d39184b544b30..676418cbaaad14b909fd44c22441766d4f90b52a 100644 (file)
@@ -115,8 +115,7 @@ void ivtv_reset_ir_gpio(struct ivtv *itv)
        curout = (curout & ~0xF) | 1;
        write_reg(curout, IVTV_REG_GPIO_OUT);
        /* We could use something else for smaller time */
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(1);
+       schedule_timeout_interruptible(msecs_to_jiffies(1));
        curout |= 2;
        write_reg(curout, IVTV_REG_GPIO_OUT);
        curdir &= ~0x80;
@@ -138,13 +137,11 @@ int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr)
 
        curout &= ~(1 << 12);
        write_reg(curout, IVTV_REG_GPIO_OUT);
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(1);
+       schedule_timeout_interruptible(msecs_to_jiffies(1));
 
        curout |= (1 << 12);
        write_reg(curout, IVTV_REG_GPIO_OUT);
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(1);
+       schedule_timeout_interruptible(msecs_to_jiffies(1));
 
        return 0;
 }
index 57af1762de1f736ebcfe3f79c16322198796f75a..4773453e8dab2b8e966523f2948965616ec3fdf6 100644 (file)
@@ -1159,7 +1159,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
 
                memset(fb, 0, sizeof(*fb));
                if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
-                       break;
+                       return -EINVAL;
                fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
                        V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_GLOBAL_ALPHA;
                fb->fmt.pixelformat = itv->osd_pixelformat;
@@ -1179,7 +1179,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
                struct v4l2_framebuffer *fb = arg;
 
                if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
-                       break;
+                       return -EINVAL;
                itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
                itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0;
                itv->osd_color_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
index ba98bf054f2e8371057d58f684d776bfc67dcea0..1a3ee464a826297d7c5245f33c5d5495ba9cb08b 100644 (file)
@@ -48,7 +48,7 @@ static void ivtv_pio_work_handler(struct ivtv *itv)
        struct list_head *p;
        int i = 0;
 
-       IVTV_DEBUG_DMA("ivtv_pio_work_handler\n");
+       IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n");
        if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS ||
                        s->v4l2dev == NULL || !ivtv_use_pio(s)) {
                itv->cur_pio_stream = -1;
@@ -56,7 +56,7 @@ static void ivtv_pio_work_handler(struct ivtv *itv)
                write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
                return;
        }
-       IVTV_DEBUG_DMA("Process PIO %s\n", s->name);
+       IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name);
        buf = list_entry(s->q_dma.list.next, struct ivtv_buffer, list);
        list_for_each(p, &s->q_dma.list) {
                struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
@@ -187,7 +187,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
                bytes_needed += UVsize;
        }
 
-       IVTV_DEBUG_DMA("%s %s: 0x%08x bytes at 0x%08x\n",
+       IVTV_DEBUG_HI_DMA("%s %s: 0x%08x bytes at 0x%08x\n",
                ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset);
 
        rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed);
@@ -242,7 +242,7 @@ static void dma_post(struct ivtv_stream *s)
        u32 *u32buf;
        int x = 0;
 
-       IVTV_DEBUG_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
+       IVTV_DEBUG_HI_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
                        s->name, s->dma_offset);
        list_for_each(p, &s->q_dma.list) {
                buf = list_entry(p, struct ivtv_buffer, list);
@@ -321,7 +321,7 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
        unsigned long flags = 0;
        int idx = 0;
 
-       IVTV_DEBUG_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
+       IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
        buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list);
        list_for_each(p, &s->q_predma.list) {
                struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
@@ -368,7 +368,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
        struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
        int i;
 
-       IVTV_DEBUG_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name);
+       IVTV_DEBUG_HI_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name);
 
        if (s->q_predma.bytesused)
                ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
@@ -397,7 +397,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
                itv->vbi.dma_offset = s_vbi->dma_offset;
                s_vbi->SG_length = 0;
                set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
-               IVTV_DEBUG_DMA("include DMA for %s\n", s->name);
+               IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name);
        }
 
        /* Mark last buffer size for Interrupt flag */
@@ -431,7 +431,7 @@ static void ivtv_dma_dec_start(struct ivtv_stream *s)
 
        if (s->q_predma.bytesused)
                ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
-       IVTV_DEBUG_DMA("start DMA for %s\n", s->name);
+       IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name);
        /* put SG Handle into register 0x0c */
        write_reg(s->SG_handle, IVTV_REG_DECDMAADDR);
        write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
@@ -447,7 +447,7 @@ static void ivtv_irq_dma_read(struct ivtv *itv)
        struct ivtv_buffer *buf;
        int hw_stream_type;
 
-       IVTV_DEBUG_IRQ("DEC DMA READ\n");
+       IVTV_DEBUG_HI_IRQ("DEC DMA READ\n");
        del_timer(&itv->dma_timer);
        if (read_reg(IVTV_REG_DMASTATUS) & 0x14) {
                IVTV_DEBUG_WARN("DEC DMA ERROR %x\n", read_reg(IVTV_REG_DMASTATUS));
@@ -462,7 +462,7 @@ static void ivtv_irq_dma_read(struct ivtv *itv)
                        s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
                        hw_stream_type = 0;
                }
-               IVTV_DEBUG_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
+               IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
 
                ivtv_stream_sync_for_cpu(s);
 
@@ -495,7 +495,7 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv)
 
        del_timer(&itv->dma_timer);
        ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data);
-       IVTV_DEBUG_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]);
+       IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]);
        if (test_and_clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags))
                data[1] = 3;
        else if (data[1] > 2)
@@ -532,7 +532,7 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv)
                return;
        }
        s = &itv->streams[itv->cur_pio_stream];
-       IVTV_DEBUG_IRQ("ENC PIO COMPLETE %s\n", s->name);
+       IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name);
        s->SG_length = 0;
        clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
        clear_bit(IVTV_F_I_PIO, &itv->i_flags);
@@ -590,7 +590,7 @@ static void ivtv_irq_enc_start_cap(struct ivtv *itv)
 
        /* Get DMA destination and size arguments from card */
        ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, data);
-       IVTV_DEBUG_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
+       IVTV_DEBUG_HI_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
 
        if (data[0] > 2 || data[1] == 0 || data[2] == 0) {
                IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n",
@@ -610,7 +610,7 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
        u32 data[CX2341X_MBOX_MAX_DATA];
        struct ivtv_stream *s;
 
-       IVTV_DEBUG_IRQ("ENC START VBI CAP\n");
+       IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n");
        s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
 
        /* If more than two VBI buffers are pending, then
@@ -644,7 +644,7 @@ static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv)
        u32 data[CX2341X_MBOX_MAX_DATA];
        struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI];
 
-       IVTV_DEBUG_IRQ("DEC VBI REINSERT\n");
+       IVTV_DEBUG_HI_IRQ("DEC VBI REINSERT\n");
        if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) &&
                        !stream_enc_dma_append(s, data)) {
                set_bit(IVTV_F_S_PIO_PENDING, &s->s_flags);
@@ -669,7 +669,7 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv)
                itv->dma_data_req_offset = data[1];
                s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
        }
-       IVTV_DEBUG_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused,
+       IVTV_DEBUG_HI_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused,
                       itv->dma_data_req_offset, itv->dma_data_req_size);
        if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) {
                set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
@@ -791,10 +791,10 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
        /* Exclude interrupts noted below from the output, otherwise the log is flooded with
           these messages */
        if (combo & ~0xff6d0400)
-               IVTV_DEBUG_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo);
+               IVTV_DEBUG_HI_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo);
 
        if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) {
-               IVTV_DEBUG_IRQ("DEC DMA COMPLETE\n");
+               IVTV_DEBUG_HI_IRQ("DEC DMA COMPLETE\n");
        }
 
        if (combo & IVTV_IRQ_DMA_READ) {
index 6af88ae9295f8f4096ef3b8b230fba06ce9a4d48..287117187499776bebc43b8cc1951e2641c303a7 100644 (file)
@@ -446,6 +446,9 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
        if (s->v4l2dev == NULL)
                return -EINVAL;
 
+       /* Big serialization lock to ensure no two streams are started
+          simultaneously: that can give all sorts of weird results. */
+       mutex_lock(&itv->serialize_lock);
        IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);
 
        switch (s->type) {
@@ -487,6 +490,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
                        0, sizeof(itv->vbi.sliced_mpeg_size));
                break;
        default:
+               mutex_unlock(&itv->serialize_lock);
                return -EINVAL;
        }
        s->subtype = subtype;
@@ -568,6 +572,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
        if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype))
        {
                IVTV_DEBUG_WARN( "Error starting capture!\n");
+               mutex_unlock(&itv->serialize_lock);
                return -EINVAL;
        }
 
@@ -583,6 +588,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
 
        /* you're live! sit back and await interrupts :) */
        atomic_inc(&itv->capturing);
+       mutex_unlock(&itv->serialize_lock);
        return 0;
 }
 
@@ -762,17 +768,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
        /* when: 0 =  end of GOP  1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */
        ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype);
 
-       /* only run these if we're shutting down the last cap */
-       if (atomic_read(&itv->capturing) - 1 == 0) {
-               /* event notification (off) */
-               if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
-                       /* type: 0 = refresh */
-                       /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
-                       ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
-                       ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
-               }
-       }
-
        then = jiffies;
 
        if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) {
@@ -812,7 +807,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
                then = jiffies;
                /* Make sure DMA is complete */
                add_wait_queue(&s->waitq, &wait);
-               set_current_state(TASK_INTERRUPTIBLE);
                do {
                        /* check if DMA is pending */
                        if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) &&    /* MPG Only */
@@ -827,9 +821,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
                        } else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) {
                                break;
                        }
-
-                       ivtv_sleep_timeout(HZ / 100, 1);
-               } while (then + HZ * 2 > jiffies);
+               } while (!ivtv_sleep_timeout(HZ / 100, 1) && then + HZ * 2 > jiffies);
 
                set_current_state(TASK_RUNNING);
                remove_wait_queue(&s->waitq, &wait);
@@ -840,17 +832,30 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
        /* Clear capture and no-read bits */
        clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
 
+       /* ensure these global cleanup actions are done only once */
+       mutex_lock(&itv->serialize_lock);
+
        if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
                ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
 
        if (atomic_read(&itv->capturing) > 0) {
+               mutex_unlock(&itv->serialize_lock);
                return 0;
        }
 
        /* Set the following Interrupt mask bits for capture */
        ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
 
+       /* event notification (off) */
+       if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
+               /* type: 0 = refresh */
+               /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
+               ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
+               ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
+       }
+
        wake_up(&s->waitq);
+       mutex_unlock(&itv->serialize_lock);
 
        return 0;
 }
index 3ba46e07ea1f1b93e6c497f5ff76e4b6738b3eab..a7282a91bd9719c029badf20569b1472d5ce24ac 100644 (file)
@@ -219,31 +219,23 @@ ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count)
        int found_cc = 0;
        int cc_pos = itv->vbi.cc_pos;
 
-       if (itv->vbi.service_set_out == 0)
-               return -EPERM;
-
        while (count >= sizeof(struct v4l2_sliced_vbi_data)) {
                switch (p->id) {
                case V4L2_SLICED_CAPTION_525:
-                       if (p->id == V4L2_SLICED_CAPTION_525 &&
-                           p->line == 21 &&
-                           (itv->vbi.service_set_out &
-                               V4L2_SLICED_CAPTION_525) == 0) {
-                               break;
-                       }
-                       found_cc = 1;
-                       if (p->field) {
-                               cc[2] = p->data[0];
-                               cc[3] = p->data[1];
-                       } else {
-                               cc[0] = p->data[0];
-                               cc[1] = p->data[1];
+                       if (p->line == 21) {
+                               found_cc = 1;
+                               if (p->field) {
+                                       cc[2] = p->data[0];
+                                       cc[3] = p->data[1];
+                               } else {
+                                       cc[0] = p->data[0];
+                                       cc[1] = p->data[1];
+                               }
                        }
                        break;
 
                case V4L2_SLICED_VPS:
-                       if (p->line == 16 && p->field == 0 &&
-                           (itv->vbi.service_set_out & V4L2_SLICED_VPS)) {
+                       if (p->line == 16 && p->field == 0) {
                                itv->vbi.vps[0] = p->data[2];
                                itv->vbi.vps[1] = p->data[8];
                                itv->vbi.vps[2] = p->data[9];
@@ -255,8 +247,7 @@ ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count)
                        break;
 
                case V4L2_SLICED_WSS_625:
-                       if (p->line == 23 && p->field == 0 &&
-                           (itv->vbi.service_set_out & V4L2_SLICED_WSS_625)) {
+                       if (p->line == 23 && p->field == 0) {
                                /* No lock needed for WSS */
                                itv->vbi.wss = p->data[0] | (p->data[1] << 8);
                                itv->vbi.wss_found = 1;
index 3bb7d6634862be289f789b810a7b1d73c7fd3ac7..507b1d4260ed2ab7f451a2fa44a26dd4033c5c79 100644 (file)
@@ -157,8 +157,7 @@ static int msp_read(struct i2c_client *client, int dev, int addr)
                        break;
                v4l_warn(client, "I/O error #%d (read 0x%02x/0x%02x)\n", err,
                       dev, addr);
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(msecs_to_jiffies(10));
+               schedule_timeout_interruptible(msecs_to_jiffies(10));
        }
        if (err == 3) {
                v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
@@ -197,8 +196,7 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val)
                        break;
                v4l_warn(client, "I/O error #%d (write 0x%02x/0x%02x)\n", err,
                       dev, addr);
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(msecs_to_jiffies(10));
+               schedule_timeout_interruptible(msecs_to_jiffies(10));
        }
        if (err == 3) {
                v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
index c7c9f3f8715cbd62b96491c2965baef70520b763..7549114aaaca3537f48820287b7921ee8061c703 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/i2c.h>
 #include <linux/videodev.h>
 #include <linux/moduleparam.h>
-#include <media/tuner.h>
+#include "tuner-driver.h"
 
 /* ---------------------------------------------------------------------- */
 
@@ -37,6 +37,19 @@ static char *microtune_part[] = {
        [ MT2050 ] = "MT2050",
 };
 
+struct microtune_priv {
+       unsigned int xogc;
+       unsigned int radio_if2;
+};
+
+static void microtune_release(struct i2c_client *c)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+
+       kfree(t->priv);
+       t->priv = NULL;
+}
+
 // IsSpurInBand()?
 static int mt2032_spurcheck(struct i2c_client *c,
                            int f1, int f2, int spectrum_from,int spectrum_to)
@@ -218,6 +231,7 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
        unsigned char buf[21];
        int lint_try,ret,sel,lock=0;
        struct tuner *t = i2c_get_clientdata(c);
+       struct microtune_priv *priv = t->priv;
 
        tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",
                  rfin,if1,if2,from,to);
@@ -227,7 +241,7 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
        i2c_master_recv(c,buf,21);
 
        buf[0]=0;
-       ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,t->xogc);
+       ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc);
        if (ret<0)
                return;
 
@@ -251,10 +265,10 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
 
                tuner_dbg("mt2032: re-init PLLs by LINT\n");
                buf[0]=7;
-               buf[1]=0x80 +8+t->xogc; // set LINT to re-init PLLs
+               buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs
                i2c_master_send(c,buf,2);
                mdelay(10);
-               buf[1]=8+t->xogc;
+               buf[1]=8+priv->xogc;
                i2c_master_send(c,buf,2);
        }
 
@@ -294,17 +308,25 @@ static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq)
 static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
 {
        struct tuner *t = i2c_get_clientdata(c);
-       int if2 = t->radio_if2;
+       struct microtune_priv *priv = t->priv;
+       int if2 = priv->radio_if2;
 
        // per Manual for FM tuning: first if center freq. 1085 MHz
        mt2032_set_if_freq(c, freq * 1000 / 16,
                              1085*1000*1000,if2,if2,if2);
 }
 
+static struct tuner_operations mt2032_tuner_ops = {
+       .set_tv_freq    = mt2032_set_tv_freq,
+       .set_radio_freq = mt2032_set_radio_freq,
+       .release        = microtune_release,
+};
+
 // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
 static int mt2032_init(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       struct microtune_priv *priv = t->priv;
        unsigned char buf[21];
        int ret,xogc,xok=0;
 
@@ -351,23 +373,23 @@ static int mt2032_init(struct i2c_client *c)
                if (ret!=2)
                        tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
        } while (xok != 1 );
-       t->xogc=xogc;
+       priv->xogc=xogc;
+
+       memcpy(&t->ops, &mt2032_tuner_ops, sizeof(struct tuner_operations));
 
-       t->set_tv_freq    = mt2032_set_tv_freq;
-       t->set_radio_freq = mt2032_set_radio_freq;
        return(1);
 }
 
 static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna)
 {
        struct tuner *t = i2c_get_clientdata(c);
-       unsigned char buf[2];
-       int ret;
+       unsigned char buf[2];
+       int ret;
 
-       buf[0] = 6;
-       buf[1] = antenna ? 0x11 : 0x10;
-       ret=i2c_master_send(c,buf,2);
-       tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
+       buf[0] = 6;
+       buf[1] = antenna ? 0x11 : 0x10;
+       ret=i2c_master_send(c,buf,2);
+       tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
 }
 
 static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2)
@@ -456,12 +478,19 @@ static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq)
 static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq)
 {
        struct tuner *t = i2c_get_clientdata(c);
-       int if2 = t->radio_if2;
+       struct microtune_priv *priv = t->priv;
+       int if2 = priv->radio_if2;
 
        mt2050_set_if_freq(c, freq * 1000 / 16, if2);
        mt2050_set_antenna(c, radio_antenna);
 }
 
+static struct tuner_operations mt2050_tuner_ops = {
+       .set_tv_freq    = mt2050_set_tv_freq,
+       .set_radio_freq = mt2050_set_radio_freq,
+       .release        = microtune_release,
+};
+
 static int mt2050_init(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
@@ -481,28 +510,35 @@ static int mt2050_init(struct i2c_client *c)
        i2c_master_recv(c,buf,1);
 
        tuner_dbg("mt2050: sro is %x\n",buf[0]);
-       t->set_tv_freq    = mt2050_set_tv_freq;
-       t->set_radio_freq = mt2050_set_radio_freq;
+
+       memcpy(&t->ops, &mt2050_tuner_ops, sizeof(struct tuner_operations));
+
        return 0;
 }
 
 int microtune_init(struct i2c_client *c)
 {
+       struct microtune_priv *priv = NULL;
        struct tuner *t = i2c_get_clientdata(c);
        char *name;
        unsigned char buf[21];
        int company_code;
 
+       priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+       t->priv = priv;
+
+       priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
+
        memset(buf,0,sizeof(buf));
-       t->set_tv_freq    = NULL;
-       t->set_radio_freq = NULL;
-       t->standby    = NULL;
+
        if (t->std & V4L2_STD_525_60) {
                tuner_dbg("pinnacle ntsc\n");
-               t->radio_if2 = 41300 * 1000;
+               priv->radio_if2 = 41300 * 1000;
        } else {
                tuner_dbg("pinnacle pal\n");
-               t->radio_if2 = 33300 * 1000;
+               priv->radio_if2 = 33300 * 1000;
        }
        name = "unknown";
 
index 3ceb8a6249ddf137bed3a58a168a0918ad4095ee..f8f21ddd98431c9d689db3d80684efaad303d01a 100644 (file)
@@ -617,7 +617,7 @@ static struct ov7670_win_size {
        },
 };
 
-#define N_WIN_SIZES (sizeof(ov7670_win_sizes)/sizeof(ov7670_win_sizes[0]))
+#define N_WIN_SIZES (ARRAY_SIZE(ov7670_win_sizes))
 
 
 /*
@@ -1183,7 +1183,7 @@ static struct ov7670_control {
                .query = ov7670_q_hflip,
        },
 };
-#define N_CONTROLS (sizeof(ov7670_controls)/sizeof(ov7670_controls[0]))
+#define N_CONTROLS (ARRAY_SIZE(ov7670_controls))
 
 static struct ov7670_control *ov7670_find_control(__u32 id)
 {
index 085332a503deb950e1e960cc447d31017ea5ad95..9c0e8d18c2f6085e7bcb9a39c53dcb6212283179 100644 (file)
@@ -1099,7 +1099,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
                return -EBUSY;
        }
 
-       down(&pdev->modlock);
+       mutex_lock(&pdev->modlock);
        if (!pdev->usb_init) {
                PWC_DEBUG_OPEN("Doing first time initialization.\n");
                pdev->usb_init = 1;
@@ -1131,7 +1131,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
        if (i < 0) {
                PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
                pwc_free_buffers(pdev);
-               up(&pdev->modlock);
+               mutex_unlock(&pdev->modlock);
                return i;
        }
 
@@ -1172,7 +1172,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
        if (i) {
                PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
                pwc_free_buffers(pdev);
-               up(&pdev->modlock);
+               mutex_unlock(&pdev->modlock);
                return i;
        }
 
@@ -1181,7 +1181,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
                PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
                pwc_isoc_cleanup(pdev);
                pwc_free_buffers(pdev);
-               up(&pdev->modlock);
+               mutex_unlock(&pdev->modlock);
                return i;
        }
 
@@ -1191,7 +1191,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
 
        pdev->vopen++;
        file->private_data = vdev;
-       up(&pdev->modlock);
+       mutex_unlock(&pdev->modlock);
        PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
        return 0;
 }
@@ -1685,7 +1685,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                pdev->angle_range.tilt_max =  2500;
        }
 
-       init_MUTEX(&pdev->modlock);
+       mutex_init(&pdev->modlock);
        spin_lock_init(&pdev->ptrlock);
 
        pdev->udev = udev;
index acbb9312960a84b9e1086149f26200eebb606b16..910a04f539202a2d6a5f3b2adb879c7c551a69b1 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/wait.h>
 #include <linux/smp_lock.h>
 #include <linux/version.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/errno.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
@@ -244,7 +244,7 @@ struct pwc_device
    int image_read_pos;                 /* In case we read data in pieces, keep track of were we are in the imagebuffer */
    int image_used[MAX_IMAGES];         /* For MCAPTURE and SYNC */
 
-   struct semaphore modlock;           /* to prevent races in video_open(), etc */
+   struct mutex modlock;               /* to prevent races in video_open(), etc */
    spinlock_t ptrlock;                 /* for manipulating the buffer pointers */
 
    /*** motorized pan/tilt feature */
index c1a392e47170b520d3b17c5c14463857b5b11e00..7ae2d646d0008f12a8a94fd2058c6e0673dac076 100644 (file)
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
 
 MODULE_DESCRIPTION("Philips SAA7111 video decoder driver");
 MODULE_AUTHOR("Dave Perks");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(s) (s)->name
 
-#include <linux/video_decoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0644);
index 87c3144ec7fc85e1e0aeab3cdc1fc28ac32c9f8c..677df51de1a9e3136856dd417260df4e5dd1a46e 100644 (file)
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
-
 #include <linux/slab.h>
-
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
 
 MODULE_DESCRIPTION("Philips SAA7114H video decoder driver");
 MODULE_AUTHOR("Maxim Yevtyushkin");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(x) (x)->name
 
-#include <linux/video_decoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
index 309dca368f4a56a5a38f74a501f1bff623f3e080..9f1417a4f7d2f49143a30f5bb8b788b4a7caf44f 100644 (file)
@@ -40,7 +40,7 @@ config VIDEO_SAA7134_DVB
        depends on VIDEO_SAA7134 && DVB_CORE
        select VIDEO_BUF_DVB
        select FW_LOADER
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_MT352 if !DVB_FE_CUSTOMISE
        select DVB_TDA1004X if !DVB_FE_CUSTOMISE
        select DVB_NXT200X if !DVB_FE_CUSTOMISE
index ffb0f647a86d6b7b84f873d826a370e19924f75a..3c0fc9027ad01118d8c67ee0e82fe74ab4597741 100644 (file)
@@ -75,7 +75,8 @@ typedef struct snd_card_saa7134 {
        struct saa7134_dev *dev;
 
        unsigned long iobase;
-       int irq;
+       s16 irq;
+       u16 mute_was_on;
 
        spinlock_t lock;
 } snd_card_saa7134_t;
@@ -589,8 +590,10 @@ static int snd_card_saa7134_capture_close(struct snd_pcm_substream * substream)
        snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
        struct saa7134_dev *dev = saa7134->dev;
 
-       dev->ctl_mute = 1;
-       saa7134_tvaudio_setmute(dev);
+       if (saa7134->mute_was_on) {
+               dev->ctl_mute = 1;
+               saa7134_tvaudio_setmute(dev);
+       }
        return 0;
 }
 
@@ -637,8 +640,11 @@ static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream)
        runtime->private_free = snd_card_saa7134_runtime_free;
        runtime->hw = snd_card_saa7134_capture;
 
-       dev->ctl_mute = 0;
-       saa7134_tvaudio_setmute(dev);
+       if (dev->ctl_mute != 0) {
+               saa7134->mute_was_on = 1;
+               dev->ctl_mute = 0;
+               saa7134_tvaudio_setmute(dev);
+       }
 
        if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
                return err;
index 50f15adfa7c87ff0a77a2d0284e8826aa8c54265..8ec83bd70094fd7714fb905c46c85b7848ad0ee4 100644 (file)
@@ -400,7 +400,7 @@ struct saa7134_board saa7134_boards[] = {
                .inputs         = {{
                        .name = name_tv,
                        .vmux = 1,
-                       .amux = LINE2,
+                       .amux = TV,
                        .tv   = 1,
                        .gpio = 0x20000,
                },{
@@ -3502,6 +3502,38 @@ struct saa7134_board saa7134_boards[] = {
                        .amux = TV,
                },
        },
+       [SAA7134_BOARD_10MOONSTVMASTER3] = {
+               /* Tony Wan <aloha_cn@hotmail.com> */
+               .name           = "10MOONS TM300 TV Card",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_LG_PAL_NEW_TAPC,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .gpiomask       = 0x7000,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = LINE2,
+                       .gpio = 0x0000,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = LINE1,
+                       .gpio = 0x2000,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+                       .gpio = 0x2000,
+               }},
+               .mute = {
+                       .name = name_mute,
+                       .amux = LINE2,
+                       .gpio = 0x3000,
+               },
+       },
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4218,6 +4250,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x0919, /* SinoVideo PCI 2309 Proteus (7134) */
                .subdevice    = 0x2003, /* OEM cardbus */
                .driver_data  = SAA7134_BOARD_SABRENT_TV_PCB05,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = PCI_VENDOR_ID_PHILIPS,
+               .subdevice    = 0x2304,
+               .driver_data  = SAA7134_BOARD_10MOONSTVMASTER3,
        },{
                /* --- boards without eeprom + subsystem ID --- */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -4330,6 +4368,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_AVERMEDIA_A16AR:
        case SAA7134_BOARD_ENCORE_ENLTV:
        case SAA7134_BOARD_ENCORE_ENLTV_FM:
+       case SAA7134_BOARD_10MOONSTVMASTER3:
                dev->has_remote = SAA7134_REMOTE_GPIO;
                break;
        case SAA7134_BOARD_FLYDVBS_LR300:
index e0eec80088c7e3060efc95f983d66530b0b709de..1f6bd3300715994db922aff1b00de86f7953410a 100644 (file)
@@ -175,18 +175,6 @@ static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
        return mt352_pinnacle_init(fe);
 }
 
-static int mt352_aver777_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
-{
-       if (buf_len < 5)
-               return -EINVAL;
-
-       pllbuf[0] = 0x61;
-       dvb_pll_configure(&dvb_pll_philips_td1316, pllbuf+1,
-                         params->frequency,
-                         params->u.ofdm.bandwidth);
-       return 5;
-}
-
 static struct mt352_config pinnacle_300i = {
        .demod_address = 0x3c >> 1,
        .adc_clock     = 20333,
@@ -444,135 +432,6 @@ static struct tda1004x_config philips_europa_config = {
 
 /* ------------------------------------------------------------------ */
 
-static int philips_fmd1216_tuner_init(struct dvb_frontend *fe)
-{
-       struct saa7134_dev *dev = fe->dvb->priv;
-       struct tda1004x_state *state = fe->demodulator_priv;
-       u8 addr = state->config->tuner_address;
-       /* this message is to set up ATC and ALC */
-       static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
-       struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
-               return -EIO;
-       msleep(1);
-
-       return 0;
-}
-
-static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe)
-{
-       struct saa7134_dev *dev = fe->dvb->priv;
-       struct tda1004x_state *state = fe->demodulator_priv;
-       u8 addr = state->config->tuner_address;
-       /* this message actually turns the tuner back to analog mode */
-       u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 };
-       struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
-       msleep(1);
-       fmd1216_init[2] = 0x86;
-       fmd1216_init[3] = 0x54;
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
-       msleep(1);
-       return 0;
-}
-
-static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
-       struct saa7134_dev *dev = fe->dvb->priv;
-       struct tda1004x_state *state = fe->demodulator_priv;
-       u8 addr = state->config->tuner_address;
-       u8 tuner_buf[4];
-       struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
-                       sizeof(tuner_buf) };
-       int tuner_frequency = 0;
-       int divider = 0;
-       u8 band, mode, cp;
-
-       /* determine charge pump */
-       tuner_frequency = params->frequency + 36130000;
-       if (tuner_frequency < 87000000)
-               return -EINVAL;
-       /* low band */
-       else if (tuner_frequency < 180000000) {
-               band = 1;
-               mode = 7;
-               cp   = 0;
-       } else if (tuner_frequency < 195000000) {
-               band = 1;
-               mode = 6;
-               cp   = 1;
-       /* mid band     */
-       } else if (tuner_frequency < 366000000) {
-               if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
-                       band = 10;
-               } else {
-                       band = 2;
-               }
-               mode = 7;
-               cp   = 0;
-       } else if (tuner_frequency < 478000000) {
-               if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
-                       band = 10;
-               } else {
-                       band = 2;
-               }
-               mode = 6;
-               cp   = 1;
-       /* high band */
-       } else if (tuner_frequency < 662000000) {
-               if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
-                       band = 12;
-               } else {
-                       band = 4;
-               }
-               mode = 7;
-               cp   = 0;
-       } else if (tuner_frequency < 840000000) {
-               if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
-                       band = 12;
-               } else {
-                       band = 4;
-               }
-               mode = 6;
-               cp   = 1;
-       } else {
-               if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
-                       band = 12;
-               } else {
-                       band = 4;
-               }
-               mode = 7;
-               cp   = 1;
-
-       }
-       /* calculate divisor */
-       /* ((36166000 + Finput) / 166666) rounded! */
-       divider = (tuner_frequency + 83333) / 166667;
-
-       /* setup tuner buffer */
-       tuner_buf[0] = (divider >> 8) & 0x7f;
-       tuner_buf[1] = divider & 0xff;
-       tuner_buf[2] = 0x80 | (cp << 6) | (mode  << 3) | 4;
-       tuner_buf[3] = 0x40 | band;
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) {
-               wprintk("could not write to tuner at addr: 0x%02x\n",
-                       addr << 1);
-               return -EIO;
-       }
-       return 0;
-}
-
 static struct tda1004x_config medion_cardbus = {
        .demod_address = 0x08,
        .invert        = 1,
@@ -958,18 +817,8 @@ static struct nxt200x_config avertvhda180 = {
        .demod_address    = 0x0a,
 };
 
-static int nxt200x_set_pll_input(u8 *buf, int input)
-{
-       if (input)
-               buf[3] |= 0x08;
-       else
-               buf[3] &= ~0x08;
-       return 0;
-}
-
 static struct nxt200x_config kworldatsc110 = {
        .demod_address    = 0x0a,
-       .set_pll_input    = nxt200x_set_pll_input,
 };
 
 /* ==================================================================
@@ -1005,7 +854,8 @@ static int dvb_init(struct saa7134_dev *dev)
                dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
                                               &dev->i2c_adap);
                if (dev->dvb.frontend) {
-                       dev->dvb.frontend->ops.tuner_ops.calc_regs = mt352_aver777_tuner_calc_regs;
+                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+                                  NULL, DVB_PLL_PHILIPS_TD1316);
                }
                break;
        case SAA7134_BOARD_MD7134:
@@ -1013,9 +863,8 @@ static int dvb_init(struct saa7134_dev *dev)
                                               &medion_cardbus,
                                               &dev->i2c_adap);
                if (dev->dvb.frontend) {
-                       dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
-                       dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
-                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address,
+                                  &dev->i2c_adap, DVB_PLL_FMD1216ME);
                }
                break;
        case SAA7134_BOARD_PHILIPS_TOUGH:
@@ -1113,7 +962,7 @@ static int dvb_init(struct saa7134_dev *dev)
                                               &dev->i2c_adap);
                if (dev->dvb.frontend) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, &dvb_pll_tdhu2);
+                                  NULL, DVB_PLL_TDHU2);
                }
                break;
        case SAA7134_BOARD_KWORLD_ATSC110:
@@ -1121,7 +970,7 @@ static int dvb_init(struct saa7134_dev *dev)
                                               &dev->i2c_adap);
                if (dev->dvb.frontend) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, &dvb_pll_tuv1236d);
+                                  NULL, DVB_PLL_TUV1236D);
                }
                break;
        case SAA7134_BOARD_FLYDVBS_LR300:
@@ -1144,9 +993,9 @@ static int dvb_init(struct saa7134_dev *dev)
                if (dev->dvb.frontend) {
                        dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
                        dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
-                       dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
-                       dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
-                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+
+                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address,
+                                  &dev->i2c_adap, DVB_PLL_FMD1216ME);
                }
                break;
        case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
index f521603482cab0ed249995eb740889ef2c2fa4ff..fc260ec8fdc2b940af785559b3cac06f73cd2258 100644 (file)
@@ -96,6 +96,10 @@ static int ts_open(struct inode *inode, struct file *file)
        if (dev->empress_users)
                goto done_up;
 
+       /* Unmute audio */
+       saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+               saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
+
        dev->empress_users++;
        file->private_data = dev;
        err = 0;
@@ -121,6 +125,10 @@ static int ts_release(struct inode *inode, struct file *file)
        /* stop the encoder */
        ts_reset_encoder(dev);
 
+       /* Mute audio */
+       saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+               saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
+
        mutex_unlock(&dev->empress_tsq.lock);
        return 0;
 }
index c0de37e3f5c6f2bb27daae26644ded2402a88b42..1b6dfd801cc1f6e9d0c3c95571b0eaf4974bf3b7 100644 (file)
@@ -153,21 +153,18 @@ void saa7134_input_irq(struct saa7134_dev *dev)
 
 static void saa7134_input_timer(unsigned long data)
 {
-       struct saa7134_dev *dev = (struct saa7134_dev*)data;
+       struct saa7134_dev *dev = (struct saa7134_dev *)data;
        struct card_ir *ir = dev->remote;
-       unsigned long timeout;
 
        build_key(dev);
-       timeout = jiffies + (ir->polling * HZ / 1000);
-       mod_timer(&ir->timer, timeout);
+       mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
 }
 
 static void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
 {
        if (ir->polling) {
-               init_timer(&ir->timer);
-               ir->timer.function = saa7134_input_timer;
-               ir->timer.data     = (unsigned long)dev;
+               setup_timer(&ir->timer, saa7134_input_timer,
+                           (unsigned long)dev);
                ir->timer.expires  = jiffies + HZ;
                add_timer(&ir->timer);
        } else if (ir->rc5_gpio) {
@@ -314,6 +311,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                mask_keycode = 0x003F00;
                mask_keyup   = 0x040000;
                break;
+       case SAA7134_BOARD_FLYDVBS_LR300:
        case SAA7134_BOARD_FLYDVBT_LR301:
        case SAA7134_BOARD_FLYDVBTDUO:
                ir_codes     = ir_codes_flydvb;
@@ -333,6 +331,12 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                mask_keyup   = 0x040000;
                polling      = 50; // ms
                break;
+       case SAA7134_BOARD_10MOONSTVMASTER3:
+               ir_codes     = ir_codes_encore_enltv;
+               mask_keycode = 0x5f80000;
+               mask_keyup   = 0x8000000;
+               polling      = 50; //ms
+               break;
        }
        if (NULL == ir_codes) {
                printk("%s: Oops: IR config error [card=%d]\n",
@@ -374,7 +378,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                input_dev->id.vendor  = dev->pci->vendor;
                input_dev->id.product = dev->pci->device;
        }
-       input_dev->cdev.dev = &dev->pci->dev;
+       input_dev->dev.parent = &dev->pci->dev;
 
        dev->remote = ir;
        saa7134_ir_start(dev, ir);
index 30395d6b5f14234a0a7cd12aeacd5365629e4ad5..18b4817b4aac6edb2ac79f0f6298f24cbdd0fb4f 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
+#include <linux/kthread.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <asm/div64.h>
@@ -341,10 +342,8 @@ static void tvaudio_setmode(struct saa7134_dev *dev,
 
 static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
 {
-       DECLARE_WAITQUEUE(wait, current);
-
-       add_wait_queue(&dev->thread.wq, &wait);
-       if (dev->thread.scan1 == dev->thread.scan2 && !dev->thread.shutdown) {
+       if (dev->thread.scan1 == dev->thread.scan2 &&
+           !kthread_should_stop()) {
                if (timeout < 0) {
                        set_current_state(TASK_INTERRUPTIBLE);
                        schedule();
@@ -353,7 +352,6 @@ static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
                                                (msecs_to_jiffies(timeout));
                }
        }
-       remove_wait_queue(&dev->thread.wq, &wait);
        return dev->thread.scan1 != dev->thread.scan2;
 }
 
@@ -505,11 +503,10 @@ static int tvaudio_thread(void *data)
        unsigned int i, audio, nscan;
        int max1,max2,carrier,rx,mode,lastmode,default_carrier;
 
-       daemonize("%s", dev->name);
        allow_signal(SIGTERM);
        for (;;) {
                tvaudio_sleep(dev,-1);
-               if (dev->thread.shutdown || signal_pending(current))
+               if (kthread_should_stop() || signal_pending(current))
                        goto done;
 
        restart:
@@ -618,7 +615,7 @@ static int tvaudio_thread(void *data)
                for (;;) {
                        if (tvaudio_sleep(dev,5000))
                                goto restart;
-                       if (dev->thread.shutdown || signal_pending(current))
+                       if (kthread_should_stop() || signal_pending(current))
                                break;
                        if (UNSET == dev->thread.mode) {
                                rx = tvaudio_getstereo(dev,&tvaudio[i]);
@@ -634,7 +631,6 @@ static int tvaudio_thread(void *data)
        }
 
  done:
-       complete_and_exit(&dev->thread.exit, 0);
        return 0;
 }
 
@@ -782,7 +778,6 @@ static int tvaudio_thread_ddep(void *data)
        struct saa7134_dev *dev = data;
        u32 value, norms, clock;
 
-       daemonize("%s", dev->name);
        allow_signal(SIGTERM);
 
        clock = saa7134_boards[dev->board].audio_clock;
@@ -796,7 +791,7 @@ static int tvaudio_thread_ddep(void *data)
 
        for (;;) {
                tvaudio_sleep(dev,-1);
-               if (dev->thread.shutdown || signal_pending(current))
+               if (kthread_should_stop() || signal_pending(current))
                        goto done;
 
        restart:
@@ -876,7 +871,6 @@ static int tvaudio_thread_ddep(void *data)
        }
 
  done:
-       complete_and_exit(&dev->thread.exit, 0);
        return 0;
 }
 
@@ -973,7 +967,6 @@ int saa7134_tvaudio_getstereo(struct saa7134_dev *dev)
 
 int saa7134_tvaudio_init2(struct saa7134_dev *dev)
 {
-       DECLARE_MUTEX_LOCKED(sem);
        int (*my_thread)(void *data) = NULL;
 
        switch (dev->pci->device) {
@@ -986,15 +979,15 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
                break;
        }
 
-       dev->thread.pid = -1;
+       dev->thread.thread = NULL;
        if (my_thread) {
                /* start tvaudio thread */
-               init_waitqueue_head(&dev->thread.wq);
-               init_completion(&dev->thread.exit);
-               dev->thread.pid = kernel_thread(my_thread,dev,0);
-               if (dev->thread.pid < 0)
+               dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name);
+               if (IS_ERR(dev->thread.thread)) {
                        printk(KERN_WARNING "%s: kernel_thread() failed\n",
                               dev->name);
+                       /* XXX: missing error handling here */
+               }
                saa7134_tvaudio_do_scan(dev);
        }
 
@@ -1005,11 +998,9 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
 int saa7134_tvaudio_fini(struct saa7134_dev *dev)
 {
        /* shutdown tvaudio thread */
-       if (dev->thread.pid > 0) {
-               dev->thread.shutdown = 1;
-               wake_up_interruptible(&dev->thread.wq);
-               wait_for_completion(&dev->thread.exit);
-       }
+       if (dev->thread.thread)
+               kthread_stop(dev->thread.thread);
+
        saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */
        return 0;
 }
@@ -1020,10 +1011,10 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
                dprintk("sound IF not in use, skipping scan\n");
                dev->automute = 0;
                saa7134_tvaudio_setmute(dev);
-       } else if (dev->thread.pid >= 0) {
+       } else if (dev->thread.thread) {
                dev->thread.mode = UNSET;
                dev->thread.scan2++;
-               wake_up_interruptible(&dev->thread.wq);
+               wake_up_process(dev->thread.thread);
        } else {
                dev->automute = 0;
                saa7134_tvaudio_setmute(dev);
@@ -1040,4 +1031,3 @@ EXPORT_SYMBOL(saa7134_tvaudio_setmute);
  * c-basic-offset: 8
  * End:
  */
-
index 15623b27ad2e0f92ff16434e70a1050c81648c0d..d32a856192d742a0dfe2adcf2fce18104f30f68e 100644 (file)
@@ -238,6 +238,7 @@ struct saa7134_format {
 #define SAA7134_BOARD_ECS_TVP3XP_4CB6  113
 #define SAA7134_BOARD_KWORLD_DVBT_210 114
 #define SAA7134_BOARD_SABRENT_TV_PCB05     115
+#define SAA7134_BOARD_10MOONSTVMASTER3     116
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -327,10 +328,7 @@ struct saa7134_pgtable {
 
 /* tvaudio thread status */
 struct saa7134_thread {
-       pid_t                      pid;
-       struct completion          exit;
-       wait_queue_head_t          wq;
-       unsigned int               shutdown;
+       struct task_struct         *thread;
        unsigned int               scan1;
        unsigned int               scan2;
        unsigned int               mode;
index 339592e7722d1d34d6b5e10471fdaa91a3bd1634..66cc92c0ea66f725a43a29ea652621218ff11212 100644 (file)
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
 
 MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
 MODULE_AUTHOR("Dave Perks");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(s) (s)->name
 
-#include <linux/video_encoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
index 11fcb49f5b99180b34de68f522f1090ca96fa07a..2e3c3de793a72a2161a2bf1c0ca69fd8c3b91b7c 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/mutex.h>
 #include <linux/string.h>
 #include <linux/stddef.h>
+#include <linux/kref.h>
 
 #include "sn9c102_config.h"
 #include "sn9c102_sensor.h"
@@ -94,7 +95,7 @@ struct sn9c102_module_param {
 };
 
 static DEFINE_MUTEX(sn9c102_sysfs_lock);
-static DECLARE_RWSEM(sn9c102_disconnect);
+static DECLARE_RWSEM(sn9c102_dev_lock);
 
 struct sn9c102_device {
        struct video_device* v4ldev;
@@ -122,12 +123,14 @@ struct sn9c102_device {
 
        struct sn9c102_module_param module_param;
 
+       struct kref kref;
        enum sn9c102_dev_state state;
        u8 users;
 
-       struct mutex dev_mutex, fileop_mutex;
+       struct completion probe;
+       struct mutex open_mutex, fileop_mutex;
        spinlock_t queue_lock;
-       wait_queue_head_t open, wait_frame, wait_stream;
+       wait_queue_head_t wait_open, wait_frame, wait_stream;
 };
 
 /*****************************************************************************/
index 74a204f8ebc870c254f7b0a850bf9ab5699ede9d..36d8a455e0ecf224ab41d49000fcaa968602726f 100644 (file)
@@ -48,8 +48,8 @@
 #define SN9C102_MODULE_AUTHOR   "(C) 2004-2007 Luca Risolia"
 #define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
 #define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.44"
-#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 44)
+#define SN9C102_MODULE_VERSION  "1:1.47"
+#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 47)
 
 /*****************************************************************************/
 
@@ -64,9 +64,10 @@ MODULE_LICENSE(SN9C102_MODULE_LICENSE);
 static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1};
 module_param_array(video_nr, short, NULL, 0444);
 MODULE_PARM_DESC(video_nr,
-                "\n<-1|n[,...]> Specify V4L2 minor mode number."
-                "\n -1 = use next available (default)"
-                "\n  n = use minor number n (integer >= 0)"
+                " <-1|n[,...]>"
+                "\nSpecify V4L2 minor mode number."
+                "\n-1 = use next available (default)"
+                "\n n = use minor number n (integer >= 0)"
                 "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES)
                 " cameras this way."
                 "\nFor example:"
@@ -79,13 +80,14 @@ static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] =
                               SN9C102_FORCE_MUNMAP};
 module_param_array(force_munmap, bool, NULL, 0444);
 MODULE_PARM_DESC(force_munmap,
-                "\n<0|1[,...]> Force the application to unmap previously"
+                " <0|1[,...]>"
+                "\nForce the application to unmap previously"
                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
                 "\nthis feature. This parameter is specific for each"
                 "\ndetected camera."
-                "\n 0 = do not force memory unmapping"
-                "\n 1 = force memory unmapping (save memory)"
+                "\n0 = do not force memory unmapping"
+                "\n1 = force memory unmapping (save memory)"
                 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
                 "\n");
 
@@ -93,7 +95,8 @@ static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
                                       SN9C102_FRAME_TIMEOUT};
 module_param_array(frame_timeout, uint, NULL, 0644);
 MODULE_PARM_DESC(frame_timeout,
-                "\n<0|n[,...]> Timeout for a video frame in seconds before"
+                " <0|n[,...]>"
+                "\nTimeout for a video frame in seconds before"
                 "\nreturning an I/O error; 0 for infinity."
                 "\nThis parameter is specific for each detected camera."
                 "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
@@ -103,7 +106,8 @@ MODULE_PARM_DESC(frame_timeout,
 static unsigned short debug = SN9C102_DEBUG_LEVEL;
 module_param(debug, ushort, 0644);
 MODULE_PARM_DESC(debug,
-                "\n<n> Debugging information level, from 0 to 3:"
+                " <n>"
+                "\nDebugging information level, from 0 to 3:"
                 "\n0 = none (use carefully)"
                 "\n1 = critical errors"
                 "\n2 = significant informations"
@@ -1616,7 +1620,8 @@ static int sn9c102_init(struct sn9c102_device* cam)
        int err = 0;
 
        if (!(cam->state & DEV_INITIALIZED)) {
-               init_waitqueue_head(&cam->open);
+               mutex_init(&cam->open_mutex);
+               init_waitqueue_head(&cam->wait_open);
                qctrl = s->qctrl;
                rect = &(s->cropcap.defrect);
        } else { /* use current values */
@@ -1706,21 +1711,27 @@ static int sn9c102_init(struct sn9c102_device* cam)
        return 0;
 }
 
+/*****************************************************************************/
 
-static void sn9c102_release_resources(struct sn9c102_device* cam)
+static void sn9c102_release_resources(struct kref *kref)
 {
+       struct sn9c102_device *cam;
+
        mutex_lock(&sn9c102_sysfs_lock);
 
+       cam = container_of(kref, struct sn9c102_device, kref);
+
        DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
        video_set_drvdata(cam->v4ldev, NULL);
        video_unregister_device(cam->v4ldev);
+       usb_put_dev(cam->usbdev);
+       kfree(cam->control_buffer);
+       kfree(cam);
 
        mutex_unlock(&sn9c102_sysfs_lock);
 
-       kfree(cam->control_buffer);
 }
 
-/*****************************************************************************/
 
 static int sn9c102_open(struct inode* inode, struct file* filp)
 {
@@ -1728,43 +1739,78 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
        int err = 0;
 
        /*
-          This is the only safe way to prevent race conditions with
-          disconnect
+          A read_trylock() in open() is the only safe way to prevent race
+          conditions with disconnect(), one close() and multiple (not
+          necessarily simultaneous) attempts to open(). For example, it
+          prevents from waiting for a second access, while the device
+          structure is being deallocated, after a possible disconnect() and
+          during a following close() holding the write lock: given that, after
+          this deallocation, no access will be possible anymore, using the
+          non-trylock version would have let open() gain the access to the
+          device structure improperly.
+          For this reason the lock must also not be per-device.
        */
-       if (!down_read_trylock(&sn9c102_disconnect))
+       if (!down_read_trylock(&sn9c102_dev_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(video_devdata(filp));
 
-       if (mutex_lock_interruptible(&cam->dev_mutex)) {
-               up_read(&sn9c102_disconnect);
+       if (wait_for_completion_interruptible(&cam->probe)) {
+               up_read(&sn9c102_dev_lock);
+               return -ERESTARTSYS;
+       }
+
+       kref_get(&cam->kref);
+
+       /*
+           Make sure to isolate all the simultaneous opens.
+       */
+       if (mutex_lock_interruptible(&cam->open_mutex)) {
+               kref_put(&cam->kref, sn9c102_release_resources);
+               up_read(&sn9c102_dev_lock);
                return -ERESTARTSYS;
        }
 
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               err = -ENODEV;
+               goto out;
+       }
+
        if (cam->users) {
-               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+               DBG(2, "Device /dev/video%d is already in use",
+                      cam->v4ldev->minor);
                DBG(3, "Simultaneous opens are not supported");
+               /*
+                  open() must follow the open flags and should block
+                  eventually while the device is in use.
+               */
                if ((filp->f_flags & O_NONBLOCK) ||
                    (filp->f_flags & O_NDELAY)) {
                        err = -EWOULDBLOCK;
                        goto out;
                }
-               mutex_unlock(&cam->dev_mutex);
-               err = wait_event_interruptible_exclusive(cam->open,
-                                                 cam->state & DEV_DISCONNECTED
+               DBG(2, "A blocking open() has been requested. Wait for the "
+                      "device to be released...");
+               up_read(&sn9c102_dev_lock);
+               /*
+                  We will not release the "open_mutex" lock, so that only one
+                  process can be in the wait queue below. This way the process
+                  will be sleeping while holding the lock, without loosing its
+                  priority after any wake_up().
+               */
+               err = wait_event_interruptible_exclusive(cam->wait_open,
+                                               (cam->state & DEV_DISCONNECTED)
                                                         || !cam->users);
-               if (err) {
-                       up_read(&sn9c102_disconnect);
-                       return err;
-               }
+               down_read(&sn9c102_dev_lock);
+               if (err)
+                       goto out;
                if (cam->state & DEV_DISCONNECTED) {
-                       up_read(&sn9c102_disconnect);
-                       return -ENODEV;
+                       err = -ENODEV;
+                       goto out;
                }
-               mutex_lock(&cam->dev_mutex);
        }
 
-
        if (cam->state & DEV_MISCONFIGURED) {
                err = sn9c102_init(cam);
                if (err) {
@@ -1789,36 +1835,33 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
        DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
 
 out:
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&sn9c102_disconnect);
+       mutex_unlock(&cam->open_mutex);
+       if (err)
+               kref_put(&cam->kref, sn9c102_release_resources);
+
+       up_read(&sn9c102_dev_lock);
        return err;
 }
 
 
 static int sn9c102_release(struct inode* inode, struct file* filp)
 {
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+       struct sn9c102_device* cam;
 
-       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+       down_write(&sn9c102_dev_lock);
 
-       sn9c102_stop_transfer(cam);
+       cam = video_get_drvdata(video_devdata(filp));
 
+       sn9c102_stop_transfer(cam);
        sn9c102_release_buffers(cam);
-
-       if (cam->state & DEV_DISCONNECTED) {
-               sn9c102_release_resources(cam);
-               usb_put_dev(cam->usbdev);
-               mutex_unlock(&cam->dev_mutex);
-               kfree(cam);
-               return 0;
-       }
-
        cam->users--;
-       wake_up_interruptible_nr(&cam->open, 1);
+       wake_up_interruptible_nr(&cam->wait_open, 1);
 
        DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
 
-       mutex_unlock(&cam->dev_mutex);
+       kref_put(&cam->kref, sn9c102_release_resources);
+
+       up_write(&sn9c102_dev_lock);
 
        return 0;
 }
@@ -2085,7 +2128,6 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
 
        vma->vm_ops = &sn9c102_vm_ops;
        vma->vm_private_data = &cam->frame[i];
-
        sn9c102_vm_open(vma);
 
        mutex_unlock(&cam->fileop_mutex);
@@ -3215,8 +3257,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                goto fail;
        }
 
-       mutex_init(&cam->dev_mutex);
-
        r = sn9c102_read_reg(cam, 0x00);
        if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) {
                DBG(1, "Sorry, this is not a SN9C1xx-based camera "
@@ -3282,7 +3322,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        cam->v4ldev->release = video_device_release;
        video_set_drvdata(cam->v4ldev, cam);
 
-       mutex_lock(&cam->dev_mutex);
+       init_completion(&cam->probe);
 
        err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
                                    video_nr[dev_nr]);
@@ -3292,7 +3332,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                        DBG(1, "Free /dev/videoX node not found");
                video_nr[dev_nr] = -1;
                dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               mutex_unlock(&cam->dev_mutex);
+               complete_all(&cam->probe);
                goto fail;
        }
 
@@ -3318,8 +3358,10 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 #endif
 
        usb_set_intfdata(intf, cam);
+       kref_init(&cam->kref);
+       usb_get_dev(cam->usbdev);
 
-       mutex_unlock(&cam->dev_mutex);
+       complete_all(&cam->probe);
 
        return 0;
 
@@ -3336,40 +3378,31 @@ fail:
 
 static void sn9c102_usb_disconnect(struct usb_interface* intf)
 {
-       struct sn9c102_device* cam = usb_get_intfdata(intf);
-
-       if (!cam)
-               return;
+       struct sn9c102_device* cam;
 
-       down_write(&sn9c102_disconnect);
+       down_write(&sn9c102_dev_lock);
 
-       mutex_lock(&cam->dev_mutex);
+       cam = usb_get_intfdata(intf);
 
        DBG(2, "Disconnecting %s...", cam->v4ldev->name);
 
-       wake_up_interruptible_all(&cam->open);
-
        if (cam->users) {
                DBG(2, "Device /dev/video%d is open! Deregistration and "
-                      "memory deallocation are deferred on close.",
+                      "memory deallocation are deferred.",
                    cam->v4ldev->minor);
                cam->state |= DEV_MISCONFIGURED;
                sn9c102_stop_transfer(cam);
                cam->state |= DEV_DISCONNECTED;
                wake_up_interruptible(&cam->wait_frame);
                wake_up(&cam->wait_stream);
-               usb_get_dev(cam->usbdev);
-       } else {
+       } else
                cam->state |= DEV_DISCONNECTED;
-               sn9c102_release_resources(cam);
-       }
 
-       mutex_unlock(&cam->dev_mutex);
+       wake_up_interruptible_all(&cam->wait_open);
 
-       if (!cam->users)
-               kfree(cam);
+       kref_put(&cam->kref, sn9c102_release_resources);
 
-       up_write(&sn9c102_disconnect);
+       up_write(&sn9c102_dev_lock);
 }
 
 
index e6832347894fb273c622dc7abdc1e228a4f270cd..e4856fd779823af7c0bd508f1c313b1673453245 100644 (file)
@@ -104,6 +104,145 @@ static int ov7630_init(struct sn9c102_device* cam)
                err += sn9c102_i2c_write(cam, 0x74, 0x21);
                err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
                break;
+       case BRIDGE_SN9C105:
+       case BRIDGE_SN9C120:
+       err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03},
+                                      {0x1a, 0x04}, {0x03, 0x10},
+                                      {0x0a, 0x14}, {0xe2, 0x17},
+                                      {0x0b, 0x18}, {0x00, 0x19},
+                                      {0x1d, 0x1a}, {0x10, 0x1b},
+                                      {0x02, 0x1c}, {0x03, 0x1d},
+                                      {0x0f, 0x1e}, {0x0c, 0x1f},
+                                      {0x00, 0x20}, {0x24, 0x21},
+                                      {0x3b, 0x22}, {0x47, 0x23},
+                                      {0x60, 0x24}, {0x71, 0x25},
+                                      {0x80, 0x26}, {0x8f, 0x27},
+                                      {0x9d, 0x28}, {0xaa, 0x29},
+                                      {0xb8, 0x2a}, {0xc4, 0x2b},
+                                      {0xd1, 0x2c}, {0xdd, 0x2d},
+                                      {0xe8, 0x2e}, {0xf4, 0x2f},
+                                      {0xff, 0x30}, {0x00, 0x3f},
+                                      {0xc7, 0x40}, {0x01, 0x41},
+                                      {0x44, 0x42}, {0x00, 0x43},
+                                      {0x44, 0x44}, {0x00, 0x45},
+                                      {0x44, 0x46}, {0x00, 0x47},
+                                      {0xc7, 0x48}, {0x01, 0x49},
+                                      {0xc7, 0x4a}, {0x01, 0x4b},
+                                      {0xc7, 0x4c}, {0x01, 0x4d},
+                                      {0x44, 0x4e}, {0x00, 0x4f},
+                                      {0x44, 0x50}, {0x00, 0x51},
+                                      {0x44, 0x52}, {0x00, 0x53},
+                                      {0xc7, 0x54}, {0x01, 0x55},
+                                      {0xc7, 0x56}, {0x01, 0x57},
+                                      {0xc7, 0x58}, {0x01, 0x59},
+                                      {0x44, 0x5a}, {0x00, 0x5b},
+                                      {0x44, 0x5c}, {0x00, 0x5d},
+                                      {0x44, 0x5e}, {0x00, 0x5f},
+                                      {0xc7, 0x60}, {0x01, 0x61},
+                                      {0xc7, 0x62}, {0x01, 0x63},
+                                      {0xc7, 0x64}, {0x01, 0x65},
+                                      {0x44, 0x66}, {0x00, 0x67},
+                                      {0x44, 0x68}, {0x00, 0x69},
+                                      {0x44, 0x6a}, {0x00, 0x6b},
+                                      {0xc7, 0x6c}, {0x01, 0x6d},
+                                      {0xc7, 0x6e}, {0x01, 0x6f},
+                                      {0xc7, 0x70}, {0x01, 0x71},
+                                      {0x44, 0x72}, {0x00, 0x73},
+                                      {0x44, 0x74}, {0x00, 0x75},
+                                      {0x44, 0x76}, {0x00, 0x77},
+                                      {0xc7, 0x78}, {0x01, 0x79},
+                                      {0xc7, 0x7a}, {0x01, 0x7b},
+                                      {0xc7, 0x7c}, {0x01, 0x7d},
+                                      {0x44, 0x7e}, {0x00, 0x7f},
+                                      {0x17, 0x84}, {0x00, 0x85},
+                                      {0x2e, 0x86}, {0x00, 0x87},
+                                      {0x09, 0x88}, {0x00, 0x89},
+                                      {0xe8, 0x8a}, {0x0f, 0x8b},
+                                      {0xda, 0x8c}, {0x0f, 0x8d},
+                                      {0x40, 0x8e}, {0x00, 0x8f},
+                                      {0x37, 0x90}, {0x00, 0x91},
+                                      {0xcf, 0x92}, {0x0f, 0x93},
+                                      {0xfa, 0x94}, {0x0f, 0x95},
+                                      {0x00, 0x96}, {0x00, 0x97},
+                                      {0x00, 0x98}, {0x66, 0x99},
+                                      {0x00, 0x9a}, {0x40, 0x9b},
+                                      {0x20, 0x9c}, {0x00, 0x9d},
+                                      {0x00, 0x9e}, {0x00, 0x9f},
+                                      {0x2d, 0xc0}, {0x2d, 0xc1},
+                                      {0x3a, 0xc2}, {0x00, 0xc3},
+                                      {0x04, 0xc4}, {0x3f, 0xc5},
+                                      {0x00, 0xc6}, {0x00, 0xc7},
+                                      {0x50, 0xc8}, {0x3c, 0xc9},
+                                      {0x28, 0xca}, {0xd8, 0xcb},
+                                      {0x14, 0xcc}, {0xec, 0xcd},
+                                      {0x32, 0xce}, {0xdd, 0xcf},
+                                      {0x32, 0xd0}, {0xdd, 0xd1},
+                                      {0x6a, 0xd2}, {0x50, 0xd3},
+                                      {0x60, 0xd4}, {0x00, 0xd5},
+                                      {0x00, 0xd6});
+
+               err += sn9c102_i2c_write(cam, 0x12, 0x80);
+               err += sn9c102_i2c_write(cam, 0x12, 0x48);
+               err += sn9c102_i2c_write(cam, 0x01, 0x80);
+               err += sn9c102_i2c_write(cam, 0x02, 0x80);
+               err += sn9c102_i2c_write(cam, 0x03, 0x80);
+               err += sn9c102_i2c_write(cam, 0x04, 0x10);
+               err += sn9c102_i2c_write(cam, 0x05, 0x20);
+               err += sn9c102_i2c_write(cam, 0x06, 0x80);
+               err += sn9c102_i2c_write(cam, 0x11, 0x00);
+               err += sn9c102_i2c_write(cam, 0x0c, 0x20);
+               err += sn9c102_i2c_write(cam, 0x0d, 0x20);
+               err += sn9c102_i2c_write(cam, 0x15, 0x80);
+               err += sn9c102_i2c_write(cam, 0x16, 0x03);
+               err += sn9c102_i2c_write(cam, 0x17, 0x1b);
+               err += sn9c102_i2c_write(cam, 0x18, 0xbd);
+               err += sn9c102_i2c_write(cam, 0x19, 0x05);
+               err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
+               err += sn9c102_i2c_write(cam, 0x1b, 0x04);
+               err += sn9c102_i2c_write(cam, 0x21, 0x1b);
+               err += sn9c102_i2c_write(cam, 0x22, 0x00);
+               err += sn9c102_i2c_write(cam, 0x23, 0xde);
+               err += sn9c102_i2c_write(cam, 0x24, 0x10);
+               err += sn9c102_i2c_write(cam, 0x25, 0x8a);
+               err += sn9c102_i2c_write(cam, 0x26, 0xa0);
+               err += sn9c102_i2c_write(cam, 0x27, 0xca);
+               err += sn9c102_i2c_write(cam, 0x28, 0xa2);
+               err += sn9c102_i2c_write(cam, 0x29, 0x74);
+               err += sn9c102_i2c_write(cam, 0x2a, 0x88);
+               err += sn9c102_i2c_write(cam, 0x2b, 0x34);
+               err += sn9c102_i2c_write(cam, 0x2c, 0x88);
+               err += sn9c102_i2c_write(cam, 0x2e, 0x00);
+               err += sn9c102_i2c_write(cam, 0x2f, 0x00);
+               err += sn9c102_i2c_write(cam, 0x30, 0x00);
+               err += sn9c102_i2c_write(cam, 0x32, 0xc2);
+               err += sn9c102_i2c_write(cam, 0x33, 0x08);
+               err += sn9c102_i2c_write(cam, 0x4c, 0x40);
+               err += sn9c102_i2c_write(cam, 0x4d, 0xf3);
+               err += sn9c102_i2c_write(cam, 0x60, 0x05);
+               err += sn9c102_i2c_write(cam, 0x61, 0x40);
+               err += sn9c102_i2c_write(cam, 0x62, 0x12);
+               err += sn9c102_i2c_write(cam, 0x63, 0x57);
+               err += sn9c102_i2c_write(cam, 0x64, 0x73);
+               err += sn9c102_i2c_write(cam, 0x65, 0x00);
+               err += sn9c102_i2c_write(cam, 0x66, 0x55);
+               err += sn9c102_i2c_write(cam, 0x67, 0x01);
+               err += sn9c102_i2c_write(cam, 0x68, 0xac);
+               err += sn9c102_i2c_write(cam, 0x69, 0x38);
+               err += sn9c102_i2c_write(cam, 0x6f, 0x1f);
+               err += sn9c102_i2c_write(cam, 0x70, 0x01);
+               err += sn9c102_i2c_write(cam, 0x71, 0x00);
+               err += sn9c102_i2c_write(cam, 0x72, 0x10);
+               err += sn9c102_i2c_write(cam, 0x73, 0x50);
+               err += sn9c102_i2c_write(cam, 0x74, 0x20);
+               err += sn9c102_i2c_write(cam, 0x76, 0x01);
+               err += sn9c102_i2c_write(cam, 0x77, 0xf3);
+               err += sn9c102_i2c_write(cam, 0x78, 0x90);
+               err += sn9c102_i2c_write(cam, 0x79, 0x98);
+               err += sn9c102_i2c_write(cam, 0x7a, 0x98);
+               err += sn9c102_i2c_write(cam, 0x7b, 0x00);
+               err += sn9c102_i2c_write(cam, 0x7c, 0x38);
+               err += sn9c102_i2c_write(cam, 0x7d, 0xff);
+               break;
        default:
                break;
        }
@@ -115,6 +254,7 @@ static int ov7630_init(struct sn9c102_device* cam)
 static int ov7630_get_ctrl(struct sn9c102_device* cam,
                           struct v4l2_control* ctrl)
 {
+       enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
        int err = 0;
 
        switch (ctrl->id) {
@@ -123,13 +263,20 @@ static int ov7630_get_ctrl(struct sn9c102_device* cam,
                        return -EIO;
                break;
        case V4L2_CID_RED_BALANCE:
-               ctrl->value = sn9c102_pread_reg(cam, 0x07);
+               if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+                       ctrl->value = sn9c102_pread_reg(cam, 0x05);
+               else
+                       ctrl->value = sn9c102_pread_reg(cam, 0x07);
                break;
        case V4L2_CID_BLUE_BALANCE:
                ctrl->value = sn9c102_pread_reg(cam, 0x06);
                break;
        case SN9C102_V4L2_CID_GREEN_BALANCE:
-               ctrl->value = sn9c102_pread_reg(cam, 0x05);
+               if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+                       ctrl->value = sn9c102_pread_reg(cam, 0x07);
+               else
+                       ctrl->value = sn9c102_pread_reg(cam, 0x05);
+               break;
                break;
        case V4L2_CID_GAIN:
                if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
@@ -177,6 +324,7 @@ static int ov7630_get_ctrl(struct sn9c102_device* cam,
 static int ov7630_set_ctrl(struct sn9c102_device* cam,
                           const struct v4l2_control* ctrl)
 {
+       enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
        int err = 0;
 
        switch (ctrl->id) {
@@ -184,13 +332,19 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
                err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
                break;
        case V4L2_CID_RED_BALANCE:
-               err += sn9c102_write_reg(cam, ctrl->value, 0x07);
+               if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+                       err += sn9c102_write_reg(cam, ctrl->value, 0x05);
+               else
+                       err += sn9c102_write_reg(cam, ctrl->value, 0x07);
                break;
        case V4L2_CID_BLUE_BALANCE:
                err += sn9c102_write_reg(cam, ctrl->value, 0x06);
                break;
        case SN9C102_V4L2_CID_GREEN_BALANCE:
-               err += sn9c102_write_reg(cam, ctrl->value, 0x05);
+               if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+                       err += sn9c102_write_reg(cam, ctrl->value, 0x07);
+               else
+                       err += sn9c102_write_reg(cam, ctrl->value, 0x05);
                break;
        case V4L2_CID_GAIN:
                err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
@@ -227,8 +381,21 @@ static int ov7630_set_crop(struct sn9c102_device* cam,
 {
        struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
        int err = 0;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
-          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+       u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+
+       switch (sn9c102_get_bridge(cam)) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+       case BRIDGE_SN9C103:
+               h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1;
+               break;
+       case BRIDGE_SN9C105:
+       case BRIDGE_SN9C120:
+               h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4;
+               break;
+       default:
+               break;
+       }
 
        err += sn9c102_write_reg(cam, h_start, 0x12);
        err += sn9c102_write_reg(cam, v_start, 0x13);
@@ -242,10 +409,28 @@ static int ov7630_set_pix_format(struct sn9c102_device* cam,
 {
        int err = 0;
 
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x20, 0x19);
-       else
-               err += sn9c102_write_reg(cam, 0x50, 0x19);
+       switch (sn9c102_get_bridge(cam)) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+       case BRIDGE_SN9C103:
+               if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8)
+                       err += sn9c102_write_reg(cam, 0x50, 0x19);
+               else
+                       err += sn9c102_write_reg(cam, 0x20, 0x19);
+               break;
+       case BRIDGE_SN9C105:
+       case BRIDGE_SN9C120:
+               if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
+                       err += sn9c102_write_reg(cam, 0xe5, 0x17);
+                       err += sn9c102_i2c_write(cam, 0x11, 0x04);
+               } else {
+                       err += sn9c102_write_reg(cam, 0xe2, 0x17);
+                       err += sn9c102_i2c_write(cam, 0x11, 0x02);
+               }
+               break;
+       default:
+               break;
+       }
 
        return err;
 }
@@ -254,7 +439,8 @@ static int ov7630_set_pix_format(struct sn9c102_device* cam,
 static const struct sn9c102_sensor ov7630 = {
        .name = "OV7630",
        .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
+       .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103 |
+                           BRIDGE_SN9C105 | BRIDGE_SN9C120,
        .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
        .frequency = SN9C102_I2C_100KHZ,
        .interface = SN9C102_I2C_2WIRES,
@@ -417,6 +603,12 @@ int sn9c102_probe_ov7630(struct sn9c102_device* cam)
                        err += sn9c102_write_const_regs(cam, {0x01, 0x01},
                                                        {0x00, 0x01});
                break;
+       case BRIDGE_SN9C105:
+       case BRIDGE_SN9C120:
+               err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
+                                              {0x29, 0x01}, {0x74, 0x02},
+                                              {0x0e, 0x01}, {0x44, 0x01});
+               break;
        default:
                break;
        }
index 4b6474048a72976a66638f8896edc36dc5aa79e0..8aae416ba8ec236bf06c88cc67ffbfb32e6a575c 100644 (file)
@@ -41,65 +41,65 @@ static int ov7660_init(struct sn9c102_device* cam)
                                       {0xbb, 0x2a}, {0xc7, 0x2b},
                                       {0xd3, 0x2c}, {0xde, 0x2d},
                                       {0xea, 0x2e}, {0xf4, 0x2f},
-                                      {0xff, 0x30}, {0x00, 0x3F},
-                                      {0xC7, 0x40}, {0x01, 0x41},
+                                      {0xff, 0x30}, {0x00, 0x3f},
+                                      {0xc7, 0x40}, {0x01, 0x41},
                                       {0x44, 0x42}, {0x00, 0x43},
                                       {0x44, 0x44}, {0x00, 0x45},
                                       {0x44, 0x46}, {0x00, 0x47},
-                                      {0xC7, 0x48}, {0x01, 0x49},
-                                      {0xC7, 0x4A}, {0x01, 0x4B},
-                                      {0xC7, 0x4C}, {0x01, 0x4D},
-                                      {0x44, 0x4E}, {0x00, 0x4F},
+                                      {0xc7, 0x48}, {0x01, 0x49},
+                                      {0xc7, 0x4a}, {0x01, 0x4b},
+                                      {0xc7, 0x4c}, {0x01, 0x4d},
+                                      {0x44, 0x4e}, {0x00, 0x4f},
                                       {0x44, 0x50}, {0x00, 0x51},
                                       {0x44, 0x52}, {0x00, 0x53},
-                                      {0xC7, 0x54}, {0x01, 0x55},
-                                      {0xC7, 0x56}, {0x01, 0x57},
-                                      {0xC7, 0x58}, {0x01, 0x59},
-                                      {0x44, 0x5A}, {0x00, 0x5B},
-                                      {0x44, 0x5C}, {0x00, 0x5D},
-                                      {0x44, 0x5E}, {0x00, 0x5F},
-                                      {0xC7, 0x60}, {0x01, 0x61},
-                                      {0xC7, 0x62}, {0x01, 0x63},
-                                      {0xC7, 0x64}, {0x01, 0x65},
+                                      {0xc7, 0x54}, {0x01, 0x55},
+                                      {0xc7, 0x56}, {0x01, 0x57},
+                                      {0xc7, 0x58}, {0x01, 0x59},
+                                      {0x44, 0x5a}, {0x00, 0x5b},
+                                      {0x44, 0x5c}, {0x00, 0x5d},
+                                      {0x44, 0x5e}, {0x00, 0x5f},
+                                      {0xc7, 0x60}, {0x01, 0x61},
+                                      {0xc7, 0x62}, {0x01, 0x63},
+                                      {0xc7, 0x64}, {0x01, 0x65},
                                       {0x44, 0x66}, {0x00, 0x67},
                                       {0x44, 0x68}, {0x00, 0x69},
-                                      {0x44, 0x6A}, {0x00, 0x6B},
-                                      {0xC7, 0x6C}, {0x01, 0x6D},
-                                      {0xC7, 0x6E}, {0x01, 0x6F},
-                                      {0xC7, 0x70}, {0x01, 0x71},
+                                      {0x44, 0x6a}, {0x00, 0x6b},
+                                      {0xc7, 0x6c}, {0x01, 0x6d},
+                                      {0xc7, 0x6e}, {0x01, 0x6f},
+                                      {0xc7, 0x70}, {0x01, 0x71},
                                       {0x44, 0x72}, {0x00, 0x73},
                                       {0x44, 0x74}, {0x00, 0x75},
                                       {0x44, 0x76}, {0x00, 0x77},
-                                      {0xC7, 0x78}, {0x01, 0x79},
-                                      {0xC7, 0x7A}, {0x01, 0x7B},
-                                      {0xC7, 0x7C}, {0x01, 0x7D},
-                                      {0x44, 0x7E}, {0x00, 0x7F},
+                                      {0xc7, 0x78}, {0x01, 0x79},
+                                      {0xc7, 0x7a}, {0x01, 0x7b},
+                                      {0xc7, 0x7c}, {0x01, 0x7d},
+                                      {0x44, 0x7e}, {0x00, 0x7f},
                                       {0x14, 0x84}, {0x00, 0x85},
                                       {0x27, 0x86}, {0x00, 0x87},
                                       {0x07, 0x88}, {0x00, 0x89},
-                                      {0xEC, 0x8A}, {0x0f, 0x8B},
-                                      {0xD8, 0x8C}, {0x0f, 0x8D},
-                                      {0x3D, 0x8E}, {0x00, 0x8F},
-                                      {0x3D, 0x90}, {0x00, 0x91},
-                                      {0xCD, 0x92}, {0x0f, 0x93},
+                                      {0xec, 0x8a}, {0x0f, 0x8b},
+                                      {0xd8, 0x8c}, {0x0f, 0x8d},
+                                      {0x3d, 0x8e}, {0x00, 0x8f},
+                                      {0x3d, 0x90}, {0x00, 0x91},
+                                      {0xcd, 0x92}, {0x0f, 0x93},
                                       {0xf7, 0x94}, {0x0f, 0x95},
-                                      {0x0C, 0x96}, {0x00, 0x97},
+                                      {0x0c, 0x96}, {0x00, 0x97},
                                       {0x00, 0x98}, {0x66, 0x99},
-                                      {0x05, 0x9A}, {0x00, 0x9B},
-                                      {0x04, 0x9C}, {0x00, 0x9D},
-                                      {0x08, 0x9E}, {0x00, 0x9F},
-                                      {0x2D, 0xC0}, {0x2D, 0xC1},
-                                      {0x3A, 0xC2}, {0x05, 0xC3},
-                                      {0x04, 0xC4}, {0x3F, 0xC5},
-                                      {0x00, 0xC6}, {0x00, 0xC7},
-                                      {0x50, 0xC8}, {0x3C, 0xC9},
-                                      {0x28, 0xCA}, {0xD8, 0xCB},
-                                      {0x14, 0xCC}, {0xEC, 0xCD},
-                                      {0x32, 0xCE}, {0xDD, 0xCF},
-                                      {0x32, 0xD0}, {0xDD, 0xD1},
-                                      {0x6A, 0xD2}, {0x50, 0xD3},
-                                      {0x00, 0xD4}, {0x00, 0xD5},
-                                      {0x00, 0xD6});
+                                      {0x05, 0x9a}, {0x00, 0x9b},
+                                      {0x04, 0x9c}, {0x00, 0x9d},
+                                      {0x08, 0x9e}, {0x00, 0x9f},
+                                      {0x2d, 0xc0}, {0x2d, 0xc1},
+                                      {0x3a, 0xc2}, {0x05, 0xc3},
+                                      {0x04, 0xc4}, {0x3f, 0xc5},
+                                      {0x00, 0xc6}, {0x00, 0xc7},
+                                      {0x50, 0xc8}, {0x3C, 0xc9},
+                                      {0x28, 0xca}, {0xd8, 0xcb},
+                                      {0x14, 0xcc}, {0xec, 0xcd},
+                                      {0x32, 0xce}, {0xdd, 0xcf},
+                                      {0x32, 0xd0}, {0xdd, 0xd1},
+                                      {0x6a, 0xd2}, {0x50, 0xd3},
+                                      {0x00, 0xd4}, {0x00, 0xd5},
+                                      {0x00, 0xd6});
 
        err += sn9c102_i2c_write(cam, 0x12, 0x80);
        err += sn9c102_i2c_write(cam, 0x11, 0x09);
index 3e736be5de84496305cb1ac53767881be4df6955..eb220461ac77a8e9f973dae81f837ee4ae54a198 100644 (file)
@@ -1321,7 +1321,7 @@ static int saa_ioctl(struct inode *inode, struct file *file,
                        u32 format;
                        if (copy_from_user(&p, arg, sizeof(p)))
                                return -EFAULT;
-                       if (p.palette < sizeof(palette2fmt) / sizeof(u32)) {
+                       if (p.palette < ARRAY_SIZE(palette2fmt)) {
                                format = palette2fmt[p.palette];
                                saa->win.color_fmt = format;
                                saawrite(format | 0x60,
index bf3aa8d2d57e3ccc7ecdcbdf29b4e67e2e041aaa..4dc5bc714b953044467a8b7020a65884767ed51b 100644 (file)
@@ -715,8 +715,11 @@ static int stv680_start_stream (struct usb_stv *stv680)
                                   stv680_video_irq, stv680);
                stv680->urb[i] = urb;
                err = usb_submit_urb (stv680->urb[i], GFP_KERNEL);
-               if (err)
-                       PDEBUG (0, "STV(e): urb burned down in start stream");
+               if (err) {
+                       PDEBUG (0, "STV(e): urb burned down with err "
+                                  "%d in start stream %d", err, i);
+                       goto nomem_err;
+               }
        }                       /* i STV680_NUMSBUF */
 
        stv680->framecount = 0;
index 1a1bef0e9c3dcf65ad5314b2952fc238ac6a5682..59cff5a3c59e106fb47cf243160ccdf62b2cafe3 100644 (file)
 #include <linux/i2c.h>
 #include <linux/videodev.h>
 #include <linux/delay.h>
-#include <media/tuner.h>
+#include "tuner-driver.h"
+
+/* ---------------------------------------------------------------------- */
+
+struct tda8290_priv {
+       unsigned char tda8290_easy_mode;
+       unsigned char tda827x_lpsel;
+       unsigned char tda827x_addr;
+       unsigned char tda827x_ver;
+       unsigned int sgIF;
+};
 
 /* ---------------------------------------------------------------------- */
 
@@ -76,7 +86,8 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
        u32 N;
        int i;
        struct tuner *t = i2c_get_clientdata(c);
-       struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0};
+       struct tda8290_priv *priv = t->priv;
+       struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0};
 
        if (t->mode == V4L2_TUNER_RADIO)
                freq = freq / 1000;
@@ -95,7 +106,7 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
        tuner_reg[1] = (unsigned char)(N>>8);
        tuner_reg[2] = (unsigned char) N;
        tuner_reg[3] = 0x40;
-       tuner_reg[4] = 0x52 + (t->tda827x_lpsel << 5);
+       tuner_reg[4] = 0x52 + (priv->tda827x_lpsel << 5);
        tuner_reg[5] = (tda827x_analog[i].spd   << 6) + (tda827x_analog[i].div1p5 <<5) +
                       (tda827x_analog[i].bs     <<3) +  tda827x_analog[i].bp;
        tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4);
@@ -146,8 +157,9 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
 static void tda827x_agcf(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       struct tda8290_priv *priv = t->priv;
        unsigned char data[] = {0x80, 0x0c};
-       struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+       struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
                              .flags = 0, .len = 2};
        i2c_transfer(c->adapter, &msg, 1);
 }
@@ -234,7 +246,8 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
        u32 N;
        int i;
        struct tuner *t = i2c_get_clientdata(c);
-       struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0, .buf = tuner_reg};
+       struct tda8290_priv *priv = t->priv;
+       struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg};
 
        tda827xa_lna_gain( c, 1);
        msleep(10);
@@ -271,7 +284,7 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
        tuner_reg[1] = 0xff;
        tuner_reg[2] = 0xe0;
        tuner_reg[3] = 0;
-       tuner_reg[4] = 0x99 + (t->tda827x_lpsel << 1);
+       tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1);
        msg.len = 5;
        i2c_transfer(c->adapter, &msg, 1);
 
@@ -311,15 +324,16 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
        i2c_transfer(c->adapter, &msg, 1);
 
        tuner_reg[0] = 0xc0;
-       tuner_reg[1] = 0x19 + (t->tda827x_lpsel << 1);
+       tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1);
        i2c_transfer(c->adapter, &msg, 1);
 }
 
 static void tda827xa_agcf(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       struct tda8290_priv *priv = t->priv;
        unsigned char data[] = {0x80, 0x2c};
-       struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+       struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
                              .flags = 0, .len = 2};
        i2c_transfer(c->adapter, &msg, 1);
 }
@@ -347,8 +361,9 @@ static void tda8290_i2c_bridge(struct i2c_client *c, int close)
 static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       struct tda8290_priv *priv = t->priv;
        unsigned char soft_reset[]  = { 0x00, 0x00 };
-       unsigned char easy_mode[]   = { 0x01, t->tda8290_easy_mode };
+       unsigned char easy_mode[]   = { 0x01, priv->tda8290_easy_mode };
        unsigned char expert_mode[] = { 0x01, 0x80 };
        unsigned char agc_out_on[]  = { 0x02, 0x00 };
        unsigned char gainset_off[] = { 0x28, 0x14 };
@@ -375,18 +390,18 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
        i2c_master_send(c, soft_reset, 2);
        msleep(1);
 
-       expert_mode[1] = t->tda8290_easy_mode + 0x80;
+       expert_mode[1] = priv->tda8290_easy_mode + 0x80;
        i2c_master_send(c, expert_mode, 2);
        i2c_master_send(c, gainset_off, 2);
        i2c_master_send(c, if_agc_spd, 2);
-       if (t->tda8290_easy_mode & 0x60)
+       if (priv->tda8290_easy_mode & 0x60)
                i2c_master_send(c, adc_head_9, 2);
        else
                i2c_master_send(c, adc_head_6, 2);
        i2c_master_send(c, pll_bw_nom, 2);
 
        tda8290_i2c_bridge(c, 1);
-       if (t->tda827x_ver != 0)
+       if (priv->tda827x_ver != 0)
                tda827xa_tune(c, ifc, freq);
        else
                tda827x_tune(c, ifc, freq);
@@ -418,7 +433,7 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
                if ((agc_stat > 115) || !(pll_stat & 0x80)) {
                        tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
                                   agc_stat, pll_stat & 0x80);
-                       if (t->tda827x_ver != 0)
+                       if (priv->tda827x_ver != 0)
                                tda827xa_agcf(c);
                        else
                                tda827x_agcf(c);
@@ -437,7 +452,7 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
        }
 
        /* l/ l' deadlock? */
-       if(t->tda8290_easy_mode & 0x60) {
+       if(priv->tda8290_easy_mode & 0x60) {
                i2c_master_send(c, &addr_adc_sat, 1);
                i2c_master_recv(c, &adc_sat, 1);
                i2c_master_send(c, &addr_pll_stat, 1);
@@ -459,41 +474,42 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
 
 static void set_audio(struct tuner *t)
 {
+       struct tda8290_priv *priv = t->priv;
        char* mode;
 
-       t->tda827x_lpsel = 0;
+       priv->tda827x_lpsel = 0;
        if (t->std & V4L2_STD_MN) {
-               t->sgIF = 92;
-               t->tda8290_easy_mode = 0x01;
-               t->tda827x_lpsel = 1;
+               priv->sgIF = 92;
+               priv->tda8290_easy_mode = 0x01;
+               priv->tda827x_lpsel = 1;
                mode = "MN";
        } else if (t->std & V4L2_STD_B) {
-               t->sgIF = 108;
-               t->tda8290_easy_mode = 0x02;
+               priv->sgIF = 108;
+               priv->tda8290_easy_mode = 0x02;
                mode = "B";
        } else if (t->std & V4L2_STD_GH) {
-               t->sgIF = 124;
-               t->tda8290_easy_mode = 0x04;
+               priv->sgIF = 124;
+               priv->tda8290_easy_mode = 0x04;
                mode = "GH";
        } else if (t->std & V4L2_STD_PAL_I) {
-               t->sgIF = 124;
-               t->tda8290_easy_mode = 0x08;
+               priv->sgIF = 124;
+               priv->tda8290_easy_mode = 0x08;
                mode = "I";
        } else if (t->std & V4L2_STD_DK) {
-               t->sgIF = 124;
-               t->tda8290_easy_mode = 0x10;
+               priv->sgIF = 124;
+               priv->tda8290_easy_mode = 0x10;
                mode = "DK";
        } else if (t->std & V4L2_STD_SECAM_L) {
-               t->sgIF = 124;
-               t->tda8290_easy_mode = 0x20;
+               priv->sgIF = 124;
+               priv->tda8290_easy_mode = 0x20;
                mode = "L";
        } else if (t->std & V4L2_STD_SECAM_LC) {
-               t->sgIF = 20;
-               t->tda8290_easy_mode = 0x40;
+               priv->sgIF = 20;
+               priv->tda8290_easy_mode = 0x40;
                mode = "LC";
        } else {
-               t->sgIF = 124;
-               t->tda8290_easy_mode = 0x10;
+               priv->sgIF = 124;
+               priv->tda8290_easy_mode = 0x10;
                mode = "xx";
        }
        tuner_dbg("setting tda8290 to system %s\n", mode);
@@ -502,9 +518,10 @@ static void set_audio(struct tuner *t)
 static void set_tv_freq(struct i2c_client *c, unsigned int freq)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       struct tda8290_priv *priv = t->priv;
 
        set_audio(t);
-       tda8290_tune(c, t->sgIF, freq);
+       tda8290_tune(c, priv->sgIF, freq);
 }
 
 static void set_radio_freq(struct i2c_client *c, unsigned int freq)
@@ -528,13 +545,14 @@ static int has_signal(struct i2c_client *c)
 static void standby(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       struct tda8290_priv *priv = t->priv;
        unsigned char cb1[] = { 0x30, 0xD0 };
        unsigned char tda8290_standby[] = { 0x00, 0x02 };
        unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
-       struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
+       struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
 
        tda8290_i2c_bridge(c, 1);
-       if (t->tda827x_ver != 0)
+       if (priv->tda827x_ver != 0)
                cb1[1] = 0x90;
        i2c_transfer(c->adapter, &msg, 1);
        tda8290_i2c_bridge(c, 0);
@@ -560,13 +578,14 @@ static void tda8290_init_if(struct i2c_client *c)
 static void tda8290_init_tuner(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       struct tda8290_priv *priv = t->priv;
        unsigned char tda8275_init[]  = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
                                          0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
        unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
                                          0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
-       struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0,
+       struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0,
                              .buf=tda8275_init, .len = 14};
-       if (t->tda827x_ver != 0)
+       if (priv->tda827x_ver != 0)
                msg.buf = tda8275a_init;
 
        tda8290_i2c_bridge(c, 1);
@@ -576,14 +595,36 @@ static void tda8290_init_tuner(struct i2c_client *c)
 
 /*---------------------------------------------------------------------*/
 
+static void tda8290_release(struct i2c_client *c)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+
+       kfree(t->priv);
+       t->priv = NULL;
+}
+
+static struct tuner_operations tda8290_tuner_ops = {
+       .set_tv_freq    = set_tv_freq,
+       .set_radio_freq = set_radio_freq,
+       .has_signal     = has_signal,
+       .standby        = standby,
+       .release        = tda8290_release,
+};
+
 int tda8290_init(struct i2c_client *c)
 {
+       struct tda8290_priv *priv = NULL;
        struct tuner *t = i2c_get_clientdata(c);
        u8 data;
        int i, ret, tuners_found;
        u32 tuner_addrs;
        struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1};
 
+       priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+       t->priv = priv;
+
        tda8290_i2c_bridge(c, 1);
        /* probe for tuner chip */
        tuners_found = 0;
@@ -618,7 +659,7 @@ int tda8290_init(struct i2c_client *c)
                tuner_addrs = tuner_addrs & 0xff;
                tuner_info ("setting tuner address to %x\n", tuner_addrs);
        }
-       t->tda827x_addr = tuner_addrs;
+       priv->tda827x_addr = tuner_addrs;
        msg.addr = tuner_addrs;
 
        tda8290_i2c_bridge(c, 1);
@@ -627,18 +668,16 @@ int tda8290_init(struct i2c_client *c)
                tuner_warn ("TDA827x access failed!\n");
        if ((data & 0x3c) == 0) {
                strlcpy(c->name, "tda8290+75", sizeof(c->name));
-               t->tda827x_ver = 0;
+               priv->tda827x_ver = 0;
        } else {
                strlcpy(c->name, "tda8290+75a", sizeof(c->name));
-               t->tda827x_ver = 2;
+               priv->tda827x_ver = 2;
        }
        tuner_info("type set to %s\n", c->name);
 
-       t->set_tv_freq    = set_tv_freq;
-       t->set_radio_freq = set_radio_freq;
-       t->has_signal = has_signal;
-       t->standby = standby;
-       t->tda827x_lpsel = 0;
+       memcpy(&t->ops, &tda8290_tuner_ops, sizeof(struct tuner_operations));
+
+       priv->tda827x_lpsel = 0;
        t->mode = V4L2_TUNER_ANALOG_TV;
 
        tda8290_init_tuner(c);
index fde576f1101cb3f980c9cb616aa3ae7ee1be48c3..a8f773274fe3f8188f0e7131f86f27fa74d0a24d 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <media/v4l2-common.h>
 #include <media/tuner.h>
+#include "tuner-driver.h"
 
 
 /* Chips:
@@ -29,6 +30,9 @@
                printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
                        i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
 
+struct tda9887_priv {
+       unsigned char      data[4];
+};
 
 /* ---------------------------------------------------------------------- */
 
@@ -508,10 +512,11 @@ static int tda9887_status(struct tuner *t)
 static void tda9887_configure(struct i2c_client *client)
 {
        struct tuner *t = i2c_get_clientdata(client);
+       struct tda9887_priv *priv = t->priv;
        int rc;
 
-       memset(t->tda9887_data,0,sizeof(t->tda9887_data));
-       tda9887_set_tvnorm(t,t->tda9887_data);
+       memset(priv->data,0,sizeof(priv->data));
+       tda9887_set_tvnorm(t,priv->data);
 
        /* A note on the port settings:
           These settings tend to depend on the specifics of the board.
@@ -526,22 +531,22 @@ static void tda9887_configure(struct i2c_client *client)
           the ports should be set to active (0), but, again, that may
           differ depending on the precise hardware configuration.
         */
-       t->tda9887_data[1] |= cOutputPort1Inactive;
-       t->tda9887_data[1] |= cOutputPort2Inactive;
+       priv->data[1] |= cOutputPort1Inactive;
+       priv->data[1] |= cOutputPort2Inactive;
 
-       tda9887_set_config(t,t->tda9887_data);
-       tda9887_set_insmod(t,t->tda9887_data);
+       tda9887_set_config(t,priv->data);
+       tda9887_set_insmod(t,priv->data);
 
        if (t->mode == T_STANDBY) {
-               t->tda9887_data[1] |= cForcedMuteAudioON;
+               priv->data[1] |= cForcedMuteAudioON;
        }
 
        tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
-               t->tda9887_data[1],t->tda9887_data[2],t->tda9887_data[3]);
+               priv->data[1],priv->data[2],priv->data[3]);
        if (tuner_debug > 1)
-               dump_write_message(t, t->tda9887_data);
+               dump_write_message(t, priv->data);
 
-       if (4 != (rc = i2c_master_send(&t->i2c,t->tda9887_data,4)))
+       if (4 != (rc = i2c_master_send(&t->i2c,priv->data,4)))
                tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
 
        if (tuner_debug > 2) {
@@ -555,7 +560,8 @@ static void tda9887_configure(struct i2c_client *client)
 static void tda9887_tuner_status(struct i2c_client *client)
 {
        struct tuner *t = i2c_get_clientdata(client);
-       tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->tda9887_data[1], t->tda9887_data[2], t->tda9887_data[3]);
+       struct tda9887_priv *priv = t->priv;
+       tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]);
 }
 
 static int tda9887_get_afc(struct i2c_client *client)
@@ -586,20 +592,39 @@ static void tda9887_set_freq(struct i2c_client *client, unsigned int freq)
        tda9887_configure(client);
 }
 
+static void tda9887_release(struct i2c_client *c)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+
+       kfree(t->priv);
+       t->priv = NULL;
+}
+
+static struct tuner_operations tda9887_tuner_ops = {
+       .set_tv_freq    = tda9887_set_freq,
+       .set_radio_freq = tda9887_set_freq,
+       .standby        = tda9887_standby,
+       .tuner_status   = tda9887_tuner_status,
+       .get_afc        = tda9887_get_afc,
+       .release        = tda9887_release,
+};
+
 int tda9887_tuner_init(struct i2c_client *c)
 {
+       struct tda9887_priv *priv = NULL;
        struct tuner *t = i2c_get_clientdata(c);
 
+       priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+       t->priv = priv;
+
        strlcpy(c->name, "tda9887", sizeof(c->name));
 
        tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
                                                t->i2c.driver->driver.name);
 
-       t->set_tv_freq = tda9887_set_freq;
-       t->set_radio_freq = tda9887_set_freq;
-       t->standby = tda9887_standby;
-       t->tuner_status = tda9887_tuner_status;
-       t->get_afc = tda9887_get_afc;
+       memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations));
 
        return 0;
 }
diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c
new file mode 100644 (file)
index 0000000..ae105c2
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * For Philips TEA5761 FM Chip
+ * I2C address is allways 0x20 (0x10 at 7-bit mode).
+ *
+ * Copyright (c) 2005-2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNUv2 General Public License
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/delay.h>
+#include <media/tuner.h>
+#include "tuner-driver.h"
+
+#define PREFIX "TEA5761 "
+
+/* from tuner-core.c */
+extern int tuner_debug;
+
+/*****************************************************************************/
+
+/***************************
+ * TEA5761HN I2C registers *
+ ***************************/
+
+/* INTREG - Read: bytes 0 and 1 / Write: byte 0 */
+
+       /* first byte for reading */
+#define TEA5761_INTREG_IFFLAG          0x10
+#define TEA5761_INTREG_LEVFLAG         0x8
+#define TEA5761_INTREG_FRRFLAG         0x2
+#define TEA5761_INTREG_BLFLAG          0x1
+
+       /* second byte for reading / byte for writing */
+#define TEA5761_INTREG_IFMSK           0x10
+#define TEA5761_INTREG_LEVMSK          0x8
+#define TEA5761_INTREG_FRMSK           0x2
+#define TEA5761_INTREG_BLMSK           0x1
+
+/* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */
+
+       /* First byte */
+#define TEA5761_FRQSET_SEARCH_UP 0x80          /* 1=Station search from botton to up */
+#define TEA5761_FRQSET_SEARCH_MODE 0x40                /* 1=Search mode */
+
+       /* Bits 0-5 for divider MSB */
+
+       /* Second byte */
+       /* Bits 0-7 for divider LSB */
+
+/* TNCTRL - Read: bytes 4 and 5 / Write: Bytes 3 and 4 */
+
+       /* first byte */
+
+#define TEA5761_TNCTRL_PUPD_0  0x40    /* Power UP/Power Down MSB */
+#define TEA5761_TNCTRL_BLIM    0X20    /* 1= Japan Frequencies, 0= European frequencies */
+#define TEA5761_TNCTRL_SWPM    0x10    /* 1= software port is FRRFLAG */
+#define TEA5761_TNCTRL_IFCTC   0x08    /* 1= IF count time 15.02 ms, 0= IF count time 2.02 ms */
+#define TEA5761_TNCTRL_AFM     0x04
+#define TEA5761_TNCTRL_SMUTE   0x02    /* 1= Soft mute */
+#define TEA5761_TNCTRL_SNC     0x01
+
+       /* second byte */
+
+#define TEA5761_TNCTRL_MU      0x80    /* 1=Hard mute */
+#define TEA5761_TNCTRL_SSL_1   0x40
+#define TEA5761_TNCTRL_SSL_0   0x20
+#define TEA5761_TNCTRL_HLSI    0x10
+#define TEA5761_TNCTRL_MST     0x08    /* 1 = mono */
+#define TEA5761_TNCTRL_SWP     0x04
+#define TEA5761_TNCTRL_DTC     0x02    /* 1 = deemphasis 50 us, 0 = deemphasis 75 us */
+#define TEA5761_TNCTRL_AHLSI   0x01
+
+/* FRQCHECK - Read: bytes 6 and 7  */
+       /* First byte */
+
+       /* Bits 0-5 for divider MSB */
+
+       /* Second byte */
+       /* Bits 0-7 for divider LSB */
+
+/* TUNCHECK - Read: bytes 8 and 9  */
+
+       /* First byte */
+#define TEA5761_TUNCHECK_IF_MASK       0x7e    /* IF count */
+#define TEA5761_TUNCHECK_TUNTO         0x01
+
+       /* Second byte */
+#define TEA5761_TUNCHECK_LEV_MASK      0xf0    /* Level Count */
+#define TEA5761_TUNCHECK_LD            0x08
+#define TEA5761_TUNCHECK_STEREO                0x04
+
+/* TESTREG - Read: bytes 10 and 11 / Write: bytes 5 and 6 */
+
+       /* All zero = no test mode */
+
+/* MANID - Read: bytes 12 and 13 */
+
+       /* First byte - should be 0x10 */
+#define TEA5767_MANID_VERSION_MASK     0xf0    /* Version = 1 */
+#define TEA5767_MANID_ID_MSB_MASK      0x0f    /* Manufacurer ID - should be 0 */
+
+       /* Second byte - Should be 0x2b */
+
+#define TEA5767_MANID_ID_LSB_MASK      0xfe    /* Manufacturer ID - should be 0x15 */
+#define TEA5767_MANID_IDAV             0x01    /* 1 = Chip has ID, 0 = Chip has no ID */
+
+/* Chip ID - Read: bytes 14 and 15 */
+
+       /* First byte - should be 0x57 */
+
+       /* Second byte - should be 0x61 */
+
+/*****************************************************************************/
+
+static void set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+
+       tuner_warn("This tuner doesn't support TV freq.\n");
+}
+
+#define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */
+static void tea5761_status_dump(unsigned char *buffer)
+{
+       unsigned int div, frq;
+
+       div = ((buffer[2] & 0x3f) << 8) | buffer[3];
+
+       frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4;      /* Freq in KHz */
+
+       printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n",
+              frq / 1000, frq % 1000, div);
+}
+
+/* Freq should be specifyed at 62.5 Hz */
+static void set_radio_freq(struct i2c_client *c, unsigned int frq)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+       unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 };
+       unsigned div;
+       int rc;
+
+       tuner_dbg (PREFIX "radio freq counter %d\n", frq);
+
+       if (t->mode == T_STANDBY) {
+               tuner_dbg("TEA5761 set to standby mode\n");
+               buffer[5] |= TEA5761_TNCTRL_MU;
+       } else {
+               buffer[4] |= TEA5761_TNCTRL_PUPD_0;
+       }
+
+
+       if (t->audmode == V4L2_TUNER_MODE_MONO) {
+               tuner_dbg("TEA5761 set to mono\n");
+               buffer[5] |= TEA5761_TNCTRL_MST;
+;
+       } else {
+               tuner_dbg("TEA5761 set to stereo\n");
+       }
+
+       div = (1000 * (frq * 4 / 16 + 700 + 225) ) >> 15;
+       buffer[1] = (div >> 8) & 0x3f;
+       buffer[2] = div & 0xff;
+
+       if (tuner_debug)
+               tea5761_status_dump(buffer);
+
+       if (7 != (rc = i2c_master_send(c, buffer, 7)))
+               tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+}
+
+static int tea5761_signal(struct i2c_client *c)
+{
+       unsigned char buffer[16];
+       int rc;
+       struct tuner *t = i2c_get_clientdata(c);
+
+       memset(buffer, 0, sizeof(buffer));
+       if (16 != (rc = i2c_master_recv(c, buffer, 16)))
+               tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+       return ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4));
+}
+
+static int tea5761_stereo(struct i2c_client *c)
+{
+       unsigned char buffer[16];
+       int rc;
+       struct tuner *t = i2c_get_clientdata(c);
+
+       memset(buffer, 0, sizeof(buffer));
+       if (16 != (rc = i2c_master_recv(c, buffer, 16)))
+               tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+       rc = buffer[9] & TEA5761_TUNCHECK_STEREO;
+
+       tuner_dbg("TEA5761 radio ST GET = %02x\n", rc);
+
+       return (rc ? V4L2_TUNER_SUB_STEREO : 0);
+}
+
+int tea5761_autodetection(struct i2c_client *c)
+{
+       unsigned char buffer[16];
+       int rc;
+       struct tuner *t = i2c_get_clientdata(c);
+
+       if (16 != (rc = i2c_master_recv(c, buffer, 16))) {
+               tuner_warn("it is not a TEA5761. Received %i chars.\n", rc);
+               return EINVAL;
+       }
+
+       if (!((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061))) {
+               tuner_warn("Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]);
+               return EINVAL;
+       }
+       tuner_warn("TEA5761 detected.\n");
+       return 0;
+}
+
+static struct tuner_operations tea5761_tuner_ops = {
+       .set_tv_freq    = set_tv_freq,
+       .set_radio_freq = set_radio_freq,
+       .has_signal     = tea5761_signal,
+       .is_stereo      = tea5761_stereo,
+};
+
+int tea5761_tuner_init(struct i2c_client *c)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+
+       if (tea5761_autodetection(c) == EINVAL)
+               return EINVAL;
+
+       tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5761HN FM Radio");
+       strlcpy(c->name, "tea5761", sizeof(c->name));
+
+       memcpy(&t->ops, &tea5761_tuner_ops, sizeof(struct tuner_operations));
+
+       return (0);
+}
index d1c41781ccc47dd3dd00ea8d7d5d15f3a6dd5cda..4985d47a508f7465b5840debe71e0324d71a3c6e 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/i2c.h>
 #include <linux/videodev.h>
 #include <linux/delay.h>
-#include <media/tuner.h>
+#include "tuner-driver.h"
 
 #define PREFIX "TEA5767 "
 
@@ -343,6 +343,14 @@ int tea5767_autodetection(struct i2c_client *c)
        return 0;
 }
 
+static struct tuner_operations tea5767_tuner_ops = {
+       .set_tv_freq    = set_tv_freq,
+       .set_radio_freq = set_radio_freq,
+       .has_signal     = tea5767_signal,
+       .is_stereo      = tea5767_stereo,
+       .standby        = tea5767_standby,
+};
+
 int tea5767_tuner_init(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
@@ -350,11 +358,7 @@ int tea5767_tuner_init(struct i2c_client *c)
        tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio");
        strlcpy(c->name, "tea5767", sizeof(c->name));
 
-       t->set_tv_freq = set_tv_freq;
-       t->set_radio_freq = set_radio_freq;
-       t->has_signal = tea5767_signal;
-       t->is_stereo = tea5767_stereo;
-       t->standby = tea5767_standby;
+       memcpy(&t->ops, &tea5767_tuner_ops, sizeof(struct tuner_operations));
 
        return (0);
 }
index 505591a7abe970dbaa694c9c714e32a660159ca9..e646465464a1e8c7e29a63823fac88fa14b478b1 100644 (file)
 
 #include <media/tuner.h>
 #include <media/v4l2-common.h>
+#include "tuner-driver.h"
 
 #define UNSET (-1U)
 
 /* standard i2c insmod options */
 static unsigned short normal_i2c[] = {
+#ifdef CONFIG_TUNER_TEA5761
+       0x10,
+#endif
        0x42, 0x43, 0x4a, 0x4b,                 /* tda8290 */
        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
        0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
@@ -77,7 +81,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
                tuner_warn ("tuner type not set\n");
                return;
        }
-       if (NULL == t->set_tv_freq) {
+       if (NULL == t->ops.set_tv_freq) {
                tuner_warn ("Tuner has no way to set tv freq\n");
                return;
        }
@@ -92,7 +96,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
                else
                        freq = tv_range[1] * 16;
        }
-       t->set_tv_freq(c, freq);
+       t->ops.set_tv_freq(c, freq);
 }
 
 static void set_radio_freq(struct i2c_client *c, unsigned int freq)
@@ -103,7 +107,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
                tuner_warn ("tuner type not set\n");
                return;
        }
-       if (NULL == t->set_radio_freq) {
+       if (NULL == t->ops.set_radio_freq) {
                tuner_warn ("tuner has no way to set radio frequency\n");
                return;
        }
@@ -119,7 +123,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
                        freq = radio_range[1] * 16000;
        }
 
-       t->set_radio_freq(c, freq);
+       t->ops.set_radio_freq(c, freq);
 }
 
 static void set_freq(struct i2c_client *c, unsigned long freq)
@@ -174,6 +178,14 @@ static void set_type(struct i2c_client *c, unsigned int type,
                return;
        }
 
+       /* discard private data, in case set_type() was previously called */
+       if (t->ops.release)
+               t->ops.release(c);
+       else {
+               kfree(t->priv);
+               t->priv = NULL;
+       }
+
        switch (t->type) {
        case TUNER_MT2032:
                microtune_init(c);
@@ -189,6 +201,16 @@ static void set_type(struct i2c_client *c, unsigned int type,
                }
                t->mode_mask = T_RADIO;
                break;
+#ifdef CONFIG_TUNER_TEA5761
+       case TUNER_TEA5761:
+               if (tea5761_tuner_init(c) == EINVAL) {
+                       t->type = TUNER_ABSENT;
+                       t->mode_mask = T_UNINITIALIZED;
+                       return;
+               }
+               t->mode_mask = T_RADIO;
+               break;
+#endif
        case TUNER_PHILIPS_FMD1216ME_MK3:
                buffer[0] = 0x0b;
                buffer[1] = 0xdc;
@@ -408,11 +430,11 @@ static void tuner_status(struct i2c_client *client)
        tuner_info("Standard:        0x%08lx\n", (unsigned long)t->std);
        if (t->mode != V4L2_TUNER_RADIO)
               return;
-       if (t->has_signal) {
-               tuner_info("Signal strength: %d\n", t->has_signal(client));
+       if (t->ops.has_signal) {
+               tuner_info("Signal strength: %d\n", t->ops.has_signal(client));
        }
-       if (t->is_stereo) {
-               tuner_info("Stereo:          %s\n", t->is_stereo(client) ? "yes" : "no");
+       if (t->ops.is_stereo) {
+               tuner_info("Stereo:          %s\n", t->ops.is_stereo(client) ? "yes" : "no");
        }
 }
 
@@ -437,10 +459,9 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
        memcpy(&t->i2c, &client_template, sizeof(struct i2c_client));
        i2c_set_clientdata(&t->i2c, t);
        t->type = UNSET;
-       t->radio_if2 = 10700 * 1000;    /* 10.7MHz - FM radio */
        t->audmode = V4L2_TUNER_MODE_STEREO;
        t->mode_mask = T_UNINITIALIZED;
-       t->tuner_status = tuner_status;
+       t->ops.tuner_status = tuner_status;
 
        if (show_i2c) {
                unsigned char buffer[16];
@@ -460,6 +481,19 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
        /* autodetection code based on the i2c addr */
        if (!no_autodetect) {
                switch (addr) {
+#ifdef CONFIG_TUNER_TEA5761
+               case 0x10:
+                       if (tea5761_autodetection(&t->i2c) != EINVAL) {
+                               t->type = TUNER_TEA5761;
+                               t->mode_mask = T_RADIO;
+                               t->mode = T_STANDBY;
+                               t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
+                               default_mode_mask &= ~T_RADIO;
+
+                               goto register_client;
+                       }
+                       break;
+#endif
                case 0x42:
                case 0x43:
                case 0x4a:
@@ -533,6 +567,11 @@ static int tuner_detach(struct i2c_client *client)
                return err;
        }
 
+       if (t->ops.release)
+               t->ops.release(client);
+       else {
+               kfree(t->priv);
+       }
        kfree(t);
        return 0;
 }
@@ -553,8 +592,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode,
 
        if (check_mode(t, cmd) == EINVAL) {
                t->mode = T_STANDBY;
-               if (t->standby)
-                       t->standby (client);
+               if (t->ops.standby)
+                       t->ops.standby (client);
                return EINVAL;
        }
        return 0;
@@ -602,8 +641,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
                        return 0;
                t->mode = T_STANDBY;
-               if (t->standby)
-                       t->standby (client);
+               if (t->ops.standby)
+                       t->ops.standby (client);
                break;
 #ifdef CONFIG_VIDEO_V4L1
        case VIDIOCSAUDIO:
@@ -662,10 +701,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                                return 0;
 
                        if (V4L2_TUNER_RADIO == t->mode) {
-                               if (t->has_signal)
-                                       vt->signal = t->has_signal(client);
-                               if (t->is_stereo) {
-                                       if (t->is_stereo(client))
+                               if (t->ops.has_signal)
+                                       vt->signal = t->ops.has_signal(client);
+                               if (t->ops.is_stereo) {
+                                       if (t->ops.is_stereo(client))
                                                vt->flags |=
                                                    VIDEO_TUNER_STEREO_ON;
                                        else
@@ -693,8 +732,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        if (check_v4l2(t) == EINVAL)
                                return 0;
 
-                       if (V4L2_TUNER_RADIO == t->mode && t->is_stereo)
-                               va->mode = t->is_stereo(client)
+                       if (V4L2_TUNER_RADIO == t->mode && t->ops.is_stereo)
+                               va->mode = t->ops.is_stereo(client)
                                    ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
                        return 0;
                }
@@ -759,8 +798,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        switch_v4l2();
 
                        tuner->type = t->mode;
-                       if (t->get_afc)
-                               tuner->afc=t->get_afc(client);
+                       if (t->ops.get_afc)
+                               tuner->afc=t->ops.get_afc(client);
                        if (t->mode == V4L2_TUNER_ANALOG_TV)
                                tuner->capability |= V4L2_TUNER_CAP_NORM;
                        if (t->mode != V4L2_TUNER_RADIO) {
@@ -770,13 +809,13 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        }
 
                        /* radio mode */
-                       if (t->has_signal)
-                               tuner->signal = t->has_signal(client);
+                       if (t->ops.has_signal)
+                               tuner->signal = t->ops.has_signal(client);
 
                        tuner->rxsubchans =
                                V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-                       if (t->is_stereo) {
-                               tuner->rxsubchans = t->is_stereo(client) ?
+                       if (t->ops.is_stereo) {
+                               tuner->rxsubchans = t->ops.is_stereo(client) ?
                                        V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
                        }
 
@@ -804,8 +843,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        break;
                }
        case VIDIOC_LOG_STATUS:
-               if (t->tuner_status)
-                       t->tuner_status(client);
+               if (t->ops.tuner_status)
+                       t->ops.tuner_status(client);
                break;
        }
 
diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h
new file mode 100644 (file)
index 0000000..0334a91
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+    tuner-driver.h - interface for different tuners
+
+    Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de)
+    minor modifications by Ralph Metzler (rjkm@thp.uni-koeln.de)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TUNER_HW_H__
+#define __TUNER_HW_H__
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+
+extern unsigned const int tuner_count;
+
+struct tuner_operations {
+       void (*set_tv_freq)(struct i2c_client *c, unsigned int freq);
+       void (*set_radio_freq)(struct i2c_client *c, unsigned int freq);
+       int  (*has_signal)(struct i2c_client *c);
+       int  (*is_stereo)(struct i2c_client *c);
+       int  (*get_afc)(struct i2c_client *c);
+       void (*tuner_status)(struct i2c_client *c);
+       void (*standby)(struct i2c_client *c);
+       void (*release)(struct i2c_client *c);
+};
+
+struct tuner {
+       /* device */
+       struct i2c_client i2c;
+
+       unsigned int type;      /* chip type */
+
+       unsigned int mode;
+       unsigned int mode_mask; /* Combination of allowable modes */
+
+       unsigned int tv_freq;   /* keep track of the current settings */
+       unsigned int radio_freq;
+       u16          last_div;
+       unsigned int audmode;
+       v4l2_std_id  std;
+
+       int          using_v4l2;
+       void *priv;
+
+       /* used by tda9887 */
+       unsigned int       tda9887_config;
+
+       unsigned int config;
+       int (*tuner_callback) (void *dev, int command,int arg);
+
+       struct tuner_operations ops;
+};
+
+/* ------------------------------------------------------------------------ */
+
+extern int default_tuner_init(struct i2c_client *c);
+
+extern int tda9887_tuner_init(struct i2c_client *c);
+
+extern int microtune_init(struct i2c_client *c);
+
+extern int tda8290_init(struct i2c_client *c);
+extern int tda8290_probe(struct i2c_client *c);
+
+extern int tea5761_tuner_init(struct i2c_client *c);
+extern int tea5761_autodetection(struct i2c_client *c);
+
+extern int tea5767_autodetection(struct i2c_client *c);
+extern int tea5767_tuner_init(struct i2c_client *c);
+
+/* ------------------------------------------------------------------------ */
+
+#define tuner_warn(fmt, arg...) do {\
+       printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+#define tuner_info(fmt, arg...) do {\
+       printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+#define tuner_dbg(fmt, arg...) do {\
+       extern int tuner_debug; \
+       if (tuner_debug) \
+               printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+
+#endif /* __TUNER_HW_H__ */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
index c40b92ce1fadefcd0c46db8ece473ee3581d3a33..2d57e8bc0db3467e406d184d80647582abf2c0c8 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/videodev.h>
 #include <media/tuner.h>
 #include <media/v4l2-common.h>
+#include <media/tuner-types.h>
+#include "tuner-driver.h"
 
 static int offset = 0;
 module_param(offset, int, 0664);
@@ -54,9 +56,9 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
     sound 2          33.16  -      -
     NICAM            33.05  33.05  39.80
  */
-#define PHILIPS_MF_SET_BG      0x01 /* Bit 2 must be zero, Bit 3 is system output */
-#define PHILIPS_MF_SET_PAL_L   0x03 // France
-#define PHILIPS_MF_SET_PAL_L2  0x02 // L'
+#define PHILIPS_MF_SET_STD_BG  0x01 /* Bit 2 must be zero, Bit 3 is system output */
+#define PHILIPS_MF_SET_STD_L   0x03 /* Used on Secam France */
+#define PHILIPS_MF_SET_STD_LC  0x02 /* Used on SECAM L' */
 
 /* Control byte */
 
@@ -207,11 +209,11 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
                /* 0x04 -> ??? PAL others / SECAM others ??? */
                cb &= ~0x03;
                if (t->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM
-                       cb |= PHILIPS_MF_SET_PAL_L;
+                       cb |= PHILIPS_MF_SET_STD_L;
                else if (t->std & V4L2_STD_SECAM_LC)
-                       cb |= PHILIPS_MF_SET_PAL_L2;
+                       cb |= PHILIPS_MF_SET_STD_LC;
                else /* V4L2_STD_B|V4L2_STD_GH */
-                       cb |= PHILIPS_MF_SET_BG;
+                       cb |= PHILIPS_MF_SET_STD_BG;
                break;
 
        case TUNER_TEMIC_4046FM5:
@@ -479,6 +481,13 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
                tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
 }
 
+static struct tuner_operations simple_tuner_ops = {
+       .set_tv_freq    = default_set_tv_freq,
+       .set_radio_freq = default_set_radio_freq,
+       .has_signal     = tuner_signal,
+       .is_stereo      = tuner_stereo,
+};
+
 int default_tuner_init(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
@@ -487,11 +496,7 @@ int default_tuner_init(struct i2c_client *c)
                   t->type, tuners[t->type].name);
        strlcpy(c->name, tuners[t->type].name, sizeof(c->name));
 
-       t->set_tv_freq = default_set_tv_freq;
-       t->set_radio_freq = default_set_radio_freq;
-       t->has_signal = tuner_signal;
-       t->is_stereo = tuner_stereo;
-       t->standby = NULL;
+       memcpy(&t->ops, &simple_tuner_ops, sizeof(struct tuner_operations));
 
        return 0;
 }
index 74c3e6f96f1a7b0846b93d57938c3d1788e7011e..417f642b435985bae6937070cc9fb83d55a2f2b1 100644 (file)
@@ -594,19 +594,19 @@ static struct tuner_params tuner_philips_pal_mk_params[] = {
        },
 };
 
-/* ------------ TUNER_PHILIPS_ATSC - Philips ATSC ------------ */
+/* ---- TUNER_PHILIPS_ATSC - Philips FCV1236D (ATSC/NTSC) ---- */
 
-static struct tuner_range tuner_philips_atsc_ranges[] = {
+static struct tuner_range tuner_philips_fcv1236d_ranges[] = {
        { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
-       { 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
+       { 16 * 451.25 /*MHz*/, 0x8e, 0x90, },
        { 16 * 999.99        , 0x8e, 0x30, },
 };
 
-static struct tuner_params tuner_philips_atsc_params[] = {
+static struct tuner_params tuner_philips_fcv1236d_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_NTSC,
-               .ranges = tuner_philips_atsc_ranges,
-               .count  = ARRAY_SIZE(tuner_philips_atsc_ranges),
+               .ranges = tuner_philips_fcv1236d_ranges,
+               .count  = ARRAY_SIZE(tuner_philips_fcv1236d_ranges),
        },
 };
 
@@ -1296,9 +1296,9 @@ struct tunertype tuners[] = {
                .count  = ARRAY_SIZE(tuner_philips_pal_mk_params),
        },
        [TUNER_PHILIPS_ATSC] = { /* Philips ATSC */
-               .name   = "Philips 1236D ATSC/NTSC dual in",
-               .params = tuner_philips_atsc_params,
-               .count  = ARRAY_SIZE(tuner_philips_atsc_params),
+               .name   = "Philips FCV1236D ATSC/NTSC dual in",
+               .params = tuner_philips_fcv1236d_params,
+               .count  = ARRAY_SIZE(tuner_philips_fcv1236d_params),
        },
        [TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */
                .name   = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)",
@@ -1463,6 +1463,10 @@ struct tunertype tuners[] = {
                .name   = "Philips TDA988[5,6,7] IF PLL Demodulator",
                /* see tda9887.c for details */
        },
+       [TUNER_TEA5761] = { /* Philips RADIO */
+               .name   = "Philips TEA5761 FM Radio",
+               /* see tea5767.c for details */
+       },
 };
 
 unsigned const int tuner_count = ARRAY_SIZE(tuners);
index a1136da74ba847d48de46fc1e2f613be5f938706..fdc3def437b134214181344564d3b2eaae45e61f 100644 (file)
@@ -183,7 +183,7 @@ hauppauge_tuner[] =
        { TUNER_ABSENT,        "Silicon TDA8275C1 8290 FM"},
        { TUNER_ABSENT,        "Thompson DTT757"},
        /* 80-89 */
-       { TUNER_ABSENT,        "Philips FQ1216LME MK3"},
+       { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"},
        { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"},
        { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"},
        { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
@@ -490,7 +490,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                        to indicate 4052 mux was removed in favor of using MSP
                        inputs directly. */
                        audioic = eeprom_data[i+2] & 0x7f;
-                       if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+                       if (audioic < ARRAY_SIZE(audioIC))
                                tvee->audio_processor = audioIC[audioic].id;
                        else
                                tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
@@ -523,7 +523,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                        to indicate 4052 mux was removed in favor of using MSP
                        inputs directly. */
                        audioic = eeprom_data[i+1] & 0x7f;
-                       if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+                       if (audioic < ARRAY_SIZE(audioIC))
                                tvee->audio_processor = audioIC[audioic].id;
                        else
                                tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
@@ -678,7 +678,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                tveeprom_info("audio processor is unknown (no idx)\n");
                tvee->audio_processor=AUDIO_CHIP_UNKNOWN;
        } else {
-               if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+               if (audioic < ARRAY_SIZE(audioIC))
                        tveeprom_info("audio processor is %s (idx %d)\n",
                                        audioIC[audioic].name,audioic);
                else
index d5ec05f56adfad470a6edca177746a134113290a..e2f1c972754bc56487222b023c2a63b5d914d4bf 100644 (file)
@@ -1006,7 +1006,7 @@ static int tvp5150_command(struct i2c_client *c,
                {
                        struct v4l2_control *ctrl = arg;
                        u8 i, n;
-                       n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
+                       n = ARRAY_SIZE(tvp5150_qctrl);
                        for (i = 0; i < n; i++)
                                if (ctrl->id == tvp5150_qctrl[i].id) {
                                        if (ctrl->value <
index abe214619092036accc9b50dc262cf6714a0549d..491505d6fdeea14d4c7b9934aa656666d83eaa6e 100644 (file)
@@ -236,7 +236,7 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev
        input_dev->name = "Konicawc snapshot button";
        input_dev->phys = cam->input_physname;
        usb_to_input_id(dev, &input_dev->id);
-       input_dev->cdev.dev = &dev->dev;
+       input_dev->dev.parent = &dev->dev;
 
        input_dev->evbit[0] = BIT(EV_KEY);
        input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
index ec0ff2247f06a6c74c8382640b913903e7c96cc7..dd1a6d6bbc9eef80a81f30162f9f20ca49eaf780 100644 (file)
@@ -100,7 +100,7 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
        input_dev->name = "QCM button";
        input_dev->phys = cam->input_physname;
        usb_to_input_id(dev, &input_dev->id);
-       input_dev->cdev.dev = &dev->dev;
+       input_dev->dev.parent = &dev->dev;
 
        input_dev->evbit[0] = BIT(EV_KEY);
        input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
@@ -439,7 +439,7 @@ static int qcm_sensor_init(struct uvd *uvd)
        int ret;
        int i;
 
-       for (i=0; i < sizeof(regval_table)/sizeof(regval_table[0]) ; i++) {
+       for (i=0; i < ARRAY_SIZE(regval_table) ; i++) {
                CHECK_RET(ret, qcm_stv_setb(uvd->dev,
                                        regval_table[i].reg,
                                        regval_table[i].val));
index 982b115193f855e5e6cdee2191b9b1ae1e11c78c..2d9c0dd3b733c02aeade8c1e72373857cec52816 100644 (file)
@@ -42,7 +42,6 @@
 #include <linux/usb.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
-#include <linux/proc_fs.h>
 #include <linux/mutex.h>
 #include "usbvideo.h"
 
@@ -417,11 +416,6 @@ struct vicam_camera {
        u8 open_count;
        u8 bulkEndpoint;
        int needsDummyRead;
-
-#if defined(CONFIG_VIDEO_PROC_FS)
-       struct proc_dir_entry *proc_dir;
-#endif
-
 };
 
 static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
@@ -1065,175 +1059,6 @@ vicam_mmap(struct file *file, struct vm_area_struct *vma)
        return 0;
 }
 
-#if defined(CONFIG_VIDEO_PROC_FS)
-
-static struct proc_dir_entry *vicam_proc_root = NULL;
-
-static int vicam_read_helper(char *page, char **start, off_t off,
-                               int count, int *eof, int value)
-{
-       char *out = page;
-       int len;
-
-       out += sprintf(out, "%d",value);
-
-       len = out - page;
-       len -= off;
-       if (len < count) {
-               *eof = 1;
-               if (len <= 0)
-                       return 0;
-       } else
-               len = count;
-
-       *start = page + off;
-       return len;
-}
-
-static int vicam_read_proc_shutter(char *page, char **start, off_t off,
-                               int count, int *eof, void *data)
-{
-       return vicam_read_helper(page,start,off,count,eof,
-                               ((struct vicam_camera *)data)->shutter_speed);
-}
-
-static int vicam_read_proc_gain(char *page, char **start, off_t off,
-                               int count, int *eof, void *data)
-{
-       return vicam_read_helper(page,start,off,count,eof,
-                               ((struct vicam_camera *)data)->gain);
-}
-
-static int
-vicam_write_proc_shutter(struct file *file, const char *buffer,
-                        unsigned long count, void *data)
-{
-       u16 stmp;
-       char kbuf[8];
-       struct vicam_camera *cam = (struct vicam_camera *) data;
-
-       if (count > 6)
-               return -EINVAL;
-
-       if (copy_from_user(kbuf, buffer, count))
-               return -EFAULT;
-
-       stmp = (u16) simple_strtoul(kbuf, NULL, 10);
-       if (stmp < 4 || stmp > 32000)
-               return -EINVAL;
-
-       cam->shutter_speed = stmp;
-
-       return count;
-}
-
-static int
-vicam_write_proc_gain(struct file *file, const char *buffer,
-                     unsigned long count, void *data)
-{
-       u16 gtmp;
-       char kbuf[8];
-
-       struct vicam_camera *cam = (struct vicam_camera *) data;
-
-       if (count > 4)
-               return -EINVAL;
-
-       if (copy_from_user(kbuf, buffer, count))
-               return -EFAULT;
-
-       gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
-       if (gtmp > 255)
-               return -EINVAL;
-       cam->gain = gtmp;
-
-       return count;
-}
-
-static void
-vicam_create_proc_root(void)
-{
-       vicam_proc_root = proc_mkdir("video/vicam", NULL);
-
-       if (vicam_proc_root)
-               vicam_proc_root->owner = THIS_MODULE;
-       else
-               printk(KERN_ERR
-                      "could not create /proc entry for vicam!");
-}
-
-static void
-vicam_destroy_proc_root(void)
-{
-       if (vicam_proc_root)
-               remove_proc_entry("video/vicam", 0);
-}
-
-static void
-vicam_create_proc_entry(struct vicam_camera *cam)
-{
-       char name[64];
-       struct proc_dir_entry *ent;
-
-       DBG(KERN_INFO "vicam: creating proc entry\n");
-
-       if (!vicam_proc_root || !cam) {
-               printk(KERN_INFO
-                      "vicam: could not create proc entry, %s pointer is null.\n",
-                      (!cam ? "camera" : "root"));
-               return;
-       }
-
-       sprintf(name, "video%d", cam->vdev.minor);
-
-       cam->proc_dir = proc_mkdir(name, vicam_proc_root);
-
-       if ( !cam->proc_dir )
-               return; // FIXME: We should probably return an error here
-
-       ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
-                               cam->proc_dir);
-       if (ent) {
-               ent->data = cam;
-               ent->read_proc = vicam_read_proc_shutter;
-               ent->write_proc = vicam_write_proc_shutter;
-               ent->size = 64;
-       }
-
-       ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
-                               cam->proc_dir);
-       if (ent) {
-               ent->data = cam;
-               ent->read_proc = vicam_read_proc_gain;
-               ent->write_proc = vicam_write_proc_gain;
-               ent->size = 64;
-       }
-}
-
-static void
-vicam_destroy_proc_entry(void *ptr)
-{
-       struct vicam_camera *cam = (struct vicam_camera *) ptr;
-       char name[16];
-
-       if ( !cam->proc_dir )
-               return;
-
-       sprintf(name, "video%d", cam->vdev.minor);
-       remove_proc_entry("shutter", cam->proc_dir);
-       remove_proc_entry("gain", cam->proc_dir);
-       remove_proc_entry(name,vicam_proc_root);
-       cam->proc_dir = NULL;
-
-}
-
-#else
-static inline void vicam_create_proc_root(void) { }
-static inline void vicam_destroy_proc_root(void) { }
-static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
-static inline void vicam_destroy_proc_entry(void *ptr) { }
-#endif
-
 static const struct file_operations vicam_fops = {
        .owner          = THIS_MODULE,
        .open           = vicam_open,
@@ -1330,8 +1155,6 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
                return -EIO;
        }
 
-       vicam_create_proc_entry(cam);
-
        printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
 
        usb_set_intfdata (intf, cam);
@@ -1363,8 +1186,6 @@ vicam_disconnect(struct usb_interface *intf)
 
        cam->udev = NULL;
 
-       vicam_destroy_proc_entry(cam);
-
        /* the only thing left to do is synchronize with
         * our close/release function on who should release
         * the camera memory. if there are any users using the
@@ -1390,7 +1211,6 @@ usb_vicam_init(void)
 {
        int retval;
        DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
-       vicam_create_proc_root();
        retval = usb_register(&vicam_driver);
        if (retval)
                printk(KERN_WARNING "usb_register failed!\n");
@@ -1404,7 +1224,6 @@ usb_vicam_exit(void)
               "ViCam-based WebCam driver shutdown\n");
 
        usb_deregister(&vicam_driver);
-       vicam_destroy_proc_root();
 }
 
 module_init(usb_vicam_init);
index 51ab265d566ac29154c9234d3c7d60167a7fa482..380564cd3317d222ea2908c7e6e6d8ef1a12e43b 100644 (file)
@@ -79,7 +79,7 @@ struct usbvision_device_data_st  usbvision_device_data[] = {
                .Interface     = -1,
                .Codec         = CODEC_SAA7113,
                .VideoChannels = 2,
-               .VideoNorm     = V4L2_STD_PAL,
+               .VideoNorm     = V4L2_STD_NTSC,
                .AudioChannels = 1,
                .Radio         = 0,
                .vbi           = 1,
@@ -311,8 +311,8 @@ struct usbvision_device_data_st  usbvision_device_data[] = {
                .vbi           = 1,
                .Tuner         = 1,
                .TunerType     = TUNER_PHILIPS_SECAM,
-               .X_Offset      = -1,
-               .Y_Offset      = -1,
+               .X_Offset      = 0x80,
+               .Y_Offset      = 0x16,
                .ModelString   = "Hauppauge WinTV USB (PAL/SECAM L)",
        },
        [HPG_WINTV_PAL_D_K] = {
@@ -586,7 +586,7 @@ struct usbvision_device_data_st  usbvision_device_data[] = {
                .Radio         = 0,
                .vbi           = 1,
                .Tuner         = 1,
-               .TunerType     = TUNER_PHILIPS_PAL,
+               .TunerType     = TUNER_LG_PAL_NEW_TAPC,
                .X_Offset      = 0,
                .Y_Offset      = 3,
                .Dvi_yuv_override = 1,
index 7df071eb0a3b2f2bc1317ca2cabe4b9a7ac443db..5b1e346df20684c7df22d3c9a6b9b1357974cc51 100644 (file)
@@ -1742,7 +1742,7 @@ static int usbvision_set_video_format(struct usb_usbvision *usbvision, int forma
                format = ISOC_MODE_YUV420;
        }
        value[0] = 0x0A;  //TODO: See the effect of the filter
-       value[1] = format;
+       value[1] = format; // Sets the VO_MODE register which follows FILT_CONT
        rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
                             USBVISION_OP_CODE,
                             USB_DIR_OUT | USB_TYPE_VENDOR |
@@ -1831,10 +1831,10 @@ int usbvision_set_output(struct usb_usbvision *usbvision, int width,
                frameRate = FRAMERATE_MAX;
        }
 
-       if (usbvision->tvnorm->id & V4L2_STD_625_50) {
+       if (usbvision->tvnormId & V4L2_STD_625_50) {
                frameDrop = frameRate * 32 / 25 - 1;
        }
-       else if (usbvision->tvnorm->id & V4L2_STD_525_60) {
+       else if (usbvision->tvnormId & V4L2_STD_525_60) {
                frameDrop = frameRate * 32 / 30 - 1;
        }
 
@@ -2067,7 +2067,7 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
        }
 
 
-       if (usbvision->tvnorm->id & V4L2_STD_PAL) {
+       if (usbvision->tvnormId & V4L2_STD_PAL) {
                value[0] = 0xC0;
                value[1] = 0x02;        //0x02C0 -> 704 Input video line length
                value[2] = 0x20;
@@ -2076,7 +2076,7 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
                value[5] = 0x00;        //0x0060 -> 96 Input video h offset
                value[6] = 0x16;
                value[7] = 0x00;        //0x0016 -> 22 Input video v offset
-       } else if (usbvision->tvnorm->id & V4L2_STD_SECAM) {
+       } else if (usbvision->tvnormId & V4L2_STD_SECAM) {
                value[0] = 0xC0;
                value[1] = 0x02;        //0x02C0 -> 704 Input video line length
                value[2] = 0x20;
@@ -2537,7 +2537,9 @@ void usbvision_stop_isoc(struct usb_usbvision *usbvision)
 
 int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
 {
-       int mode[4];
+       /* inputs #0 and #3 are constant for every SAA711x. */
+       /* inputs #1 and #2 are variable for SAA7111 and SAA7113 */
+       int mode[4]= {SAA7115_COMPOSITE0, 0, 0, SAA7115_COMPOSITE3};
        int audio[]= {1, 0, 0, 0};
        struct v4l2_routing route;
        //channel 0 is TV with audiochannel 1 (tuner mono)
@@ -2547,10 +2549,6 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
 
        RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs);
        usbvision->ctl_input = channel;
-         route.input = SAA7115_COMPOSITE1;
-         route.output = 0;
-         call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
-         call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input);
 
        // set the new channel
        // Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video
@@ -2558,28 +2556,27 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
 
        switch (usbvision_device_data[usbvision->DevModel].Codec) {
                case CODEC_SAA7113:
-                       if (SwitchSVideoInput) { // To handle problems with S-Video Input for some devices.  Use SwitchSVideoInput parameter when loading the module.
-                               mode[2] = 1;
+                       mode[1] = SAA7115_COMPOSITE2;
+                       if (SwitchSVideoInput) {
+                               /* To handle problems with S-Video Input for
+                                * some devices.  Use SwitchSVideoInput
+                                * parameter when loading the module.*/
+                               mode[2] = SAA7115_COMPOSITE1;
                        }
                        else {
-                               mode[2] = 7;
-                       }
-                       if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
-                               mode[0] = 0; mode[1] = 2; mode[3] = 3;  // Special for four input devices
-                       }
-                       else {
-                               mode[0] = 0; mode[1] = 2; //modes for regular saa7113 devices
+                               mode[2] = SAA7115_SVIDEO1;
                        }
                        break;
                case CODEC_SAA7111:
-                       mode[0] = 0; mode[1] = 1; mode[2] = 7; //modes for saa7111
-                       break;
                default:
-                       mode[0] = 0; mode[1] = 1; mode[2] = 7; //default modes
+                       /* modes for saa7111 */
+                       mode[1] = SAA7115_COMPOSITE1;
+                       mode[2] = SAA7115_SVIDEO1;
+                       break;
        }
        route.input = mode[channel];
+       route.output = 0;
        call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
-       usbvision->channel = channel;
        usbvision_set_audio(usbvision, audio[channel]);
        return 0;
 }
index aa3258bbb4afe49f81b52bcd17d20d0420908e42..868b6886fe7fcb44d892c4b7090213eb01342b89 100644 (file)
@@ -36,7 +36,8 @@
  *     - use submit_urb for all setup packets
  *     - Fix memory settings for nt1004. It is 4 times as big as the
  *       nt1003 memory.
- *     - Add audio on endpoint 3 for nt1004 chip.  Seems impossible, needs a codec interface.  Which one?
+ *     - Add audio on endpoint 3 for nt1004 chip.
+ *         Seems impossible, needs a codec interface.  Which one?
  *     - Clean up the driver.
  *     - optimization for performance.
  *     - Add Videotext capability (VBI).  Working on it.....
@@ -77,7 +78,8 @@
 #include "usbvision.h"
 #include "usbvision-cards.h"
 
-#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>, Dwaine Garden <DwaineGarden@rogers.com>"
+#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>,\
+ Dwaine Garden <DwaineGarden@rogers.com>"
 #define DRIVER_NAME "usbvision"
 #define DRIVER_ALIAS "USBVision"
 #define DRIVER_DESC "USBVision USB Video Device Driver for Linux"
 #define USBVISION_DRIVER_VERSION_MAJOR 0
 #define USBVISION_DRIVER_VERSION_MINOR 9
 #define USBVISION_DRIVER_VERSION_PATCHLEVEL 9
-#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,USBVISION_DRIVER_VERSION_MINOR,USBVISION_DRIVER_VERSION_PATCHLEVEL)
-#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR) "." __stringify(USBVISION_DRIVER_VERSION_MINOR) "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
+#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,\
+USBVISION_DRIVER_VERSION_MINOR,\
+USBVISION_DRIVER_VERSION_PATCHLEVEL)
+#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR)\
+ "." __stringify(USBVISION_DRIVER_VERSION_MINOR)\
+ "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
 
 #define        ENABLE_HEXDUMP  0       /* Enable if you need it */
 
 
 #ifdef USBVISION_DEBUG
        #define PDEBUG(level, fmt, args...) \
-               if (video_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
+               if (video_debug & (level)) \
+                       info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ ,\
+                               ## args)
 #else
        #define PDEBUG(level, fmt, args...) do {} while(0)
 #endif
 
-#define DBG_IOCTL      1<<0
 #define DBG_IO         1<<1
 #define DBG_PROBE      1<<2
 #define DBG_MMAP       1<<3
 #define goto2next(str) while(*str!=' ') str++; while(*str==' ') str++;
 
 
-static int usbvision_nr = 0;                   // sequential number of usbvision device
+/* sequential number of usbvision device */
+static int usbvision_nr = 0;
 
 static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
        { 1, 1,  8, V4L2_PIX_FMT_GREY    , "GREY" },
@@ -121,55 +129,32 @@ static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
        { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" }
 };
 
-/* supported tv norms */
-static struct usbvision_tvnorm tvnorms[] = {
-       {
-               .name = "PAL",
-               .id = V4L2_STD_PAL,
-       }, {
-               .name = "NTSC",
-               .id = V4L2_STD_NTSC,
-       }, {
-                .name = "SECAM",
-                .id = V4L2_STD_SECAM,
-       }, {
-               .name = "PAL-M",
-               .id = V4L2_STD_PAL_M,
-       }
-};
-
-#define TVNORMS ARRAY_SIZE(tvnorms)
-
-// Function prototypes
+/* Function prototypes */
 static void usbvision_release(struct usb_usbvision *usbvision);
 
-// Default initalization of device driver parameters
-static int isocMode = ISOC_MODE_COMPRESS;              // Set the default format for ISOC endpoint
-static int video_debug = 0;                            // Set the default Debug Mode of the device driver
-static int PowerOnAtOpen = 1;                          // Set the default device to power on at startup
-static int video_nr = -1;                              // Sequential Number of Video Device
-static int radio_nr = -1;                              // Sequential Number of Radio Device
-static int vbi_nr = -1;                                        // Sequential Number of VBI Device
-
-// Grab parameters for the device driver
-
-#if defined(module_param)                               // Showing parameters under SYSFS
+/* Default initalization of device driver parameters */
+/* Set the default format for ISOC endpoint */
+static int isocMode = ISOC_MODE_COMPRESS;
+/* Set the default Debug Mode of the device driver */
+static int video_debug = 0;
+/* Set the default device to power on at startup */
+static int PowerOnAtOpen = 1;
+/* Sequential Number of Video Device */
+static int video_nr = -1;
+/* Sequential Number of Radio Device */
+static int radio_nr = -1;
+/* Sequential Number of VBI Device */
+static int vbi_nr = -1;
+
+/* Grab parameters for the device driver */
+
+/* Showing parameters under SYSFS */
 module_param(isocMode, int, 0444);
 module_param(video_debug, int, 0444);
 module_param(PowerOnAtOpen, int, 0444);
 module_param(video_nr, int, 0444);
 module_param(radio_nr, int, 0444);
 module_param(vbi_nr, int, 0444);
-#else                                                  // Old Style
-MODULE_PARAM(isocMode, "i");
-MODULE_PARM(video_debug, "i");                         // Grab the Debug Mode of the device driver
-MODULE_PARM(adjustCompression, "i");                   // Grab the compression to be adaptive
-MODULE_PARM(PowerOnAtOpen, "i");                       // Grab the device to power on at startup
-MODULE_PARM(SwitchSVideoInput, "i");                   // To help people with Black and White output with using s-video input.  Some cables and input device are wired differently.
-MODULE_PARM(video_nr, "i");                            // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...)
-MODULE_PARM(radio_nr, "i");                            // radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...)
-MODULE_PARM(vbi_nr, "i");                              // vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...)
-#endif
 
 MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint.  Default: 0x60 (Compression On)");
 MODULE_PARM_DESC(video_debug, " Set the default Debug Mode of the device driver.  Default: 0 (Off)");
@@ -187,19 +172,21 @@ MODULE_VERSION(USBVISION_VERSION_STRING);
 MODULE_ALIAS(DRIVER_ALIAS);
 
 
-/****************************************************************************************/
-/* SYSFS Code - Copied from the stv680.c usb module.                                   */
-/* Device information is located at /sys/class/video4linux/video0                      */
-/* Device parameters information is located at /sys/module/usbvision                    */
-/* Device USB Information is located at /sys/bus/usb/drivers/USBVision Video Grabber    */
-/****************************************************************************************/
+/*****************************************************************************/
+/* SYSFS Code - Copied from the stv680.c usb module.                        */
+/* Device information is located at /sys/class/video4linux/video0            */
+/* Device parameters information is located at /sys/module/usbvision         */
+/* Device USB Information is located at                                      */
+/*   /sys/bus/usb/drivers/USBVision Video Grabber                            */
+/*****************************************************************************/
 
 
 #define YES_NO(x) ((x) ? "Yes" : "No")
 
 static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        return video_get_drvdata(vdev);
 }
 
@@ -211,15 +198,18 @@ static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
 
 static ssize_t show_model(struct class_device *cd, char *buf)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        struct usb_usbvision *usbvision = video_get_drvdata(vdev);
-       return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString);
+       return sprintf(buf, "%s\n",
+                      usbvision_device_data[usbvision->DevModel].ModelString);
 }
 static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
 
 static ssize_t show_hue(struct class_device *cd, char *buf)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        struct usb_usbvision *usbvision = video_get_drvdata(vdev);
        struct v4l2_control ctrl;
        ctrl.id = V4L2_CID_HUE;
@@ -232,7 +222,8 @@ static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
 
 static ssize_t show_contrast(struct class_device *cd, char *buf)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        struct usb_usbvision *usbvision = video_get_drvdata(vdev);
        struct v4l2_control ctrl;
        ctrl.id = V4L2_CID_CONTRAST;
@@ -245,7 +236,8 @@ static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
 
 static ssize_t show_brightness(struct class_device *cd, char *buf)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        struct usb_usbvision *usbvision = video_get_drvdata(vdev);
        struct v4l2_control ctrl;
        ctrl.id = V4L2_CID_BRIGHTNESS;
@@ -258,7 +250,8 @@ static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
 
 static ssize_t show_saturation(struct class_device *cd, char *buf)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        struct usb_usbvision *usbvision = video_get_drvdata(vdev);
        struct v4l2_control ctrl;
        ctrl.id = V4L2_CID_SATURATION;
@@ -271,23 +264,28 @@ static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
 
 static ssize_t show_streaming(struct class_device *cd, char *buf)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        struct usb_usbvision *usbvision = video_get_drvdata(vdev);
-       return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0));
+       return sprintf(buf, "%s\n",
+                      YES_NO(usbvision->streaming==Stream_On?1:0));
 }
 static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);
 
 static ssize_t show_compression(struct class_device *cd, char *buf)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        struct usb_usbvision *usbvision = video_get_drvdata(vdev);
-       return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));
+       return sprintf(buf, "%s\n",
+                      YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));
 }
 static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);
 
 static ssize_t show_device_bridge(struct class_device *cd, char *buf)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        struct usb_usbvision *usbvision = video_get_drvdata(vdev);
        return sprintf(buf, "%d\n", usbvision->bridgeType);
 }
@@ -376,7 +374,8 @@ static void usbvision_remove_sysfs(struct video_device *vdev)
 static int usbvision_v4l2_open(struct inode *inode, struct file *file)
 {
        struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
        int errCode = 0;
 
        PDEBUG(DBG_IO, "open");
@@ -390,7 +389,8 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
                /* Allocate memory for the scratch ring buffer */
                errCode = usbvision_scratch_alloc(usbvision);
                if (isocMode==ISOC_MODE_COMPRESS) {
-                       /* Allocate intermediate decompression buffers only if needed */
+                       /* Allocate intermediate decompression buffers
+                          only if needed */
                        errCode = usbvision_decompress_alloc(usbvision);
                }
                if (errCode) {
@@ -421,11 +421,10 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
                if (!errCode) {
                        usbvision_begin_streaming(usbvision);
                        errCode = usbvision_init_isoc(usbvision);
-                       /* device needs to be initialized before isoc transfer */
+                       /* device must be initialized before isoc transfer */
                        usbvision_muxsel(usbvision,0);
                        usbvision->user++;
-               }
-               else {
+               } else {
                        if (PowerOnAtOpen) {
                                usbvision_i2c_unregister(usbvision);
                                usbvision_power_off(usbvision);
@@ -456,7 +455,8 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
 static int usbvision_v4l2_close(struct inode *inode, struct file *file)
 {
        struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
        PDEBUG(DBG_IO, "close");
        down(&usbvision->lock);
@@ -473,7 +473,8 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
        usbvision->user--;
 
        if (PowerOnAtOpen) {
-               /* power off in a little while to avoid off/on every close/open short sequences */
+               /* power off in a little while
+                  to avoid off/on every close/open short sequences */
                usbvision_set_powerOffTimer(usbvision);
                usbvision->initialized = 0;
        }
@@ -498,583 +499,612 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
  * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
  *
  */
-static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
-                                unsigned int cmd, void *arg)
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register (struct file *file, void *priv,
+                               struct v4l2_register *reg)
 {
        struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
-
-       if (!USBVISION_IS_OPERATIONAL(usbvision))
-               return -EFAULT;
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int errCode;
 
-       switch (cmd) {
+       if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+               return -EINVAL;
+       /* NT100x has a 8-bit register space */
+       errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
+       if (errCode < 0) {
+               err("%s: VIDIOC_DBG_G_REGISTER failed: error %d",
+                   __FUNCTION__, errCode);
+               return errCode;
+       }
+       return 0;
+}
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-               /* ioctls to allow direct acces to the NT100x registers */
-               case VIDIOC_DBG_G_REGISTER:
-               case VIDIOC_DBG_S_REGISTER:
-               {
-                       struct v4l2_register *reg = arg;
-                       int errCode;
-
-                       if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
-                               return -EINVAL;
-                       if (!capable(CAP_SYS_ADMIN))
-                               return -EPERM;
-                       /* NT100x has a 8-bit register space */
-                       if (cmd == VIDIOC_DBG_G_REGISTER)
-                               errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
-                       else
-                               errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
-                       if (errCode < 0) {
-                               err("%s: VIDIOC_DBG_%c_REGISTER failed: error %d", __FUNCTION__,
-                                   cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S', errCode);
-                               return errCode;
-                       }
-                       if (cmd == VIDIOC_DBG_S_REGISTER)
-                               reg->val = (u8)errCode;
+static int vidioc_s_register (struct file *file, void *priv,
+                               struct v4l2_register *reg)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int errCode;
 
-                       PDEBUG(DBG_IOCTL, "VIDIOC_DBG_%c_REGISTER reg=0x%02X, value=0x%02X",
-                              cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S',
-                              (unsigned int)reg->reg, (unsigned int)reg->val);
-                       return 0;
-               }
+       if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+               return -EINVAL;
+       /* NT100x has a 8-bit register space */
+       reg->val = (u8)usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
+       if (reg->val < 0) {
+               err("%s: VIDIOC_DBG_S_REGISTER failed: error %d",
+                   __FUNCTION__, errCode);
+               return errCode;
+       }
+       return 0;
+}
 #endif
-               case VIDIOC_QUERYCAP:
-               {
-                       struct v4l2_capability *vc=arg;
-
-                       memset(vc, 0, sizeof(*vc));
-                       strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
-                       strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString,
-                               sizeof(vc->card));
-                       strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
-                               sizeof(vc->bus_info));
-                       vc->version = USBVISION_DRIVER_VERSION;
-                       vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
-                               V4L2_CAP_AUDIO |
-                               V4L2_CAP_READWRITE |
-                               V4L2_CAP_STREAMING |
-                               (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
-                       PDEBUG(DBG_IOCTL, "VIDIOC_QUERYCAP");
-                       return 0;
-               }
-               case VIDIOC_ENUMINPUT:
-               {
-                       struct v4l2_input *vi = arg;
-                       int chan;
-
-                       if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
-                               return -EINVAL;
-                       if (usbvision->have_tuner) {
-                               chan = vi->index;
-                       }
-                       else {
-                               chan = vi->index + 1; //skip Television string
-                       }
-                       switch(chan) {
-                               case 0:
-                                       if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
-                                               strcpy(vi->name, "White Video Input");
-                                       }
-                                       else {
-                                               strcpy(vi->name, "Television");
-                                               vi->type = V4L2_INPUT_TYPE_TUNER;
-                                               vi->audioset = 1;
-                                               vi->tuner = chan;
-                                               vi->std = V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM;
-                                       }
-                                       break;
-                               case 1:
-                                       vi->type = V4L2_INPUT_TYPE_CAMERA;
-                                       if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
-                                               strcpy(vi->name, "Green Video Input");
-                                       }
-                                       else {
-                                               strcpy(vi->name, "Composite Video Input");
-                                       }
-                                       vi->std = V4L2_STD_PAL;
-                                       break;
-                               case 2:
-                                       vi->type = V4L2_INPUT_TYPE_CAMERA;
-                                       if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
-                                               strcpy(vi->name, "Yellow Video Input");
-                                       }
-                                       else {
-                                       strcpy(vi->name, "S-Video Input");
-                                       }
-                                       vi->std = V4L2_STD_PAL;
-                                       break;
-                               case 3:
-                                       vi->type = V4L2_INPUT_TYPE_CAMERA;
-                                       strcpy(vi->name, "Red Video Input");
-                                       vi->std = V4L2_STD_PAL;
-                                       break;
-                       }
-                       PDEBUG(DBG_IOCTL, "VIDIOC_ENUMINPUT name=%s:%d tuners=%d type=%d norm=%x",
-                              vi->name, vi->index, vi->tuner,vi->type,(int)vi->std);
-                       return 0;
-               }
-               case VIDIOC_ENUMSTD:
-               {
-                       struct v4l2_standard *e = arg;
-                       unsigned int i;
-                       int ret;
-
-                       i = e->index;
-                       if (i >= TVNORMS)
-                               return -EINVAL;
-                       ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
-                                                      tvnorms[e->index].name);
-                       e->index = i;
-                       if (ret < 0)
-                               return ret;
-                       return 0;
+
+static int vidioc_querycap (struct file *file, void  *priv,
+                                       struct v4l2_capability *vc)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+
+       strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
+       strlcpy(vc->card,
+               usbvision_device_data[usbvision->DevModel].ModelString,
+               sizeof(vc->card));
+       strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
+               sizeof(vc->bus_info));
+       vc->version = USBVISION_DRIVER_VERSION;
+       vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_AUDIO |
+               V4L2_CAP_READWRITE |
+               V4L2_CAP_STREAMING |
+               (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
+       return 0;
+}
+
+static int vidioc_enum_input (struct file *file, void *priv,
+                               struct v4l2_input *vi)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int chan;
+
+       if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
+               return -EINVAL;
+       if (usbvision->have_tuner) {
+               chan = vi->index;
+       } else {
+               chan = vi->index + 1; /*skip Television string*/
+       }
+       /* Determine the requested input characteristics
+          specific for each usbvision card model */
+       switch(chan) {
+       case 0:
+               if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+                       strcpy(vi->name, "White Video Input");
+               } else {
+                       strcpy(vi->name, "Television");
+                       vi->type = V4L2_INPUT_TYPE_TUNER;
+                       vi->audioset = 1;
+                       vi->tuner = chan;
+                       vi->std = USBVISION_NORMS;
                }
-               case VIDIOC_G_INPUT:
-               {
-                       int *input = arg;
-                       *input = usbvision->ctl_input;
-                       return 0;
+               break;
+       case 1:
+               vi->type = V4L2_INPUT_TYPE_CAMERA;
+               if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+                       strcpy(vi->name, "Green Video Input");
+               } else {
+                       strcpy(vi->name, "Composite Video Input");
                }
-               case VIDIOC_S_INPUT:
-               {
-                       int *input = arg;
-                       if ((*input >= usbvision->video_inputs) || (*input < 0) )
-                               return -EINVAL;
-                       usbvision->ctl_input = *input;
-
-                       down(&usbvision->lock);
-                       usbvision_muxsel(usbvision, usbvision->ctl_input);
-                       usbvision_set_input(usbvision);
-                       usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight);
-                       up(&usbvision->lock);
-                       return 0;
+               vi->std = V4L2_STD_PAL;
+               break;
+       case 2:
+               vi->type = V4L2_INPUT_TYPE_CAMERA;
+               if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+                       strcpy(vi->name, "Yellow Video Input");
+               } else {
+                       strcpy(vi->name, "S-Video Input");
                }
-               case VIDIOC_G_STD:
-               {
-                       v4l2_std_id *id = arg;
+               vi->std = V4L2_STD_PAL;
+               break;
+       case 3:
+               vi->type = V4L2_INPUT_TYPE_CAMERA;
+               strcpy(vi->name, "Red Video Input");
+               vi->std = V4L2_STD_PAL;
+               break;
+       }
+       return 0;
+}
 
-                       *id = usbvision->tvnorm->id;
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *input)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
-                       PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%s", usbvision->tvnorm->name);
-                       return 0;
-               }
-               case VIDIOC_S_STD:
-               {
-                       v4l2_std_id *id = arg;
-                       unsigned int i;
-
-                       for (i = 0; i < TVNORMS; i++)
-                               if (*id == tvnorms[i].id)
-                                       break;
-                       if (i == TVNORMS)
-                               for (i = 0; i < TVNORMS; i++)
-                                       if (*id & tvnorms[i].id)
-                                               break;
-                       if (i == TVNORMS)
-                               return -EINVAL;
-
-                       down(&usbvision->lock);
-                       usbvision->tvnorm = &tvnorms[i];
-
-                       call_i2c_clients(usbvision, VIDIOC_S_STD,
-                                        &usbvision->tvnorm->id);
+       *input = usbvision->ctl_input;
+       return 0;
+}
 
-                       up(&usbvision->lock);
+static int vidioc_s_input (struct file *file, void *priv, unsigned int input)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
-                       PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%s", usbvision->tvnorm->name);
-                       return 0;
-               }
-               case VIDIOC_G_TUNER:
-               {
-                       struct v4l2_tuner *vt = arg;
-
-                       if (!usbvision->have_tuner || vt->index)        // Only tuner 0
-                               return -EINVAL;
-                       strcpy(vt->name, "Television");
-                       /* Let clients fill in the remainder of this struct */
-                       call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
-
-                       PDEBUG(DBG_IOCTL, "VIDIOC_G_TUNER signal=%x, afc=%x",vt->signal,vt->afc);
-                       return 0;
-               }
-               case VIDIOC_S_TUNER:
-               {
-                       struct v4l2_tuner *vt = arg;
-
-                       // Only no or one tuner for now
-                       if (!usbvision->have_tuner || vt->index)
-                               return -EINVAL;
-                       /* let clients handle this */
-                       call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
-
-                       PDEBUG(DBG_IOCTL, "VIDIOC_S_TUNER");
-                       return 0;
-               }
-               case VIDIOC_G_FREQUENCY:
-               {
-                       struct v4l2_frequency *freq = arg;
-
-                       freq->tuner = 0; // Only one tuner
-                       freq->type = V4L2_TUNER_ANALOG_TV;
-                       freq->frequency = usbvision->freq;
-                       PDEBUG(DBG_IOCTL, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)freq->frequency);
-                       return 0;
-               }
-               case VIDIOC_S_FREQUENCY:
-               {
-                       struct v4l2_frequency *freq = arg;
-
-                       // Only no or one tuner for now
-                       if (!usbvision->have_tuner || freq->tuner)
-                               return -EINVAL;
-
-                       usbvision->freq = freq->frequency;
-                       call_i2c_clients(usbvision, cmd, freq);
-                       PDEBUG(DBG_IOCTL, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)freq->frequency);
-                       return 0;
-               }
-               case VIDIOC_G_AUDIO:
-               {
-                       struct v4l2_audio *v = arg;
-                       memset(v,0, sizeof(v));
-                       strcpy(v->name, "TV");
-                       PDEBUG(DBG_IOCTL, "VIDIOC_G_AUDIO");
-                       return 0;
-               }
-               case VIDIOC_S_AUDIO:
-               {
-                       struct v4l2_audio *v = arg;
-                       if(v->index) {
-                               return -EINVAL;
-                       }
-                       PDEBUG(DBG_IOCTL, "VIDIOC_S_AUDIO");
-                       return 0;
-               }
-               case VIDIOC_QUERYCTRL:
-               {
-                       struct v4l2_queryctrl *ctrl = arg;
-                       int id=ctrl->id;
+       if ((input >= usbvision->video_inputs) || (input < 0) )
+               return -EINVAL;
 
-                       memset(ctrl,0,sizeof(*ctrl));
-                       ctrl->id=id;
+       down(&usbvision->lock);
+       usbvision_muxsel(usbvision, input);
+       usbvision_set_input(usbvision);
+       usbvision_set_output(usbvision,
+                            usbvision->curwidth,
+                            usbvision->curheight);
+       up(&usbvision->lock);
+       return 0;
+}
 
-                       call_i2c_clients(usbvision, cmd, arg);
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       usbvision->tvnormId=*id;
 
-                       if (ctrl->type)
-                               return 0;
-                       else
-                               return -EINVAL;
+       down(&usbvision->lock);
+       call_i2c_clients(usbvision, VIDIOC_S_STD,
+                        &usbvision->tvnormId);
+       up(&usbvision->lock);
+       /* propagate the change to the decoder */
+       usbvision_muxsel(usbvision, usbvision->ctl_input);
 
-                       PDEBUG(DBG_IOCTL,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type);
-               }
-               case VIDIOC_G_CTRL:
-               {
-                       struct v4l2_control *ctrl = arg;
-                       call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
-                       PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
-                       return 0;
-               }
-               case VIDIOC_S_CTRL:
-               {
-                       struct v4l2_control *ctrl = arg;
+       return 0;
+}
 
-                       PDEBUG(DBG_IOCTL, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value);
-                       call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
-                       return 0;
-               }
-               case VIDIOC_REQBUFS:
-               {
-                       struct v4l2_requestbuffers *vr = arg;
-                       int ret;
+static int vidioc_g_tuner (struct file *file, void *priv,
+                               struct v4l2_tuner *vt)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
-                       RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
+       if (!usbvision->have_tuner || vt->index)        // Only tuner 0
+               return -EINVAL;
+       if(usbvision->radio) {
+               strcpy(vt->name, "Radio");
+               vt->type = V4L2_TUNER_RADIO;
+       } else {
+               strcpy(vt->name, "Television");
+       }
+       /* Let clients fill in the remainder of this struct */
+       call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
 
-                       // Check input validity : the user must do a VIDEO CAPTURE and MMAP method.
-                       if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
-                          (vr->memory != V4L2_MEMORY_MMAP))
-                               return -EINVAL;
+       return 0;
+}
 
-                       if(usbvision->streaming == Stream_On) {
-                               if ((ret = usbvision_stream_interrupt(usbvision)))
-                                   return ret;
-                       }
+static int vidioc_s_tuner (struct file *file, void *priv,
+                               struct v4l2_tuner *vt)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
-                       usbvision_frames_free(usbvision);
-                       usbvision_empty_framequeues(usbvision);
-                       vr->count = usbvision_frames_alloc(usbvision,vr->count);
+       // Only no or one tuner for now
+       if (!usbvision->have_tuner || vt->index)
+               return -EINVAL;
+       /* let clients handle this */
+       call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
 
-                       usbvision->curFrame = NULL;
+       return 0;
+}
 
-                       PDEBUG(DBG_IOCTL, "VIDIOC_REQBUFS count=%d",vr->count);
-                       return 0;
-               }
-               case VIDIOC_QUERYBUF:
-               {
-                       struct v4l2_buffer *vb = arg;
-                       struct usbvision_frame *frame;
+static int vidioc_g_frequency (struct file *file, void *priv,
+                               struct v4l2_frequency *freq)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
-                       // FIXME : must control that buffers are mapped (VIDIOC_REQBUFS has been called)
+       freq->tuner = 0; // Only one tuner
+       if(usbvision->radio) {
+               freq->type = V4L2_TUNER_RADIO;
+       } else {
+               freq->type = V4L2_TUNER_ANALOG_TV;
+       }
+       freq->frequency = usbvision->freq;
 
-                       if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
-                               return -EINVAL;
-                       }
-                       if(vb->index>=usbvision->num_frames)  {
-                               return -EINVAL;
-                       }
-                       // Updating the corresponding frame state
-                       vb->flags = 0;
-                       frame = &usbvision->frame[vb->index];
-                       if(frame->grabstate >= FrameState_Ready)
-                               vb->flags |= V4L2_BUF_FLAG_QUEUED;
-                       if(frame->grabstate >= FrameState_Done)
-                               vb->flags |= V4L2_BUF_FLAG_DONE;
-                       if(frame->grabstate == FrameState_Unused)
-                               vb->flags |= V4L2_BUF_FLAG_MAPPED;
-                       vb->memory = V4L2_MEMORY_MMAP;
-
-                       vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
-
-                       vb->memory = V4L2_MEMORY_MMAP;
-                       vb->field = V4L2_FIELD_NONE;
-                       vb->length = usbvision->curwidth*usbvision->curheight*usbvision->palette.bytes_per_pixel;
-                       vb->timestamp = usbvision->frame[vb->index].timestamp;
-                       vb->sequence = usbvision->frame[vb->index].sequence;
-                       return 0;
-               }
-               case VIDIOC_QBUF:
-               {
-                       struct v4l2_buffer *vb = arg;
-                       struct usbvision_frame *frame;
-                       unsigned long lock_flags;
-
-                       // FIXME : works only on VIDEO_CAPTURE MODE, MMAP.
-                       if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
-                               return -EINVAL;
-                       }
-                       if(vb->index>=usbvision->num_frames)  {
-                               return -EINVAL;
-                       }
+       return 0;
+}
 
-                       frame = &usbvision->frame[vb->index];
+static int vidioc_s_frequency (struct file *file, void *priv,
+                               struct v4l2_frequency *freq)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
-                       if (frame->grabstate != FrameState_Unused) {
-                               return -EAGAIN;
-                       }
+       // Only no or one tuner for now
+       if (!usbvision->have_tuner || freq->tuner)
+               return -EINVAL;
 
-                       /* Mark it as ready and enqueue frame */
-                       frame->grabstate = FrameState_Ready;
-                       frame->scanstate = ScanState_Scanning;
-                       frame->scanlength = 0;  /* Accumulated in usbvision_parse_data() */
+       usbvision->freq = freq->frequency;
+       call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, freq);
 
-                       vb->flags &= ~V4L2_BUF_FLAG_DONE;
+       return 0;
+}
 
-                       /* set v4l2_format index */
-                       frame->v4l2_format = usbvision->palette;
+static int vidioc_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
-                       spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
-                       list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue);
-                       spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+       memset(a,0,sizeof(*a));
+       if(usbvision->radio) {
+               strcpy(a->name,"Radio");
+       } else {
+               strcpy(a->name, "TV");
+       }
 
-                       PDEBUG(DBG_IOCTL, "VIDIOC_QBUF frame #%d",vb->index);
-                       return 0;
-               }
-               case VIDIOC_DQBUF:
-               {
-                       struct v4l2_buffer *vb = arg;
-                       int ret;
-                       struct usbvision_frame *f;
-                       unsigned long lock_flags;
-
-                       if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                               return -EINVAL;
-
-                       if (list_empty(&(usbvision->outqueue))) {
-                               if (usbvision->streaming == Stream_Idle)
-                                       return -EINVAL;
-                               ret = wait_event_interruptible
-                                       (usbvision->wait_frame,
-                                        !list_empty(&(usbvision->outqueue)));
-                               if (ret)
-                                       return ret;
-                       }
+       return 0;
+}
 
-                       spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
-                       f = list_entry(usbvision->outqueue.next,
-                                      struct usbvision_frame, frame);
-                       list_del(usbvision->outqueue.next);
-                       spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
-
-                       f->grabstate = FrameState_Unused;
-
-                       vb->memory = V4L2_MEMORY_MMAP;
-                       vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE;
-                       vb->index = f->index;
-                       vb->sequence = f->sequence;
-                       vb->timestamp = f->timestamp;
-                       vb->field = V4L2_FIELD_NONE;
-                       vb->bytesused = f->scanlength;
-
-                       return 0;
-               }
-               case VIDIOC_STREAMON:
-               {
-                       int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+static int vidioc_s_audio (struct file *file, void *fh,
+                         struct v4l2_audio *a)
+{
+       if(a->index) {
+               return -EINVAL;
+       }
 
-                       usbvision->streaming = Stream_On;
+       return 0;
+}
 
-                       call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
+static int vidioc_queryctrl (struct file *file, void *priv,
+                           struct v4l2_queryctrl *ctrl)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int id=ctrl->id;
 
-                       PDEBUG(DBG_IOCTL, "VIDIOC_STREAMON");
+       memset(ctrl,0,sizeof(*ctrl));
+       ctrl->id=id;
 
-                       return 0;
-               }
-               case VIDIOC_STREAMOFF:
-               {
-                       int *type = arg;
-                       int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-                       if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                               return -EINVAL;
-
-                       if(usbvision->streaming == Stream_On) {
-                               usbvision_stream_interrupt(usbvision);
-                               // Stop all video streamings
-                               call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
-                       }
-                       usbvision_empty_framequeues(usbvision);
+       call_i2c_clients(usbvision, VIDIOC_QUERYCTRL, ctrl);
 
-                       PDEBUG(DBG_IOCTL, "VIDIOC_STREAMOFF");
-                       return 0;
-               }
-               case VIDIOC_ENUM_FMT:
-               {
-                       struct v4l2_fmtdesc *vfd = arg;
+       if (!ctrl->type)
+               return -EINVAL;
 
-                       if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
-                               return -EINVAL;
-                       }
-                       vfd->flags = 0;
-                       vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                       strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
-                       vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
-                       memset(vfd->reserved, 0, sizeof(vfd->reserved));
-                       return 0;
-               }
-               case VIDIOC_G_FMT:
-               {
-                       struct v4l2_format *vf = arg;
-
-                       switch (vf->type) {
-                               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                               {
-                                       vf->fmt.pix.width = usbvision->curwidth;
-                                       vf->fmt.pix.height = usbvision->curheight;
-                                       vf->fmt.pix.pixelformat = usbvision->palette.format;
-                                       vf->fmt.pix.bytesperline =  usbvision->curwidth*usbvision->palette.bytes_per_pixel;
-                                       vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight;
-                                       vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-                                       vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */
-                                       PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT w=%d, h=%d, format=%s",
-                                              vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
-                                       return 0;
-                               }
-                               default:
-                                       PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT invalid type %d",vf->type);
-                                       return -EINVAL;
-                       }
-                       return 0;
-               }
-               case VIDIOC_TRY_FMT:
-               case VIDIOC_S_FMT:
-               {
-                       struct v4l2_format *vf = arg;
-                       int formatIdx,ret;
-
-                       switch(vf->type) {
-                               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                               {
-                                       /* Find requested format in available ones */
-                                       for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) {
-                                               if(vf->fmt.pix.pixelformat == usbvision_v4l2_format[formatIdx].format) {
-                                                       usbvision->palette = usbvision_v4l2_format[formatIdx];
-                                                       break;
-                                               }
-                                       }
-                                       /* robustness */
-                                       if(formatIdx == USBVISION_SUPPORTED_PALETTES) {
-                                               return -EINVAL;
-                                       }
-                                       RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
-                                       RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
-
-                                       vf->fmt.pix.bytesperline = vf->fmt.pix.width*usbvision->palette.bytes_per_pixel;
-                                       vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height;
-
-                                       if(cmd == VIDIOC_TRY_FMT) {
-                                               PDEBUG(DBG_IOCTL, "VIDIOC_TRY_FMT grabdisplay w=%d, h=%d, format=%s",
-                                              vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
-                                               return 0;
-                                       }
-
-                                       /* stop io in case it is already in progress */
-                                       if(usbvision->streaming == Stream_On) {
-                                               if ((ret = usbvision_stream_interrupt(usbvision)))
-                                                       return ret;
-                                       }
-                                       usbvision_frames_free(usbvision);
-                                       usbvision_empty_framequeues(usbvision);
-
-                                       usbvision->curFrame = NULL;
-
-                                       // by now we are committed to the new data...
-                                       down(&usbvision->lock);
-                                       usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
-                                       up(&usbvision->lock);
-
-                                       PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT grabdisplay w=%d, h=%d, format=%s",
-                                              vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
-                                       return 0;
-                               }
-                               default:
-                                       return -EINVAL;
-                       }
-               }
-               default:
-                       return -ENOIOCTLCMD;
+       return 0;
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
+
+       return 0;
+}
+
+static int vidioc_s_ctrl (struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
+
+       return 0;
+}
+
+static int vidioc_reqbufs (struct file *file,
+                          void *priv, struct v4l2_requestbuffers *vr)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int ret;
+
+       RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
+
+       /* Check input validity:
+          the user must do a VIDEO CAPTURE and MMAP method. */
+       if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
+          (vr->memory != V4L2_MEMORY_MMAP))
+               return -EINVAL;
+
+       if(usbvision->streaming == Stream_On) {
+               if ((ret = usbvision_stream_interrupt(usbvision)))
+                       return ret;
        }
+
+       usbvision_frames_free(usbvision);
+       usbvision_empty_framequeues(usbvision);
+       vr->count = usbvision_frames_alloc(usbvision,vr->count);
+
+       usbvision->curFrame = NULL;
+
        return 0;
 }
 
-static int usbvision_v4l2_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
+static int vidioc_querybuf (struct file *file,
+                           void *priv, struct v4l2_buffer *vb)
 {
-       return video_usercopy(inode, file, cmd, arg, usbvision_v4l2_do_ioctl);
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usbvision_frame *frame;
+
+       /* FIXME : must control
+          that buffers are mapped (VIDIOC_REQBUFS has been called) */
+       if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
+               return -EINVAL;
+       }
+       if(vb->index>=usbvision->num_frames)  {
+               return -EINVAL;
+       }
+       /* Updating the corresponding frame state */
+       vb->flags = 0;
+       frame = &usbvision->frame[vb->index];
+       if(frame->grabstate >= FrameState_Ready)
+               vb->flags |= V4L2_BUF_FLAG_QUEUED;
+       if(frame->grabstate >= FrameState_Done)
+               vb->flags |= V4L2_BUF_FLAG_DONE;
+       if(frame->grabstate == FrameState_Unused)
+               vb->flags |= V4L2_BUF_FLAG_MAPPED;
+       vb->memory = V4L2_MEMORY_MMAP;
+
+       vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
+
+       vb->memory = V4L2_MEMORY_MMAP;
+       vb->field = V4L2_FIELD_NONE;
+       vb->length = usbvision->curwidth*
+               usbvision->curheight*
+               usbvision->palette.bytes_per_pixel;
+       vb->timestamp = usbvision->frame[vb->index].timestamp;
+       vb->sequence = usbvision->frame[vb->index].sequence;
+       return 0;
+}
+
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usbvision_frame *frame;
+       unsigned long lock_flags;
+
+       /* FIXME : works only on VIDEO_CAPTURE MODE, MMAP. */
+       if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
+               return -EINVAL;
+       }
+       if(vb->index>=usbvision->num_frames)  {
+               return -EINVAL;
+       }
+
+       frame = &usbvision->frame[vb->index];
+
+       if (frame->grabstate != FrameState_Unused) {
+               return -EAGAIN;
+       }
+
+       /* Mark it as ready and enqueue frame */
+       frame->grabstate = FrameState_Ready;
+       frame->scanstate = ScanState_Scanning;
+       frame->scanlength = 0;  /* Accumulated in usbvision_parse_data() */
+
+       vb->flags &= ~V4L2_BUF_FLAG_DONE;
+
+       /* set v4l2_format index */
+       frame->v4l2_format = usbvision->palette;
+
+       spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+       list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue);
+       spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+       return 0;
 }
 
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int ret;
+       struct usbvision_frame *f;
+       unsigned long lock_flags;
+
+       if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (list_empty(&(usbvision->outqueue))) {
+               if (usbvision->streaming == Stream_Idle)
+                       return -EINVAL;
+               ret = wait_event_interruptible
+                       (usbvision->wait_frame,
+                        !list_empty(&(usbvision->outqueue)));
+               if (ret)
+                       return ret;
+       }
+
+       spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+       f = list_entry(usbvision->outqueue.next,
+                      struct usbvision_frame, frame);
+       list_del(usbvision->outqueue.next);
+       spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+       f->grabstate = FrameState_Unused;
+
+       vb->memory = V4L2_MEMORY_MMAP;
+       vb->flags = V4L2_BUF_FLAG_MAPPED |
+               V4L2_BUF_FLAG_QUEUED |
+               V4L2_BUF_FLAG_DONE;
+       vb->index = f->index;
+       vb->sequence = f->sequence;
+       vb->timestamp = f->timestamp;
+       vb->field = V4L2_FIELD_NONE;
+       vb->bytesused = f->scanlength;
+
+       return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       usbvision->streaming = Stream_On;
+       call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
+
+       return 0;
+}
+
+static int vidioc_streamoff(struct file *file,
+                           void *priv, enum v4l2_buf_type type)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if(usbvision->streaming == Stream_On) {
+               usbvision_stream_interrupt(usbvision);
+               /* Stop all video streamings */
+               call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
+       }
+       usbvision_empty_framequeues(usbvision);
+
+       return 0;
+}
+
+static int vidioc_enum_fmt_cap (struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *vfd)
+{
+       if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
+               return -EINVAL;
+       }
+       vfd->flags = 0;
+       vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
+       vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
+       memset(vfd->reserved, 0, sizeof(vfd->reserved));
+       return 0;
+}
+
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+                                       struct v4l2_format *vf)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       vf->fmt.pix.width = usbvision->curwidth;
+       vf->fmt.pix.height = usbvision->curheight;
+       vf->fmt.pix.pixelformat = usbvision->palette.format;
+       vf->fmt.pix.bytesperline =
+               usbvision->curwidth*usbvision->palette.bytes_per_pixel;
+       vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight;
+       vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+       vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */
+
+       return 0;
+}
+
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
+                              struct v4l2_format *vf)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int formatIdx;
+
+       /* Find requested format in available ones */
+       for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) {
+               if(vf->fmt.pix.pixelformat ==
+                  usbvision_v4l2_format[formatIdx].format) {
+                       usbvision->palette = usbvision_v4l2_format[formatIdx];
+                       break;
+               }
+       }
+       /* robustness */
+       if(formatIdx == USBVISION_SUPPORTED_PALETTES) {
+               return -EINVAL;
+       }
+       RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
+       RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
+
+       vf->fmt.pix.bytesperline = vf->fmt.pix.width*
+               usbvision->palette.bytes_per_pixel;
+       vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height;
+
+       return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+                              struct v4l2_format *vf)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int ret;
+
+       if( 0 != (ret=vidioc_try_fmt_cap (file, priv, vf)) ) {
+               return ret;
+       }
+
+       /* stop io in case it is already in progress */
+       if(usbvision->streaming == Stream_On) {
+               if ((ret = usbvision_stream_interrupt(usbvision)))
+                       return ret;
+       }
+       usbvision_frames_free(usbvision);
+       usbvision_empty_framequeues(usbvision);
+
+       usbvision->curFrame = NULL;
+
+       /* by now we are committed to the new data... */
+       down(&usbvision->lock);
+       usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
+       up(&usbvision->lock);
+
+       return 0;
+}
 
 static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
                      size_t count, loff_t *ppos)
 {
        struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
        int noblock = file->f_flags & O_NONBLOCK;
        unsigned long lock_flags;
 
        int ret,i;
        struct usbvision_frame *frame;
 
-       PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock);
+       PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__,
+              (unsigned long)count, noblock);
 
        if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL))
                return -EFAULT;
 
-       /* This entry point is compatible with the mmap routines so that a user can do either
-          VIDIOC_QBUF/VIDIOC_DQBUF to get frames or call read on the device. */
+       /* This entry point is compatible with the mmap routines
+          so that a user can do either VIDIOC_QBUF/VIDIOC_DQBUF
+          to get frames or call read on the device. */
        if(!usbvision->num_frames) {
-               /* First, allocate some frames to work with if this has not been done with
-                VIDIOC_REQBUF */
+               /* First, allocate some frames to work with
+                  if this has not been done with VIDIOC_REQBUF */
                usbvision_frames_free(usbvision);
                usbvision_empty_framequeues(usbvision);
                usbvision_frames_alloc(usbvision,USBVISION_NUMFRAMES);
@@ -1086,21 +1116,24 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
                call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
        }
 
-       /* Then, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */
+       /* Then, enqueue as many frames as possible
+          (like a user of VIDIOC_QBUF would do) */
        for(i=0;i<usbvision->num_frames;i++) {
                frame = &usbvision->frame[i];
                if(frame->grabstate == FrameState_Unused) {
                        /* Mark it as ready and enqueue frame */
                        frame->grabstate = FrameState_Ready;
                        frame->scanstate = ScanState_Scanning;
-                       frame->scanlength = 0;  /* Accumulated in usbvision_parse_data() */
+                       /* Accumulated in usbvision_parse_data() */
+                       frame->scanlength = 0;
 
                        /* set v4l2_format index */
                        frame->v4l2_format = usbvision->palette;
 
                        spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
                        list_add_tail(&frame->frame, &usbvision->inqueue);
-                       spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+                       spin_unlock_irqrestore(&usbvision->queue_lock,
+                                              lock_flags);
                }
        }
 
@@ -1128,8 +1161,9 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
                return 0;
        }
 
-       PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", __FUNCTION__,
-                      frame->index, frame->bytes_read, frame->scanlength);
+       PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld",
+              __FUNCTION__,
+              frame->index, frame->bytes_read, frame->scanlength);
 
        /* copy bytes to user space; we allow for partials reads */
        if ((count + frame->bytes_read) > (unsigned long)frame->scanlength)
@@ -1140,10 +1174,11 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
        }
 
        frame->bytes_read += count;
-       PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", __FUNCTION__,
-                      (unsigned long)count, frame->bytes_read);
+       PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld",
+              __FUNCTION__,
+              (unsigned long)count, frame->bytes_read);
 
-       // For now, forget the frame if it has not been read in one shot.
+       /* For now, forget the frame if it has not been read in one shot. */
 /*     if (frame->bytes_read >= frame->scanlength) {// All data has been read */
                frame->bytes_read = 0;
 
@@ -1162,7 +1197,8 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
        u32 i;
 
        struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
        PDEBUG(DBG_MMAP, "mmap");
 
@@ -1180,11 +1216,13 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
        }
 
        for (i = 0; i < usbvision->num_frames; i++) {
-               if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) == vma->vm_pgoff)
+               if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) ==
+                   vma->vm_pgoff)
                        break;
        }
        if (i == usbvision->num_frames) {
-               PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range");
+               PDEBUG(DBG_MMAP,
+                      "mmap: user supplied mapping address is out of range");
                up(&usbvision->lock);
                return -EINVAL;
        }
@@ -1218,8 +1256,8 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 static int usbvision_radio_open(struct inode *inode, struct file *file)
 {
        struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
-       struct v4l2_frequency freq;
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
        int errCode = 0;
 
        PDEBUG(DBG_IO, "%s:", __FUNCTION__);
@@ -1249,8 +1287,6 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
                // If so far no errors then we shall start the radio
                usbvision->radio = 1;
                call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type);
-               freq.frequency = 1517; //SWR3 @ 94.8MHz
-               call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, &freq);
                usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO);
                usbvision->user++;
        }
@@ -1270,7 +1306,8 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
 static int usbvision_radio_close(struct inode *inode, struct file *file)
 {
        struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
        int errCode = 0;
 
        PDEBUG(DBG_IO, "");
@@ -1304,149 +1341,6 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
        return errCode;
 }
 
-static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file,
-                                unsigned int cmd, void *arg)
-{
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
-
-       if (!USBVISION_IS_OPERATIONAL(usbvision))
-               return -EIO;
-
-       switch (cmd) {
-               case VIDIOC_QUERYCAP:
-               {
-                       struct v4l2_capability *vc=arg;
-
-                       memset(vc, 0, sizeof(*vc));
-                       strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
-                       strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString,
-                               sizeof(vc->card));
-                       strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
-                               sizeof(vc->bus_info));
-                       vc->version = USBVISION_DRIVER_VERSION;
-                       vc->capabilities = (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
-                       PDEBUG(DBG_IO, "VIDIOC_QUERYCAP");
-                       return 0;
-               }
-               case VIDIOC_QUERYCTRL:
-               {
-                       struct v4l2_queryctrl *ctrl = arg;
-                       int id=ctrl->id;
-
-                       memset(ctrl,0,sizeof(*ctrl));
-                       ctrl->id=id;
-
-                       call_i2c_clients(usbvision, cmd, arg);
-                       PDEBUG(DBG_IO,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type);
-
-                       if (ctrl->type)
-                               return 0;
-                       else
-                               return -EINVAL;
-
-               }
-               case VIDIOC_G_CTRL:
-               {
-                       struct v4l2_control *ctrl = arg;
-
-                       call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
-                       PDEBUG(DBG_IO,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
-                       return 0;
-               }
-               case VIDIOC_S_CTRL:
-               {
-                       struct v4l2_control *ctrl = arg;
-
-                       call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
-                       PDEBUG(DBG_IO, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value);
-                       return 0;
-               }
-               case VIDIOC_G_TUNER:
-               {
-                       struct v4l2_tuner *t = arg;
-
-                       if (t->index > 0)
-                               return -EINVAL;
-
-                       memset(t,0,sizeof(*t));
-                       strcpy(t->name, "Radio");
-                       t->type = V4L2_TUNER_RADIO;
-
-                       /* Let clients fill in the remainder of this struct */
-                       call_i2c_clients(usbvision,VIDIOC_G_TUNER,t);
-                       PDEBUG(DBG_IO, "VIDIOC_G_TUNER signal=%x, afc=%x",t->signal,t->afc);
-                       return 0;
-               }
-               case VIDIOC_S_TUNER:
-               {
-                       struct v4l2_tuner *vt = arg;
-
-                       // Only no or one tuner for now
-                       if (!usbvision->have_tuner || vt->index)
-                               return -EINVAL;
-                       /* let clients handle this */
-                       call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
-
-                       PDEBUG(DBG_IO, "VIDIOC_S_TUNER");
-                       return 0;
-               }
-               case VIDIOC_G_AUDIO:
-               {
-                       struct v4l2_audio *a = arg;
-
-                       memset(a,0,sizeof(*a));
-                       strcpy(a->name,"Radio");
-                       PDEBUG(DBG_IO, "VIDIOC_G_AUDIO");
-                       return 0;
-               }
-               case VIDIOC_S_AUDIO:
-               case VIDIOC_S_INPUT:
-               case VIDIOC_S_STD:
-               return 0;
-
-               case VIDIOC_G_FREQUENCY:
-               {
-                       struct v4l2_frequency *f = arg;
-
-                       memset(f,0,sizeof(*f));
-
-                       f->type = V4L2_TUNER_RADIO;
-                       f->frequency = usbvision->freq;
-                       call_i2c_clients(usbvision, cmd, f);
-                       PDEBUG(DBG_IO, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)f->frequency);
-
-                       return 0;
-               }
-               case VIDIOC_S_FREQUENCY:
-               {
-                       struct v4l2_frequency *f = arg;
-
-                       if (f->tuner != 0)
-                               return -EINVAL;
-                       usbvision->freq = f->frequency;
-                       call_i2c_clients(usbvision, cmd, f);
-                       PDEBUG(DBG_IO, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)f->frequency);
-
-                       return 0;
-               }
-               default:
-               {
-                       PDEBUG(DBG_IO, "%s: Unknown command %x", __FUNCTION__, cmd);
-                       return -ENOIOCTLCMD;
-               }
-       }
-       return 0;
-}
-
-
-static int usbvision_radio_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       return video_usercopy(inode, file, cmd, arg, usbvision_do_radio_ioctl);
-}
-
-
 /*
  * Here comes the stuff for vbi on usbvision based devices
  *
@@ -1454,21 +1348,21 @@ static int usbvision_radio_ioctl(struct inode *inode, struct file *file,
 static int usbvision_vbi_open(struct inode *inode, struct file *file)
 {
        /* TODO */
-       return -EINVAL;
+       return -ENODEV;
 
 }
 
 static int usbvision_vbi_close(struct inode *inode, struct file *file)
 {
        /* TODO */
-       return -EINVAL;
+       return -ENODEV;
 }
 
 static int usbvision_do_vbi_ioctl(struct inode *inode, struct file *file,
                                 unsigned int cmd, void *arg)
 {
        /* TODO */
-       return -EINVAL;
+       return -ENOIOCTLCMD;
 }
 
 static int usbvision_vbi_ioctl(struct inode *inode, struct file *file,
@@ -1489,8 +1383,11 @@ static const struct file_operations usbvision_fops = {
        .release        = usbvision_v4l2_close,
        .read           = usbvision_v4l2_read,
        .mmap           = usbvision_v4l2_mmap,
-       .ioctl          = usbvision_v4l2_ioctl,
+       .ioctl          = video_ioctl2,
        .llseek         = no_llseek,
+/*     .poll          = video_poll, */
+       .mmap          = usbvision_v4l2_mmap,
+       .compat_ioctl  = v4l_compat_ioctl32,
 };
 static struct video_device usbvision_video_template = {
        .owner             = THIS_MODULE,
@@ -1500,6 +1397,39 @@ static struct video_device usbvision_video_template = {
        .name           = "usbvision-video",
        .release        = video_device_release,
        .minor          = -1,
+       .vidioc_querycap      = vidioc_querycap,
+       .vidioc_enum_fmt_cap  = vidioc_enum_fmt_cap,
+       .vidioc_g_fmt_cap     = vidioc_g_fmt_cap,
+       .vidioc_try_fmt_cap   = vidioc_try_fmt_cap,
+       .vidioc_s_fmt_cap     = vidioc_s_fmt_cap,
+       .vidioc_reqbufs       = vidioc_reqbufs,
+       .vidioc_querybuf      = vidioc_querybuf,
+       .vidioc_qbuf          = vidioc_qbuf,
+       .vidioc_dqbuf         = vidioc_dqbuf,
+       .vidioc_s_std         = vidioc_s_std,
+       .vidioc_enum_input    = vidioc_enum_input,
+       .vidioc_g_input       = vidioc_g_input,
+       .vidioc_s_input       = vidioc_s_input,
+       .vidioc_queryctrl     = vidioc_queryctrl,
+       .vidioc_g_audio       = vidioc_g_audio,
+       .vidioc_g_audio       = vidioc_s_audio,
+       .vidioc_g_ctrl        = vidioc_g_ctrl,
+       .vidioc_s_ctrl        = vidioc_s_ctrl,
+       .vidioc_streamon      = vidioc_streamon,
+       .vidioc_streamoff     = vidioc_streamoff,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+/*     .vidiocgmbuf          = vidiocgmbuf, */
+#endif
+       .vidioc_g_tuner       = vidioc_g_tuner,
+       .vidioc_s_tuner       = vidioc_s_tuner,
+       .vidioc_g_frequency   = vidioc_g_frequency,
+       .vidioc_s_frequency   = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register    = vidioc_g_register,
+       .vidioc_s_register    = vidioc_s_register,
+#endif
+       .tvnorms              = USBVISION_NORMS,
+       .current_norm         = V4L2_STD_PAL
 };
 
 
@@ -1508,8 +1438,9 @@ static const struct file_operations usbvision_radio_fops = {
        .owner             = THIS_MODULE,
        .open           = usbvision_radio_open,
        .release        = usbvision_radio_close,
-       .ioctl          = usbvision_radio_ioctl,
+       .ioctl          = video_ioctl2,
        .llseek         = no_llseek,
+       .compat_ioctl  = v4l_compat_ioctl32,
 };
 
 static struct video_device usbvision_radio_template=
@@ -1518,12 +1449,27 @@ static struct video_device usbvision_radio_template=
        .type           = VID_TYPE_TUNER,
        .hardware       = VID_HARDWARE_USBVISION,
        .fops           = &usbvision_radio_fops,
-       .release        = video_device_release,
        .name           = "usbvision-radio",
+       .release        = video_device_release,
        .minor          = -1,
+       .vidioc_querycap      = vidioc_querycap,
+       .vidioc_enum_input    = vidioc_enum_input,
+       .vidioc_g_input       = vidioc_g_input,
+       .vidioc_s_input       = vidioc_s_input,
+       .vidioc_queryctrl     = vidioc_queryctrl,
+       .vidioc_g_audio       = vidioc_g_audio,
+       .vidioc_g_audio       = vidioc_s_audio,
+       .vidioc_g_ctrl        = vidioc_g_ctrl,
+       .vidioc_s_ctrl        = vidioc_s_ctrl,
+       .vidioc_g_tuner       = vidioc_g_tuner,
+       .vidioc_s_tuner       = vidioc_s_tuner,
+       .vidioc_g_frequency   = vidioc_g_frequency,
+       .vidioc_s_frequency   = vidioc_s_frequency,
+
+       .tvnorms              = USBVISION_NORMS,
+       .current_norm         = V4L2_STD_PAL
 };
 
-
 // vbi template
 static const struct file_operations usbvision_vbi_fops = {
        .owner             = THIS_MODULE,
@@ -1531,6 +1477,7 @@ static const struct file_operations usbvision_vbi_fops = {
        .release        = usbvision_vbi_close,
        .ioctl          = usbvision_vbi_ioctl,
        .llseek         = no_llseek,
+       .compat_ioctl  = v4l_compat_ioctl32,
 };
 
 static struct video_device usbvision_vbi_template=
@@ -1574,11 +1521,11 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
 {
        // vbi Device:
        if (usbvision->vbi) {
-               PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]", usbvision->vbi->minor & 0x1f);
+               PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]",
+                      usbvision->vbi->minor & 0x1f);
                if (usbvision->vbi->minor != -1) {
                        video_unregister_device(usbvision->vbi);
-               }
-               else {
+               } else {
                        video_device_release(usbvision->vbi);
                }
                usbvision->vbi = NULL;
@@ -1586,11 +1533,11 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
 
        // Radio Device:
        if (usbvision->rdev) {
-               PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]", usbvision->rdev->minor & 0x1f);
+               PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]",
+                      usbvision->rdev->minor & 0x1f);
                if (usbvision->rdev->minor != -1) {
                        video_unregister_device(usbvision->rdev);
-               }
-               else {
+               } else {
                        video_device_release(usbvision->rdev);
                }
                usbvision->rdev = NULL;
@@ -1598,11 +1545,11 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
 
        // Video Device:
        if (usbvision->vdev) {
-               PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]", usbvision->vdev->minor & 0x1f);
+               PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]",
+                      usbvision->vdev->minor & 0x1f);
                if (usbvision->vdev->minor != -1) {
                        video_unregister_device(usbvision->vdev);
-               }
-               else {
+               } else {
                        video_device_release(usbvision->vdev);
                }
                usbvision->vdev = NULL;
@@ -1613,37 +1560,52 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
 static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
 {
        // Video Device:
-       usbvision->vdev = usbvision_vdev_init(usbvision, &usbvision_video_template, "USBVision Video");
+       usbvision->vdev = usbvision_vdev_init(usbvision,
+                                             &usbvision_video_template,
+                                             "USBVision Video");
        if (usbvision->vdev == NULL) {
                goto err_exit;
        }
-       if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr)<0) {
+       if (video_register_device(usbvision->vdev,
+                                 VFL_TYPE_GRABBER,
+                                 video_nr)<0) {
                goto err_exit;
        }
-       printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n", usbvision->nr,usbvision->vdev->minor & 0x1f);
+       printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n",
+              usbvision->nr,usbvision->vdev->minor & 0x1f);
 
        // Radio Device:
        if (usbvision_device_data[usbvision->DevModel].Radio) {
                // usbvision has radio
-               usbvision->rdev = usbvision_vdev_init(usbvision, &usbvision_radio_template, "USBVision Radio");
+               usbvision->rdev = usbvision_vdev_init(usbvision,
+                                                     &usbvision_radio_template,
+                                                     "USBVision Radio");
                if (usbvision->rdev == NULL) {
                        goto err_exit;
                }
-               if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr)<0) {
+               if (video_register_device(usbvision->rdev,
+                                         VFL_TYPE_RADIO,
+                                         radio_nr)<0) {
                        goto err_exit;
                }
-               printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n", usbvision->nr, usbvision->rdev->minor & 0x1f);
+               printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n",
+                      usbvision->nr, usbvision->rdev->minor & 0x1f);
        }
        // vbi Device:
        if (usbvision_device_data[usbvision->DevModel].vbi) {
-               usbvision->vbi = usbvision_vdev_init(usbvision, &usbvision_vbi_template, "USBVision VBI");
+               usbvision->vbi = usbvision_vdev_init(usbvision,
+                                                    &usbvision_vbi_template,
+                                                    "USBVision VBI");
                if (usbvision->vdev == NULL) {
                        goto err_exit;
                }
-               if (video_register_device(usbvision->vbi, VFL_TYPE_VBI, vbi_nr)<0) {
+               if (video_register_device(usbvision->vbi,
+                                         VFL_TYPE_VBI,
+                                         vbi_nr)<0) {
                        goto err_exit;
                }
-               printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n", usbvision->nr,usbvision->vbi->minor & 0x1f);
+               printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n",
+                      usbvision->nr,usbvision->vbi->minor & 0x1f);
        }
        // all done
        return 0;
@@ -1657,7 +1619,8 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
 /*
  * usbvision_alloc()
  *
- * This code allocates the struct usb_usbvision. It is filled with default values.
+ * This code allocates the struct usb_usbvision.
+ * It is filled with default values.
  *
  * Returns NULL on error, a pointer to usb_usbvision else.
  *
@@ -1666,7 +1629,8 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
 {
        struct usb_usbvision *usbvision;
 
-       if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) == NULL) {
+       if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) ==
+           NULL) {
                goto err_exit;
        }
 
@@ -1728,11 +1692,11 @@ static void usbvision_release(struct usb_usbvision *usbvision)
 }
 
 
-/******************************** usb interface *****************************************/
+/*********************** usb interface **********************************/
 
 static void usbvision_configure_video(struct usb_usbvision *usbvision)
 {
-       int model,i;
+       int model;
 
        if (usbvision == NULL)
                return;
@@ -1741,25 +1705,23 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision)
        usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24;
 
        if (usbvision_device_data[usbvision->DevModel].Vin_Reg2_override) {
-               usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2;
+               usbvision->Vin_Reg2_Preset =
+                       usbvision_device_data[usbvision->DevModel].Vin_Reg2;
        } else {
                usbvision->Vin_Reg2_Preset = 0;
        }
 
-       for (i = 0; i < TVNORMS; i++)
-               if (usbvision_device_data[model].VideoNorm == tvnorms[i].mode)
-                       break;
-       if (i == TVNORMS)
-               i = 0;
-       usbvision->tvnorm = &tvnorms[i];        /* set default norm */
+       usbvision->tvnormId = usbvision_device_data[model].VideoNorm;
 
        usbvision->video_inputs = usbvision_device_data[model].VideoChannels;
        usbvision->ctl_input = 0;
 
        /* This should be here to make i2c clients to be able to register */
-       usbvision_audio_off(usbvision); //first switch off audio
+       /* first switch off audio */
+       usbvision_audio_off(usbvision);
        if (!PowerOnAtOpen) {
-               usbvision_power_on(usbvision);  //and then power up the noisy tuner
+               /* and then power up the noisy tuner */
+               usbvision_power_on(usbvision);
                usbvision_i2c_register(usbvision);
        }
 }
@@ -1796,18 +1758,22 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
 
        if (usbvision_device_data[model].Interface >= 0) {
                interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0];
-       }
-       else {
+       } else {
                interface = &dev->actconfig->interface[ifnum]->altsetting[0];
        }
        endpoint = &interface->endpoint[1].desc;
-       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) {
-               err("%s: interface %d. has non-ISO endpoint!", __FUNCTION__, ifnum);
-               err("%s: Endpoint attributes %d", __FUNCTION__, endpoint->bmAttributes);
+       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+           USB_ENDPOINT_XFER_ISOC) {
+               err("%s: interface %d. has non-ISO endpoint!",
+                   __FUNCTION__, ifnum);
+               err("%s: Endpoint attributes %d",
+                   __FUNCTION__, endpoint->bmAttributes);
                return -ENODEV;
        }
-       if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
-               err("%s: interface %d. has ISO OUT endpoint!", __FUNCTION__, ifnum);
+       if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
+           USB_DIR_OUT) {
+               err("%s: interface %d. has ISO OUT endpoint!",
+                   __FUNCTION__, ifnum);
                return -ENODEV;
        }
 
@@ -1818,11 +1784,9 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
 
        if (dev->descriptor.bNumConfigurations > 1) {
                usbvision->bridgeType = BRIDGE_NT1004;
-       }
-       else if (model == DAZZLE_DVC_90_REV_1_SECAM) {
+       } else if (model == DAZZLE_DVC_90_REV_1_SECAM) {
                usbvision->bridgeType = BRIDGE_NT1005;
-       }
-       else {
+       } else {
                usbvision->bridgeType = BRIDGE_NT1003;
        }
        PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType);
@@ -1919,11 +1883,11 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
        up(&usbvision->lock);
 
        if (usbvision->user) {
-               printk(KERN_INFO "%s: In use, disconnect pending\n", __FUNCTION__);
+               printk(KERN_INFO "%s: In use, disconnect pending\n",
+                      __FUNCTION__);
                wake_up_interruptible(&usbvision->wait_frame);
                wake_up_interruptible(&usbvision->wait_stream);
-       }
-       else {
+       } else {
                usbvision_release(usbvision);
        }
 
@@ -1950,7 +1914,6 @@ static int __init usbvision_init(void)
 
        PDEBUG(DBG_PROBE, "");
 
-       PDEBUG(DBG_IOCTL, "IOCTL   debugging is enabled [video]");
        PDEBUG(DBG_IO,  "IO      debugging is enabled [video]");
        PDEBUG(DBG_PROBE, "PROBE   debugging is enabled [video]");
        PDEBUG(DBG_MMAP, "MMAP    debugging is enabled [video]");
index c759d00d701461272ee41552bfca254867ce2821..c5b6c501c869fc638dfa6aea3a7bdae7e8833247 100644 (file)
@@ -221,6 +221,8 @@ enum {
 
 #define I2C_USB_ADAP_MAX       16
 
+#define USBVISION_NORMS (V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM | V4L2_STD_PAL_M)
+
 /* ----------------------------------------------------------------- */
 /* usbvision video structures                                        */
 /* ----------------------------------------------------------------- */
@@ -301,14 +303,6 @@ struct usbvision_frame_header {
        __u16 frameHeight;                              /* 10 - 11 after endian correction*/
 };
 
-/* tvnorms */
-struct usbvision_tvnorm {
-       char *name;
-       v4l2_std_id id;
-       /* mode for saa7113h */
-       int mode;
-};
-
 struct usbvision_frame {
        char *data;                                     /* Frame buffer */
        struct usbvision_frame_header isocHeader;       /* Header from stream */
@@ -386,7 +380,6 @@ struct usb_usbvision {
        int tuner_type;
        int tuner_addr;
        int bridgeType;                                                 // NT1003, NT1004, NT1005
-       int channel;
        int radio;
        int video_inputs;                                               // # of inputs
        unsigned long freq;
@@ -441,7 +434,7 @@ struct usb_usbvision {
 
        struct v4l2_capability vcap;                                    /* Video capabilities */
        unsigned int ctl_input;                                         /* selected input */
-       struct usbvision_tvnorm *tvnorm;                                /* selected tv norm */
+       v4l2_std_id tvnormId;                                           /* selected tv norm */
        unsigned char video_endp;                                       /* 0x82 for USBVISION devices based */
 
        // Decompression stuff:
index 0c658b74f2c428aabff64c71e106d901e016d15f..e94a9a6036f59d59723bc07a799318653f716c61 100644 (file)
@@ -2077,12 +2077,10 @@ static int vino_wait_for_frame(struct vino_channel_settings *vcs)
        init_waitqueue_entry(&wait, current);
        /* add ourselves into wait queue */
        add_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait);
-       /* and set current state */
-       set_current_state(TASK_INTERRUPTIBLE);
 
        /* to ensure that schedule_timeout will return immediately
-        * if VINO interrupt was triggred meanwhile */
-       schedule_timeout(HZ / 10);
+        * if VINO interrupt was triggered meanwhile */
+       schedule_timeout_interruptible(HZ / 10);
 
        if (signal_pending(current))
                err = -EINTR;
index 3ef4d0159c3306fcbf7b0bf5b41803e1de7ebaa4..f6d3a9460ccce1e0ca83ee27c0f466c11490cbbe 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/pci.h>
 #include <linux/random.h>
 #include <linux/version.h>
+#include <linux/mutex.h>
 #include <linux/videodev2.h>
 #include <linux/dma-mapping.h>
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -145,9 +146,6 @@ struct vivi_buffer {
 
        struct vivi_fmt        *fmt;
 
-#ifdef CONFIG_VIVI_SCATTER
-       struct sg_to_addr      *to_addr;
-#endif
 };
 
 struct vivi_dmaqueue {
@@ -168,7 +166,7 @@ static LIST_HEAD(vivi_devlist);
 struct vivi_dev {
        struct list_head           vivi_devlist;
 
-       struct semaphore           lock;
+       struct mutex               lock;
 
        int                        users;
 
@@ -232,68 +230,13 @@ static u8 bars[8][3] = {
 #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
 #define TSTAMP_MIN_X 64
 
-#ifdef CONFIG_VIVI_SCATTER
-static void prep_to_addr(struct sg_to_addr to_addr[],
-                        struct videobuf_buffer *vb)
-{
-       int i, pos=0;
-
-       for (i=0;i<vb->dma.nr_pages;i++) {
-               to_addr[i].sg=&vb->dma.sglist[i];
-               to_addr[i].pos=pos;
-               pos += vb->dma.sglist[i].length;
-       }
-}
-
-static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
-{
-       int p1=0,p2=pages-1,p3=pages/2;
-
-       /* Sanity test */
-       BUG_ON (pos>=to_addr[p2].pos+to_addr[p2].sg->length);
-
-       while (p1+1<p2) {
-               if (pos < to_addr[p3].pos) {
-                       p2=p3;
-               } else {
-                       p1=p3;
-               }
-               p3=(p1+p2)/2;
-       }
-       if (pos >= to_addr[p2].pos)
-               p1=p2;
-
-       return (p1);
-}
-#endif
 
-#ifdef CONFIG_VIVI_SCATTER
-static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
-                    int hmax, int line, char *timestr)
-#else
 static void gen_line(char *basep,int inipos,int wmax,
                     int hmax, int line, char *timestr)
-#endif
 {
        int  w,i,j,pos=inipos,y;
        char *p,*s;
        u8   chr,r,g,b,color;
-#ifdef CONFIG_VIVI_SCATTER
-       int pgpos,oldpg;
-       char *basep;
-       struct page *pg;
-
-       unsigned long flags;
-       spinlock_t spinlock;
-
-       spin_lock_init(&spinlock);
-
-       /* Get first addr pointed to pixel position */
-       oldpg=get_addr_pos(pos,pages,to_addr);
-       pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT);
-       spin_lock_irqsave(&spinlock,flags);
-       basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset;
-#endif
 
        /* We will just duplicate the second pixel at the packet */
        wmax/=2;
@@ -305,18 +248,7 @@ static void gen_line(char *basep,int inipos,int wmax,
                b=bars[w*7/wmax][2];
 
                for (color=0;color<4;color++) {
-#ifdef CONFIG_VIVI_SCATTER
-                       pgpos=get_addr_pos(pos,pages,to_addr);
-                       if (pgpos!=oldpg) {
-                               pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT);
-                               kunmap_atomic(basep, KM_BOUNCE_READ);
-                               basep= kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[pgpos].sg->offset;
-                               oldpg=pgpos;
-                       }
-                       p=basep+pos-to_addr[pgpos].pos;
-#else
                        p=basep+pos;
-#endif
 
                        switch (color) {
                                case 0:
@@ -361,23 +293,7 @@ static void gen_line(char *basep,int inipos,int wmax,
 
                                pos=inipos+j*2;
                                for (color=0;color<4;color++) {
-#ifdef CONFIG_VIVI_SCATTER
-                                       pgpos=get_addr_pos(pos,pages,to_addr);
-                                       if (pgpos!=oldpg) {
-                                               pg=pfn_to_page(sg_dma_address(
-                                                               to_addr[pgpos].sg)
-                                                               >> PAGE_SHIFT);
-                                               kunmap_atomic(basep,
-                                                               KM_BOUNCE_READ);
-                                               basep= kmap_atomic(pg,
-                                                       KM_BOUNCE_READ)+
-                                                       to_addr[pgpos].sg->offset;
-                                               oldpg=pgpos;
-                                       }
-                                       p=basep+pos-to_addr[pgpos].pos;
-#else
                                        p=basep+pos;
-#endif
 
                                        y=TO_Y(r,g,b);
 
@@ -402,12 +318,7 @@ static void gen_line(char *basep,int inipos,int wmax,
 
 
 end:
-#ifdef CONFIG_VIVI_SCATTER
-       kunmap_atomic(basep, KM_BOUNCE_READ);
-       spin_unlock_irqrestore(&spinlock,flags);
-#else
        return;
-#endif
 }
 static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
 {
@@ -415,35 +326,16 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
        int hmax  = buf->vb.height;
        int wmax  = buf->vb.width;
        struct timeval ts;
-#ifdef CONFIG_VIVI_SCATTER
-       struct sg_to_addr *to_addr=buf->to_addr;
-       struct videobuf_buffer *vb=&buf->vb;
-#else
        char *tmpbuf;
-#endif
-
-#ifdef CONFIG_VIVI_SCATTER
-       /* Test if DMA mapping is ready */
-       if (!sg_dma_address(&vb->dma.sglist[0]))
-               return;
-
-       prep_to_addr(to_addr,vb);
 
-       /* Check if there is enough memory */
-       BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2);
-#else
        if (buf->vb.dma.varea) {
                tmpbuf=kmalloc (wmax*2, GFP_KERNEL);
        } else {
                tmpbuf=buf->vb.dma.vmalloc;
        }
 
-#endif
 
        for (h=0;h<hmax;h++) {
-#ifdef CONFIG_VIVI_SCATTER
-               gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr);
-#else
                if (buf->vb.dma.varea) {
                        gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr);
                        /* FIXME: replacing to __copy_to_user */
@@ -452,7 +344,6 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
                } else {
                        gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr);
                }
-#endif
                pos += wmax*2;
        }
 
@@ -718,11 +609,6 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
        if (in_interrupt())
                BUG();
 
-#ifdef CONFIG_VIVI_SCATTER
-       /*FIXME: Maybe a spinlock is required here */
-       kfree(buf->to_addr);
-       buf->to_addr=NULL;
-#endif
 
        videobuf_waiton(&buf->vb,0,0);
        videobuf_dma_unmap(vq, &buf->vb.dma);
@@ -768,12 +654,6 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
 
        buf->vb.state = STATE_PREPARED;
 
-#ifdef CONFIG_VIVI_SCATTER
-       if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) {
-               rc=-ENOMEM;
-               goto fail;
-       }
-#endif
        return 0;
 
 fail:
@@ -838,40 +718,6 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb
        free_buffer(vq,buf);
 }
 
-#ifdef CONFIG_VIVI_SCATTER
-static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents,
-                      int direction)
-{
-       int i;
-
-       dprintk(1,"%s, number of pages=%d\n",__FUNCTION__,nents);
-       BUG_ON(direction == DMA_NONE);
-
-       for (i = 0; i < nents; i++ ) {
-               BUG_ON(!sg[i].page);
-
-               sg_dma_address(&sg[i]) = page_to_phys(sg[i].page) + sg[i].offset;
-       }
-
-       return nents;
-}
-
-static int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
-                        int direction)
-{
-       dprintk(1,"%s\n",__FUNCTION__);
-       return 0;
-}
-
-static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages,
-                           int direction)
-{
-//     dprintk(1,"%s\n",__FUNCTION__);
-
-//     flush_write_buffers();
-       return 0;
-}
-#endif
 
 static struct videobuf_queue_ops vivi_video_qops = {
        .buf_setup      = buffer_setup,
@@ -893,16 +739,16 @@ static struct videobuf_queue_ops vivi_video_qops = {
 static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
 {
        /* is it free? */
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        if (dev->resources) {
                /* no, someone else uses it */
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                return 0;
        }
        /* it's free, grab it */
        dev->resources =1;
        dprintk(1,"res: get\n");
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
        return 1;
 }
 
@@ -913,10 +759,10 @@ static int res_locked(struct vivi_dev *dev)
 
 static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
 {
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        dev->resources = 0;
        dprintk(1,"res: put\n");
-       up(&dev->lock);
+       mutex_lock(&dev->lock);
 }
 
 /* ------------------------------------------------------------------
@@ -1260,19 +1106,11 @@ static int vivi_open(struct inode *inode, struct file *file)
        sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
                        dev->h,dev->m,dev->s,(dev->us+500)/1000);
 
-#ifdef CONFIG_VIVI_SCATTER
-       videobuf_queue_init(&fh->vb_vidq,VIDEOBUF_DMA_SCATTER, &vivi_video_qops,
-                       NULL, NULL,
-                       fh->type,
-                       V4L2_FIELD_INTERLACED,
-                       sizeof(struct vivi_buffer),fh);
-#else
        videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops,
                        NULL, NULL,
                        fh->type,
                        V4L2_FIELD_INTERLACED,
                        sizeof(struct vivi_buffer),fh);
-#endif
 
        return 0;
 }
@@ -1423,7 +1261,7 @@ static int __init vivi_init(void)
        init_waitqueue_head(&dev->vidq.wq);
 
        /* initialize locks */
-       init_MUTEX(&dev->lock);
+       mutex_init(&dev->lock);
 
        dev->vidq.timeout.function = vivi_vid_timeout;
        dev->vidq.timeout.data     = (unsigned long)dev;
index 47cd93f9c7de8555c7f181b0d17fc7a75793dbc6..edb00293cd590f125fd1eda40e551066be11bac0 100644 (file)
@@ -1,6 +1,6 @@
 config USB_ZC0301
        tristate "USB ZC0301[P] Image Processor and Control Chip support"
-       depends on VIDEO_V4L1
+       depends on VIDEO_V4L2
        ---help---
          Say Y here if you want support for cameras based on the ZC0301 or
          ZC0301P Image Processors and Control Chips.
index 710f12eb9126a9c2a0d4638766706368c36b78ac..a2de50efa31adec2c439b182070e8db95f6e7781 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/rwsem.h>
 #include <linux/stddef.h>
 #include <linux/string.h>
+#include <linux/kref.h>
 
 #include "zc0301_sensor.h"
 
@@ -98,7 +99,7 @@ struct zc0301_module_param {
        u16 frame_timeout;
 };
 
-static DECLARE_RWSEM(zc0301_disconnect);
+static DECLARE_RWSEM(zc0301_dev_lock);
 
 struct zc0301_device {
        struct video_device* v4ldev;
@@ -121,12 +122,14 @@ struct zc0301_device {
 
        struct zc0301_module_param module_param;
 
+       struct kref kref;
        enum zc0301_dev_state state;
        u8 users;
 
-       struct mutex dev_mutex, fileop_mutex;
+       struct completion probe;
+       struct mutex open_mutex, fileop_mutex;
        spinlock_t queue_lock;
-       wait_queue_head_t open, wait_frame, wait_stream;
+       wait_queue_head_t wait_open, wait_frame, wait_stream;
 };
 
 /*****************************************************************************/
@@ -156,8 +159,8 @@ do {                                                                          \
                else if ((level) == 2)                                        \
                        dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
                else if ((level) >= 3)                                        \
-                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
-                                __FUNCTION__, __LINE__ , ## args);           \
+                       dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n",   \
+                                __FILE__, __FUNCTION__, __LINE__ , ## args); \
        }                                                                     \
 } while (0)
 #      define KDBG(level, fmt, args...)                                      \
@@ -166,8 +169,8 @@ do {                                                                          \
                if ((level) == 1 || (level) == 2)                             \
                        pr_info("zc0301: " fmt "\n", ## args);                \
                else if ((level) == 3)                                        \
-                       pr_debug("zc0301: [%s:%d] " fmt "\n", __FUNCTION__,   \
-                                __LINE__ , ## args);                         \
+                       pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__,   \
+                                __FUNCTION__, __LINE__ , ## args);           \
        }                                                                     \
 } while (0)
 #      define V4LDBG(level, name, cmd)                                       \
@@ -183,8 +186,8 @@ do {                                                                          \
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
-        __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__,   \
+        __LINE__ , ## args)
 
 #undef PDBGG
 #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
index f1120551c70c2377f434c8267bd57f380c0bc79f..703b741e46df4477fb5ec5975465458e308ee18a 100644 (file)
 
 #define ZC0301_MODULE_NAME    "V4L2 driver for ZC0301[P] "                    \
                              "Image Processor and Control Chip"
-#define ZC0301_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
+#define ZC0301_MODULE_AUTHOR  "(C) 2006-2007 Luca Risolia"
 #define ZC0301_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
 #define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.07"
-#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 7)
+#define ZC0301_MODULE_VERSION "1:1.10"
+#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 10)
 
 /*****************************************************************************/
 
@@ -573,7 +573,8 @@ static int zc0301_init(struct zc0301_device* cam)
        int err = 0;
 
        if (!(cam->state & DEV_INITIALIZED)) {
-               init_waitqueue_head(&cam->open);
+               mutex_init(&cam->open_mutex);
+               init_waitqueue_head(&cam->wait_open);
                qctrl = s->qctrl;
                rect = &(s->cropcap.defrect);
                cam->compression.quality = ZC0301_COMPRESSION_QUALITY;
@@ -634,59 +635,73 @@ static int zc0301_init(struct zc0301_device* cam)
        return 0;
 }
 
+/*****************************************************************************/
 
-static void zc0301_release_resources(struct zc0301_device* cam)
+static void zc0301_release_resources(struct kref *kref)
 {
+       struct zc0301_device *cam = container_of(kref, struct zc0301_device,
+                                                kref);
        DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
        video_set_drvdata(cam->v4ldev, NULL);
        video_unregister_device(cam->v4ldev);
+       usb_put_dev(cam->usbdev);
        kfree(cam->control_buffer);
+       kfree(cam);
 }
 
-/*****************************************************************************/
 
 static int zc0301_open(struct inode* inode, struct file* filp)
 {
        struct zc0301_device* cam;
        int err = 0;
 
-       /*
-          This is the only safe way to prevent race conditions with
-          disconnect
-       */
-       if (!down_read_trylock(&zc0301_disconnect))
+       if (!down_read_trylock(&zc0301_dev_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(video_devdata(filp));
 
-       if (mutex_lock_interruptible(&cam->dev_mutex)) {
-               up_read(&zc0301_disconnect);
+       if (wait_for_completion_interruptible(&cam->probe)) {
+               up_read(&zc0301_dev_lock);
                return -ERESTARTSYS;
        }
 
+       kref_get(&cam->kref);
+
+       if (mutex_lock_interruptible(&cam->open_mutex)) {
+               kref_put(&cam->kref, zc0301_release_resources);
+               up_read(&zc0301_dev_lock);
+               return -ERESTARTSYS;
+       }
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               err = -ENODEV;
+               goto out;
+       }
+
        if (cam->users) {
                DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+               DBG(3, "Simultaneous opens are not supported");
                if ((filp->f_flags & O_NONBLOCK) ||
                    (filp->f_flags & O_NDELAY)) {
                        err = -EWOULDBLOCK;
                        goto out;
                }
-               mutex_unlock(&cam->dev_mutex);
-               err = wait_event_interruptible_exclusive(cam->open,
-                                                 cam->state & DEV_DISCONNECTED
+               DBG(2, "A blocking open() has been requested. Wait for the "
+                      "device to be released...");
+               up_read(&zc0301_dev_lock);
+               err = wait_event_interruptible_exclusive(cam->wait_open,
+                                               (cam->state & DEV_DISCONNECTED)
                                                         || !cam->users);
-               if (err) {
-                       up_read(&zc0301_disconnect);
-                       return err;
-               }
+               down_read(&zc0301_dev_lock);
+               if (err)
+                       goto out;
                if (cam->state & DEV_DISCONNECTED) {
-                       up_read(&zc0301_disconnect);
-                       return -ENODEV;
+                       err = -ENODEV;
+                       goto out;
                }
-               mutex_lock(&cam->dev_mutex);
        }
 
-
        if (cam->state & DEV_MISCONFIGURED) {
                err = zc0301_init(cam);
                if (err) {
@@ -711,36 +726,32 @@ static int zc0301_open(struct inode* inode, struct file* filp)
        DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
 
 out:
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&zc0301_disconnect);
+       mutex_unlock(&cam->open_mutex);
+       if (err)
+               kref_put(&cam->kref, zc0301_release_resources);
+       up_read(&zc0301_dev_lock);
        return err;
 }
 
 
 static int zc0301_release(struct inode* inode, struct file* filp)
 {
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       struct zc0301_device* cam;
 
-       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+       down_write(&zc0301_dev_lock);
 
-       zc0301_stop_transfer(cam);
+       cam = video_get_drvdata(video_devdata(filp));
 
+       zc0301_stop_transfer(cam);
        zc0301_release_buffers(cam);
-
-       if (cam->state & DEV_DISCONNECTED) {
-               zc0301_release_resources(cam);
-               usb_put_dev(cam->usbdev);
-               mutex_unlock(&cam->dev_mutex);
-               kfree(cam);
-               return 0;
-       }
-
        cam->users--;
-       wake_up_interruptible_nr(&cam->open, 1);
+       wake_up_interruptible_nr(&cam->wait_open, 1);
 
        DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
 
-       mutex_unlock(&cam->dev_mutex);
+       kref_put(&cam->kref, zc0301_release_resources);
+
+       up_write(&zc0301_dev_lock);
 
        return 0;
 }
@@ -775,7 +786,7 @@ zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
                DBG(3, "Close and open the device again to choose the read "
                       "method");
                mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
+               return -EBUSY;
        }
 
        if (cam->io == IO_NONE) {
@@ -953,7 +964,12 @@ static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
                return -EIO;
        }
 
-       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+       if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EACCES;
+       }
+
+       if (cam->io != IO_MMAP ||
            size != PAGE_ALIGN(cam->frame[0].buf.length)) {
                mutex_unlock(&cam->fileop_mutex);
                return -EINVAL;
@@ -984,7 +1000,6 @@ static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
 
        vma->vm_ops = &zc0301_vm_ops;
        vma->vm_private_data = &cam->frame[i];
-
        zc0301_vm_open(vma);
 
        mutex_unlock(&cam->fileop_mutex);
@@ -1211,7 +1226,7 @@ zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
                        if (cam->frame[i].vma_use_count) {
                                DBG(3, "VIDIOC_S_CROP failed. "
                                       "Unmap the buffers first.");
-                               return -EINVAL;
+                               return -EBUSY;
                        }
 
        if (!s->set_crop) {
@@ -1434,7 +1449,7 @@ zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd,
                        if (cam->frame[i].vma_use_count) {
                                DBG(3, "VIDIOC_S_FMT failed. "
                                       "Unmap the buffers first.");
-                               return -EINVAL;
+                               return -EBUSY;
                        }
 
        if (cam->stream == STREAM_ON)
@@ -1544,14 +1559,14 @@ zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg)
        if (cam->io == IO_READ) {
                DBG(3, "Close and open the device again to choose the mmap "
                       "I/O method");
-               return -EINVAL;
+               return -EBUSY;
        }
 
        for (i = 0; i < cam->nbuffers; i++)
                if (cam->frame[i].vma_use_count) {
                        DBG(3, "VIDIOC_REQBUFS failed. "
                               "Previous buffers are still mapped.");
-                       return -EINVAL;
+                       return -EBUSY;
                }
 
        if (cam->stream == STREAM_ON)
@@ -1699,9 +1714,6 @@ zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg)
        if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
                return -EINVAL;
 
-       if (list_empty(&cam->inqueue))
-               return -EINVAL;
-
        cam->stream = STREAM_ON;
 
        DBG(3, "Stream on");
@@ -1949,8 +1961,6 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                goto fail;
        }
 
-       mutex_init(&cam->dev_mutex);
-
        DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
               "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
 
@@ -1982,7 +1992,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        cam->v4ldev->release = video_device_release;
        video_set_drvdata(cam->v4ldev, cam);
 
-       mutex_lock(&cam->dev_mutex);
+       init_completion(&cam->probe);
 
        err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
                                    video_nr[dev_nr]);
@@ -1992,7 +2002,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                        DBG(1, "Free /dev/videoX node not found");
                video_nr[dev_nr] = -1;
                dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               mutex_unlock(&cam->dev_mutex);
+               complete_all(&cam->probe);
                goto fail;
        }
 
@@ -2004,8 +2014,10 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
 
        usb_set_intfdata(intf, cam);
+       kref_init(&cam->kref);
+       usb_get_dev(cam->usbdev);
 
-       mutex_unlock(&cam->dev_mutex);
+       complete_all(&cam->probe);
 
        return 0;
 
@@ -2022,40 +2034,31 @@ fail:
 
 static void zc0301_usb_disconnect(struct usb_interface* intf)
 {
-       struct zc0301_device* cam = usb_get_intfdata(intf);
-
-       if (!cam)
-               return;
+       struct zc0301_device* cam;
 
-       down_write(&zc0301_disconnect);
+       down_write(&zc0301_dev_lock);
 
-       mutex_lock(&cam->dev_mutex);
+       cam = usb_get_intfdata(intf);
 
        DBG(2, "Disconnecting %s...", cam->v4ldev->name);
 
-       wake_up_interruptible_all(&cam->open);
-
        if (cam->users) {
                DBG(2, "Device /dev/video%d is open! Deregistration and "
-                      "memory deallocation are deferred on close.",
+                      "memory deallocation are deferred.",
                    cam->v4ldev->minor);
                cam->state |= DEV_MISCONFIGURED;
                zc0301_stop_transfer(cam);
                cam->state |= DEV_DISCONNECTED;
                wake_up_interruptible(&cam->wait_frame);
                wake_up(&cam->wait_stream);
-               usb_get_dev(cam->usbdev);
-       } else {
+       } else
                cam->state |= DEV_DISCONNECTED;
-               zc0301_release_resources(cam);
-       }
 
-       mutex_unlock(&cam->dev_mutex);
+       wake_up_interruptible_all(&cam->wait_open);
 
-       if (!cam->users)
-               kfree(cam);
+       kref_put(&cam->kref, zc0301_release_resources);
 
-       up_write(&zc0301_disconnect);
+       up_write(&zc0301_dev_lock);
 }
 
 
index 3efb92a0d0daec8de05728ec001fa3ee1721a9d8..24b0dfba357e2d7f832b41db6d4132fc9558ea38 100644 (file)
@@ -327,6 +327,7 @@ static struct zc0301_sensor pas202bcb = {
                .height = 480,
                .pixelformat = V4L2_PIX_FMT_JPEG,
                .priv = 8,
+               .colorspace = V4L2_COLORSPACE_JPEG,
        },
 };
 
index 5784b1d1491c8be0d9c01d0745b3f1b26b0956d1..9519aba3612ed7fa90e1d3d9e9bcb4649baebf7e 100644 (file)
@@ -157,6 +157,7 @@ static struct zc0301_sensor pb0330 = {
                .height = 480,
                .pixelformat = V4L2_PIX_FMT_JPEG,
                .priv = 8,
+               .colorspace = V4L2_COLORSPACE_JPEG,
        },
 };
 
index 44e82cff9319598e1ba2e4fe7f3422f86c48af25..70fe6fc6cdd531eac31b8fc98c321b70d1bba18f 100644 (file)
@@ -23,7 +23,7 @@
 #define _ZC0301_SENSOR_H_
 
 #include <linux/usb.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <linux/device.h>
 #include <linux/stddef.h>
 #include <linux/errno.h>
index cf0ed6cbb0e39eb8363120e477bef27549c754ff..17118a490f8166cb2d3ddffdf7c304a473d4287d 100644 (file)
@@ -183,14 +183,7 @@ static const int zoran_num_formats =
     (sizeof(zoran_formats) / sizeof(struct zoran_format));
 
 // RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined
-#if !defined(CONFIG_BIGPHYS_AREA)
-//#undef CONFIG_BIGPHYS_AREA
-#define BUZ_USE_HIMEM
-#endif
 
-#if defined(CONFIG_BIGPHYS_AREA)
-#   include <linux/bigphysarea.h>
-#endif
 
 extern int *zr_debug;
 
@@ -250,7 +243,6 @@ static void jpg_fbuffer_free(struct file *file);
  *   Linux with the necessary memory left over).
  */
 
-#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA)
 static unsigned long
 get_high_mem (unsigned long size)
 {
@@ -314,7 +306,6 @@ get_high_mem (unsigned long size)
 
        return hi_mem_ph;
 }
-#endif
 
 static int
 v4l_fbuffer_alloc (struct file *file)
@@ -323,9 +314,7 @@ v4l_fbuffer_alloc (struct file *file)
        struct zoran *zr = fh->zr;
        int i, off;
        unsigned char *mem;
-#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA)
        unsigned long pmem = 0;
-#endif
 
        /* we might have old buffers lying around... */
        if (fh->v4l_buffers.ready_to_be_freed) {
@@ -369,39 +358,6 @@ v4l_fbuffer_alloc (struct file *file)
                                ZR_DEVNAME(zr), i, (unsigned long) mem,
                                virt_to_bus(mem));
                } else {
-#if defined(CONFIG_BIGPHYS_AREA)
-                       /* Use bigphysarea_alloc_pages */
-
-                       int n =
-                           (fh->v4l_buffers.buffer_size + PAGE_SIZE -
-                            1) / PAGE_SIZE;
-
-                       mem =
-                           (unsigned char *) bigphysarea_alloc_pages(n, 0,
-                                                                     GFP_KERNEL);
-                       if (mem == 0) {
-                               dprintk(1,
-                                       KERN_ERR
-                                       "%s: v4l_fbuffer_alloc() - bigphysarea_alloc_pages for V4L buf %d failed\n",
-                                       ZR_DEVNAME(zr), i);
-                               v4l_fbuffer_free(file);
-                               return -ENOBUFS;
-                       }
-                       fh->v4l_buffers.buffer[i].fbuffer = mem;
-                       fh->v4l_buffers.buffer[i].fbuffer_phys =
-                           virt_to_phys(mem);
-                       fh->v4l_buffers.buffer[i].fbuffer_bus =
-                           virt_to_bus(mem);
-                       dprintk(4,
-                               KERN_INFO
-                               "%s: Bigphysarea frame %d mem 0x%x (bus: 0x%x)\n",
-                               ZR_DEVNAME(zr), i, (unsigned) mem,
-                               (unsigned) virt_to_bus(mem));
-
-                       /* Zero out the allocated memory */
-                       memset(fh->v4l_buffers.buffer[i].fbuffer, 0,
-                              fh->v4l_buffers.buffer_size);
-#elif defined(BUZ_USE_HIMEM)
 
                        /* Use high memory which has been left at boot time */
 
@@ -441,20 +397,6 @@ v4l_fbuffer_alloc (struct file *file)
                                fh->v4l_buffers.buffer[i].fbuffer_bus =
                                    pmem + i * fh->v4l_buffers.buffer_size;
                        }
-#else
-                       /* No bigphysarea present, usage of high memory disabled,
-                        * but user wants buffers of more than MAX_KMALLOC_MEM */
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: v4l_fbuffer_alloc() - no bigphysarea_patch present, usage of high memory disabled,\n",
-                               ZR_DEVNAME(zr));
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: v4l_fbuffer_alloc() - sorry, could not allocate %d V4L buffers of size %d KB.\n",
-                               ZR_DEVNAME(zr), fh->v4l_buffers.num_buffers,
-                               fh->v4l_buffers.buffer_size >> 10);
-                       return -ENOBUFS;
-#endif
                }
        }
 
@@ -485,11 +427,6 @@ v4l_fbuffer_free (struct file *file)
                                ClearPageReserved(MAP_NR(mem + off));
                        kfree((void *) fh->v4l_buffers.buffer[i].fbuffer);
                }
-#if defined(CONFIG_BIGPHYS_AREA)
-               else
-                       bigphysarea_free_pages((void *) fh->v4l_buffers.
-                                              buffer[i].fbuffer);
-#endif
                fh->v4l_buffers.buffer[i].fbuffer = NULL;
        }
 
index b5d3364c94c73144077206b532b4fddef41e0bb6..6f1892585cbbac304eae05df4324fb6931c7f58b 100644 (file)
@@ -92,6 +92,7 @@ static struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0784, 0x0040), .driver_info = METHOD1 },
        {USB_DEVICE(0x06d6, 0x0034), .driver_info = METHOD0 },
        {USB_DEVICE(0x0a17, 0x0062), .driver_info = METHOD2 },
+       {USB_DEVICE(0x06d6, 0x003b), .driver_info = METHOD0 },
        {}                      /* Terminating entry */
 };
 
@@ -792,6 +793,7 @@ static int zr364xx_probe(struct usb_interface *intf,
 {
        struct usb_device *udev = interface_to_usbdev(intf);
        struct zr364xx_camera *cam = NULL;
+       int err;
 
        DBG("probing...");
 
@@ -799,12 +801,11 @@ static int zr364xx_probe(struct usb_interface *intf,
        info("model %04x:%04x detected", udev->descriptor.idVendor,
             udev->descriptor.idProduct);
 
-       if ((cam =
-            kmalloc(sizeof(struct zr364xx_camera), GFP_KERNEL)) == NULL) {
+       cam = kzalloc(sizeof(struct zr364xx_camera), GFP_KERNEL);
+       if (cam == NULL) {
                info("cam: out of memory !");
-               return -ENODEV;
+               return -ENOMEM;
        }
-       memset(cam, 0x00, sizeof(struct zr364xx_camera));
        /* save the init method used by this camera */
        cam->method = id->driver_info;
 
@@ -812,7 +813,7 @@ static int zr364xx_probe(struct usb_interface *intf,
        if (cam->vdev == NULL) {
                info("cam->vdev: out of memory !");
                kfree(cam);
-               return -ENODEV;
+               return -ENOMEM;
        }
        memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template));
        video_set_drvdata(cam->vdev, cam);
@@ -858,12 +859,13 @@ static int zr364xx_probe(struct usb_interface *intf,
        cam->brightness = 64;
        mutex_init(&cam->lock);
 
-       if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
+       err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
+       if (err) {
                info("video_register_device failed");
                video_device_release(cam->vdev);
                kfree(cam->buffer);
                kfree(cam);
-               return -ENODEV;
+               return err;
        }
 
        usb_set_intfdata(intf, cam);
@@ -905,7 +907,7 @@ static struct usb_driver zr364xx_driver = {
 static int __init zr364xx_init(void)
 {
        int retval;
-       retval = usb_register(&zr364xx_driver) < 0;
+       retval = usb_register(&zr364xx_driver);
        if (retval)
                info("usb_register failed!");
        else
index 555d594d1811d7f4bb29ddd9ac329ffff85de6af..1cb22bfae75066f31ee73ef9385b801f36e6b01d 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/moduleparam.h>
 #include <linux/stringify.h>
 #include <linux/stat.h>
+#include <linux/log2.h>
 #include "ubi.h"
 
 /* Maximum length of the 'mtd=' parameter */
@@ -369,7 +370,7 @@ static int attach_by_scanning(struct ubi_device *ubi)
 out_wl:
        ubi_wl_close(ubi);
 out_vtbl:
-       kfree(ubi->vtbl);
+       vfree(ubi->vtbl);
 out_si:
        ubi_scan_destroy_si(si);
        return err;
@@ -422,8 +423,7 @@ static int io_init(struct ubi_device *ubi)
        ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
 
        /* Make sure minimal I/O unit is power of 2 */
-       if (ubi->min_io_size == 0 ||
-           (ubi->min_io_size & (ubi->min_io_size - 1))) {
+       if (!is_power_of_2(ubi->min_io_size)) {
                ubi_err("bad min. I/O unit");
                return -EINVAL;
        }
@@ -593,8 +593,6 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
        if (err)
                goto out_detach;
 
-       ubi_devices_cnt += 1;
-
        ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt);
        ubi_msg("MTD device name:            \"%s\"", ubi->mtd->name);
        ubi_msg("MTD device size:            %llu MiB", ubi->flash_size >> 20);
@@ -624,12 +622,13 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
                wake_up_process(ubi->bgt_thread);
        }
 
+       ubi_devices_cnt += 1;
        return 0;
 
 out_detach:
        ubi_eba_close(ubi);
        ubi_wl_close(ubi);
-       kfree(ubi->vtbl);
+       vfree(ubi->vtbl);
 out_free:
        kfree(ubi);
 out_mtd:
@@ -650,7 +649,7 @@ static void detach_mtd_dev(struct ubi_device *ubi)
        uif_close(ubi);
        ubi_eba_close(ubi);
        ubi_wl_close(ubi);
-       kfree(ubi->vtbl);
+       vfree(ubi->vtbl);
        put_mtd_device(ubi->mtd);
        kfree(ubi_devices[ubi_num]);
        ubi_devices[ubi_num] = NULL;
@@ -686,13 +685,6 @@ static int __init ubi_init(void)
                struct mtd_dev_param *p = &mtd_dev_param[i];
 
                cond_resched();
-
-               if (!p->name) {
-                       dbg_err("empty name");
-                       err = -EINVAL;
-                       goto out_detach;
-               }
-
                err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs);
                if (err)
                        goto out_detach;
@@ -799,7 +791,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
 
        /* Get rid of the final newline */
        if (buf[len - 1] == '\n')
-               buf[len - 1] = 0;
+               buf[len - 1] = '\0';
 
        for (i = 0; i < 3; i++)
                tokens[i] = strsep(&pbuf, ",");
@@ -809,9 +801,6 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
                return -EINVAL;
        }
 
-       if (tokens[0] == '\0')
-               return -EINVAL;
-
        p = &mtd_dev_param[mtd_devs];
        strcpy(&p->name[0], tokens[0]);
 
index 6612eb79bf17b2fd7529ed9a4aba00e6a6060637..fe4da1e96c52a67b1b79676ff281e1e4f6162b8b 100644 (file)
@@ -64,6 +64,7 @@ static struct ubi_device *major_to_device(int major)
                if (ubi_devices[i] && ubi_devices[i]->major == major)
                        return ubi_devices[i];
        BUG();
+       return NULL;
 }
 
 /**
@@ -153,7 +154,7 @@ static int vol_cdev_release(struct inode *inode, struct file *file)
                ubi_warn("update of volume %d not finished, volume is damaged",
                         vol->vol_id);
                vol->updating = 0;
-               kfree(vol->upd_buf);
+               vfree(vol->upd_buf);
        }
 
        ubi_close_volume(desc);
@@ -232,7 +233,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
        tbuf_size = vol->usable_leb_size;
        if (count < tbuf_size)
                tbuf_size = ALIGN(count, ubi->min_io_size);
-       tbuf = kmalloc(tbuf_size, GFP_KERNEL);
+       tbuf = vmalloc(tbuf_size);
        if (!tbuf)
                return -ENOMEM;
 
@@ -271,7 +272,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
                len = count > tbuf_size ? tbuf_size : count;
        } while (count);
 
-       kfree(tbuf);
+       vfree(tbuf);
        return err ? err : count_save - count;
 }
 
@@ -320,7 +321,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
        tbuf_size = vol->usable_leb_size;
        if (count < tbuf_size)
                tbuf_size = ALIGN(count, ubi->min_io_size);
-       tbuf = kmalloc(tbuf_size, GFP_KERNEL);
+       tbuf = vmalloc(tbuf_size);
        if (!tbuf)
                return -ENOMEM;
 
@@ -355,7 +356,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
                len = count > tbuf_size ? tbuf_size : count;
        }
 
-       kfree(tbuf);
+       vfree(tbuf);
        return err ? err : count_save - count;
 }
 
@@ -397,6 +398,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
                        vol->corrupted = 1;
                }
                vol->checked = 1;
+               ubi_gluebi_updated(vol);
                revoke_exclusive(desc, UBI_READWRITE);
        }
 
@@ -413,19 +415,7 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
        struct ubi_device *ubi = vol->ubi;
        void __user *argp = (void __user *)arg;
 
-       if (_IOC_NR(cmd) > VOL_CDEV_IOC_MAX_SEQ ||
-           _IOC_TYPE(cmd) != UBI_VOL_IOC_MAGIC)
-               return -ENOTTY;
-
-       if (_IOC_DIR(cmd) && _IOC_READ)
-               err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
-       else if (_IOC_DIR(cmd) && _IOC_WRITE)
-               err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
-       if (err)
-               return -EFAULT;
-
        switch (cmd) {
-
        /* Volume update command */
        case UBI_IOCVOLUP:
        {
@@ -471,7 +461,7 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
        {
                int32_t lnum;
 
-               err = __get_user(lnum, (__user int32_t *)argp);
+               err = get_user(lnum, (__user int32_t *)argp);
                if (err) {
                        err = -EFAULT;
                        break;
@@ -587,17 +577,6 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
        struct ubi_volume_desc *desc;
        void __user *argp = (void __user *)arg;
 
-       if (_IOC_NR(cmd) > UBI_CDEV_IOC_MAX_SEQ ||
-           _IOC_TYPE(cmd) != UBI_IOC_MAGIC)
-               return -ENOTTY;
-
-       if (_IOC_DIR(cmd) && _IOC_READ)
-               err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
-       else if (_IOC_DIR(cmd) && _IOC_WRITE)
-               err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
-       if (err)
-               return -EFAULT;
-
        if (!capable(CAP_SYS_RESOURCE))
                return -EPERM;
 
@@ -612,7 +591,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                struct ubi_mkvol_req req;
 
                dbg_msg("create volume");
-               err = __copy_from_user(&req, argp,
+               err = copy_from_user(&req, argp,
                                       sizeof(struct ubi_mkvol_req));
                if (err) {
                        err = -EFAULT;
@@ -629,7 +608,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                if (err)
                        break;
 
-               err = __put_user(req.vol_id, (__user int32_t *)argp);
+               err = put_user(req.vol_id, (__user int32_t *)argp);
                if (err)
                        err = -EFAULT;
 
@@ -642,7 +621,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                int vol_id;
 
                dbg_msg("remove volume");
-               err = __get_user(vol_id, (__user int32_t *)argp);
+               err = get_user(vol_id, (__user int32_t *)argp);
                if (err) {
                        err = -EFAULT;
                        break;
@@ -669,7 +648,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                struct ubi_rsvol_req req;
 
                dbg_msg("re-size volume");
-               err = __copy_from_user(&req, argp,
+               err = copy_from_user(&req, argp,
                                       sizeof(struct ubi_rsvol_req));
                if (err) {
                        err = -EFAULT;
@@ -707,7 +686,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
 struct file_operations ubi_cdev_operations = {
        .owner = THIS_MODULE,
        .ioctl = ubi_cdev_ioctl,
-       .llseek = no_llseek
+       .llseek = no_llseek,
 };
 
 /* UBI volume character device operations */
@@ -718,5 +697,5 @@ struct file_operations ubi_vol_cdev_operations = {
        .llseek  = vol_cdev_llseek,
        .read    = vol_cdev_read,
        .write   = vol_cdev_write,
-       .ioctl   = vol_cdev_ioctl
+       .ioctl   = vol_cdev_ioctl,
 };
index 86364221fafe92985026c267f51344cd6ea249a3..310341e5cd43065b8e5e3df1a7afefd56a161a67 100644 (file)
 void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
 {
        dbg_msg("erase counter header dump:");
-       dbg_msg("magic          %#08x", ubi32_to_cpu(ec_hdr->magic));
+       dbg_msg("magic          %#08x", be32_to_cpu(ec_hdr->magic));
        dbg_msg("version        %d",    (int)ec_hdr->version);
-       dbg_msg("ec             %llu",  (long long)ubi64_to_cpu(ec_hdr->ec));
-       dbg_msg("vid_hdr_offset %d",    ubi32_to_cpu(ec_hdr->vid_hdr_offset));
-       dbg_msg("data_offset    %d",    ubi32_to_cpu(ec_hdr->data_offset));
-       dbg_msg("hdr_crc        %#08x", ubi32_to_cpu(ec_hdr->hdr_crc));
+       dbg_msg("ec             %llu",  (long long)be64_to_cpu(ec_hdr->ec));
+       dbg_msg("vid_hdr_offset %d",    be32_to_cpu(ec_hdr->vid_hdr_offset));
+       dbg_msg("data_offset    %d",    be32_to_cpu(ec_hdr->data_offset));
+       dbg_msg("hdr_crc        %#08x", be32_to_cpu(ec_hdr->hdr_crc));
        dbg_msg("erase counter header hexdump:");
        ubi_dbg_hexdump(ec_hdr, UBI_EC_HDR_SIZE);
 }
@@ -52,20 +52,20 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
 void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
 {
        dbg_msg("volume identifier header dump:");
-       dbg_msg("magic     %08x", ubi32_to_cpu(vid_hdr->magic));
+       dbg_msg("magic     %08x", be32_to_cpu(vid_hdr->magic));
        dbg_msg("version   %d",   (int)vid_hdr->version);
        dbg_msg("vol_type  %d",   (int)vid_hdr->vol_type);
        dbg_msg("copy_flag %d",   (int)vid_hdr->copy_flag);
        dbg_msg("compat    %d",   (int)vid_hdr->compat);
-       dbg_msg("vol_id    %d",   ubi32_to_cpu(vid_hdr->vol_id));
-       dbg_msg("lnum      %d",   ubi32_to_cpu(vid_hdr->lnum));
-       dbg_msg("leb_ver   %u",   ubi32_to_cpu(vid_hdr->leb_ver));
-       dbg_msg("data_size %d",   ubi32_to_cpu(vid_hdr->data_size));
-       dbg_msg("used_ebs  %d",   ubi32_to_cpu(vid_hdr->used_ebs));
-       dbg_msg("data_pad  %d",   ubi32_to_cpu(vid_hdr->data_pad));
+       dbg_msg("vol_id    %d",   be32_to_cpu(vid_hdr->vol_id));
+       dbg_msg("lnum      %d",   be32_to_cpu(vid_hdr->lnum));
+       dbg_msg("leb_ver   %u",   be32_to_cpu(vid_hdr->leb_ver));
+       dbg_msg("data_size %d",   be32_to_cpu(vid_hdr->data_size));
+       dbg_msg("used_ebs  %d",   be32_to_cpu(vid_hdr->used_ebs));
+       dbg_msg("data_pad  %d",   be32_to_cpu(vid_hdr->data_pad));
        dbg_msg("sqnum     %llu",
-               (unsigned long long)ubi64_to_cpu(vid_hdr->sqnum));
-       dbg_msg("hdr_crc   %08x", ubi32_to_cpu(vid_hdr->hdr_crc));
+               (unsigned long long)be64_to_cpu(vid_hdr->sqnum));
+       dbg_msg("hdr_crc   %08x", be32_to_cpu(vid_hdr->hdr_crc));
        dbg_msg("volume identifier header hexdump:");
 }
 
@@ -91,7 +91,7 @@ void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
 
        if (vol->name_len <= UBI_VOL_NAME_MAX &&
            strnlen(vol->name, vol->name_len + 1) == vol->name_len) {
-               dbg_msg("name          %s", vol->name);
+               dbg_msg("name            %s", vol->name);
        } else {
                dbg_msg("the 1st 5 characters of the name: %c%c%c%c%c",
                        vol->name[0], vol->name[1], vol->name[2],
@@ -106,30 +106,30 @@ void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
  */
 void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
 {
-       int name_len = ubi16_to_cpu(r->name_len);
+       int name_len = be16_to_cpu(r->name_len);
 
        dbg_msg("volume table record %d dump:", idx);
-       dbg_msg("reserved_pebs   %d", ubi32_to_cpu(r->reserved_pebs));
-       dbg_msg("alignment       %d", ubi32_to_cpu(r->alignment));
-       dbg_msg("data_pad        %d", ubi32_to_cpu(r->data_pad));
+       dbg_msg("reserved_pebs   %d", be32_to_cpu(r->reserved_pebs));
+       dbg_msg("alignment       %d", be32_to_cpu(r->alignment));
+       dbg_msg("data_pad        %d", be32_to_cpu(r->data_pad));
        dbg_msg("vol_type        %d", (int)r->vol_type);
        dbg_msg("upd_marker      %d", (int)r->upd_marker);
        dbg_msg("name_len        %d", name_len);
 
        if (r->name[0] == '\0') {
-               dbg_msg("name          NULL");
+               dbg_msg("name            NULL");
                return;
        }
 
        if (name_len <= UBI_VOL_NAME_MAX &&
            strnlen(&r->name[0], name_len + 1) == name_len) {
-               dbg_msg("name          %s", &r->name[0]);
+               dbg_msg("name            %s", &r->name[0]);
        } else {
                dbg_msg("1st 5 characters of the name: %c%c%c%c%c",
                        r->name[0], r->name[1], r->name[2], r->name[3],
                        r->name[4]);
        }
-       dbg_msg("crc             %#08x", ubi32_to_cpu(r->crc));
+       dbg_msg("crc             %#08x", be32_to_cpu(r->crc));
 }
 
 /**
index f816ad9a36c00a1987622c09c6f5727c23488044..ff8f39548cd80aaf58cb979d291e609f4d80f214 100644 (file)
@@ -52,7 +52,6 @@ struct ubi_scan_volume;
 struct ubi_scan_leb;
 struct ubi_mkvol_req;
 
-void ubi_dbg_print(int type, const char *func, const char *fmt, ...);
 void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
 void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
 void ubi_dbg_dump_vol_info(const struct ubi_volume *vol);
@@ -66,7 +65,6 @@ void ubi_dbg_hexdump(const void *buf, int size);
 
 #define dbg_msg(fmt, ...)    ({})
 #define ubi_dbg_dump_stack() ({})
-#define ubi_dbg_print(func, fmt, ...)    ({})
 #define ubi_dbg_dump_ec_hdr(ec_hdr)      ({})
 #define ubi_dbg_dump_vid_hdr(vid_hdr)    ({})
 #define ubi_dbg_dump_vol_info(vol)       ({})
index 74002945b71b6d1123f21c0f2766eca37d2f53e8..8aff9385613f36601316ce0b9df2a4b410a2358a 100644 (file)
@@ -368,7 +368,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf,
        int err, pnum, scrub = 0, idx = vol_id2idx(ubi, vol_id);
        struct ubi_vid_hdr *vid_hdr;
        struct ubi_volume *vol = ubi->volumes[idx];
-       uint32_t crc, crc1;
+       uint32_t uninitialized_var(crc);
 
        err = leb_read_lock(ubi, vol_id, lnum);
        if (err)
@@ -425,10 +425,10 @@ retry:
                } else if (err == UBI_IO_BITFLIPS)
                        scrub = 1;
 
-               ubi_assert(lnum < ubi32_to_cpu(vid_hdr->used_ebs));
-               ubi_assert(len == ubi32_to_cpu(vid_hdr->data_size));
+               ubi_assert(lnum < be32_to_cpu(vid_hdr->used_ebs));
+               ubi_assert(len == be32_to_cpu(vid_hdr->data_size));
 
-               crc = ubi32_to_cpu(vid_hdr->data_crc);
+               crc = be32_to_cpu(vid_hdr->data_crc);
                ubi_free_vid_hdr(ubi, vid_hdr);
        }
 
@@ -451,7 +451,7 @@ retry:
        }
 
        if (check) {
-               crc1 = crc32(UBI_CRC32_INIT, buf, len);
+               uint32_t crc1 = crc32(UBI_CRC32_INIT, buf, len);
                if (crc1 != crc) {
                        ubi_warn("CRC error: calculated %#08x, must be %#08x",
                                 crc1, crc);
@@ -518,13 +518,13 @@ retry:
                goto out_put;
        }
 
-       vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
        err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
        if (err)
                goto write_error;
 
        data_size = offset + len;
-       new_buf = kmalloc(data_size, GFP_KERNEL);
+       new_buf = vmalloc(data_size);
        if (!new_buf) {
                err = -ENOMEM;
                goto out_put;
@@ -535,7 +535,7 @@ retry:
        if (offset > 0) {
                err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset);
                if (err && err != UBI_IO_BITFLIPS) {
-                       kfree(new_buf);
+                       vfree(new_buf);
                        goto out_put;
                }
        }
@@ -544,11 +544,11 @@ retry:
 
        err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size);
        if (err) {
-               kfree(new_buf);
+               vfree(new_buf);
                goto write_error;
        }
 
-       kfree(new_buf);
+       vfree(new_buf);
        ubi_free_vid_hdr(ubi, vid_hdr);
 
        vol->eba_tbl[lnum] = new_pnum;
@@ -634,11 +634,11 @@ int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum,
        }
 
        vid_hdr->vol_type = UBI_VID_DYNAMIC;
-       vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
-       vid_hdr->vol_id = cpu_to_ubi32(vol_id);
-       vid_hdr->lnum = cpu_to_ubi32(lnum);
+       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+       vid_hdr->vol_id = cpu_to_be32(vol_id);
+       vid_hdr->lnum = cpu_to_be32(lnum);
        vid_hdr->compat = ubi_get_compat(ubi, vol_id);
-       vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+       vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
 
 retry:
        pnum = ubi_wl_get_peb(ubi, dtype);
@@ -692,7 +692,7 @@ write_error:
                return err;
        }
 
-       vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
        ubi_msg("try another PEB");
        goto retry;
 }
@@ -748,17 +748,17 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum,
                return err;
        }
 
-       vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
-       vid_hdr->vol_id = cpu_to_ubi32(vol_id);
-       vid_hdr->lnum = cpu_to_ubi32(lnum);
+       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+       vid_hdr->vol_id = cpu_to_be32(vol_id);
+       vid_hdr->lnum = cpu_to_be32(lnum);
        vid_hdr->compat = ubi_get_compat(ubi, vol_id);
-       vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+       vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
 
        crc = crc32(UBI_CRC32_INIT, buf, data_size);
        vid_hdr->vol_type = UBI_VID_STATIC;
-       vid_hdr->data_size = cpu_to_ubi32(data_size);
-       vid_hdr->used_ebs = cpu_to_ubi32(used_ebs);
-       vid_hdr->data_crc = cpu_to_ubi32(crc);
+       vid_hdr->data_size = cpu_to_be32(data_size);
+       vid_hdr->used_ebs = cpu_to_be32(used_ebs);
+       vid_hdr->data_crc = cpu_to_be32(crc);
 
 retry:
        pnum = ubi_wl_get_peb(ubi, dtype);
@@ -813,7 +813,7 @@ write_error:
                return err;
        }
 
-       vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
        ubi_msg("try another PEB");
        goto retry;
 }
@@ -854,17 +854,17 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
                return err;
        }
 
-       vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
-       vid_hdr->vol_id = cpu_to_ubi32(vol_id);
-       vid_hdr->lnum = cpu_to_ubi32(lnum);
+       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+       vid_hdr->vol_id = cpu_to_be32(vol_id);
+       vid_hdr->lnum = cpu_to_be32(lnum);
        vid_hdr->compat = ubi_get_compat(ubi, vol_id);
-       vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+       vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
 
        crc = crc32(UBI_CRC32_INIT, buf, len);
-       vid_hdr->vol_type = UBI_VID_STATIC;
-       vid_hdr->data_size = cpu_to_ubi32(len);
+       vid_hdr->vol_type = UBI_VID_DYNAMIC;
+       vid_hdr->data_size = cpu_to_be32(len);
        vid_hdr->copy_flag = 1;
-       vid_hdr->data_crc = cpu_to_ubi32(crc);
+       vid_hdr->data_crc = cpu_to_be32(crc);
 
 retry:
        pnum = ubi_wl_get_peb(ubi, dtype);
@@ -891,11 +891,13 @@ retry:
                goto write_error;
        }
 
-       err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
-       if (err) {
-               ubi_free_vid_hdr(ubi, vid_hdr);
-               leb_write_unlock(ubi, vol_id, lnum);
-               return err;
+       if (vol->eba_tbl[lnum] >= 0) {
+               err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
+               if (err) {
+                       ubi_free_vid_hdr(ubi, vid_hdr);
+                       leb_write_unlock(ubi, vol_id, lnum);
+                       return err;
+               }
        }
 
        vol->eba_tbl[lnum] = pnum;
@@ -924,7 +926,7 @@ write_error:
                return err;
        }
 
-       vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
        ubi_msg("try another PEB");
        goto retry;
 }
@@ -965,19 +967,19 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
        uint32_t crc;
        void *buf, *buf1 = NULL;
 
-       vol_id = ubi32_to_cpu(vid_hdr->vol_id);
-       lnum = ubi32_to_cpu(vid_hdr->lnum);
+       vol_id = be32_to_cpu(vid_hdr->vol_id);
+       lnum = be32_to_cpu(vid_hdr->lnum);
 
        dbg_eba("copy LEB %d:%d, PEB %d to PEB %d", vol_id, lnum, from, to);
 
        if (vid_hdr->vol_type == UBI_VID_STATIC) {
-               data_size = ubi32_to_cpu(vid_hdr->data_size);
+               data_size = be32_to_cpu(vid_hdr->data_size);
                aldata_size = ALIGN(data_size, ubi->min_io_size);
        } else
                data_size = aldata_size =
-                           ubi->leb_size - ubi32_to_cpu(vid_hdr->data_pad);
+                           ubi->leb_size - be32_to_cpu(vid_hdr->data_pad);
 
-       buf = kmalloc(aldata_size, GFP_KERNEL);
+       buf = vmalloc(aldata_size);
        if (!buf)
                return -ENOMEM;
 
@@ -987,7 +989,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
         */
        err = leb_write_lock(ubi, vol_id, lnum);
        if (err) {
-               kfree(buf);
+               vfree(buf);
                return err;
        }
 
@@ -1054,10 +1056,10 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
         */
        if (data_size > 0) {
                vid_hdr->copy_flag = 1;
-               vid_hdr->data_size = cpu_to_ubi32(data_size);
-               vid_hdr->data_crc = cpu_to_ubi32(crc);
+               vid_hdr->data_size = cpu_to_be32(data_size);
+               vid_hdr->data_crc = cpu_to_be32(crc);
        }
-       vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
 
        err = ubi_io_write_vid_hdr(ubi, to, vid_hdr);
        if (err)
@@ -1082,7 +1084,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                 * We've written the data and are going to read it back to make
                 * sure it was written correctly.
                 */
-               buf1 = kmalloc(aldata_size, GFP_KERNEL);
+               buf1 = vmalloc(aldata_size);
                if (!buf1) {
                        err = -ENOMEM;
                        goto out_unlock;
@@ -1111,15 +1113,15 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
        vol->eba_tbl[lnum] = to;
 
        leb_write_unlock(ubi, vol_id, lnum);
-       kfree(buf);
-       kfree(buf1);
+       vfree(buf);
+       vfree(buf1);
 
        return 0;
 
 out_unlock:
        leb_write_unlock(ubi, vol_id, lnum);
-       kfree(buf);
-       kfree(buf1);
+       vfree(buf);
+       vfree(buf1);
        return err;
 }
 
index fc9478d605ff134255e91f5834a3c6ba17eab122..41ff74c60e1483d7a25d70f5df7832d77c603cb8 100644 (file)
@@ -282,7 +282,6 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
                mtd->flags = MTD_WRITEABLE;
        mtd->writesize  = ubi->min_io_size;
        mtd->owner      = THIS_MODULE;
-       mtd->size       = vol->usable_leb_size * vol->reserved_pebs;
        mtd->erasesize  = vol->usable_leb_size;
        mtd->read       = gluebi_read;
        mtd->write      = gluebi_write;
@@ -290,6 +289,15 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
        mtd->get_device = gluebi_get_device;
        mtd->put_device = gluebi_put_device;
 
+       /*
+        * In case of dynamic volume, MTD device size is just volume size. In
+        * case of a static volume the size is equivalent to the amount of data
+        * bytes, which is zero at this moment and will be changed after volume
+        * update.
+        */
+       if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+               mtd->size = vol->usable_leb_size * vol->reserved_pebs;
+
        if (add_mtd_device(mtd)) {
                ubi_err("cannot not add MTD device\n");
                kfree(mtd->name);
@@ -321,3 +329,20 @@ int ubi_destroy_gluebi(struct ubi_volume *vol)
        kfree(mtd->name);
        return 0;
 }
+
+/**
+ * ubi_gluebi_updated - UBI volume was updated notifier.
+ * @vol: volume description object
+ *
+ * This function is called every time an UBI volume is updated. This function
+ * does nothing if volume @vol is dynamic, and changes MTD device size if the
+ * volume is static. This is needed because static volumes cannot be read past
+ * data they contain.
+ */
+void ubi_gluebi_updated(struct ubi_volume *vol)
+{
+       struct mtd_info *mtd = &vol->gluebi_mtd;
+
+       if (vol->vol_type == UBI_STATIC_VOLUME)
+               mtd->size = vol->used_bytes;
+}
index 438914d05151017b9fe18ad478d68eb0b64faea1..b0d8f4cede97ebdca9eeafd5f8808ecb8835b55b 100644 (file)
@@ -125,9 +125,9 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
  * o %UBI_IO_BITFLIPS if all the requested data were successfully read, but
  *   correctable bit-flips were detected; this is harmless but may indicate
  *   that this eraseblock may become bad soon (but do not have to);
- * o %-EBADMSG if the MTD subsystem reported about data data integrity
- *   problems, for example it can me an ECC error in case of NAND; this most
- *   probably means that the data is corrupted;
+ * o %-EBADMSG if the MTD subsystem reported about data integrity problems, for
+ *   example it can be an ECC error in case of NAND; this most probably means
+ *   that the data is corrupted;
  * o %-EIO if some I/O error occurred;
  * o other negative error codes in case of other errors.
  */
@@ -298,7 +298,7 @@ retry:
        memset(&ei, 0, sizeof(struct erase_info));
 
        ei.mtd      = ubi->mtd;
-       ei.addr     = pnum * ubi->peb_size;
+       ei.addr     = (loff_t)pnum * ubi->peb_size;
        ei.len      = ubi->peb_size;
        ei.callback = erase_callback;
        ei.priv     = (unsigned long)&wq;
@@ -382,7 +382,7 @@ static int torture_peb(const struct ubi_device *ubi, int pnum)
        void *buf;
        int err, i, patt_count;
 
-       buf = kmalloc(ubi->peb_size, GFP_KERNEL);
+       buf = vmalloc(ubi->peb_size);
        if (!buf)
                return -ENOMEM;
 
@@ -437,7 +437,7 @@ out:
                 * physical eraseblock which means something is wrong with it.
                 */
                err = -EIO;
-       kfree(buf);
+       vfree(buf);
        return err;
 }
 
@@ -557,9 +557,9 @@ static int validate_ec_hdr(const struct ubi_device *ubi,
        long long ec;
        int vid_hdr_offset, leb_start;
 
-       ec = ubi64_to_cpu(ec_hdr->ec);
-       vid_hdr_offset = ubi32_to_cpu(ec_hdr->vid_hdr_offset);
-       leb_start = ubi32_to_cpu(ec_hdr->data_offset);
+       ec = be64_to_cpu(ec_hdr->ec);
+       vid_hdr_offset = be32_to_cpu(ec_hdr->vid_hdr_offset);
+       leb_start = be32_to_cpu(ec_hdr->data_offset);
 
        if (ec_hdr->version != UBI_VERSION) {
                ubi_err("node with incompatible UBI version found: "
@@ -640,7 +640,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
                read_err = err;
        }
 
-       magic = ubi32_to_cpu(ec_hdr->magic);
+       magic = be32_to_cpu(ec_hdr->magic);
        if (magic != UBI_EC_HDR_MAGIC) {
                /*
                 * The magic field is wrong. Let's check if we have read all
@@ -684,7 +684,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
        }
 
        crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
-       hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc);
+       hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
 
        if (hdr_crc != crc) {
                if (verbose) {
@@ -729,12 +729,12 @@ int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum,
        dbg_io("write EC header to PEB %d", pnum);
        ubi_assert(pnum >= 0 &&  pnum < ubi->peb_count);
 
-       ec_hdr->magic = cpu_to_ubi32(UBI_EC_HDR_MAGIC);
+       ec_hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
        ec_hdr->version = UBI_VERSION;
-       ec_hdr->vid_hdr_offset = cpu_to_ubi32(ubi->vid_hdr_offset);
-       ec_hdr->data_offset = cpu_to_ubi32(ubi->leb_start);
+       ec_hdr->vid_hdr_offset = cpu_to_be32(ubi->vid_hdr_offset);
+       ec_hdr->data_offset = cpu_to_be32(ubi->leb_start);
        crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
-       ec_hdr->hdr_crc = cpu_to_ubi32(crc);
+       ec_hdr->hdr_crc = cpu_to_be32(crc);
 
        err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
        if (err)
@@ -757,13 +757,13 @@ static int validate_vid_hdr(const struct ubi_device *ubi,
 {
        int vol_type = vid_hdr->vol_type;
        int copy_flag = vid_hdr->copy_flag;
-       int vol_id = ubi32_to_cpu(vid_hdr->vol_id);
-       int lnum = ubi32_to_cpu(vid_hdr->lnum);
+       int vol_id = be32_to_cpu(vid_hdr->vol_id);
+       int lnum = be32_to_cpu(vid_hdr->lnum);
        int compat = vid_hdr->compat;
-       int data_size = ubi32_to_cpu(vid_hdr->data_size);
-       int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
-       int data_pad = ubi32_to_cpu(vid_hdr->data_pad);
-       int data_crc = ubi32_to_cpu(vid_hdr->data_crc);
+       int data_size = be32_to_cpu(vid_hdr->data_size);
+       int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+       int data_pad = be32_to_cpu(vid_hdr->data_pad);
+       int data_crc = be32_to_cpu(vid_hdr->data_crc);
        int usable_leb_size = ubi->leb_size - data_pad;
 
        if (copy_flag != 0 && copy_flag != 1) {
@@ -914,7 +914,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
                read_err = err;
        }
 
-       magic = ubi32_to_cpu(vid_hdr->magic);
+       magic = be32_to_cpu(vid_hdr->magic);
        if (magic != UBI_VID_HDR_MAGIC) {
                /*
                 * If we have read all 0xFF bytes, the VID header probably does
@@ -957,7 +957,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
        }
 
        crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
-       hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc);
+       hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
 
        if (hdr_crc != crc) {
                if (verbose) {
@@ -1007,10 +1007,10 @@ int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum,
        if (err)
                return err > 0 ? -EINVAL: err;
 
-       vid_hdr->magic = cpu_to_ubi32(UBI_VID_HDR_MAGIC);
+       vid_hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
        vid_hdr->version = UBI_VERSION;
        crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
-       vid_hdr->hdr_crc = cpu_to_ubi32(crc);
+       vid_hdr->hdr_crc = cpu_to_be32(crc);
 
        err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
        if (err)
@@ -1060,7 +1060,7 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
        int err;
        uint32_t magic;
 
-       magic = ubi32_to_cpu(ec_hdr->magic);
+       magic = be32_to_cpu(ec_hdr->magic);
        if (magic != UBI_EC_HDR_MAGIC) {
                ubi_err("bad magic %#08x, must be %#08x",
                        magic, UBI_EC_HDR_MAGIC);
@@ -1105,7 +1105,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
                goto exit;
 
        crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
-       hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc);
+       hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
        if (hdr_crc != crc) {
                ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc);
                ubi_err("paranoid check failed for PEB %d", pnum);
@@ -1137,7 +1137,7 @@ static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
        int err;
        uint32_t magic;
 
-       magic = ubi32_to_cpu(vid_hdr->magic);
+       magic = be32_to_cpu(vid_hdr->magic);
        if (magic != UBI_VID_HDR_MAGIC) {
                ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x",
                        magic, pnum, UBI_VID_HDR_MAGIC);
@@ -1187,7 +1187,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
                goto exit;
 
        crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
-       hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc);
+       hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
        if (hdr_crc != crc) {
                ubi_err("bad VID header CRC at PEB %d, calculated %#08x, "
                        "read %#08x", pnum, crc, hdr_crc);
@@ -1224,9 +1224,10 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
        void *buf;
        loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
 
-       buf = kzalloc(len, GFP_KERNEL);
+       buf = vmalloc(len);
        if (!buf)
                return -ENOMEM;
+       memset(buf, 0, len);
 
        err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
        if (err && err != -EUCLEAN) {
@@ -1242,7 +1243,7 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
                goto fail;
        }
 
-       kfree(buf);
+       vfree(buf);
        return 0;
 
 fail:
@@ -1252,7 +1253,7 @@ fail:
        err = 1;
 error:
        ubi_dbg_dump_stack();
-       kfree(buf);
+       vfree(buf);
        return err;
 }
 
index d352c4575c3da3d6f3f834116daa72062eb2bf86..4a458e83e4e90ccb1fac426203919c7af2e58b77 100644 (file)
@@ -37,14 +37,9 @@ int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
 {
        const struct ubi_device *ubi;
 
-       if (!try_module_get(THIS_MODULE))
-               return -ENODEV;
-
        if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES ||
-           !ubi_devices[ubi_num]) {
-               module_put(THIS_MODULE);
+           !ubi_devices[ubi_num])
                return -ENODEV;
-       }
 
        ubi = ubi_devices[ubi_num];
        di->ubi_num = ubi->ubi_num;
@@ -52,7 +47,6 @@ int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
        di->min_io_size = ubi->min_io_size;
        di->ro_mode = ubi->ro_mode;
        di->cdev = MKDEV(ubi->major, 0);
-       module_put(THIS_MODULE);
        return 0;
 }
 EXPORT_SYMBOL_GPL(ubi_get_device_info);
@@ -319,9 +313,14 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
            offset + len > vol->usable_leb_size)
                return -EINVAL;
 
-       if (vol->vol_type == UBI_STATIC_VOLUME && lnum == vol->used_ebs - 1 &&
-           offset + len > vol->last_eb_bytes)
-               return -EINVAL;
+       if (vol->vol_type == UBI_STATIC_VOLUME) {
+               if (vol->used_ebs == 0)
+                       /* Empty static UBI volume */
+                       return 0;
+               if (lnum == vol->used_ebs - 1 &&
+                   offset + len > vol->last_eb_bytes)
+                       return -EINVAL;
+       }
 
        if (vol->upd_marker)
                return -EBADF;
index 38d4e6757dc791590e061ae4191333b47203ef8e..9e2338c8e2cf545f097bd74d6c1d7c20d26093bc 100644 (file)
@@ -67,7 +67,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
        if (vol->vol_type != UBI_STATIC_VOLUME)
                return 0;
 
-       buf = kmalloc(vol->usable_leb_size, GFP_KERNEL);
+       buf = vmalloc(vol->usable_leb_size);
        if (!buf)
                return -ENOMEM;
 
@@ -87,7 +87,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
                }
        }
 
-       kfree(buf);
+       vfree(buf);
        return err;
 }
 
index 473f3200b868c76b6c53e28ccdc7ba6d78948a96..94ee549344118987e2e2a73ded2c13fc00a1f2f0 100644 (file)
@@ -24,7 +24,7 @@
  * This unit is responsible for scanning the flash media, checking UBI
  * headers and providing complete information about the UBI flash image.
  *
- * The scanning information is reoresented by a &struct ubi_scan_info' object.
+ * The scanning information is represented by a &struct ubi_scan_info' object.
  * Information about found volumes is represented by &struct ubi_scan_volume
  * objects which are kept in volume RB-tree with root at the @volumes field.
  * The RB-tree is indexed by the volume ID.
@@ -55,8 +55,19 @@ static int paranoid_check_si(const struct ubi_device *ubi,
 static struct ubi_ec_hdr *ech;
 static struct ubi_vid_hdr *vidh;
 
-int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec,
-                        struct list_head *list)
+/**
+ * add_to_list - add physical eraseblock to a list.
+ * @si: scanning information
+ * @pnum: physical eraseblock number to add
+ * @ec: erase counter of the physical eraseblock
+ * @list: the list to add to
+ *
+ * This function adds physical eraseblock @pnum to free, erase, corrupted or
+ * alien lists. Returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
+                      struct list_head *list)
 {
        struct ubi_scan_leb *seb;
 
@@ -121,9 +132,9 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
                            const struct ubi_scan_volume *sv, int pnum)
 {
        int vol_type = vid_hdr->vol_type;
-       int vol_id = ubi32_to_cpu(vid_hdr->vol_id);
-       int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
-       int data_pad = ubi32_to_cpu(vid_hdr->data_pad);
+       int vol_id = be32_to_cpu(vid_hdr->vol_id);
+       int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+       int data_pad = be32_to_cpu(vid_hdr->data_pad);
 
        if (sv->leb_count != 0) {
                int sv_vol_type;
@@ -189,7 +200,7 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
        struct ubi_scan_volume *sv;
        struct rb_node **p = &si->volumes.rb_node, *parent = NULL;
 
-       ubi_assert(vol_id == ubi32_to_cpu(vid_hdr->vol_id));
+       ubi_assert(vol_id == be32_to_cpu(vid_hdr->vol_id));
 
        /* Walk the volume RB-tree to look if this volume is already present */
        while (*p) {
@@ -211,11 +222,10 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
                return ERR_PTR(-ENOMEM);
 
        sv->highest_lnum = sv->leb_count = 0;
-       si->max_sqnum = 0;
        sv->vol_id = vol_id;
        sv->root = RB_ROOT;
-       sv->used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
-       sv->data_pad = ubi32_to_cpu(vid_hdr->data_pad);
+       sv->used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+       sv->data_pad = be32_to_cpu(vid_hdr->data_pad);
        sv->compat = vid_hdr->compat;
        sv->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME
                                                            : UBI_STATIC_VOLUME;
@@ -257,10 +267,10 @@ static int compare_lebs(const struct ubi_device *ubi,
        int len, err, second_is_newer, bitflips = 0, corrupted = 0;
        uint32_t data_crc, crc;
        struct ubi_vid_hdr *vidh = NULL;
-       unsigned long long sqnum2 = ubi64_to_cpu(vid_hdr->sqnum);
+       unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);
 
        if (seb->sqnum == 0 && sqnum2 == 0) {
-               long long abs, v1 = seb->leb_ver, v2 = ubi32_to_cpu(vid_hdr->leb_ver);
+               long long abs, v1 = seb->leb_ver, v2 = be32_to_cpu(vid_hdr->leb_ver);
 
                /*
                 * UBI constantly increases the logical eraseblock version
@@ -344,8 +354,8 @@ static int compare_lebs(const struct ubi_device *ubi,
 
        /* Read the data of the copy and check the CRC */
 
-       len = ubi32_to_cpu(vid_hdr->data_size);
-       buf = kmalloc(len, GFP_KERNEL);
+       len = be32_to_cpu(vid_hdr->data_size);
+       buf = vmalloc(len);
        if (!buf) {
                err = -ENOMEM;
                goto out_free_vidh;
@@ -355,7 +365,7 @@ static int compare_lebs(const struct ubi_device *ubi,
        if (err && err != UBI_IO_BITFLIPS)
                goto out_free_buf;
 
-       data_crc = ubi32_to_cpu(vid_hdr->data_crc);
+       data_crc = be32_to_cpu(vid_hdr->data_crc);
        crc = crc32(UBI_CRC32_INIT, buf, len);
        if (crc != data_crc) {
                dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x",
@@ -368,7 +378,7 @@ static int compare_lebs(const struct ubi_device *ubi,
                bitflips = !!err;
        }
 
-       kfree(buf);
+       vfree(buf);
        ubi_free_vid_hdr(ubi, vidh);
 
        if (second_is_newer)
@@ -379,7 +389,7 @@ static int compare_lebs(const struct ubi_device *ubi,
        return second_is_newer | (bitflips << 1) | (corrupted << 2);
 
 out_free_buf:
-       kfree(buf);
+       vfree(buf);
 out_free_vidh:
        ubi_free_vid_hdr(ubi, vidh);
        ubi_assert(err < 0);
@@ -396,8 +406,12 @@ out_free_vidh:
  * @vid_hdr: the volume identifier header
  * @bitflips: if bit-flips were detected when this physical eraseblock was read
  *
- * This function returns zero in case of success and a negative error code in
- * case of failure.
+ * This function adds information about a used physical eraseblock to the
+ * 'used' tree of the corresponding volume. The function is rather complex
+ * because it has to handle cases when this is not the first physical
+ * eraseblock belonging to the same logical eraseblock, and the newer one has
+ * to be picked, while the older one has to be dropped. This function returns
+ * zero in case of success and a negative error code in case of failure.
  */
 int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
                      int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
@@ -410,10 +424,10 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
        struct ubi_scan_leb *seb;
        struct rb_node **p, *parent = NULL;
 
-       vol_id = ubi32_to_cpu(vid_hdr->vol_id);
-       lnum = ubi32_to_cpu(vid_hdr->lnum);
-       sqnum = ubi64_to_cpu(vid_hdr->sqnum);
-       leb_ver = ubi32_to_cpu(vid_hdr->leb_ver);
+       vol_id = be32_to_cpu(vid_hdr->vol_id);
+       lnum = be32_to_cpu(vid_hdr->lnum);
+       sqnum = be64_to_cpu(vid_hdr->sqnum);
+       leb_ver = be32_to_cpu(vid_hdr->leb_ver);
 
        dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, ver %u, bitflips %d",
                pnum, vol_id, lnum, ec, sqnum, leb_ver, bitflips);
@@ -422,6 +436,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
        if (IS_ERR(sv) < 0)
                return PTR_ERR(sv);
 
+       if (si->max_sqnum < sqnum)
+               si->max_sqnum = sqnum;
+
        /*
         * Walk the RB-tree of logical eraseblocks of volume @vol_id to look
         * if this is the first instance of this logical eraseblock or not.
@@ -492,11 +509,11 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
                                return err;
 
                        if (cmp_res & 4)
-                               err = ubi_scan_add_to_list(si, seb->pnum,
-                                                          seb->ec, &si->corr);
+                               err = add_to_list(si, seb->pnum, seb->ec,
+                                                 &si->corr);
                        else
-                               err = ubi_scan_add_to_list(si, seb->pnum,
-                                                          seb->ec, &si->erase);
+                               err = add_to_list(si, seb->pnum, seb->ec,
+                                                 &si->erase);
                        if (err)
                                return err;
 
@@ -508,7 +525,7 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
 
                        if (sv->highest_lnum == lnum)
                                sv->last_data_size =
-                                       ubi32_to_cpu(vid_hdr->data_size);
+                                       be32_to_cpu(vid_hdr->data_size);
 
                        return 0;
                } else {
@@ -517,11 +534,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
                         * previously.
                         */
                        if (cmp_res & 4)
-                               return ubi_scan_add_to_list(si, pnum, ec,
-                                                           &si->corr);
+                               return add_to_list(si, pnum, ec, &si->corr);
                        else
-                               return ubi_scan_add_to_list(si, pnum, ec,
-                                                           &si->erase);
+                               return add_to_list(si, pnum, ec, &si->erase);
                }
        }
 
@@ -547,12 +562,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
 
        if (sv->highest_lnum <= lnum) {
                sv->highest_lnum = lnum;
-               sv->last_data_size = ubi32_to_cpu(vid_hdr->data_size);
+               sv->last_data_size = be32_to_cpu(vid_hdr->data_size);
        }
 
-       if (si->max_sqnum < sqnum)
-               si->max_sqnum = sqnum;
-
        sv->leb_count += 1;
        rb_link_node(&seb->u.rb, parent, p);
        rb_insert_color(&seb->u.rb, &sv->root);
@@ -674,7 +686,7 @@ int ubi_scan_erase_peb(const struct ubi_device *ubi,
                return -EINVAL;
        }
 
-       ec_hdr->ec = cpu_to_ubi64(ec);
+       ec_hdr->ec = cpu_to_be64(ec);
 
        err = ubi_io_sync_erase(ubi, pnum, 0);
        if (err < 0)
@@ -754,7 +766,7 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi,
  * @si: scanning information
  * @pnum: the physical eraseblock number
  *
- * This function returns a zero if the physical eraseblock was succesfully
+ * This function returns a zero if the physical eraseblock was successfully
  * handled and a negative error code in case of failure.
  */
 static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum)
@@ -783,8 +795,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
        else if (err == UBI_IO_BITFLIPS)
                bitflips = 1;
        else if (err == UBI_IO_PEB_EMPTY)
-               return ubi_scan_add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC,
-                                           &si->erase);
+               return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase);
        else if (err == UBI_IO_BAD_EC_HDR) {
                /*
                 * We have to also look at the VID header, possibly it is not
@@ -806,7 +817,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
                        return -EINVAL;
                }
 
-               ec = ubi64_to_cpu(ech->ec);
+               ec = be64_to_cpu(ech->ec);
                if (ec > UBI_MAX_ERASECOUNTER) {
                        /*
                         * Erase counter overflow. The EC headers have 64 bits
@@ -832,28 +843,28 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
        else if (err == UBI_IO_BAD_VID_HDR ||
                 (err == UBI_IO_PEB_FREE && ec_corr)) {
                /* VID header is corrupted */
-               err = ubi_scan_add_to_list(si, pnum, ec, &si->corr);
+               err = add_to_list(si, pnum, ec, &si->corr);
                if (err)
                        return err;
                goto adjust_mean_ec;
        } else if (err == UBI_IO_PEB_FREE) {
                /* No VID header - the physical eraseblock is free */
-               err = ubi_scan_add_to_list(si, pnum, ec, &si->free);
+               err = add_to_list(si, pnum, ec, &si->free);
                if (err)
                        return err;
                goto adjust_mean_ec;
        }
 
-       vol_id = ubi32_to_cpu(vidh->vol_id);
+       vol_id = be32_to_cpu(vidh->vol_id);
        if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) {
-               int lnum = ubi32_to_cpu(vidh->lnum);
+               int lnum = be32_to_cpu(vidh->lnum);
 
                /* Unsupported internal volume */
                switch (vidh->compat) {
                case UBI_COMPAT_DELETE:
                        ubi_msg("\"delete\" compatible internal volume %d:%d"
                                " found, remove it", vol_id, lnum);
-                       err = ubi_scan_add_to_list(si, pnum, ec, &si->corr);
+                       err = add_to_list(si, pnum, ec, &si->corr);
                        if (err)
                                return err;
                        break;
@@ -868,7 +879,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
                case UBI_COMPAT_PRESERVE:
                        ubi_msg("\"preserve\" compatible internal volume %d:%d"
                                " found", vol_id, lnum);
-                       err = ubi_scan_add_to_list(si, pnum, ec, &si->alien);
+                       err = add_to_list(si, pnum, ec, &si->alien);
                        if (err)
                                return err;
                        si->alien_peb_count += 1;
@@ -1109,7 +1120,7 @@ static int paranoid_check_si(const struct ubi_device *ubi,
        uint8_t *buf;
 
        /*
-        * At first, check that scanning information is ok.
+        * At first, check that scanning information is OK.
         */
        ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
                int leb_count = 0;
@@ -1249,12 +1260,12 @@ static int paranoid_check_si(const struct ubi_device *ubi,
                                goto bad_vid_hdr;
                        }
 
-                       if (seb->sqnum != ubi64_to_cpu(vidh->sqnum)) {
+                       if (seb->sqnum != be64_to_cpu(vidh->sqnum)) {
                                ubi_err("bad sqnum %llu", seb->sqnum);
                                goto bad_vid_hdr;
                        }
 
-                       if (sv->vol_id != ubi32_to_cpu(vidh->vol_id)) {
+                       if (sv->vol_id != be32_to_cpu(vidh->vol_id)) {
                                ubi_err("bad vol_id %d", sv->vol_id);
                                goto bad_vid_hdr;
                        }
@@ -1264,22 +1275,22 @@ static int paranoid_check_si(const struct ubi_device *ubi,
                                goto bad_vid_hdr;
                        }
 
-                       if (seb->lnum != ubi32_to_cpu(vidh->lnum)) {
+                       if (seb->lnum != be32_to_cpu(vidh->lnum)) {
                                ubi_err("bad lnum %d", seb->lnum);
                                goto bad_vid_hdr;
                        }
 
-                       if (sv->used_ebs != ubi32_to_cpu(vidh->used_ebs)) {
+                       if (sv->used_ebs != be32_to_cpu(vidh->used_ebs)) {
                                ubi_err("bad used_ebs %d", sv->used_ebs);
                                goto bad_vid_hdr;
                        }
 
-                       if (sv->data_pad != ubi32_to_cpu(vidh->data_pad)) {
+                       if (sv->data_pad != be32_to_cpu(vidh->data_pad)) {
                                ubi_err("bad data_pad %d", sv->data_pad);
                                goto bad_vid_hdr;
                        }
 
-                       if (seb->leb_ver != ubi32_to_cpu(vidh->leb_ver)) {
+                       if (seb->leb_ver != be32_to_cpu(vidh->leb_ver)) {
                                ubi_err("bad leb_ver %u", seb->leb_ver);
                                goto bad_vid_hdr;
                        }
@@ -1288,12 +1299,12 @@ static int paranoid_check_si(const struct ubi_device *ubi,
                if (!last_seb)
                        continue;
 
-               if (sv->highest_lnum != ubi32_to_cpu(vidh->lnum)) {
+               if (sv->highest_lnum != be32_to_cpu(vidh->lnum)) {
                        ubi_err("bad highest_lnum %d", sv->highest_lnum);
                        goto bad_vid_hdr;
                }
 
-               if (sv->last_data_size != ubi32_to_cpu(vidh->data_size)) {
+               if (sv->last_data_size != be32_to_cpu(vidh->data_size)) {
                        ubi_err("bad last_data_size %d", sv->last_data_size);
                        goto bad_vid_hdr;
                }
@@ -1310,8 +1321,10 @@ static int paranoid_check_si(const struct ubi_device *ubi,
        memset(buf, 1, ubi->peb_count);
        for (pnum = 0; pnum < ubi->peb_count; pnum++) {
                err = ubi_io_is_bad(ubi, pnum);
-               if (err < 0)
+               if (err < 0) {
+                       kfree(buf);
                        return err;
+               }
                else if (err)
                        buf[pnum] = 0;
        }
index 3949f6192c76692f5f603d4cb1a70a42ba0bec18..140e82e265349e7dafc7e6da4ec1e41706d41a1f 100644 (file)
@@ -147,8 +147,6 @@ static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv,
                list_add_tail(&seb->u.list, list);
 }
 
-int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec,
-                        struct list_head *list);
 int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
                      int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
                      int bitflips);
index feb647f108f013a2b5c1753751688aae26a3e643..5959f91be240655b3219a6d6359a060d732aeaf7 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/cdev.h>
 #include <linux/device.h>
 #include <linux/string.h>
+#include <linux/vmalloc.h>
 #include <linux/mtd/mtd.h>
 
 #include <mtd/ubi-header.h>
@@ -374,9 +375,11 @@ void ubi_calculate_reserved(struct ubi_device *ubi);
 #ifdef CONFIG_MTD_UBI_GLUEBI
 int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol);
 int ubi_destroy_gluebi(struct ubi_volume *vol);
+void ubi_gluebi_updated(struct ubi_volume *vol);
 #else
 #define ubi_create_gluebi(ubi, vol) 0
 #define ubi_destroy_gluebi(vol) 0
+#define ubi_gluebi_updated(vol)
 #endif
 
 /* eba.c */
index 8925b977e3dcc8ffc4492fd386357c547dab37ed..0efc586a83288fd5ccde9bc6b39a5ea432cf8f4c 100644 (file)
@@ -150,7 +150,7 @@ int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes)
                        vol->updating = 0;
        }
 
-       vol->upd_buf = kmalloc(ubi->leb_size, GFP_KERNEL);
+       vol->upd_buf = vmalloc(ubi->leb_size);
        if (!vol->upd_buf)
                return -ENOMEM;
 
@@ -339,7 +339,7 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id,
                err = ubi_wl_flush(ubi);
                if (err == 0) {
                        err = to_write;
-                       kfree(vol->upd_buf);
+                       vfree(vol->upd_buf);
                        vol->updating = 0;
                }
        }
index 622d0d18952c8c5fb9dbc6ae3f37d20a7ef40be0..ea0d5c825ab41034b5dd4b91cfba6ce587680fbe 100644 (file)
@@ -228,7 +228,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
        for (i = 0; i < ubi->vtbl_slots; i++)
                if (ubi->volumes[i] &&
                    ubi->volumes[i]->name_len == req->name_len &&
-                   strcmp(ubi->volumes[i]->name, req->name) == 0) {
+                   !strcmp(ubi->volumes[i]->name, req->name)) {
                        dbg_err("volume \"%s\" exists (ID %d)", req->name, i);
                        goto out_unlock;
                }
@@ -243,7 +243,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
        /* Reserve physical eraseblocks */
        if (vol->reserved_pebs > ubi->avail_pebs) {
                dbg_err("not enough PEBs, only %d available", ubi->avail_pebs);
-               spin_unlock(&ubi->volumes_lock);
                err = -ENOSPC;
                goto out_unlock;
        }
@@ -281,7 +280,8 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
        if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
                vol->used_ebs = vol->reserved_pebs;
                vol->last_eb_bytes = vol->usable_leb_size;
-               vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+               vol->used_bytes =
+                       (long long)vol->used_ebs * vol->usable_leb_size;
        } else {
                bytes = vol->used_bytes;
                vol->last_eb_bytes = do_div(bytes, vol->usable_leb_size);
@@ -320,10 +320,10 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
 
        /* Fill volume table record */
        memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
-       vtbl_rec.reserved_pebs = cpu_to_ubi32(vol->reserved_pebs);
-       vtbl_rec.alignment     = cpu_to_ubi32(vol->alignment);
-       vtbl_rec.data_pad      = cpu_to_ubi32(vol->data_pad);
-       vtbl_rec.name_len      = cpu_to_ubi16(vol->name_len);
+       vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs);
+       vtbl_rec.alignment     = cpu_to_be32(vol->alignment);
+       vtbl_rec.data_pad      = cpu_to_be32(vol->data_pad);
+       vtbl_rec.name_len      = cpu_to_be16(vol->name_len);
        if (vol->vol_type == UBI_DYNAMIC_VOLUME)
                vtbl_rec.vol_type = UBI_VID_DYNAMIC;
        else
@@ -352,6 +352,7 @@ out_acc:
        spin_lock(&ubi->volumes_lock);
        ubi->rsvd_pebs -= vol->reserved_pebs;
        ubi->avail_pebs += vol->reserved_pebs;
+       ubi->volumes[vol_id] = NULL;
 out_unlock:
        spin_unlock(&ubi->volumes_lock);
        kfree(vol);
@@ -368,6 +369,7 @@ out_sysfs:
        spin_lock(&ubi->volumes_lock);
        ubi->rsvd_pebs -= vol->reserved_pebs;
        ubi->avail_pebs += vol->reserved_pebs;
+       ubi->volumes[vol_id] = NULL;
        spin_unlock(&ubi->volumes_lock);
        volume_sysfs_close(vol);
        return err;
@@ -503,7 +505,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
 
        /* Change volume table record */
        memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
-       vtbl_rec.reserved_pebs = cpu_to_ubi32(reserved_pebs);
+       vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
        err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
        if (err)
                goto out_acc;
@@ -537,7 +539,8 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
        if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
                vol->used_ebs = reserved_pebs;
                vol->last_eb_bytes = vol->usable_leb_size;
-               vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+               vol->used_bytes =
+                       (long long)vol->used_ebs * vol->usable_leb_size;
        }
 
        paranoid_check_volumes(ubi);
@@ -643,21 +646,33 @@ void ubi_free_volume(struct ubi_device *ubi, int vol_id)
  * @ubi: UBI device description object
  * @vol_id: volume ID
  */
-static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
+static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
 {
        int idx = vol_id2idx(ubi, vol_id);
        int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker;
-       const struct ubi_volume *vol = ubi->volumes[idx];
+       const struct ubi_volume *vol;
        long long n;
        const char *name;
 
-       reserved_pebs = ubi32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
+       spin_lock(&ubi->volumes_lock);
+       reserved_pebs = be32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
+       vol = ubi->volumes[idx];
 
        if (!vol) {
                if (reserved_pebs) {
                        ubi_err("no volume info, but volume exists");
                        goto fail;
                }
+               spin_unlock(&ubi->volumes_lock);
+               return;
+       }
+
+       if (vol->exclusive) {
+               /*
+                * The volume may be being created at the moment, do not check
+                * it (e.g., it may be in the middle of ubi_create_volume().
+                */
+               spin_unlock(&ubi->volumes_lock);
                return;
        }
 
@@ -726,7 +741,7 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
                goto fail;
        }
 
-       n = vol->used_ebs * vol->usable_leb_size;
+       n = (long long)vol->used_ebs * vol->usable_leb_size;
        if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
                if (vol->corrupted != 0) {
                        ubi_err("corrupted dynamic volume");
@@ -765,9 +780,9 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
                }
        }
 
-       alignment  = ubi32_to_cpu(ubi->vtbl[vol_id].alignment);
-       data_pad   = ubi32_to_cpu(ubi->vtbl[vol_id].data_pad);
-       name_len   = ubi16_to_cpu(ubi->vtbl[vol_id].name_len);
+       alignment  = be32_to_cpu(ubi->vtbl[vol_id].alignment);
+       data_pad   = be32_to_cpu(ubi->vtbl[vol_id].data_pad);
+       name_len   = be16_to_cpu(ubi->vtbl[vol_id].name_len);
        upd_marker = ubi->vtbl[vol_id].upd_marker;
        name       = &ubi->vtbl[vol_id].name[0];
        if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC)
@@ -782,12 +797,14 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
                goto fail;
        }
 
+       spin_unlock(&ubi->volumes_lock);
        return;
 
 fail:
-       ubi_err("paranoid check failed");
+       ubi_err("paranoid check failed for volume %d", vol_id);
        ubi_dbg_dump_vol_info(vol);
        ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
+       spin_unlock(&ubi->volumes_lock);
        BUG();
 }
 
@@ -800,10 +817,8 @@ static void paranoid_check_volumes(struct ubi_device *ubi)
        int i;
 
        mutex_lock(&ubi->vtbl_mutex);
-       spin_lock(&ubi->volumes_lock);
        for (i = 0; i < ubi->vtbl_slots; i++)
                paranoid_check_volume(ubi, i);
-       spin_unlock(&ubi->volumes_lock);
        mutex_unlock(&ubi->vtbl_mutex);
 }
 #endif
index b6fd6bbd941e63782d25aadad09b0e136c4d13fe..bc5df50813d67cc2cbd8bd635dbd8e11657cbb8c 100644 (file)
@@ -93,12 +93,9 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
                vtbl_rec = &empty_vtbl_record;
        else {
                crc = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
-               vtbl_rec->crc = cpu_to_ubi32(crc);
+               vtbl_rec->crc = cpu_to_be32(crc);
        }
 
-       dbg_msg("change record %d", idx);
-       ubi_dbg_dump_vtbl_record(vtbl_rec, idx);
-
        mutex_lock(&ubi->vtbl_mutex);
        memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record));
        for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
@@ -141,18 +138,18 @@ static int vtbl_check(const struct ubi_device *ubi,
        for (i = 0; i < ubi->vtbl_slots; i++) {
                cond_resched();
 
-               reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs);
-               alignment = ubi32_to_cpu(vtbl[i].alignment);
-               data_pad = ubi32_to_cpu(vtbl[i].data_pad);
+               reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
+               alignment = be32_to_cpu(vtbl[i].alignment);
+               data_pad = be32_to_cpu(vtbl[i].data_pad);
                upd_marker = vtbl[i].upd_marker;
                vol_type = vtbl[i].vol_type;
-               name_len = ubi16_to_cpu(vtbl[i].name_len);
+               name_len = be16_to_cpu(vtbl[i].name_len);
                name = &vtbl[i].name[0];
 
                crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC);
-               if (ubi32_to_cpu(vtbl[i].crc) != crc) {
+               if (be32_to_cpu(vtbl[i].crc) != crc) {
                        ubi_err("bad CRC at record %u: %#08x, not %#08x",
-                                i, crc, ubi32_to_cpu(vtbl[i].crc));
+                                i, crc, be32_to_cpu(vtbl[i].crc));
                        ubi_dbg_dump_vtbl_record(&vtbl[i], i);
                        return 1;
                }
@@ -225,8 +222,8 @@ static int vtbl_check(const struct ubi_device *ubi,
        /* Checks that all names are unique */
        for (i = 0; i < ubi->vtbl_slots - 1; i++) {
                for (n = i + 1; n < ubi->vtbl_slots; n++) {
-                       int len1 = ubi16_to_cpu(vtbl[i].name_len);
-                       int len2 = ubi16_to_cpu(vtbl[n].name_len);
+                       int len1 = be16_to_cpu(vtbl[i].name_len);
+                       int len2 = be16_to_cpu(vtbl[n].name_len);
 
                        if (len1 > 0 && len1 == len2 &&
                            !strncmp(vtbl[i].name, vtbl[n].name, len1)) {
@@ -288,13 +285,13 @@ retry:
        }
 
        vid_hdr->vol_type = UBI_VID_DYNAMIC;
-       vid_hdr->vol_id = cpu_to_ubi32(UBI_LAYOUT_VOL_ID);
+       vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOL_ID);
        vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT;
        vid_hdr->data_size = vid_hdr->used_ebs =
-                            vid_hdr->data_pad = cpu_to_ubi32(0);
-       vid_hdr->lnum = cpu_to_ubi32(copy);
-       vid_hdr->sqnum = cpu_to_ubi64(++si->max_sqnum);
-       vid_hdr->leb_ver = cpu_to_ubi32(old_seb ? old_seb->leb_ver + 1: 0);
+                            vid_hdr->data_pad = cpu_to_be32(0);
+       vid_hdr->lnum = cpu_to_be32(copy);
+       vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum);
+       vid_hdr->leb_ver = cpu_to_be32(old_seb ? old_seb->leb_ver + 1: 0);
 
        /* The EC header is already there, write the VID header */
        err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr);
@@ -317,14 +314,15 @@ retry:
        return err;
 
 write_error:
-       kfree(new_seb);
-       /* May be this physical eraseblock went bad, try to pick another one */
-       if (++tries <= 5) {
-               err = ubi_scan_add_to_list(si, new_seb->pnum, new_seb->ec,
-                                          &si->corr);
-               if (!err)
-                       goto retry;
+       if (err == -EIO && ++tries <= 5) {
+               /*
+                * Probably this physical eraseblock went bad, try to pick
+                * another one.
+                */
+               list_add_tail(&new_seb->u.list, &si->corr);
+               goto retry;
        }
+       kfree(new_seb);
 out_free:
        ubi_free_vid_hdr(ubi, vid_hdr);
        return err;
@@ -380,11 +378,12 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
 
        /* Read both LEB 0 and LEB 1 into memory */
        ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
-               leb[seb->lnum] = kzalloc(ubi->vtbl_size, GFP_KERNEL);
+               leb[seb->lnum] = vmalloc(ubi->vtbl_size);
                if (!leb[seb->lnum]) {
                        err = -ENOMEM;
                        goto out_free;
                }
+               memset(leb[seb->lnum], 0, ubi->vtbl_size);
 
                err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
                                       ubi->vtbl_size);
@@ -415,7 +414,7 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
                }
 
                /* Both LEB 1 and LEB 2 are OK and consistent */
-               kfree(leb[1]);
+               vfree(leb[1]);
                return leb[0];
        } else {
                /* LEB 0 is corrupted or does not exist */
@@ -436,13 +435,13 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
                        goto out_free;
                ubi_msg("volume table was restored");
 
-               kfree(leb[0]);
+               vfree(leb[0]);
                return leb[1];
        }
 
 out_free:
-       kfree(leb[0]);
-       kfree(leb[1]);
+       vfree(leb[0]);
+       vfree(leb[1]);
        return ERR_PTR(err);
 }
 
@@ -460,9 +459,10 @@ static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi,
        int i;
        struct ubi_vtbl_record *vtbl;
 
-       vtbl = kzalloc(ubi->vtbl_size, GFP_KERNEL);
+       vtbl = vmalloc(ubi->vtbl_size);
        if (!vtbl)
                return ERR_PTR(-ENOMEM);
+       memset(vtbl, 0, ubi->vtbl_size);
 
        for (i = 0; i < ubi->vtbl_slots; i++)
                memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE);
@@ -472,7 +472,7 @@ static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi,
 
                err = create_vtbl(ubi, si, i, vtbl);
                if (err) {
-                       kfree(vtbl);
+                       vfree(vtbl);
                        return ERR_PTR(err);
                }
        }
@@ -500,19 +500,19 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
        for (i = 0; i < ubi->vtbl_slots; i++) {
                cond_resched();
 
-               if (ubi32_to_cpu(vtbl[i].reserved_pebs) == 0)
+               if (be32_to_cpu(vtbl[i].reserved_pebs) == 0)
                        continue; /* Empty record */
 
                vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
                if (!vol)
                        return -ENOMEM;
 
-               vol->reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs);
-               vol->alignment = ubi32_to_cpu(vtbl[i].alignment);
-               vol->data_pad = ubi32_to_cpu(vtbl[i].data_pad);
+               vol->reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
+               vol->alignment = be32_to_cpu(vtbl[i].alignment);
+               vol->data_pad = be32_to_cpu(vtbl[i].data_pad);
                vol->vol_type = vtbl[i].vol_type == UBI_VID_DYNAMIC ?
                                        UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
-               vol->name_len = ubi16_to_cpu(vtbl[i].name_len);
+               vol->name_len = be16_to_cpu(vtbl[i].name_len);
                vol->usable_leb_size = ubi->leb_size - vol->data_pad;
                memcpy(vol->name, vtbl[i].name, vol->name_len);
                vol->name[vol->name_len] = '\0';
@@ -531,7 +531,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
                if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
                        vol->used_ebs = vol->reserved_pebs;
                        vol->last_eb_bytes = vol->usable_leb_size;
-                       vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+                       vol->used_bytes =
+                               (long long)vol->used_ebs * vol->usable_leb_size;
                        continue;
                }
 
@@ -561,7 +562,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
                }
 
                vol->used_ebs = sv->used_ebs;
-               vol->used_bytes = (vol->used_ebs - 1) * vol->usable_leb_size;
+               vol->used_bytes =
+                       (long long)(vol->used_ebs - 1) * vol->usable_leb_size;
                vol->used_bytes += sv->last_data_size;
                vol->last_eb_bytes = sv->last_data_size;
        }
@@ -578,7 +580,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
        vol->usable_leb_size = ubi->leb_size;
        vol->used_ebs = vol->reserved_pebs;
        vol->last_eb_bytes = vol->reserved_pebs;
-       vol->used_bytes = vol->used_ebs * (ubi->leb_size - vol->data_pad);
+       vol->used_bytes =
+               (long long)vol->used_ebs * (ubi->leb_size - vol->data_pad);
        vol->vol_id = UBI_LAYOUT_VOL_ID;
 
        ubi_assert(!ubi->volumes[i]);
@@ -718,7 +721,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
        int i, err;
        struct ubi_scan_volume *sv;
 
-       empty_vtbl_record.crc = cpu_to_ubi32(0xf116c36b);
+       empty_vtbl_record.crc = cpu_to_be32(0xf116c36b);
 
        /*
         * The number of supported volumes is limited by the eraseblock size
@@ -783,7 +786,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
        return 0;
 
 out_free:
-       kfree(ubi->vtbl);
+       vfree(ubi->vtbl);
        for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++)
                if (ubi->volumes[i]) {
                        kfree(ubi->volumes[i]);
index ab2174a56bc28b490089129b88c23e583eb7a1fa..9de953762097c8d1746994246e8e00b91ec3d101 100644 (file)
@@ -667,7 +667,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int tortur
 
        dbg_wl("erased PEB %d, new EC %llu", e->pnum, ec);
 
-       ec_hdr->ec = cpu_to_ubi64(ec);
+       ec_hdr->ec = cpu_to_be64(ec);
 
        err = ubi_io_write_ec_hdr(ubi, e->pnum, ec_hdr);
        if (err)
@@ -1060,9 +1060,8 @@ out_unlock:
 static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
                        int cancel)
 {
-       int err;
        struct ubi_wl_entry *e = wl_wrk->e;
-       int pnum = e->pnum;
+       int pnum = e->pnum, err, need;
 
        if (cancel) {
                dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
@@ -1097,62 +1096,70 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
        kfree(wl_wrk);
        kmem_cache_free(wl_entries_slab, e);
 
-       if (err != -EIO) {
+       if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
+           err == -EBUSY) {
+               int err1;
+
+               /* Re-schedule the LEB for erasure */
+               err1 = schedule_erase(ubi, e, 0);
+               if (err1) {
+                       err = err1;
+                       goto out_ro;
+               }
+               return err;
+       } else if (err != -EIO) {
                /*
                 * If this is not %-EIO, we have no idea what to do. Scheduling
                 * this physical eraseblock for erasure again would cause
                 * errors again and again. Well, lets switch to RO mode.
                 */
-               ubi_ro_mode(ubi);
-               return err;
+               goto out_ro;
        }
 
        /* It is %-EIO, the PEB went bad */
 
        if (!ubi->bad_allowed) {
                ubi_err("bad physical eraseblock %d detected", pnum);
-               ubi_ro_mode(ubi);
-               err = -EIO;
-       } else {
-               int need;
-
-               spin_lock(&ubi->volumes_lock);
-               need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
-               if (need > 0) {
-                       need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
-                       ubi->avail_pebs -= need;
-                       ubi->rsvd_pebs += need;
-                       ubi->beb_rsvd_pebs += need;
-                       if (need > 0)
-                               ubi_msg("reserve more %d PEBs", need);
-               }
+               goto out_ro;
+       }
 
-               if (ubi->beb_rsvd_pebs == 0) {
-                       spin_unlock(&ubi->volumes_lock);
-                       ubi_err("no reserved physical eraseblocks");
-                       ubi_ro_mode(ubi);
-                       return -EIO;
-               }
+       spin_lock(&ubi->volumes_lock);
+       need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
+       if (need > 0) {
+               need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
+               ubi->avail_pebs -= need;
+               ubi->rsvd_pebs += need;
+               ubi->beb_rsvd_pebs += need;
+               if (need > 0)
+                       ubi_msg("reserve more %d PEBs", need);
+       }
 
+       if (ubi->beb_rsvd_pebs == 0) {
                spin_unlock(&ubi->volumes_lock);
-               ubi_msg("mark PEB %d as bad", pnum);
+               ubi_err("no reserved physical eraseblocks");
+               goto out_ro;
+       }
 
-               err = ubi_io_mark_bad(ubi, pnum);
-               if (err) {
-                       ubi_ro_mode(ubi);
-                       return err;
-               }
+       spin_unlock(&ubi->volumes_lock);
+       ubi_msg("mark PEB %d as bad", pnum);
 
-               spin_lock(&ubi->volumes_lock);
-               ubi->beb_rsvd_pebs -= 1;
-               ubi->bad_peb_count += 1;
-               ubi->good_peb_count -= 1;
-               ubi_calculate_reserved(ubi);
-               if (ubi->beb_rsvd_pebs == 0)
-                       ubi_warn("last PEB from the reserved pool was used");
-               spin_unlock(&ubi->volumes_lock);
-       }
+       err = ubi_io_mark_bad(ubi, pnum);
+       if (err)
+               goto out_ro;
+
+       spin_lock(&ubi->volumes_lock);
+       ubi->beb_rsvd_pebs -= 1;
+       ubi->bad_peb_count += 1;
+       ubi->good_peb_count -= 1;
+       ubi_calculate_reserved(ubi);
+       if (ubi->beb_rsvd_pebs == 0)
+               ubi_warn("last PEB from the reserved pool was used");
+       spin_unlock(&ubi->volumes_lock);
+
+       return err;
 
+out_ro:
+       ubi_ro_mode(ubi);
        return err;
 }
 
@@ -1634,7 +1641,7 @@ static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec)
                goto out_free;
        }
 
-       read_ec = ubi64_to_cpu(ec_hdr->ec);
+       read_ec = be64_to_cpu(ec_hdr->ec);
        if (ec != read_ec) {
                ubi_err("paranoid check failed for PEB %d", pnum);
                ubi_err("read EC is %lld, should be %d", read_ec, ec);
index 43d03178064dfb96f8c7957c328e0d1f2754cea8..5fb659f8b20e537c0b22ff504b182811c59a47cd 100644 (file)
@@ -2486,6 +2486,18 @@ source "drivers/atm/Kconfig"
 
 source "drivers/s390/net/Kconfig"
 
+config XEN_NETDEV_FRONTEND
+       tristate "Xen network device frontend driver"
+       depends on XEN
+       default y
+       help
+         The network device frontend driver allows the kernel to
+         access network devices exported exported by a virtual
+         machine containing a physical network device driver. The
+         frontend driver is intended for unprivileged guest domains;
+         if you are compiling a kernel for a Xen guest, you almost
+         certainly want to enable this.
+
 config ISERIES_VETH
        tristate "iSeries Virtual Ethernet driver support"
        depends on PPC_ISERIES
index eb4167622a6abdacafaa9a042f2152be9aa36865..0e286ab8855a5202d925f684e092e9117ff1f6dd 100644 (file)
@@ -127,6 +127,8 @@ obj-$(CONFIG_PPPOL2TP) += pppox.o pppol2tp.o
 obj-$(CONFIG_SLIP) += slip.o
 obj-$(CONFIG_SLHC) += slhc.o
 
+obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o
+
 obj-$(CONFIG_DUMMY) += dummy.o
 obj-$(CONFIG_IFB) += ifb.o
 obj-$(CONFIG_MACVLAN) += macvlan.o
index 4a18b881ae9a9e97c235350b52f03fb28a51309b..fd1e156f1747fcfa63999928edeb644c038faf33 100644 (file)
@@ -75,6 +75,7 @@
 #include <linux/compiler.h>
 #include <linux/delay.h>
 #include <linux/mii.h>
+#include <linux/interrupt.h>
 #include <net/checksum.h>
 
 #include <asm/atomic.h>
index d23861c8658cdca4437826a51eca4fcb952979e5..a729da061bbb649ab51ee0d53775f2a536f049fc 100644 (file)
@@ -54,8 +54,8 @@
 
 #define DRV_MODULE_NAME                "bnx2"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "1.6.2"
-#define DRV_MODULE_RELDATE     "July 6, 2007"
+#define DRV_MODULE_VERSION     "1.6.3"
+#define DRV_MODULE_RELDATE     "July 16, 2007"
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -126,91 +126,102 @@ static struct pci_device_id bnx2_pci_tbl[] = {
 
 static struct flash_spec flash_table[] =
 {
+#define BUFFERED_FLAGS         (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)
+#define NONBUFFERED_FLAGS      (BNX2_NV_WREN)
        /* Slow EEPROM */
        {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
-        1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
+        BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
         SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
         "EEPROM - slow"},
        /* Expansion entry 0001 */
        {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
         "Entry 0001"},
        /* Saifun SA25F010 (non-buffered flash) */
        /* strap, cfg1, & write1 need updates */
        {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
         "Non-buffered flash (128kB)"},
        /* Saifun SA25F020 (non-buffered flash) */
        /* strap, cfg1, & write1 need updates */
        {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
         "Non-buffered flash (256kB)"},
        /* Expansion entry 0100 */
        {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
         "Entry 0100"},
        /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
        {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
-        0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
         ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
         "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
        /* Entry 0110: ST M45PE20 (non-buffered flash)*/
        {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
-        0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
         ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
         "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
        /* Saifun SA25F005 (non-buffered flash) */
        /* strap, cfg1, & write1 need updates */
        {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
         "Non-buffered flash (64kB)"},
        /* Fast EEPROM */
        {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
-        1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
+        BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
         SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
         "EEPROM - fast"},
        /* Expansion entry 1001 */
        {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
         "Entry 1001"},
        /* Expansion entry 1010 */
        {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
         "Entry 1010"},
        /* ATMEL AT45DB011B (buffered flash) */
        {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
-        1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+        BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
         BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
         "Buffered flash (128kB)"},
        /* Expansion entry 1100 */
        {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
         "Entry 1100"},
        /* Expansion entry 1101 */
        {0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
         "Entry 1101"},
        /* Ateml Expansion entry 1110 */
        {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
-        1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+        BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
         BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
         "Entry 1110 (Atmel)"},
        /* ATMEL AT45DB021B (buffered flash) */
        {0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
-        1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+        BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
         BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
         "Buffered flash (256kB)"},
 };
 
+static struct flash_spec flash_5709 = {
+       .flags          = BNX2_NV_BUFFERED,
+       .page_bits      = BCM5709_FLASH_PAGE_BITS,
+       .page_size      = BCM5709_FLASH_PAGE_SIZE,
+       .addr_mask      = BCM5709_FLASH_BYTE_ADDR_MASK,
+       .total_size     = BUFFERED_FLASH_TOTAL_SIZE*2,
+       .name           = "5709 Buffered flash (256kB)",
+};
+
 MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
 
 static inline u32 bnx2_tx_avail(struct bnx2 *bp)
@@ -3289,7 +3300,7 @@ bnx2_enable_nvram_write(struct bnx2 *bp)
        val = REG_RD(bp, BNX2_MISC_CFG);
        REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
 
-       if (!bp->flash_info->buffered) {
+       if (bp->flash_info->flags & BNX2_NV_WREN) {
                int j;
 
                REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
@@ -3349,7 +3360,7 @@ bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
        u32 cmd;
        int j;
 
-       if (bp->flash_info->buffered)
+       if (bp->flash_info->flags & BNX2_NV_BUFFERED)
                /* Buffered flash, no erase needed */
                return 0;
 
@@ -3392,8 +3403,8 @@ bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
        /* Build the command word. */
        cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
 
-       /* Calculate an offset of a buffered flash. */
-       if (bp->flash_info->buffered) {
+       /* Calculate an offset of a buffered flash, not needed for 5709. */
+       if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
                offset = ((offset / bp->flash_info->page_size) <<
                           bp->flash_info->page_bits) +
                          (offset % bp->flash_info->page_size);
@@ -3439,8 +3450,8 @@ bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
        /* Build the command word. */
        cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
 
-       /* Calculate an offset of a buffered flash. */
-       if (bp->flash_info->buffered) {
+       /* Calculate an offset of a buffered flash, not needed for 5709. */
+       if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
                offset = ((offset / bp->flash_info->page_size) <<
                          bp->flash_info->page_bits) +
                         (offset % bp->flash_info->page_size);
@@ -3478,15 +3489,19 @@ static int
 bnx2_init_nvram(struct bnx2 *bp)
 {
        u32 val;
-       int j, entry_count, rc;
+       int j, entry_count, rc = 0;
        struct flash_spec *flash;
 
+       if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+               bp->flash_info = &flash_5709;
+               goto get_flash_size;
+       }
+
        /* Determine the selected interface. */
        val = REG_RD(bp, BNX2_NVM_CFG1);
 
        entry_count = sizeof(flash_table) / sizeof(struct flash_spec);
 
-       rc = 0;
        if (val & 0x40000000) {
 
                /* Flash interface has been reconfigured */
@@ -3542,6 +3557,7 @@ bnx2_init_nvram(struct bnx2 *bp)
                return -ENODEV;
        }
 
+get_flash_size:
        val = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG2);
        val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
        if (val)
@@ -3706,7 +3722,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
                buf = align_buf;
        }
 
-       if (bp->flash_info->buffered == 0) {
+       if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
                flash_buffer = kmalloc(264, GFP_KERNEL);
                if (flash_buffer == NULL) {
                        rc = -ENOMEM;
@@ -3739,7 +3755,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
                bnx2_enable_nvram_access(bp);
 
                cmd_flags = BNX2_NVM_COMMAND_FIRST;
-               if (bp->flash_info->buffered == 0) {
+               if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
                        int j;
 
                        /* Read the whole page into the buffer
@@ -3767,7 +3783,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
                /* Loop to write back the buffer data from page_start to
                 * data_start */
                i = 0;
-               if (bp->flash_info->buffered == 0) {
+               if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
                        /* Erase the page */
                        if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
                                goto nvram_write_end;
@@ -3791,7 +3807,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
                /* Loop to write the new data from data_start to data_end */
                for (addr = data_start; addr < data_end; addr += 4, i += 4) {
                        if ((addr == page_end - 4) ||
-                               ((bp->flash_info->buffered) &&
+                               ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
                                 (addr == data_end - 4))) {
 
                                cmd_flags |= BNX2_NVM_COMMAND_LAST;
@@ -3808,7 +3824,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
 
                /* Loop to write back the buffer data from data_end
                 * to page_end */
-               if (bp->flash_info->buffered == 0) {
+               if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
                        for (addr = data_end; addr < page_end;
                                addr += 4, i += 4) {
 
@@ -4107,7 +4123,7 @@ bnx2_init_chip(struct bnx2 *bp)
        if (CHIP_NUM(bp) == CHIP_NUM_5708)
                REG_WR(bp, BNX2_HC_STATS_TICKS, 0);
        else
-               REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks & 0xffff00);
+               REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
        REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8);  /* 3ms */
 
        if (CHIP_ID(bp) == CHIP_ID_5706_A1)
@@ -4127,10 +4143,6 @@ bnx2_init_chip(struct bnx2 *bp)
 
        REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
 
-       if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
-           BNX2_PORT_FEATURE_ASF_ENABLED)
-               bp->flags |= ASF_ENABLE_FLAG;
-
        /* Initialize the receive filter. */
        bnx2_set_rx_mode(bp->dev);
 
@@ -5786,8 +5798,9 @@ bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
                if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
                        bp->stats_ticks = USEC_PER_SEC;
        }
-       if (bp->stats_ticks > 0xffff00) bp->stats_ticks = 0xffff00;
-       bp->stats_ticks &= 0xffff00;
+       if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
+               bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
+       bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
 
        if (netif_running(bp->dev)) {
                bnx2_netif_stop(bp);
@@ -6629,6 +6642,18 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
                if (i != 2)
                        bp->fw_version[j++] = '.';
        }
+       if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
+           BNX2_PORT_FEATURE_ASF_ENABLED) {
+               bp->flags |= ASF_ENABLE_FLAG;
+
+               for (i = 0; i < 30; i++) {
+                       reg = REG_RD_IND(bp, bp->shmem_base +
+                                            BNX2_BC_STATE_CONDITION);
+                       if (reg & BNX2_CONDITION_MFW_RUN_MASK)
+                               break;
+                       msleep(10);
+               }
+       }
        reg = REG_RD_IND(bp, bp->shmem_base + BNX2_BC_STATE_CONDITION);
        reg &= BNX2_CONDITION_MFW_RUN_MASK;
        if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
@@ -6672,7 +6697,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        bp->rx_ticks_int = 18;
        bp->rx_ticks = 18;
 
-       bp->stats_ticks = 1000000 & 0xffff00;
+       bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
 
        bp->timer_interval =  HZ;
        bp->current_interval =  HZ;
index d8cd1afeb23d2b386c8300eb60911cfe26c107f3..102adfe1e92327cba3e392a9b6dfe199ee67f5ae 100644 (file)
@@ -6433,6 +6433,11 @@ struct sw_bd {
 #define ST_MICRO_FLASH_PAGE_SIZE               256
 #define ST_MICRO_FLASH_BASE_TOTAL_SIZE         65536
 
+#define BCM5709_FLASH_PAGE_BITS                        8
+#define BCM5709_FLASH_PHY_PAGE_SIZE            (1 << BCM5709_FLASH_PAGE_BITS)
+#define BCM5709_FLASH_BYTE_ADDR_MASK           (BCM5709_FLASH_PHY_PAGE_SIZE-1)
+#define BCM5709_FLASH_PAGE_SIZE                        256
+
 #define NVRAM_TIMEOUT_COUNT                    30000
 
 
@@ -6449,7 +6454,10 @@ struct flash_spec {
        u32 config2;
        u32 config3;
        u32 write1;
-       u32 buffered;
+       u32 flags;
+#define BNX2_NV_BUFFERED       0x00000001
+#define BNX2_NV_TRANSLATE      0x00000002
+#define BNX2_NV_WREN           0x00000004
        u32 page_bits;
        u32 page_size;
        u32 addr_mask;
index 9afa47edfc5850e65309530f68e8dbab2f437656..3c54014acece68be4c3217a5565ec2f47eafd7f9 100644 (file)
@@ -2292,10 +2292,15 @@ static int eepro100_resume(struct pci_dev *pdev)
        struct net_device *dev = pci_get_drvdata (pdev);
        struct speedo_private *sp = netdev_priv(dev);
        void __iomem *ioaddr = sp->regs;
+       int rc;
 
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
-       pci_enable_device(pdev);
+
+       rc = pci_enable_device(pdev);
+       if (rc)
+               return rc;
+
        pci_set_master(pdev);
 
        if (!netif_running(dev))
index 84aa2117c0ee52b0f296f265317afbae773860d4..355c6cf3d11212870f16628ebd0e7dde489354da 100644 (file)
@@ -320,7 +320,7 @@ static int eppconfig(struct baycom_state *bc)
        sprintf(portarg, "%ld", bc->pdev->port->base);
        printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg);
 
-       return call_usermodehelper(eppconfig_path, argv, envp, 1);
+       return call_usermodehelper(eppconfig_path, argv, envp, UMH_WAIT_PROC);
 }
 
 /* ---------------------------------------------------------------------- */
index 3450051ae56b635c260f56d159314466eb0e5a0a..6bb48ba809649ca7e3ab940f42ba98ba1f9dc643 100644 (file)
@@ -671,7 +671,7 @@ static ssize_t natsemi_show_##_name(struct device *dev, \
 #define NATSEMI_CREATE_FILE(_dev, _name) \
          device_create_file(&_dev->dev, &dev_attr_##_name)
 #define NATSEMI_REMOVE_FILE(_dev, _name) \
-         device_create_file(&_dev->dev, &dev_attr_##_name)
+         device_remove_file(&_dev->dev, &dev_attr_##_name)
 
 NATSEMI_ATTR(dspcfg_workaround);
 
index 995c0a5d40662ec1c7c1238faeb9bc74384c29be..cfdeaf7aa163516ba5a56c19cdabe89f419fc64e 100644 (file)
@@ -669,10 +669,15 @@ static int ne2k_pci_suspend (struct pci_dev *pdev, pm_message_t state)
 static int ne2k_pci_resume (struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata (pdev);
+       int rc;
 
        pci_set_power_state(pdev, 0);
        pci_restore_state(pdev);
-       pci_enable_device(pdev);
+
+       rc = pci_enable_device(pdev);
+       if (rc)
+               return rc;
+
        NS8390_init(dev, 1);
        netif_device_attach(dev);
 
index 5891a0fbdc8b77645711e040c07070c4c6bddfb5..f87176055d0ee6430ddc1fff6b09dea781ebd5b2 100644 (file)
@@ -824,6 +824,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
        struct pppol2tp_session *session;
        struct pppol2tp_tunnel *tunnel;
        struct udphdr *uh;
+       unsigned int len;
 
        error = -ENOTCONN;
        if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
@@ -912,14 +913,15 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
        }
 
        /* Queue the packet to IP for output */
+       len = skb->len;
        error = ip_queue_xmit(skb, 1);
 
        /* Update stats */
        if (error >= 0) {
                tunnel->stats.tx_packets++;
-               tunnel->stats.tx_bytes += skb->len;
+               tunnel->stats.tx_bytes += len;
                session->stats.tx_packets++;
-               session->stats.tx_bytes += skb->len;
+               session->stats.tx_bytes += len;
        } else {
                tunnel->stats.tx_errors++;
                session->stats.tx_errors++;
@@ -958,6 +960,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
        __wsum csum = 0;
        struct sk_buff *skb2 = NULL;
        struct udphdr *uh;
+       unsigned int len;
 
        if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
                goto abort;
@@ -1046,18 +1049,25 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
                printk("\n");
        }
 
+       memset(&(IPCB(skb2)->opt), 0, sizeof(IPCB(skb2)->opt));
+       IPCB(skb2)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
+                              IPSKB_REROUTED);
+       nf_reset(skb2);
+
        /* Get routing info from the tunnel socket */
+       dst_release(skb2->dst);
        skb2->dst = sk_dst_get(sk_tun);
 
        /* Queue the packet to IP for output */
+       len = skb2->len;
        rc = ip_queue_xmit(skb2, 1);
 
        /* Update stats */
        if (rc >= 0) {
                tunnel->stats.tx_packets++;
-               tunnel->stats.tx_bytes += skb2->len;
+               tunnel->stats.tx_bytes += len;
                session->stats.tx_packets++;
-               session->stats.tx_bytes += skb2->len;
+               session->stats.tx_bytes += len;
        } else {
                tunnel->stats.tx_errors++;
                session->stats.tx_errors++;
index 982a9010c7a925e0b2e29b14cbe156d670c57d2b..bb6896ae31517c46b098dafcf1f35a28232112b3 100644 (file)
@@ -2338,7 +2338,7 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
 {
        struct skb_shared_info *info = skb_shinfo(skb);
        unsigned int cur_frag, entry;
-       struct TxDesc *txd;
+       struct TxDesc * uninitialized_var(txd);
 
        entry = tp->cur_tx;
        for (cur_frag = 0; cur_frag < info->nr_frags; cur_frag++) {
index 8a667c13faef39ef1bdaeb8ca25f7939a908dea9..b801e3b3a11a002907d602560e3abfec4cd5234a 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
+#include <linux/mutex.h>
 
 #include <asm/vio.h>
 #include <asm/ldc.h>
@@ -497,6 +498,8 @@ static void vnet_event(void *arg, int event)
                vio_link_state_change(vio, event);
                spin_unlock_irqrestore(&vio->lock, flags);
 
+               if (event == LDC_EVENT_RESET)
+                       vio_port_up(vio);
                return;
        }
 
@@ -875,6 +878,115 @@ err_out:
        return err;
 }
 
+static LIST_HEAD(vnet_list);
+static DEFINE_MUTEX(vnet_list_mutex);
+
+static struct vnet * __devinit vnet_new(const u64 *local_mac)
+{
+       struct net_device *dev;
+       struct vnet *vp;
+       int err, i;
+
+       dev = alloc_etherdev(sizeof(*vp));
+       if (!dev) {
+               printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       for (i = 0; i < ETH_ALEN; i++)
+               dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff;
+
+       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+       vp = netdev_priv(dev);
+
+       spin_lock_init(&vp->lock);
+       vp->dev = dev;
+
+       INIT_LIST_HEAD(&vp->port_list);
+       for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
+               INIT_HLIST_HEAD(&vp->port_hash[i]);
+       INIT_LIST_HEAD(&vp->list);
+       vp->local_mac = *local_mac;
+
+       dev->open = vnet_open;
+       dev->stop = vnet_close;
+       dev->set_multicast_list = vnet_set_rx_mode;
+       dev->set_mac_address = vnet_set_mac_addr;
+       dev->tx_timeout = vnet_tx_timeout;
+       dev->ethtool_ops = &vnet_ethtool_ops;
+       dev->watchdog_timeo = VNET_TX_TIMEOUT;
+       dev->change_mtu = vnet_change_mtu;
+       dev->hard_start_xmit = vnet_start_xmit;
+
+       err = register_netdev(dev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot register net device, "
+                      "aborting.\n");
+               goto err_out_free_dev;
+       }
+
+       printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
+
+       for (i = 0; i < 6; i++)
+               printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+
+       list_add(&vp->list, &vnet_list);
+
+       return vp;
+
+err_out_free_dev:
+       free_netdev(dev);
+
+       return ERR_PTR(err);
+}
+
+static struct vnet * __devinit vnet_find_or_create(const u64 *local_mac)
+{
+       struct vnet *iter, *vp;
+
+       mutex_lock(&vnet_list_mutex);
+       vp = NULL;
+       list_for_each_entry(iter, &vnet_list, list) {
+               if (iter->local_mac == *local_mac) {
+                       vp = iter;
+                       break;
+               }
+       }
+       if (!vp)
+               vp = vnet_new(local_mac);
+       mutex_unlock(&vnet_list_mutex);
+
+       return vp;
+}
+
+static const char *local_mac_prop = "local-mac-address";
+
+static struct vnet * __devinit vnet_find_parent(struct mdesc_handle *hp,
+                                               u64 port_node)
+{
+       const u64 *local_mac = NULL;
+       u64 a;
+
+       mdesc_for_each_arc(a, hp, port_node, MDESC_ARC_TYPE_BACK) {
+               u64 target = mdesc_arc_target(hp, a);
+               const char *name;
+
+               name = mdesc_get_property(hp, target, "name", NULL);
+               if (!name || strcmp(name, "network"))
+                       continue;
+
+               local_mac = mdesc_get_property(hp, target,
+                                              local_mac_prop, NULL);
+               if (local_mac)
+                       break;
+       }
+       if (!local_mac)
+               return ERR_PTR(-ENODEV);
+
+       return vnet_find_or_create(local_mac);
+}
+
 static struct ldc_channel_config vnet_ldc_cfg = {
        .event          = vnet_event,
        .mtu            = 64,
@@ -887,6 +999,14 @@ static struct vio_driver_ops vnet_vio_ops = {
        .handshake_complete     = vnet_handshake_complete,
 };
 
+static void print_version(void)
+{
+       static int version_printed;
+
+       if (version_printed++ == 0)
+               printk(KERN_INFO "%s", version);
+}
+
 const char *remote_macaddr_prop = "remote-mac-address";
 
 static int __devinit vnet_port_probe(struct vio_dev *vdev,
@@ -899,14 +1019,17 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
        const u64 *rmac;
        int len, i, err, switch_port;
 
-       vp = dev_get_drvdata(vdev->dev.parent);
-       if (!vp) {
-               printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
-               return -ENODEV;
-       }
+       print_version();
 
        hp = mdesc_grab();
 
+       vp = vnet_find_parent(hp, vdev->mp);
+       if (IS_ERR(vp)) {
+               printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
+               err = PTR_ERR(vp);
+               goto err_out_put_mdesc;
+       }
+
        rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len);
        err = -ENODEV;
        if (!rmac) {
@@ -1025,139 +1148,14 @@ static struct vio_driver vnet_port_driver = {
        }
 };
 
-const char *local_mac_prop = "local-mac-address";
-
-static int __devinit vnet_probe(struct vio_dev *vdev,
-                               const struct vio_device_id *id)
-{
-       static int vnet_version_printed;
-       struct mdesc_handle *hp;
-       struct net_device *dev;
-       struct vnet *vp;
-       const u64 *mac;
-       int err, i, len;
-
-       if (vnet_version_printed++ == 0)
-               printk(KERN_INFO "%s", version);
-
-       hp = mdesc_grab();
-
-       mac = mdesc_get_property(hp, vdev->mp, local_mac_prop, &len);
-       if (!mac) {
-               printk(KERN_ERR PFX "vnet lacks %s property.\n",
-                      local_mac_prop);
-               err = -ENODEV;
-               goto err_out;
-       }
-
-       dev = alloc_etherdev(sizeof(*vp));
-       if (!dev) {
-               printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
-               err = -ENOMEM;
-               goto err_out;
-       }
-
-       for (i = 0; i < ETH_ALEN; i++)
-               dev->dev_addr[i] = (*mac >> (5 - i) * 8) & 0xff;
-
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-
-       SET_NETDEV_DEV(dev, &vdev->dev);
-
-       vp = netdev_priv(dev);
-
-       spin_lock_init(&vp->lock);
-       vp->dev = dev;
-       vp->vdev = vdev;
-
-       INIT_LIST_HEAD(&vp->port_list);
-       for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
-               INIT_HLIST_HEAD(&vp->port_hash[i]);
-
-       dev->open = vnet_open;
-       dev->stop = vnet_close;
-       dev->set_multicast_list = vnet_set_rx_mode;
-       dev->set_mac_address = vnet_set_mac_addr;
-       dev->tx_timeout = vnet_tx_timeout;
-       dev->ethtool_ops = &vnet_ethtool_ops;
-       dev->watchdog_timeo = VNET_TX_TIMEOUT;
-       dev->change_mtu = vnet_change_mtu;
-       dev->hard_start_xmit = vnet_start_xmit;
-
-       err = register_netdev(dev);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot register net device, "
-                      "aborting.\n");
-               goto err_out_free_dev;
-       }
-
-       printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
-
-       for (i = 0; i < 6; i++)
-               printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
-
-       dev_set_drvdata(&vdev->dev, vp);
-
-       mdesc_release(hp);
-
-       return 0;
-
-err_out_free_dev:
-       free_netdev(dev);
-
-err_out:
-       mdesc_release(hp);
-       return err;
-}
-
-static int vnet_remove(struct vio_dev *vdev)
-{
-
-       struct vnet *vp = dev_get_drvdata(&vdev->dev);
-
-       if (vp) {
-               /* XXX unregister port, or at least check XXX */
-               unregister_netdevice(vp->dev);
-               dev_set_drvdata(&vdev->dev, NULL);
-       }
-       return 0;
-}
-
-static struct vio_device_id vnet_match[] = {
-       {
-               .type = "network",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(vio, vnet_match);
-
-static struct vio_driver vnet_driver = {
-       .id_table       = vnet_match,
-       .probe          = vnet_probe,
-       .remove         = vnet_remove,
-       .driver         = {
-               .name   = "vnet",
-               .owner  = THIS_MODULE,
-       }
-};
-
 static int __init vnet_init(void)
 {
-       int err = vio_register_driver(&vnet_driver);
-
-       if (!err) {
-               err = vio_register_driver(&vnet_port_driver);
-               if (err)
-                       vio_unregister_driver(&vnet_driver);
-       }
-
-       return err;
+       return vio_register_driver(&vnet_port_driver);
 }
 
 static void __exit vnet_exit(void)
 {
        vio_unregister_driver(&vnet_port_driver);
-       vio_unregister_driver(&vnet_driver);
 }
 
 module_init(vnet_init);
index 1c887302d46dd4e76474ffd850768073243ce86e..7d3a0cac727b5a06bdda3dd4932c76df01760c85 100644 (file)
@@ -60,11 +60,13 @@ struct vnet {
        struct net_device       *dev;
 
        u32                     msg_enable;
-       struct vio_dev          *vdev;
 
        struct list_head        port_list;
 
        struct hlist_head       port_hash[VNET_PORT_HASH_SIZE];
+
+       struct list_head        list;
+       u64                     local_mac;
 };
 
 #endif /* _SUNVNET_H */
index 58d7e5d452fa7fdae1979ab96aac45213da7d026..f83bb5cb0d3d84e42e428365ee8e98da26369d80 100644 (file)
@@ -3692,7 +3692,6 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size,
         __u16 rcode, correlator;
         int err = 0;
         __u8 xframe = 1;
-        __u16 tx_fstatus;
 
         rmf->vl = SWAP_BYTES(rmf->vl);
         if(rx_status & FCB_RX_STATUS_DA_MATCHED)
@@ -3783,7 +3782,9 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size,
                                 }
                                 break;
 
-                        case TX_FORWARD:
+                        case TX_FORWARD: {
+                               __u16 uninitialized_var(tx_fstatus);
+
                                 if((rcode = smctr_rcv_tx_forward(dev, rmf))
                                         != POSITIVE_ACK)
                                 {
@@ -3811,6 +3812,7 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size,
                                         }
                                 }
                                 break;
+                       }
 
                         /* Received MAC Frames Processed by CRS/REM/RPS. */
                         case RSP:
index ec1c556a47caf65c69b81504f7a1207e7e52f013..5d8c78ee2cd9648e186f0efbdd4d1065b2715ef8 100644 (file)
@@ -2833,6 +2833,8 @@ static int clock_rate_calc(uclong rate, uclong clock, int *br_io)
        int br, tc;
        int br_pwr, error;
 
+       *br_io = 0;
+
        if (rate == 0)
                return (0);
 
index 35eded7ffb2dda831ddeea27e78c58dc37708e6d..1cc18e787a65e4c39dc8e0e1fff2eed027d1ab6c 100644 (file)
@@ -595,8 +595,8 @@ recv_frame( struct net_device  *dev )
 
        u32  crc = CRC32_INITIAL;
 
-       unsigned  framelen, frameno, ack;
-       unsigned  is_first, frame_ok;
+       unsigned  framelen = 0, frameno, ack;
+       unsigned  is_first, frame_ok = 0;
 
        if( check_fhdr( ioaddr, &framelen, &frameno, &ack, &is_first, &crc ) ) {
                frame_ok = framelen > 4
@@ -604,8 +604,7 @@ recv_frame( struct net_device  *dev )
                        :  skip_tail( ioaddr, framelen, crc );
                if( frame_ok )
                        interpret_ack( dev, ack );
-       } else
-               frame_ok = 0;
+       }
 
        outb( inb( ioaddr + CSR0 ) ^ CT_ZER, ioaddr + CSR0 );
        if( frame_ok ) {
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
new file mode 100644 (file)
index 0000000..489f69c
--- /dev/null
@@ -0,0 +1,1863 @@
+/*
+ * Virtual network driver for conversing with remote driver backends.
+ *
+ * Copyright (c) 2002-2005, K A Fraser
+ * Copyright (c) 2005, XenSource Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/if_ether.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/moduleparam.h>
+#include <linux/mm.h>
+#include <net/ip.h>
+
+#include <xen/xenbus.h>
+#include <xen/events.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+
+#include <xen/interface/io/netif.h>
+#include <xen/interface/memory.h>
+#include <xen/interface/grant_table.h>
+
+static struct ethtool_ops xennet_ethtool_ops;
+
+struct netfront_cb {
+       struct page *page;
+       unsigned offset;
+};
+
+#define NETFRONT_SKB_CB(skb)   ((struct netfront_cb *)((skb)->cb))
+
+#define RX_COPY_THRESHOLD 256
+
+#define GRANT_INVALID_REF      0
+
+#define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
+#define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
+#define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
+
+struct netfront_info {
+       struct list_head list;
+       struct net_device *netdev;
+
+       struct net_device_stats stats;
+
+       struct xen_netif_tx_front_ring tx;
+       struct xen_netif_rx_front_ring rx;
+
+       spinlock_t   tx_lock;
+       spinlock_t   rx_lock;
+
+       unsigned int evtchn;
+
+       /* Receive-ring batched refills. */
+#define RX_MIN_TARGET 8
+#define RX_DFL_MIN_TARGET 64
+#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
+       unsigned rx_min_target, rx_max_target, rx_target;
+       struct sk_buff_head rx_batch;
+
+       struct timer_list rx_refill_timer;
+
+       /*
+        * {tx,rx}_skbs store outstanding skbuffs. Free tx_skb entries
+        * are linked from tx_skb_freelist through skb_entry.link.
+        *
+        *  NB. Freelist index entries are always going to be less than
+        *  PAGE_OFFSET, whereas pointers to skbs will always be equal or
+        *  greater than PAGE_OFFSET: we use this property to distinguish
+        *  them.
+        */
+       union skb_entry {
+               struct sk_buff *skb;
+               unsigned link;
+       } tx_skbs[NET_TX_RING_SIZE];
+       grant_ref_t gref_tx_head;
+       grant_ref_t grant_tx_ref[NET_TX_RING_SIZE];
+       unsigned tx_skb_freelist;
+
+       struct sk_buff *rx_skbs[NET_RX_RING_SIZE];
+       grant_ref_t gref_rx_head;
+       grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
+
+       struct xenbus_device *xbdev;
+       int tx_ring_ref;
+       int rx_ring_ref;
+
+       unsigned long rx_pfn_array[NET_RX_RING_SIZE];
+       struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1];
+       struct mmu_update rx_mmu[NET_RX_RING_SIZE];
+};
+
+struct netfront_rx_info {
+       struct xen_netif_rx_response rx;
+       struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
+};
+
+/*
+ * Access macros for acquiring freeing slots in tx_skbs[].
+ */
+
+static void add_id_to_freelist(unsigned *head, union skb_entry *list,
+                              unsigned short id)
+{
+       list[id].link = *head;
+       *head = id;
+}
+
+static unsigned short get_id_from_freelist(unsigned *head,
+                                          union skb_entry *list)
+{
+       unsigned int id = *head;
+       *head = list[id].link;
+       return id;
+}
+
+static int xennet_rxidx(RING_IDX idx)
+{
+       return idx & (NET_RX_RING_SIZE - 1);
+}
+
+static struct sk_buff *xennet_get_rx_skb(struct netfront_info *np,
+                                        RING_IDX ri)
+{
+       int i = xennet_rxidx(ri);
+       struct sk_buff *skb = np->rx_skbs[i];
+       np->rx_skbs[i] = NULL;
+       return skb;
+}
+
+static grant_ref_t xennet_get_rx_ref(struct netfront_info *np,
+                                           RING_IDX ri)
+{
+       int i = xennet_rxidx(ri);
+       grant_ref_t ref = np->grant_rx_ref[i];
+       np->grant_rx_ref[i] = GRANT_INVALID_REF;
+       return ref;
+}
+
+#ifdef CONFIG_SYSFS
+static int xennet_sysfs_addif(struct net_device *netdev);
+static void xennet_sysfs_delif(struct net_device *netdev);
+#else /* !CONFIG_SYSFS */
+#define xennet_sysfs_addif(dev) (0)
+#define xennet_sysfs_delif(dev) do { } while (0)
+#endif
+
+static int xennet_can_sg(struct net_device *dev)
+{
+       return dev->features & NETIF_F_SG;
+}
+
+
+static void rx_refill_timeout(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       netif_rx_schedule(dev);
+}
+
+static int netfront_tx_slot_available(struct netfront_info *np)
+{
+       return ((np->tx.req_prod_pvt - np->tx.rsp_cons) <
+               (TX_MAX_TARGET - MAX_SKB_FRAGS - 2));
+}
+
+static void xennet_maybe_wake_tx(struct net_device *dev)
+{
+       struct netfront_info *np = netdev_priv(dev);
+
+       if (unlikely(netif_queue_stopped(dev)) &&
+           netfront_tx_slot_available(np) &&
+           likely(netif_running(dev)))
+               netif_wake_queue(dev);
+}
+
+static void xennet_alloc_rx_buffers(struct net_device *dev)
+{
+       unsigned short id;
+       struct netfront_info *np = netdev_priv(dev);
+       struct sk_buff *skb;
+       struct page *page;
+       int i, batch_target, notify;
+       RING_IDX req_prod = np->rx.req_prod_pvt;
+       struct xen_memory_reservation reservation;
+       grant_ref_t ref;
+       unsigned long pfn;
+       void *vaddr;
+       int nr_flips;
+       struct xen_netif_rx_request *req;
+
+       if (unlikely(!netif_carrier_ok(dev)))
+               return;
+
+       /*
+        * Allocate skbuffs greedily, even though we batch updates to the
+        * receive ring. This creates a less bursty demand on the memory
+        * allocator, so should reduce the chance of failed allocation requests
+        * both for ourself and for other kernel subsystems.
+        */
+       batch_target = np->rx_target - (req_prod - np->rx.rsp_cons);
+       for (i = skb_queue_len(&np->rx_batch); i < batch_target; i++) {
+               skb = __netdev_alloc_skb(dev, RX_COPY_THRESHOLD,
+                                        GFP_ATOMIC | __GFP_NOWARN);
+               if (unlikely(!skb))
+                       goto no_skb;
+
+               page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
+               if (!page) {
+                       kfree_skb(skb);
+no_skb:
+                       /* Any skbuffs queued for refill? Force them out. */
+                       if (i != 0)
+                               goto refill;
+                       /* Could not allocate any skbuffs. Try again later. */
+                       mod_timer(&np->rx_refill_timer,
+                                 jiffies + (HZ/10));
+                       break;
+               }
+
+               skb_shinfo(skb)->frags[0].page = page;
+               skb_shinfo(skb)->nr_frags = 1;
+               __skb_queue_tail(&np->rx_batch, skb);
+       }
+
+       /* Is the batch large enough to be worthwhile? */
+       if (i < (np->rx_target/2)) {
+               if (req_prod > np->rx.sring->req_prod)
+                       goto push;
+               return;
+       }
+
+       /* Adjust our fill target if we risked running out of buffers. */
+       if (((req_prod - np->rx.sring->rsp_prod) < (np->rx_target / 4)) &&
+           ((np->rx_target *= 2) > np->rx_max_target))
+               np->rx_target = np->rx_max_target;
+
+ refill:
+       for (nr_flips = i = 0; ; i++) {
+               skb = __skb_dequeue(&np->rx_batch);
+               if (skb == NULL)
+                       break;
+
+               skb->dev = dev;
+
+               id = xennet_rxidx(req_prod + i);
+
+               BUG_ON(np->rx_skbs[id]);
+               np->rx_skbs[id] = skb;
+
+               ref = gnttab_claim_grant_reference(&np->gref_rx_head);
+               BUG_ON((signed short)ref < 0);
+               np->grant_rx_ref[id] = ref;
+
+               pfn = page_to_pfn(skb_shinfo(skb)->frags[0].page);
+               vaddr = page_address(skb_shinfo(skb)->frags[0].page);
+
+               req = RING_GET_REQUEST(&np->rx, req_prod + i);
+               gnttab_grant_foreign_access_ref(ref,
+                                               np->xbdev->otherend_id,
+                                               pfn_to_mfn(pfn),
+                                               0);
+
+               req->id = id;
+               req->gref = ref;
+       }
+
+       if (nr_flips != 0) {
+               reservation.extent_start = np->rx_pfn_array;
+               reservation.nr_extents   = nr_flips;
+               reservation.extent_order = 0;
+               reservation.address_bits = 0;
+               reservation.domid        = DOMID_SELF;
+
+               if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+                       /* After all PTEs have been zapped, flush the TLB. */
+                       np->rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] =
+                               UVMF_TLB_FLUSH|UVMF_ALL;
+
+                       /* Give away a batch of pages. */
+                       np->rx_mcl[i].op = __HYPERVISOR_memory_op;
+                       np->rx_mcl[i].args[0] = XENMEM_decrease_reservation;
+                       np->rx_mcl[i].args[1] = (unsigned long)&reservation;
+
+                       /* Zap PTEs and give away pages in one big
+                        * multicall. */
+                       (void)HYPERVISOR_multicall(np->rx_mcl, i+1);
+
+                       /* Check return status of HYPERVISOR_memory_op(). */
+                       if (unlikely(np->rx_mcl[i].result != i))
+                               panic("Unable to reduce memory reservation\n");
+               } else {
+                       if (HYPERVISOR_memory_op(XENMEM_decrease_reservation,
+                                                &reservation) != i)
+                               panic("Unable to reduce memory reservation\n");
+               }
+       } else {
+               wmb();          /* barrier so backend seens requests */
+       }
+
+       /* Above is a suitable barrier to ensure backend will see requests. */
+       np->rx.req_prod_pvt = req_prod + i;
+ push:
+       RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
+       if (notify)
+               notify_remote_via_irq(np->netdev->irq);
+}
+
+static int xennet_open(struct net_device *dev)
+{
+       struct netfront_info *np = netdev_priv(dev);
+
+       memset(&np->stats, 0, sizeof(np->stats));
+
+       spin_lock_bh(&np->rx_lock);
+       if (netif_carrier_ok(dev)) {
+               xennet_alloc_rx_buffers(dev);
+               np->rx.sring->rsp_event = np->rx.rsp_cons + 1;
+               if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
+                       netif_rx_schedule(dev);
+       }
+       spin_unlock_bh(&np->rx_lock);
+
+       xennet_maybe_wake_tx(dev);
+
+       return 0;
+}
+
+static void xennet_tx_buf_gc(struct net_device *dev)
+{
+       RING_IDX cons, prod;
+       unsigned short id;
+       struct netfront_info *np = netdev_priv(dev);
+       struct sk_buff *skb;
+
+       BUG_ON(!netif_carrier_ok(dev));
+
+       do {
+               prod = np->tx.sring->rsp_prod;
+               rmb(); /* Ensure we see responses up to 'rp'. */
+
+               for (cons = np->tx.rsp_cons; cons != prod; cons++) {
+                       struct xen_netif_tx_response *txrsp;
+
+                       txrsp = RING_GET_RESPONSE(&np->tx, cons);
+                       if (txrsp->status == NETIF_RSP_NULL)
+                               continue;
+
+                       id  = txrsp->id;
+                       skb = np->tx_skbs[id].skb;
+                       if (unlikely(gnttab_query_foreign_access(
+                               np->grant_tx_ref[id]) != 0)) {
+                               printk(KERN_ALERT "xennet_tx_buf_gc: warning "
+                                      "-- grant still in use by backend "
+                                      "domain.\n");
+                               BUG();
+                       }
+                       gnttab_end_foreign_access_ref(
+                               np->grant_tx_ref[id], GNTMAP_readonly);
+                       gnttab_release_grant_reference(
+                               &np->gref_tx_head, np->grant_tx_ref[id]);
+                       np->grant_tx_ref[id] = GRANT_INVALID_REF;
+                       add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, id);
+                       dev_kfree_skb_irq(skb);
+               }
+
+               np->tx.rsp_cons = prod;
+
+               /*
+                * Set a new event, then check for race with update of tx_cons.
+                * Note that it is essential to schedule a callback, no matter
+                * how few buffers are pending. Even if there is space in the
+                * transmit ring, higher layers may be blocked because too much
+                * data is outstanding: in such cases notification from Xen is
+                * likely to be the only kick that we'll get.
+                */
+               np->tx.sring->rsp_event =
+                       prod + ((np->tx.sring->req_prod - prod) >> 1) + 1;
+               mb();           /* update shared area */
+       } while ((cons == prod) && (prod != np->tx.sring->rsp_prod));
+
+       xennet_maybe_wake_tx(dev);
+}
+
+static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev,
+                             struct xen_netif_tx_request *tx)
+{
+       struct netfront_info *np = netdev_priv(dev);
+       char *data = skb->data;
+       unsigned long mfn;
+       RING_IDX prod = np->tx.req_prod_pvt;
+       int frags = skb_shinfo(skb)->nr_frags;
+       unsigned int offset = offset_in_page(data);
+       unsigned int len = skb_headlen(skb);
+       unsigned int id;
+       grant_ref_t ref;
+       int i;
+
+       /* While the header overlaps a page boundary (including being
+          larger than a page), split it it into page-sized chunks. */
+       while (len > PAGE_SIZE - offset) {
+               tx->size = PAGE_SIZE - offset;
+               tx->flags |= NETTXF_more_data;
+               len -= tx->size;
+               data += tx->size;
+               offset = 0;
+
+               id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+               np->tx_skbs[id].skb = skb_get(skb);
+               tx = RING_GET_REQUEST(&np->tx, prod++);
+               tx->id = id;
+               ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+               BUG_ON((signed short)ref < 0);
+
+               mfn = virt_to_mfn(data);
+               gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
+                                               mfn, GNTMAP_readonly);
+
+               tx->gref = np->grant_tx_ref[id] = ref;
+               tx->offset = offset;
+               tx->size = len;
+               tx->flags = 0;
+       }
+
+       /* Grant backend access to each skb fragment page. */
+       for (i = 0; i < frags; i++) {
+               skb_frag_t *frag = skb_shinfo(skb)->frags + i;
+
+               tx->flags |= NETTXF_more_data;
+
+               id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+               np->tx_skbs[id].skb = skb_get(skb);
+               tx = RING_GET_REQUEST(&np->tx, prod++);
+               tx->id = id;
+               ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+               BUG_ON((signed short)ref < 0);
+
+               mfn = pfn_to_mfn(page_to_pfn(frag->page));
+               gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
+                                               mfn, GNTMAP_readonly);
+
+               tx->gref = np->grant_tx_ref[id] = ref;
+               tx->offset = frag->page_offset;
+               tx->size = frag->size;
+               tx->flags = 0;
+       }
+
+       np->tx.req_prod_pvt = prod;
+}
+
+static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       unsigned short id;
+       struct netfront_info *np = netdev_priv(dev);
+       struct xen_netif_tx_request *tx;
+       struct xen_netif_extra_info *extra;
+       char *data = skb->data;
+       RING_IDX i;
+       grant_ref_t ref;
+       unsigned long mfn;
+       int notify;
+       int frags = skb_shinfo(skb)->nr_frags;
+       unsigned int offset = offset_in_page(data);
+       unsigned int len = skb_headlen(skb);
+
+       frags += (offset + len + PAGE_SIZE - 1) / PAGE_SIZE;
+       if (unlikely(frags > MAX_SKB_FRAGS + 1)) {
+               printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n",
+                      frags);
+               dump_stack();
+               goto drop;
+       }
+
+       spin_lock_irq(&np->tx_lock);
+
+       if (unlikely(!netif_carrier_ok(dev) ||
+                    (frags > 1 && !xennet_can_sg(dev)) ||
+                    netif_needs_gso(dev, skb))) {
+               spin_unlock_irq(&np->tx_lock);
+               goto drop;
+       }
+
+       i = np->tx.req_prod_pvt;
+
+       id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+       np->tx_skbs[id].skb = skb;
+
+       tx = RING_GET_REQUEST(&np->tx, i);
+
+       tx->id   = id;
+       ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+       BUG_ON((signed short)ref < 0);
+       mfn = virt_to_mfn(data);
+       gnttab_grant_foreign_access_ref(
+               ref, np->xbdev->otherend_id, mfn, GNTMAP_readonly);
+       tx->gref = np->grant_tx_ref[id] = ref;
+       tx->offset = offset;
+       tx->size = len;
+       extra = NULL;
+
+       tx->flags = 0;
+       if (skb->ip_summed == CHECKSUM_PARTIAL)
+               /* local packet? */
+               tx->flags |= NETTXF_csum_blank | NETTXF_data_validated;
+       else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+               /* remote but checksummed. */
+               tx->flags |= NETTXF_data_validated;
+
+       if (skb_shinfo(skb)->gso_size) {
+               struct xen_netif_extra_info *gso;
+
+               gso = (struct xen_netif_extra_info *)
+                       RING_GET_REQUEST(&np->tx, ++i);
+
+               if (extra)
+                       extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE;
+               else
+                       tx->flags |= NETTXF_extra_info;
+
+               gso->u.gso.size = skb_shinfo(skb)->gso_size;
+               gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
+               gso->u.gso.pad = 0;
+               gso->u.gso.features = 0;
+
+               gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
+               gso->flags = 0;
+               extra = gso;
+       }
+
+       np->tx.req_prod_pvt = i + 1;
+
+       xennet_make_frags(skb, dev, tx);
+       tx->size = skb->len;
+
+       RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->tx, notify);
+       if (notify)
+               notify_remote_via_irq(np->netdev->irq);
+
+       xennet_tx_buf_gc(dev);
+
+       if (!netfront_tx_slot_available(np))
+               netif_stop_queue(dev);
+
+       spin_unlock_irq(&np->tx_lock);
+
+       np->stats.tx_bytes += skb->len;
+       np->stats.tx_packets++;
+
+       return 0;
+
+ drop:
+       np->stats.tx_dropped++;
+       dev_kfree_skb(skb);
+       return 0;
+}
+
+static int xennet_close(struct net_device *dev)
+{
+       struct netfront_info *np = netdev_priv(dev);
+       netif_stop_queue(np->netdev);
+       return 0;
+}
+
+static struct net_device_stats *xennet_get_stats(struct net_device *dev)
+{
+       struct netfront_info *np = netdev_priv(dev);
+       return &np->stats;
+}
+
+static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb,
+                               grant_ref_t ref)
+{
+       int new = xennet_rxidx(np->rx.req_prod_pvt);
+
+       BUG_ON(np->rx_skbs[new]);
+       np->rx_skbs[new] = skb;
+       np->grant_rx_ref[new] = ref;
+       RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new;
+       RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref;
+       np->rx.req_prod_pvt++;
+}
+
+static int xennet_get_extras(struct netfront_info *np,
+                            struct xen_netif_extra_info *extras,
+                            RING_IDX rp)
+
+{
+       struct xen_netif_extra_info *extra;
+       struct device *dev = &np->netdev->dev;
+       RING_IDX cons = np->rx.rsp_cons;
+       int err = 0;
+
+       do {
+               struct sk_buff *skb;
+               grant_ref_t ref;
+
+               if (unlikely(cons + 1 == rp)) {
+                       if (net_ratelimit())
+                               dev_warn(dev, "Missing extra info\n");
+                       err = -EBADR;
+                       break;
+               }
+
+               extra = (struct xen_netif_extra_info *)
+                       RING_GET_RESPONSE(&np->rx, ++cons);
+
+               if (unlikely(!extra->type ||
+                            extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
+                       if (net_ratelimit())
+                               dev_warn(dev, "Invalid extra type: %d\n",
+                                       extra->type);
+                       err = -EINVAL;
+               } else {
+                       memcpy(&extras[extra->type - 1], extra,
+                              sizeof(*extra));
+               }
+
+               skb = xennet_get_rx_skb(np, cons);
+               ref = xennet_get_rx_ref(np, cons);
+               xennet_move_rx_slot(np, skb, ref);
+       } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE);
+
+       np->rx.rsp_cons = cons;
+       return err;
+}
+
+static int xennet_get_responses(struct netfront_info *np,
+                               struct netfront_rx_info *rinfo, RING_IDX rp,
+                               struct sk_buff_head *list)
+{
+       struct xen_netif_rx_response *rx = &rinfo->rx;
+       struct xen_netif_extra_info *extras = rinfo->extras;
+       struct device *dev = &np->netdev->dev;
+       RING_IDX cons = np->rx.rsp_cons;
+       struct sk_buff *skb = xennet_get_rx_skb(np, cons);
+       grant_ref_t ref = xennet_get_rx_ref(np, cons);
+       int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD);
+       int frags = 1;
+       int err = 0;
+       unsigned long ret;
+
+       if (rx->flags & NETRXF_extra_info) {
+               err = xennet_get_extras(np, extras, rp);
+               cons = np->rx.rsp_cons;
+       }
+
+       for (;;) {
+               if (unlikely(rx->status < 0 ||
+                            rx->offset + rx->status > PAGE_SIZE)) {
+                       if (net_ratelimit())
+                               dev_warn(dev, "rx->offset: %x, size: %u\n",
+                                        rx->offset, rx->status);
+                       xennet_move_rx_slot(np, skb, ref);
+                       err = -EINVAL;
+                       goto next;
+               }
+
+               /*
+                * This definitely indicates a bug, either in this driver or in
+                * the backend driver. In future this should flag the bad
+                * situation to the system controller to reboot the backed.
+                */
+               if (ref == GRANT_INVALID_REF) {
+                       if (net_ratelimit())
+                               dev_warn(dev, "Bad rx response id %d.\n",
+                                        rx->id);
+                       err = -EINVAL;
+                       goto next;
+               }
+
+               ret = gnttab_end_foreign_access_ref(ref, 0);
+               BUG_ON(!ret);
+
+               gnttab_release_grant_reference(&np->gref_rx_head, ref);
+
+               __skb_queue_tail(list, skb);
+
+next:
+               if (!(rx->flags & NETRXF_more_data))
+                       break;
+
+               if (cons + frags == rp) {
+                       if (net_ratelimit())
+                               dev_warn(dev, "Need more frags\n");
+                       err = -ENOENT;
+                       break;
+               }
+
+               rx = RING_GET_RESPONSE(&np->rx, cons + frags);
+               skb = xennet_get_rx_skb(np, cons + frags);
+               ref = xennet_get_rx_ref(np, cons + frags);
+               frags++;
+       }
+
+       if (unlikely(frags > max)) {
+               if (net_ratelimit())
+                       dev_warn(dev, "Too many frags\n");
+               err = -E2BIG;
+       }
+
+       if (unlikely(err))
+               np->rx.rsp_cons = cons + frags;
+
+       return err;
+}
+
+static int xennet_set_skb_gso(struct sk_buff *skb,
+                             struct xen_netif_extra_info *gso)
+{
+       if (!gso->u.gso.size) {
+               if (net_ratelimit())
+                       printk(KERN_WARNING "GSO size must not be zero.\n");
+               return -EINVAL;
+       }
+
+       /* Currently only TCPv4 S.O. is supported. */
+       if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
+               if (net_ratelimit())
+                       printk(KERN_WARNING "Bad GSO type %d.\n", gso->u.gso.type);
+               return -EINVAL;
+       }
+
+       skb_shinfo(skb)->gso_size = gso->u.gso.size;
+       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+
+       /* Header must be checked, and gso_segs computed. */
+       skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
+       skb_shinfo(skb)->gso_segs = 0;
+
+       return 0;
+}
+
+static RING_IDX xennet_fill_frags(struct netfront_info *np,
+                                 struct sk_buff *skb,
+                                 struct sk_buff_head *list)
+{
+       struct skb_shared_info *shinfo = skb_shinfo(skb);
+       int nr_frags = shinfo->nr_frags;
+       RING_IDX cons = np->rx.rsp_cons;
+       skb_frag_t *frag = shinfo->frags + nr_frags;
+       struct sk_buff *nskb;
+
+       while ((nskb = __skb_dequeue(list))) {
+               struct xen_netif_rx_response *rx =
+                       RING_GET_RESPONSE(&np->rx, ++cons);
+
+               frag->page = skb_shinfo(nskb)->frags[0].page;
+               frag->page_offset = rx->offset;
+               frag->size = rx->status;
+
+               skb->data_len += rx->status;
+
+               skb_shinfo(nskb)->nr_frags = 0;
+               kfree_skb(nskb);
+
+               frag++;
+               nr_frags++;
+       }
+
+       shinfo->nr_frags = nr_frags;
+       return cons;
+}
+
+static int skb_checksum_setup(struct sk_buff *skb)
+{
+       struct iphdr *iph;
+       unsigned char *th;
+       int err = -EPROTO;
+
+       if (skb->protocol != htons(ETH_P_IP))
+               goto out;
+
+       iph = (void *)skb->data;
+       th = skb->data + 4 * iph->ihl;
+       if (th >= skb_tail_pointer(skb))
+               goto out;
+
+       skb->csum_start = th - skb->head;
+       switch (iph->protocol) {
+       case IPPROTO_TCP:
+               skb->csum_offset = offsetof(struct tcphdr, check);
+               break;
+       case IPPROTO_UDP:
+               skb->csum_offset = offsetof(struct udphdr, check);
+               break;
+       default:
+               if (net_ratelimit())
+                       printk(KERN_ERR "Attempting to checksum a non-"
+                              "TCP/UDP packet, dropping a protocol"
+                              " %d packet", iph->protocol);
+               goto out;
+       }
+
+       if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb))
+               goto out;
+
+       err = 0;
+
+out:
+       return err;
+}
+
+static int handle_incoming_queue(struct net_device *dev,
+                                 struct sk_buff_head *rxq)
+{
+       struct netfront_info *np = netdev_priv(dev);
+       int packets_dropped = 0;
+       struct sk_buff *skb;
+
+       while ((skb = __skb_dequeue(rxq)) != NULL) {
+               struct page *page = NETFRONT_SKB_CB(skb)->page;
+               void *vaddr = page_address(page);
+               unsigned offset = NETFRONT_SKB_CB(skb)->offset;
+
+               memcpy(skb->data, vaddr + offset,
+                      skb_headlen(skb));
+
+               if (page != skb_shinfo(skb)->frags[0].page)
+                       __free_page(page);
+
+               /* Ethernet work: Delayed to here as it peeks the header. */
+               skb->protocol = eth_type_trans(skb, dev);
+
+               if (skb->ip_summed == CHECKSUM_PARTIAL) {
+                       if (skb_checksum_setup(skb)) {
+                               kfree_skb(skb);
+                               packets_dropped++;
+                               np->stats.rx_errors++;
+                               continue;
+                       }
+               }
+
+               np->stats.rx_packets++;
+               np->stats.rx_bytes += skb->len;
+
+               /* Pass it up. */
+               netif_receive_skb(skb);
+               dev->last_rx = jiffies;
+       }
+
+       return packets_dropped;
+}
+
+static int xennet_poll(struct net_device *dev, int *pbudget)
+{
+       struct netfront_info *np = netdev_priv(dev);
+       struct sk_buff *skb;
+       struct netfront_rx_info rinfo;
+       struct xen_netif_rx_response *rx = &rinfo.rx;
+       struct xen_netif_extra_info *extras = rinfo.extras;
+       RING_IDX i, rp;
+       int work_done, budget, more_to_do = 1;
+       struct sk_buff_head rxq;
+       struct sk_buff_head errq;
+       struct sk_buff_head tmpq;
+       unsigned long flags;
+       unsigned int len;
+       int err;
+
+       spin_lock(&np->rx_lock);
+
+       if (unlikely(!netif_carrier_ok(dev))) {
+               spin_unlock(&np->rx_lock);
+               return 0;
+       }
+
+       skb_queue_head_init(&rxq);
+       skb_queue_head_init(&errq);
+       skb_queue_head_init(&tmpq);
+
+       budget = *pbudget;
+       if (budget > dev->quota)
+               budget = dev->quota;
+       rp = np->rx.sring->rsp_prod;
+       rmb(); /* Ensure we see queued responses up to 'rp'. */
+
+       i = np->rx.rsp_cons;
+       work_done = 0;
+       while ((i != rp) && (work_done < budget)) {
+               memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx));
+               memset(extras, 0, sizeof(rinfo.extras));
+
+               err = xennet_get_responses(np, &rinfo, rp, &tmpq);
+
+               if (unlikely(err)) {
+err:
+                       while ((skb = __skb_dequeue(&tmpq)))
+                               __skb_queue_tail(&errq, skb);
+                       np->stats.rx_errors++;
+                       i = np->rx.rsp_cons;
+                       continue;
+               }
+
+               skb = __skb_dequeue(&tmpq);
+
+               if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
+                       struct xen_netif_extra_info *gso;
+                       gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
+
+                       if (unlikely(xennet_set_skb_gso(skb, gso))) {
+                               __skb_queue_head(&tmpq, skb);
+                               np->rx.rsp_cons += skb_queue_len(&tmpq);
+                               goto err;
+                       }
+               }
+
+               NETFRONT_SKB_CB(skb)->page = skb_shinfo(skb)->frags[0].page;
+               NETFRONT_SKB_CB(skb)->offset = rx->offset;
+
+               len = rx->status;
+               if (len > RX_COPY_THRESHOLD)
+                       len = RX_COPY_THRESHOLD;
+               skb_put(skb, len);
+
+               if (rx->status > len) {
+                       skb_shinfo(skb)->frags[0].page_offset =
+                               rx->offset + len;
+                       skb_shinfo(skb)->frags[0].size = rx->status - len;
+                       skb->data_len = rx->status - len;
+               } else {
+                       skb_shinfo(skb)->frags[0].page = NULL;
+                       skb_shinfo(skb)->nr_frags = 0;
+               }
+
+               i = xennet_fill_frags(np, skb, &tmpq);
+
+               /*
+                * Truesize approximates the size of true data plus
+                * any supervisor overheads. Adding hypervisor
+                * overheads has been shown to significantly reduce
+                * achievable bandwidth with the default receive
+                * buffer size. It is therefore not wise to account
+                * for it here.
+                *
+                * After alloc_skb(RX_COPY_THRESHOLD), truesize is set
+                * to RX_COPY_THRESHOLD + the supervisor
+                * overheads. Here, we add the size of the data pulled
+                * in xennet_fill_frags().
+                *
+                * We also adjust for any unused space in the main
+                * data area by subtracting (RX_COPY_THRESHOLD -
+                * len). This is especially important with drivers
+                * which split incoming packets into header and data,
+                * using only 66 bytes of the main data area (see the
+                * e1000 driver for example.)  On such systems,
+                * without this last adjustement, our achievable
+                * receive throughout using the standard receive
+                * buffer size was cut by 25%(!!!).
+                */
+               skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len);
+               skb->len += skb->data_len;
+
+               if (rx->flags & NETRXF_csum_blank)
+                       skb->ip_summed = CHECKSUM_PARTIAL;
+               else if (rx->flags & NETRXF_data_validated)
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+               __skb_queue_tail(&rxq, skb);
+
+               np->rx.rsp_cons = ++i;
+               work_done++;
+       }
+
+       while ((skb = __skb_dequeue(&errq)))
+               kfree_skb(skb);
+
+       work_done -= handle_incoming_queue(dev, &rxq);
+
+       /* If we get a callback with very few responses, reduce fill target. */
+       /* NB. Note exponential increase, linear decrease. */
+       if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) >
+            ((3*np->rx_target) / 4)) &&
+           (--np->rx_target < np->rx_min_target))
+               np->rx_target = np->rx_min_target;
+
+       xennet_alloc_rx_buffers(dev);
+
+       *pbudget   -= work_done;
+       dev->quota -= work_done;
+
+       if (work_done < budget) {
+               local_irq_save(flags);
+
+               RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do);
+               if (!more_to_do)
+                       __netif_rx_complete(dev);
+
+               local_irq_restore(flags);
+       }
+
+       spin_unlock(&np->rx_lock);
+
+       return more_to_do;
+}
+
+static int xennet_change_mtu(struct net_device *dev, int mtu)
+{
+       int max = xennet_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
+
+       if (mtu > max)
+               return -EINVAL;
+       dev->mtu = mtu;
+       return 0;
+}
+
+static void xennet_release_tx_bufs(struct netfront_info *np)
+{
+       struct sk_buff *skb;
+       int i;
+
+       for (i = 0; i < NET_TX_RING_SIZE; i++) {
+               /* Skip over entries which are actually freelist references */
+               if ((unsigned long)np->tx_skbs[i].skb < PAGE_OFFSET)
+                       continue;
+
+               skb = np->tx_skbs[i].skb;
+               gnttab_end_foreign_access_ref(np->grant_tx_ref[i],
+                                             GNTMAP_readonly);
+               gnttab_release_grant_reference(&np->gref_tx_head,
+                                              np->grant_tx_ref[i]);
+               np->grant_tx_ref[i] = GRANT_INVALID_REF;
+               add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, i);
+               dev_kfree_skb_irq(skb);
+       }
+}
+
+static void xennet_release_rx_bufs(struct netfront_info *np)
+{
+       struct mmu_update      *mmu = np->rx_mmu;
+       struct multicall_entry *mcl = np->rx_mcl;
+       struct sk_buff_head free_list;
+       struct sk_buff *skb;
+       unsigned long mfn;
+       int xfer = 0, noxfer = 0, unused = 0;
+       int id, ref;
+
+       dev_warn(&np->netdev->dev, "%s: fix me for copying receiver.\n",
+                        __func__);
+       return;
+
+       skb_queue_head_init(&free_list);
+
+       spin_lock_bh(&np->rx_lock);
+
+       for (id = 0; id < NET_RX_RING_SIZE; id++) {
+               ref = np->grant_rx_ref[id];
+               if (ref == GRANT_INVALID_REF) {
+                       unused++;
+                       continue;
+               }
+
+               skb = np->rx_skbs[id];
+               mfn = gnttab_end_foreign_transfer_ref(ref);
+               gnttab_release_grant_reference(&np->gref_rx_head, ref);
+               np->grant_rx_ref[id] = GRANT_INVALID_REF;
+
+               if (0 == mfn) {
+                       skb_shinfo(skb)->nr_frags = 0;
+                       dev_kfree_skb(skb);
+                       noxfer++;
+                       continue;
+               }
+
+               if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+                       /* Remap the page. */
+                       struct page *page = skb_shinfo(skb)->frags[0].page;
+                       unsigned long pfn = page_to_pfn(page);
+                       void *vaddr = page_address(page);
+
+                       MULTI_update_va_mapping(mcl, (unsigned long)vaddr,
+                                               mfn_pte(mfn, PAGE_KERNEL),
+                                               0);
+                       mcl++;
+                       mmu->ptr = ((u64)mfn << PAGE_SHIFT)
+                               | MMU_MACHPHYS_UPDATE;
+                       mmu->val = pfn;
+                       mmu++;
+
+                       set_phys_to_machine(pfn, mfn);
+               }
+               __skb_queue_tail(&free_list, skb);
+               xfer++;
+       }
+
+       dev_info(&np->netdev->dev, "%s: %d xfer, %d noxfer, %d unused\n",
+                __func__, xfer, noxfer, unused);
+
+       if (xfer) {
+               if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+                       /* Do all the remapping work and M2P updates. */
+                       MULTI_mmu_update(mcl, np->rx_mmu, mmu - np->rx_mmu,
+                                        0, DOMID_SELF);
+                       mcl++;
+                       HYPERVISOR_multicall(np->rx_mcl, mcl - np->rx_mcl);
+               }
+       }
+
+       while ((skb = __skb_dequeue(&free_list)) != NULL)
+               dev_kfree_skb(skb);
+
+       spin_unlock_bh(&np->rx_lock);
+}
+
+static void xennet_uninit(struct net_device *dev)
+{
+       struct netfront_info *np = netdev_priv(dev);
+       xennet_release_tx_bufs(np);
+       xennet_release_rx_bufs(np);
+       gnttab_free_grant_references(np->gref_tx_head);
+       gnttab_free_grant_references(np->gref_rx_head);
+}
+
+static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev)
+{
+       int i, err;
+       struct net_device *netdev;
+       struct netfront_info *np;
+
+       netdev = alloc_etherdev(sizeof(struct netfront_info));
+       if (!netdev) {
+               printk(KERN_WARNING "%s> alloc_etherdev failed.\n",
+                      __func__);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       np                   = netdev_priv(netdev);
+       np->xbdev            = dev;
+
+       spin_lock_init(&np->tx_lock);
+       spin_lock_init(&np->rx_lock);
+
+       skb_queue_head_init(&np->rx_batch);
+       np->rx_target     = RX_DFL_MIN_TARGET;
+       np->rx_min_target = RX_DFL_MIN_TARGET;
+       np->rx_max_target = RX_MAX_TARGET;
+
+       init_timer(&np->rx_refill_timer);
+       np->rx_refill_timer.data = (unsigned long)netdev;
+       np->rx_refill_timer.function = rx_refill_timeout;
+
+       /* Initialise tx_skbs as a free chain containing every entry. */
+       np->tx_skb_freelist = 0;
+       for (i = 0; i < NET_TX_RING_SIZE; i++) {
+               np->tx_skbs[i].link = i+1;
+               np->grant_tx_ref[i] = GRANT_INVALID_REF;
+       }
+
+       /* Clear out rx_skbs */
+       for (i = 0; i < NET_RX_RING_SIZE; i++) {
+               np->rx_skbs[i] = NULL;
+               np->grant_rx_ref[i] = GRANT_INVALID_REF;
+       }
+
+       /* A grant for every tx ring slot */
+       if (gnttab_alloc_grant_references(TX_MAX_TARGET,
+                                         &np->gref_tx_head) < 0) {
+               printk(KERN_ALERT "#### netfront can't alloc tx grant refs\n");
+               err = -ENOMEM;
+               goto exit;
+       }
+       /* A grant for every rx ring slot */
+       if (gnttab_alloc_grant_references(RX_MAX_TARGET,
+                                         &np->gref_rx_head) < 0) {
+               printk(KERN_ALERT "#### netfront can't alloc rx grant refs\n");
+               err = -ENOMEM;
+               goto exit_free_tx;
+       }
+
+       netdev->open            = xennet_open;
+       netdev->hard_start_xmit = xennet_start_xmit;
+       netdev->stop            = xennet_close;
+       netdev->get_stats       = xennet_get_stats;
+       netdev->poll            = xennet_poll;
+       netdev->uninit          = xennet_uninit;
+       netdev->change_mtu      = xennet_change_mtu;
+       netdev->weight          = 64;
+       netdev->features        = NETIF_F_IP_CSUM;
+
+       SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops);
+       SET_MODULE_OWNER(netdev);
+       SET_NETDEV_DEV(netdev, &dev->dev);
+
+       np->netdev = netdev;
+
+       netif_carrier_off(netdev);
+
+       return netdev;
+
+ exit_free_tx:
+       gnttab_free_grant_references(np->gref_tx_head);
+ exit:
+       free_netdev(netdev);
+       return ERR_PTR(err);
+}
+
+/**
+ * Entry point to this code when a new device is created.  Allocate the basic
+ * structures and the ring buffers for communication with the backend, and
+ * inform the backend of the appropriate details for those.
+ */
+static int __devinit netfront_probe(struct xenbus_device *dev,
+                                   const struct xenbus_device_id *id)
+{
+       int err;
+       struct net_device *netdev;
+       struct netfront_info *info;
+
+       netdev = xennet_create_dev(dev);
+       if (IS_ERR(netdev)) {
+               err = PTR_ERR(netdev);
+               xenbus_dev_fatal(dev, err, "creating netdev");
+               return err;
+       }
+
+       info = netdev_priv(netdev);
+       dev->dev.driver_data = info;
+
+       err = register_netdev(info->netdev);
+       if (err) {
+               printk(KERN_WARNING "%s: register_netdev err=%d\n",
+                      __func__, err);
+               goto fail;
+       }
+
+       err = xennet_sysfs_addif(info->netdev);
+       if (err) {
+               unregister_netdev(info->netdev);
+               printk(KERN_WARNING "%s: add sysfs failed err=%d\n",
+                      __func__, err);
+               goto fail;
+       }
+
+       return 0;
+
+ fail:
+       free_netdev(netdev);
+       dev->dev.driver_data = NULL;
+       return err;
+}
+
+static void xennet_end_access(int ref, void *page)
+{
+       /* This frees the page as a side-effect */
+       if (ref != GRANT_INVALID_REF)
+               gnttab_end_foreign_access(ref, 0, (unsigned long)page);
+}
+
+static void xennet_disconnect_backend(struct netfront_info *info)
+{
+       /* Stop old i/f to prevent errors whilst we rebuild the state. */
+       spin_lock_bh(&info->rx_lock);
+       spin_lock_irq(&info->tx_lock);
+       netif_carrier_off(info->netdev);
+       spin_unlock_irq(&info->tx_lock);
+       spin_unlock_bh(&info->rx_lock);
+
+       if (info->netdev->irq)
+               unbind_from_irqhandler(info->netdev->irq, info->netdev);
+       info->evtchn = info->netdev->irq = 0;
+
+       /* End access and free the pages */
+       xennet_end_access(info->tx_ring_ref, info->tx.sring);
+       xennet_end_access(info->rx_ring_ref, info->rx.sring);
+
+       info->tx_ring_ref = GRANT_INVALID_REF;
+       info->rx_ring_ref = GRANT_INVALID_REF;
+       info->tx.sring = NULL;
+       info->rx.sring = NULL;
+}
+
+/**
+ * We are reconnecting to the backend, due to a suspend/resume, or a backend
+ * driver restart.  We tear down our netif structure and recreate it, but
+ * leave the device-layer structures intact so that this is transparent to the
+ * rest of the kernel.
+ */
+static int netfront_resume(struct xenbus_device *dev)
+{
+       struct netfront_info *info = dev->dev.driver_data;
+
+       dev_dbg(&dev->dev, "%s\n", dev->nodename);
+
+       xennet_disconnect_backend(info);
+       return 0;
+}
+
+static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
+{
+       char *s, *e, *macstr;
+       int i;
+
+       macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
+       if (IS_ERR(macstr))
+               return PTR_ERR(macstr);
+
+       for (i = 0; i < ETH_ALEN; i++) {
+               mac[i] = simple_strtoul(s, &e, 16);
+               if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
+                       kfree(macstr);
+                       return -ENOENT;
+               }
+               s = e+1;
+       }
+
+       kfree(macstr);
+       return 0;
+}
+
+static irqreturn_t xennet_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct netfront_info *np = netdev_priv(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&np->tx_lock, flags);
+
+       if (likely(netif_carrier_ok(dev))) {
+               xennet_tx_buf_gc(dev);
+               /* Under tx_lock: protects access to rx shared-ring indexes. */
+               if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
+                       netif_rx_schedule(dev);
+       }
+
+       spin_unlock_irqrestore(&np->tx_lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info)
+{
+       struct xen_netif_tx_sring *txs;
+       struct xen_netif_rx_sring *rxs;
+       int err;
+       struct net_device *netdev = info->netdev;
+
+       info->tx_ring_ref = GRANT_INVALID_REF;
+       info->rx_ring_ref = GRANT_INVALID_REF;
+       info->rx.sring = NULL;
+       info->tx.sring = NULL;
+       netdev->irq = 0;
+
+       err = xen_net_read_mac(dev, netdev->dev_addr);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
+               goto fail;
+       }
+
+       txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_KERNEL);
+       if (!txs) {
+               err = -ENOMEM;
+               xenbus_dev_fatal(dev, err, "allocating tx ring page");
+               goto fail;
+       }
+       SHARED_RING_INIT(txs);
+       FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE);
+
+       err = xenbus_grant_ring(dev, virt_to_mfn(txs));
+       if (err < 0) {
+               free_page((unsigned long)txs);
+               goto fail;
+       }
+
+       info->tx_ring_ref = err;
+       rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_KERNEL);
+       if (!rxs) {
+               err = -ENOMEM;
+               xenbus_dev_fatal(dev, err, "allocating rx ring page");
+               goto fail;
+       }
+       SHARED_RING_INIT(rxs);
+       FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE);
+
+       err = xenbus_grant_ring(dev, virt_to_mfn(rxs));
+       if (err < 0) {
+               free_page((unsigned long)rxs);
+               goto fail;
+       }
+       info->rx_ring_ref = err;
+
+       err = xenbus_alloc_evtchn(dev, &info->evtchn);
+       if (err)
+               goto fail;
+
+       err = bind_evtchn_to_irqhandler(info->evtchn, xennet_interrupt,
+                                       IRQF_SAMPLE_RANDOM, netdev->name,
+                                       netdev);
+       if (err < 0)
+               goto fail;
+       netdev->irq = err;
+       return 0;
+
+ fail:
+       return err;
+}
+
+/* Common code used when first setting up, and when resuming. */
+static int talk_to_backend(struct xenbus_device *dev,
+                          struct netfront_info *info)
+{
+       const char *message;
+       struct xenbus_transaction xbt;
+       int err;
+
+       /* Create shared ring, alloc event channel. */
+       err = setup_netfront(dev, info);
+       if (err)
+               goto out;
+
+again:
+       err = xenbus_transaction_start(&xbt);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "starting transaction");
+               goto destroy_ring;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref", "%u",
+                           info->tx_ring_ref);
+       if (err) {
+               message = "writing tx ring-ref";
+               goto abort_transaction;
+       }
+       err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref", "%u",
+                           info->rx_ring_ref);
+       if (err) {
+               message = "writing rx ring-ref";
+               goto abort_transaction;
+       }
+       err = xenbus_printf(xbt, dev->nodename,
+                           "event-channel", "%u", info->evtchn);
+       if (err) {
+               message = "writing event-channel";
+               goto abort_transaction;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u",
+                           1);
+       if (err) {
+               message = "writing request-rx-copy";
+               goto abort_transaction;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename, "feature-rx-notify", "%d", 1);
+       if (err) {
+               message = "writing feature-rx-notify";
+               goto abort_transaction;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1);
+       if (err) {
+               message = "writing feature-sg";
+               goto abort_transaction;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1);
+       if (err) {
+               message = "writing feature-gso-tcpv4";
+               goto abort_transaction;
+       }
+
+       err = xenbus_transaction_end(xbt, 0);
+       if (err) {
+               if (err == -EAGAIN)
+                       goto again;
+               xenbus_dev_fatal(dev, err, "completing transaction");
+               goto destroy_ring;
+       }
+
+       return 0;
+
+ abort_transaction:
+       xenbus_transaction_end(xbt, 1);
+       xenbus_dev_fatal(dev, err, "%s", message);
+ destroy_ring:
+       xennet_disconnect_backend(info);
+ out:
+       return err;
+}
+
+static int xennet_set_sg(struct net_device *dev, u32 data)
+{
+       if (data) {
+               struct netfront_info *np = netdev_priv(dev);
+               int val;
+
+               if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg",
+                                "%d", &val) < 0)
+                       val = 0;
+               if (!val)
+                       return -ENOSYS;
+       } else if (dev->mtu > ETH_DATA_LEN)
+               dev->mtu = ETH_DATA_LEN;
+
+       return ethtool_op_set_sg(dev, data);
+}
+
+static int xennet_set_tso(struct net_device *dev, u32 data)
+{
+       if (data) {
+               struct netfront_info *np = netdev_priv(dev);
+               int val;
+
+               if (xenbus_scanf(XBT_NIL, np->xbdev->otherend,
+                                "feature-gso-tcpv4", "%d", &val) < 0)
+                       val = 0;
+               if (!val)
+                       return -ENOSYS;
+       }
+
+       return ethtool_op_set_tso(dev, data);
+}
+
+static void xennet_set_features(struct net_device *dev)
+{
+       /* Turn off all GSO bits except ROBUST. */
+       dev->features &= (1 << NETIF_F_GSO_SHIFT) - 1;
+       dev->features |= NETIF_F_GSO_ROBUST;
+       xennet_set_sg(dev, 0);
+
+       /* We need checksum offload to enable scatter/gather and TSO. */
+       if (!(dev->features & NETIF_F_IP_CSUM))
+               return;
+
+       if (!xennet_set_sg(dev, 1))
+               xennet_set_tso(dev, 1);
+}
+
+static int xennet_connect(struct net_device *dev)
+{
+       struct netfront_info *np = netdev_priv(dev);
+       int i, requeue_idx, err;
+       struct sk_buff *skb;
+       grant_ref_t ref;
+       struct xen_netif_rx_request *req;
+       unsigned int feature_rx_copy;
+
+       err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
+                          "feature-rx-copy", "%u", &feature_rx_copy);
+       if (err != 1)
+               feature_rx_copy = 0;
+
+       if (!feature_rx_copy) {
+               dev_info(&dev->dev,
+                        "backend does not support copying recieve path");
+               return -ENODEV;
+       }
+
+       err = talk_to_backend(np->xbdev, np);
+       if (err)
+               return err;
+
+       xennet_set_features(dev);
+
+       spin_lock_bh(&np->rx_lock);
+       spin_lock_irq(&np->tx_lock);
+
+       /* Step 1: Discard all pending TX packet fragments. */
+       xennet_release_tx_bufs(np);
+
+       /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */
+       for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) {
+               if (!np->rx_skbs[i])
+                       continue;
+
+               skb = np->rx_skbs[requeue_idx] = xennet_get_rx_skb(np, i);
+               ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i);
+               req = RING_GET_REQUEST(&np->rx, requeue_idx);
+
+               gnttab_grant_foreign_access_ref(
+                       ref, np->xbdev->otherend_id,
+                       pfn_to_mfn(page_to_pfn(skb_shinfo(skb)->
+                                              frags->page)),
+                       0);
+               req->gref = ref;
+               req->id   = requeue_idx;
+
+               requeue_idx++;
+       }
+
+       np->rx.req_prod_pvt = requeue_idx;
+
+       /*
+        * Step 3: All public and private state should now be sane.  Get
+        * ready to start sending and receiving packets and give the driver
+        * domain a kick because we've probably just requeued some
+        * packets.
+        */
+       netif_carrier_on(np->netdev);
+       notify_remote_via_irq(np->netdev->irq);
+       xennet_tx_buf_gc(dev);
+       xennet_alloc_rx_buffers(dev);
+
+       spin_unlock_irq(&np->tx_lock);
+       spin_unlock_bh(&np->rx_lock);
+
+       return 0;
+}
+
+/**
+ * Callback received when the backend's state changes.
+ */
+static void backend_changed(struct xenbus_device *dev,
+                           enum xenbus_state backend_state)
+{
+       struct netfront_info *np = dev->dev.driver_data;
+       struct net_device *netdev = np->netdev;
+
+       dev_dbg(&dev->dev, "%s\n", xenbus_strstate(backend_state));
+
+       switch (backend_state) {
+       case XenbusStateInitialising:
+       case XenbusStateInitialised:
+       case XenbusStateConnected:
+       case XenbusStateUnknown:
+       case XenbusStateClosed:
+               break;
+
+       case XenbusStateInitWait:
+               if (dev->state != XenbusStateInitialising)
+                       break;
+               if (xennet_connect(netdev) != 0)
+                       break;
+               xenbus_switch_state(dev, XenbusStateConnected);
+               break;
+
+       case XenbusStateClosing:
+               xenbus_frontend_closed(dev);
+               break;
+       }
+}
+
+static struct ethtool_ops xennet_ethtool_ops =
+{
+       .get_tx_csum = ethtool_op_get_tx_csum,
+       .set_tx_csum = ethtool_op_set_tx_csum,
+       .get_sg = ethtool_op_get_sg,
+       .set_sg = xennet_set_sg,
+       .get_tso = ethtool_op_get_tso,
+       .set_tso = xennet_set_tso,
+       .get_link = ethtool_op_get_link,
+};
+
+#ifdef CONFIG_SYSFS
+static ssize_t show_rxbuf_min(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct net_device *netdev = to_net_dev(dev);
+       struct netfront_info *info = netdev_priv(netdev);
+
+       return sprintf(buf, "%u\n", info->rx_min_target);
+}
+
+static ssize_t store_rxbuf_min(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t len)
+{
+       struct net_device *netdev = to_net_dev(dev);
+       struct netfront_info *np = netdev_priv(netdev);
+       char *endp;
+       unsigned long target;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       target = simple_strtoul(buf, &endp, 0);
+       if (endp == buf)
+               return -EBADMSG;
+
+       if (target < RX_MIN_TARGET)
+               target = RX_MIN_TARGET;
+       if (target > RX_MAX_TARGET)
+               target = RX_MAX_TARGET;
+
+       spin_lock_bh(&np->rx_lock);
+       if (target > np->rx_max_target)
+               np->rx_max_target = target;
+       np->rx_min_target = target;
+       if (target > np->rx_target)
+               np->rx_target = target;
+
+       xennet_alloc_rx_buffers(netdev);
+
+       spin_unlock_bh(&np->rx_lock);
+       return len;
+}
+
+static ssize_t show_rxbuf_max(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct net_device *netdev = to_net_dev(dev);
+       struct netfront_info *info = netdev_priv(netdev);
+
+       return sprintf(buf, "%u\n", info->rx_max_target);
+}
+
+static ssize_t store_rxbuf_max(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t len)
+{
+       struct net_device *netdev = to_net_dev(dev);
+       struct netfront_info *np = netdev_priv(netdev);
+       char *endp;
+       unsigned long target;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       target = simple_strtoul(buf, &endp, 0);
+       if (endp == buf)
+               return -EBADMSG;
+
+       if (target < RX_MIN_TARGET)
+               target = RX_MIN_TARGET;
+       if (target > RX_MAX_TARGET)
+               target = RX_MAX_TARGET;
+
+       spin_lock_bh(&np->rx_lock);
+       if (target < np->rx_min_target)
+               np->rx_min_target = target;
+       np->rx_max_target = target;
+       if (target < np->rx_target)
+               np->rx_target = target;
+
+       xennet_alloc_rx_buffers(netdev);
+
+       spin_unlock_bh(&np->rx_lock);
+       return len;
+}
+
+static ssize_t show_rxbuf_cur(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct net_device *netdev = to_net_dev(dev);
+       struct netfront_info *info = netdev_priv(netdev);
+
+       return sprintf(buf, "%u\n", info->rx_target);
+}
+
+static struct device_attribute xennet_attrs[] = {
+       __ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf_min, store_rxbuf_min),
+       __ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf_max, store_rxbuf_max),
+       __ATTR(rxbuf_cur, S_IRUGO, show_rxbuf_cur, NULL),
+};
+
+static int xennet_sysfs_addif(struct net_device *netdev)
+{
+       int i;
+       int err;
+
+       for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) {
+               err = device_create_file(&netdev->dev,
+                                          &xennet_attrs[i]);
+               if (err)
+                       goto fail;
+       }
+       return 0;
+
+ fail:
+       while (--i >= 0)
+               device_remove_file(&netdev->dev, &xennet_attrs[i]);
+       return err;
+}
+
+static void xennet_sysfs_delif(struct net_device *netdev)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++)
+               device_remove_file(&netdev->dev, &xennet_attrs[i]);
+}
+
+#endif /* CONFIG_SYSFS */
+
+static struct xenbus_device_id netfront_ids[] = {
+       { "vif" },
+       { "" }
+};
+
+
+static int __devexit xennet_remove(struct xenbus_device *dev)
+{
+       struct netfront_info *info = dev->dev.driver_data;
+
+       dev_dbg(&dev->dev, "%s\n", dev->nodename);
+
+       unregister_netdev(info->netdev);
+
+       xennet_disconnect_backend(info);
+
+       del_timer_sync(&info->rx_refill_timer);
+
+       xennet_sysfs_delif(info->netdev);
+
+       free_netdev(info->netdev);
+
+       return 0;
+}
+
+static struct xenbus_driver netfront = {
+       .name = "vif",
+       .owner = THIS_MODULE,
+       .ids = netfront_ids,
+       .probe = netfront_probe,
+       .remove = __devexit_p(xennet_remove),
+       .resume = netfront_resume,
+       .otherend_changed = backend_changed,
+};
+
+static int __init netif_init(void)
+{
+       if (!is_running_on_xen())
+               return -ENODEV;
+
+       if (is_initial_xendomain())
+               return 0;
+
+       printk(KERN_INFO "Initialising Xen virtual ethernet driver.\n");
+
+       return xenbus_register_frontend(&netfront);
+}
+module_init(netif_init);
+
+
+static void __exit netif_exit(void)
+{
+       if (is_initial_xendomain())
+               return;
+
+       return xenbus_unregister_driver(&netfront);
+}
+module_exit(netif_exit);
+
+MODULE_DESCRIPTION("Xen virtual network device frontend");
+MODULE_LICENSE("GPL");
index a68b3b3761a229e0569a98d28cd29caa829aa519..a728a7cd2fc80156ae3fd1b1d358e6b87934eb87 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/dma-mapping.h>
 #include <linux/ioport.h>
 
 #include <asm/io.h>
index a708c329675e6305396f2d43a0cd3ad37c8ccb19..38cdf9fa36a7b8f20e5f57976220e4b5101e21a3 100644 (file)
@@ -73,6 +73,7 @@
 #include <linux/termios.h>
 #include <linux/tty.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 #include <linux/delay.h>
 
 #include <asm/io.h>
index 03baf1c64a2e04fa2307f37b504b3862e9837350..ed112ee160127f7ef81a6d2a31a1120761b3ae30 100644 (file)
@@ -147,7 +147,7 @@ static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
                info->location_id, info->serial, info->capabilities);
        envp[i] = NULL;
        
-       value = call_usermodehelper (argv [0], argv, envp, 0);
+       value = call_usermodehelper (argv [0], argv, envp, UMH_WAIT_EXEC);
        kfree (buf);
        kfree (envp);
        return 0;
index 66102a1843220ab4c8e0e77483e8f7aba3030bce..3f36cb3910ee638c3fcf167a605f42840effe755 100644 (file)
@@ -164,3 +164,10 @@ config MONWRITER
        help
          Character device driver for writing z/VM monitor service records
 
+config S390_VMUR
+       tristate "z/VM unit record device driver"
+       depends on S390
+       default "m"
+       help
+         Character device driver for z/VM reader, puncher and printer.
+
index c210784bdf465e32a44f922f7a6dce4e71e64791..130de19916f27b305deae4c2866dd29bfbda84c1 100644 (file)
@@ -29,6 +29,7 @@ obj-$(CONFIG_S390_TAPE_34XX) += tape_34xx.o
 obj-$(CONFIG_S390_TAPE_3590) += tape_3590.o
 obj-$(CONFIG_MONREADER) += monreader.o
 obj-$(CONFIG_MONWRITER) += monwriter.o
+obj-$(CONFIG_S390_VMUR) += vmur.o
 
 zcore_mod-objs := sclp_sdias.o zcore.o
 obj-$(CONFIG_ZFCPDUMP) += zcore_mod.o
index 82e6a6b253ebbbf9ddc8cbf3f7991fba90416340..2f419b0ea628bf1dd47ca0385f54f95bbf808235 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2004,2005 IBM Corporation
+ * Copyright IBM Corp. 2004,2007
  * Interface implementation for communication with the z/VM control program
- * Author(s): Christian Borntraeger <cborntra@de.ibm.com>
+ * Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
  *
  *
  * z/VMs CP offers the possibility to issue commands via the diagnose code 8
 #include "vmcp.h"
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Christian Borntraeger <cborntra@de.ibm.com>");
+MODULE_AUTHOR("Christian Borntraeger <borntraeger@de.ibm.com>");
 MODULE_DESCRIPTION("z/VM CP interface");
 
+#define PRINTK_HEADER "vmcp: "
+
 static debug_info_t *vmcp_debug;
 
 static int vmcp_open(struct inode *inode, struct file *file)
@@ -40,7 +42,7 @@ static int vmcp_open(struct inode *inode, struct file *file)
        session->bufsize = PAGE_SIZE;
        session->response = NULL;
        session->resp_size = 0;
-       init_MUTEX(&session->mutex);
+       mutex_init(&session->mutex);
        file->private_data = session;
        return nonseekable_open(inode, file);
 }
@@ -57,37 +59,37 @@ static int vmcp_release(struct inode *inode, struct file *file)
 }
 
 static ssize_t
-vmcp_read(struct file *file, char __user * buff, size_t count, loff_t * ppos)
+vmcp_read(struct file *file, char __user *buff, size_t count, loff_t *ppos)
 {
        size_t tocopy;
        struct vmcp_session *session;
 
        session = (struct vmcp_session *)file->private_data;
-       if (down_interruptible(&session->mutex))
+       if (mutex_lock_interruptible(&session->mutex))
                return -ERESTARTSYS;
        if (!session->response) {
-               up(&session->mutex);
+               mutex_unlock(&session->mutex);
                return 0;
        }
        if (*ppos > session->resp_size) {
-               up(&session->mutex);
+               mutex_unlock(&session->mutex);
                return 0;
        }
        tocopy = min(session->resp_size - (size_t) (*ppos), count);
-       tocopy = min(tocopy,session->bufsize - (size_t) (*ppos));
+       tocopy = min(tocopy, session->bufsize - (size_t) (*ppos));
 
        if (copy_to_user(buff, session->response + (*ppos), tocopy)) {
-               up(&session->mutex);
+               mutex_unlock(&session->mutex);
                return -EFAULT;
        }
-       up(&session->mutex);
+       mutex_unlock(&session->mutex);
        *ppos += tocopy;
        return tocopy;
 }
 
 static ssize_t
-vmcp_write(struct file *file, const char __user * buff, size_t count,
-          loff_t * ppos)
+vmcp_write(struct file *file, const char __user *buff, size_t count,
+          loff_t *ppos)
 {
        char *cmd;
        struct vmcp_session *session;
@@ -103,24 +105,23 @@ vmcp_write(struct file *file, const char __user * buff, size_t count,
        }
        cmd[count] = '\0';
        session = (struct vmcp_session *)file->private_data;
-       if (down_interruptible(&session->mutex)) {
+       if (mutex_lock_interruptible(&session->mutex)) {
                kfree(cmd);
                return -ERESTARTSYS;
        }
        if (!session->response)
                session->response = (char *)__get_free_pages(GFP_KERNEL
-                                               | __GFP_REPEAT  | GFP_DMA,
+                                               | __GFP_REPEAT | GFP_DMA,
                                                get_order(session->bufsize));
        if (!session->response) {
-               up(&session->mutex);
+               mutex_unlock(&session->mutex);
                kfree(cmd);
                return -ENOMEM;
        }
        debug_text_event(vmcp_debug, 1, cmd);
-       session->resp_size = cpcmd(cmd, session->response,
-                                    session->bufsize,
-                                    &session->resp_code);
-       up(&session->mutex);
+       session->resp_size = cpcmd(cmd, session->response, session->bufsize,
+                                  &session->resp_code);
+       mutex_unlock(&session->mutex);
        kfree(cmd);
        *ppos = 0;              /* reset the file pointer after a command */
        return count;
@@ -145,12 +146,12 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        int temp;
 
        session = (struct vmcp_session *)file->private_data;
-       if (down_interruptible(&session->mutex))
+       if (mutex_lock_interruptible(&session->mutex))
                return -ERESTARTSYS;
        switch (cmd) {
        case VMCP_GETCODE:
                temp = session->resp_code;
-               up(&session->mutex);
+               mutex_unlock(&session->mutex);
                return put_user(temp, (int __user *)arg);
        case VMCP_SETBUF:
                free_pages((unsigned long)session->response,
@@ -161,14 +162,14 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        session->bufsize = PAGE_SIZE;
                        temp = -EINVAL;
                }
-               up(&session->mutex);
+               mutex_unlock(&session->mutex);
                return temp;
        case VMCP_GETSIZE:
                temp = session->resp_size;
-               up(&session->mutex);
+               mutex_unlock(&session->mutex);
                return put_user(temp, (int __user *)arg);
        default:
-               up(&session->mutex);
+               mutex_unlock(&session->mutex);
                return -ENOIOCTLCMD;
        }
 }
@@ -180,7 +181,7 @@ static const struct file_operations vmcp_fops = {
        .read           = vmcp_read,
        .write          = vmcp_write,
        .unlocked_ioctl = vmcp_ioctl,
-       .compat_ioctl   = vmcp_ioctl
+       .compat_ioctl   = vmcp_ioctl,
 };
 
 static struct miscdevice vmcp_dev = {
@@ -194,26 +195,38 @@ static int __init vmcp_init(void)
        int ret;
 
        if (!MACHINE_IS_VM) {
-               printk(KERN_WARNING
-                      "z/VM CP interface is only available under z/VM\n");
+               PRINT_WARN("z/VM CP interface is only available under z/VM\n");
                return -ENODEV;
        }
-       ret = misc_register(&vmcp_dev);
-       if (!ret)
-               printk(KERN_INFO "z/VM CP interface loaded\n");
-       else
-               printk(KERN_WARNING
-                      "z/VM CP interface not loaded. Could not register misc device.\n");
        vmcp_debug = debug_register("vmcp", 1, 1, 240);
-       debug_register_view(vmcp_debug, &debug_hex_ascii_view);
-       return ret;
+       if (!vmcp_debug) {
+               PRINT_ERR("z/VM CP interface not loaded. Could not register "
+                          "debug feature\n");
+               return -ENOMEM;
+       }
+       ret = debug_register_view(vmcp_debug, &debug_hex_ascii_view);
+       if (ret) {
+               PRINT_ERR("z/VM CP interface not loaded. Could not register "
+                         "debug feature view. Error code: %d\n", ret);
+               debug_unregister(vmcp_debug);
+               return ret;
+       }
+       ret = misc_register(&vmcp_dev);
+       if (ret) {
+               PRINT_ERR("z/VM CP interface not loaded. Could not register "
+                          "misc device. Error code: %d\n", ret);
+               debug_unregister(vmcp_debug);
+               return ret;
+       }
+       PRINT_INFO("z/VM CP interface loaded\n");
+       return 0;
 }
 
 static void __exit vmcp_exit(void)
 {
-       WARN_ON(misc_deregister(&vmcp_dev) != 0);
+       misc_deregister(&vmcp_dev);
        debug_unregister(vmcp_debug);
-       printk(KERN_INFO "z/VM CP interface unloaded.\n");
+       PRINT_INFO("z/VM CP interface unloaded.\n");
 }
 
 module_init(vmcp_init);
index 8a5975f3dad7ce7b7e1442d1cfa32993329edb01..6a993948e188c3a0219832757fd51922d8dab665 100644 (file)
@@ -12,8 +12,8 @@
  * The idea of this driver is based on cpint from Neale Ferguson
  */
 
-#include <asm/semaphore.h>
 #include <linux/ioctl.h>
+#include <linux/mutex.h>
 
 #define VMCP_GETCODE _IOR(0x10, 1, int)
 #define VMCP_SETBUF _IOW(0x10, 2, int)
@@ -26,5 +26,5 @@ struct vmcp_session {
        int resp_code;
        /* As we use copy_from/to_user, which might     *
         * sleep and cannot use a spinlock              */
-       struct semaphore mutex;
+       struct mutex mutex;
 };
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
new file mode 100644 (file)
index 0000000..e90b0f8
--- /dev/null
@@ -0,0 +1,906 @@
+/*
+ * Linux driver for System z and s390 unit record devices
+ * (z/VM virtual punch, reader, printer)
+ *
+ * Copyright IBM Corp. 2001, 2007
+ * Authors: Malcolm Beattie <beattiem@uk.ibm.com>
+ *         Michael Holzheu <holzheu@de.ibm.com>
+ *         Frank Munzert <munzert@de.ibm.com>
+ */
+
+#include <linux/cdev.h>
+
+#include <asm/uaccess.h>
+#include <asm/cio.h>
+#include <asm/ccwdev.h>
+#include <asm/debug.h>
+
+#include "vmur.h"
+
+/*
+ * Driver overview
+ *
+ * Unit record device support is implemented as a character device driver.
+ * We can fit at least 16 bits into a device minor number and use the
+ * simple method of mapping a character device number with minor abcd
+ * to the unit record device with devno abcd.
+ * I/O to virtual unit record devices is handled as follows:
+ * Reads: Diagnose code 0x14 (input spool file manipulation)
+ * is used to read spool data page-wise.
+ * Writes: The CCW used is WRITE_CCW_CMD (0x01). The device's record length
+ * is available by reading sysfs attr reclen. Each write() to the device
+ * must specify an integral multiple (maximal 511) of reclen.
+ */
+
+static char ur_banner[] = "z/VM virtual unit record device driver";
+
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("s390 z/VM virtual unit record device driver");
+MODULE_LICENSE("GPL");
+
+#define PRINTK_HEADER "vmur: "
+
+static dev_t ur_first_dev_maj_min;
+static struct class *vmur_class;
+static struct debug_info *vmur_dbf;
+
+/* We put the device's record length (for writes) in the driver_info field */
+static struct ccw_device_id ur_ids[] = {
+       { CCWDEV_CU_DI(READER_PUNCH_DEVTYPE, 80) },
+       { CCWDEV_CU_DI(PRINTER_DEVTYPE, 132) },
+       { /* end of list */ }
+};
+
+MODULE_DEVICE_TABLE(ccw, ur_ids);
+
+static int ur_probe(struct ccw_device *cdev);
+static void ur_remove(struct ccw_device *cdev);
+static int ur_set_online(struct ccw_device *cdev);
+static int ur_set_offline(struct ccw_device *cdev);
+
+static struct ccw_driver ur_driver = {
+       .name           = "vmur",
+       .owner          = THIS_MODULE,
+       .ids            = ur_ids,
+       .probe          = ur_probe,
+       .remove         = ur_remove,
+       .set_online     = ur_set_online,
+       .set_offline    = ur_set_offline,
+};
+
+/*
+ * Allocation, freeing, getting and putting of urdev structures
+ */
+static struct urdev *urdev_alloc(struct ccw_device *cdev)
+{
+       struct urdev *urd;
+
+       urd = kzalloc(sizeof(struct urdev), GFP_KERNEL);
+       if (!urd)
+               return NULL;
+       urd->cdev = cdev;
+       urd->reclen = cdev->id.driver_info;
+       ccw_device_get_id(cdev, &urd->dev_id);
+       mutex_init(&urd->io_mutex);
+       mutex_init(&urd->open_mutex);
+       return urd;
+}
+
+static void urdev_free(struct urdev *urd)
+{
+       kfree(urd);
+}
+
+/*
+ * This is how the character device driver gets a reference to a
+ * ur device. When this call returns successfully, a reference has
+ * been taken (by get_device) on the underlying kobject. The recipient
+ * of this urdev pointer must eventually drop it with urdev_put(urd)
+ * which does the corresponding put_device().
+ */
+static struct urdev *urdev_get_from_devno(u16 devno)
+{
+       char bus_id[16];
+       struct ccw_device *cdev;
+
+       sprintf(bus_id, "0.0.%04x", devno);
+       cdev = get_ccwdev_by_busid(&ur_driver, bus_id);
+       if (!cdev)
+               return NULL;
+
+       return cdev->dev.driver_data;
+}
+
+static void urdev_put(struct urdev *urd)
+{
+       put_device(&urd->cdev->dev);
+}
+
+/*
+ * Low-level functions to do I/O to a ur device.
+ *     alloc_chan_prog
+ *     do_ur_io
+ *     ur_int_handler
+ *
+ * alloc_chan_prog allocates and builds the channel program
+ *
+ * do_ur_io issues the channel program to the device and blocks waiting
+ * on a completion event it publishes at urd->io_done. The function
+ * serialises itself on the device's mutex so that only one I/O
+ * is issued at a time (and that I/O is synchronous).
+ *
+ * ur_int_handler catches the "I/O done" interrupt, writes the
+ * subchannel status word into the scsw member of the urdev structure
+ * and complete()s the io_done to wake the waiting do_ur_io.
+ *
+ * The caller of do_ur_io is responsible for kfree()ing the channel program
+ * address pointer that alloc_chan_prog returned.
+ */
+
+
+/*
+ * alloc_chan_prog
+ * The channel program we use is write commands chained together
+ * with a final NOP CCW command-chained on (which ensures that CE and DE
+ * are presented together in a single interrupt instead of as separate
+ * interrupts unless an incorrect length indication kicks in first). The
+ * data length in each CCW is reclen. The caller must ensure that count
+ * is an integral multiple of reclen.
+ * The channel program pointer returned by this function must be freed
+ * with kfree. The caller is responsible for checking that
+ * count/reclen is not ridiculously large.
+ */
+static struct ccw1 *alloc_chan_prog(char *buf, size_t count, size_t reclen)
+{
+       size_t num_ccws;
+       struct ccw1 *cpa;
+       int i;
+
+       TRACE("alloc_chan_prog(%p, %zu, %zu)\n", buf, count, reclen);
+
+       /*
+        * We chain a NOP onto the writes to force CE+DE together.
+        * That means we allocate room for CCWs to cover count/reclen
+        * records plus a NOP.
+        */
+       num_ccws = count / reclen + 1;
+       cpa = kmalloc(num_ccws * sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
+       if (!cpa)
+               return NULL;
+
+       for (i = 0; count; i++) {
+               cpa[i].cmd_code = WRITE_CCW_CMD;
+               cpa[i].flags = CCW_FLAG_CC | CCW_FLAG_SLI;
+               cpa[i].count = reclen;
+               cpa[i].cda = __pa(buf);
+               buf += reclen;
+               count -= reclen;
+       }
+       /* The following NOP CCW forces CE+DE to be presented together */
+       cpa[i].cmd_code = CCW_CMD_NOOP;
+       cpa[i].flags = 0;
+       cpa[i].count = 0;
+       cpa[i].cda = 0;
+
+       return cpa;
+}
+
+static int do_ur_io(struct urdev *urd, struct ccw1 *cpa)
+{
+       int rc;
+       struct ccw_device *cdev = urd->cdev;
+       DECLARE_COMPLETION(event);
+
+       TRACE("do_ur_io: cpa=%p\n", cpa);
+
+       rc = mutex_lock_interruptible(&urd->io_mutex);
+       if (rc)
+               return rc;
+
+       urd->io_done = &event;
+
+       spin_lock_irq(get_ccwdev_lock(cdev));
+       rc = ccw_device_start(cdev, cpa, 1, 0, 0);
+       spin_unlock_irq(get_ccwdev_lock(cdev));
+
+       TRACE("do_ur_io: ccw_device_start returned %d\n", rc);
+       if (rc)
+               goto out;
+
+       wait_for_completion(&event);
+       TRACE("do_ur_io: I/O complete\n");
+       rc = 0;
+
+out:
+       mutex_unlock(&urd->io_mutex);
+       return rc;
+}
+
+/*
+ * ur interrupt handler, called from the ccw_device layer
+ */
+static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm,
+                          struct irb *irb)
+{
+       struct urdev *urd;
+
+       TRACE("ur_int_handler: intparm=0x%lx cstat=%02x dstat=%02x res=%u\n",
+             intparm, irb->scsw.cstat, irb->scsw.dstat, irb->scsw.count);
+
+       if (!intparm) {
+               TRACE("ur_int_handler: unsolicited interrupt\n");
+               return;
+       }
+       urd = cdev->dev.driver_data;
+       /* On special conditions irb is an error pointer */
+       if (IS_ERR(irb))
+               urd->io_request_rc = PTR_ERR(irb);
+       else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+               urd->io_request_rc = 0;
+       else
+               urd->io_request_rc = -EIO;
+
+       complete(urd->io_done);
+}
+
+/*
+ * reclen sysfs attribute - The record length to be used for write CCWs
+ */
+static ssize_t ur_attr_reclen_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct urdev *urd = dev->driver_data;
+
+       return sprintf(buf, "%zu\n", urd->reclen);
+}
+
+static DEVICE_ATTR(reclen, 0444, ur_attr_reclen_show, NULL);
+
+static int ur_create_attributes(struct device *dev)
+{
+       return device_create_file(dev, &dev_attr_reclen);
+}
+
+static void ur_remove_attributes(struct device *dev)
+{
+       device_remove_file(dev, &dev_attr_reclen);
+}
+
+/*
+ * diagnose code 0x210 - retrieve device information
+ * cc=0  normal completion, we have a real device
+ * cc=1  CP paging error
+ * cc=2  The virtual device exists, but is not associated with a real device
+ * cc=3  Invalid device address, or the virtual device does not exist
+ */
+static int get_urd_class(struct urdev *urd)
+{
+       static struct diag210 ur_diag210;
+       int cc;
+
+       ur_diag210.vrdcdvno = urd->dev_id.devno;
+       ur_diag210.vrdclen = sizeof(struct diag210);
+
+       cc = diag210(&ur_diag210);
+       switch (cc) {
+       case 0:
+               return -ENOTSUPP;
+       case 2:
+               return ur_diag210.vrdcvcla; /* virtual device class */
+       case 3:
+               return -ENODEV;
+       default:
+               return -EIO;
+       }
+}
+
+/*
+ * Allocation and freeing of urfile structures
+ */
+static struct urfile *urfile_alloc(struct urdev *urd)
+{
+       struct urfile *urf;
+
+       urf = kzalloc(sizeof(struct urfile), GFP_KERNEL);
+       if (!urf)
+               return NULL;
+       urf->urd = urd;
+
+       TRACE("urfile_alloc: urd=%p urf=%p rl=%zu\n", urd, urf,
+             urf->dev_reclen);
+
+       return urf;
+}
+
+static void urfile_free(struct urfile *urf)
+{
+       TRACE("urfile_free: urf=%p urd=%p\n", urf, urf->urd);
+       kfree(urf);
+}
+
+/*
+ * The fops implementation of the character device driver
+ */
+static ssize_t do_write(struct urdev *urd, const char __user *udata,
+                       size_t count, size_t reclen, loff_t *ppos)
+{
+       struct ccw1 *cpa;
+       char *buf;
+       int rc;
+
+       /* Data buffer must be under 2GB line for fmt1 CCWs: hence GFP_DMA */
+       buf = kmalloc(count, GFP_KERNEL | GFP_DMA);
+       if (!buf)
+               return -ENOMEM;
+
+       if (copy_from_user(buf, udata, count)) {
+               rc = -EFAULT;
+               goto fail_kfree_buf;
+       }
+
+       cpa = alloc_chan_prog(buf, count, reclen);
+       if (!cpa) {
+               rc = -ENOMEM;
+               goto fail_kfree_buf;
+       }
+
+       rc = do_ur_io(urd, cpa);
+       if (rc)
+               goto fail_kfree_cpa;
+
+       if (urd->io_request_rc) {
+               rc = urd->io_request_rc;
+               goto fail_kfree_cpa;
+       }
+       *ppos += count;
+       rc = count;
+fail_kfree_cpa:
+       kfree(cpa);
+fail_kfree_buf:
+       kfree(buf);
+       return rc;
+}
+
+static ssize_t ur_write(struct file *file, const char __user *udata,
+                       size_t count, loff_t *ppos)
+{
+       struct urfile *urf = file->private_data;
+
+       TRACE("ur_write: count=%zu\n", count);
+
+       if (count == 0)
+               return 0;
+
+       if (count % urf->dev_reclen)
+               return -EINVAL; /* count must be a multiple of reclen */
+
+       if (count > urf->dev_reclen * MAX_RECS_PER_IO)
+               count = urf->dev_reclen * MAX_RECS_PER_IO;
+
+       return do_write(urf->urd, udata, count, urf->dev_reclen, ppos);
+}
+
+static int do_diag_14(unsigned long rx, unsigned long ry1,
+                     unsigned long subcode)
+{
+       register unsigned long _ry1 asm("2") = ry1;
+       register unsigned long _ry2 asm("3") = subcode;
+       int rc = 0;
+
+       asm volatile(
+#ifdef CONFIG_64BIT
+               "   sam31\n"
+               "   diag    %2,2,0x14\n"
+               "   sam64\n"
+#else
+               "   diag    %2,2,0x14\n"
+#endif
+               "   ipm     %0\n"
+               "   srl     %0,28\n"
+               : "=d" (rc), "+d" (_ry2)
+               : "d" (rx), "d" (_ry1)
+               : "cc");
+
+       TRACE("diag 14: subcode=0x%lx, cc=%i\n", subcode, rc);
+       return rc;
+}
+
+/*
+ * diagnose code 0x14 subcode 0x0028 - position spool file to designated
+ *                                    record
+ * cc=0  normal completion
+ * cc=2  no file active on the virtual reader or device not ready
+ * cc=3  record specified is beyond EOF
+ */
+static int diag_position_to_record(int devno, int record)
+{
+       int cc;
+
+       cc = do_diag_14(record, devno, 0x28);
+       switch (cc) {
+       case 0:
+               return 0;
+       case 2:
+               return -ENOMEDIUM;
+       case 3:
+               return -ENODATA; /* position beyond end of file */
+       default:
+               return -EIO;
+       }
+}
+
+/*
+ * diagnose code 0x14 subcode 0x0000 - read next spool file buffer
+ * cc=0  normal completion
+ * cc=1  EOF reached
+ * cc=2  no file active on the virtual reader, and no file eligible
+ * cc=3  file already active on the virtual reader or specified virtual
+ *      reader does not exist or is not a reader
+ */
+static int diag_read_file(int devno, char *buf)
+{
+       int cc;
+
+       cc = do_diag_14((unsigned long) buf, devno, 0x00);
+       switch (cc) {
+       case 0:
+               return 0;
+       case 1:
+               return -ENODATA;
+       case 2:
+               return -ENOMEDIUM;
+       default:
+               return -EIO;
+       }
+}
+
+static ssize_t diag14_read(struct file *file, char __user *ubuf, size_t count,
+                          loff_t *offs)
+{
+       size_t len, copied, res;
+       char *buf;
+       int rc;
+       u16 reclen;
+       struct urdev *urd;
+
+       urd = ((struct urfile *) file->private_data)->urd;
+       reclen = ((struct urfile *) file->private_data)->file_reclen;
+
+       rc = diag_position_to_record(urd->dev_id.devno, *offs / PAGE_SIZE + 1);
+       if (rc == -ENODATA)
+               return 0;
+       if (rc)
+               return rc;
+
+       len = min((size_t) PAGE_SIZE, count);
+       buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       copied = 0;
+       res = (size_t) (*offs % PAGE_SIZE);
+       do {
+               rc = diag_read_file(urd->dev_id.devno, buf);
+               if (rc == -ENODATA) {
+                       break;
+               }
+               if (rc)
+                       goto fail;
+               if (reclen)
+                       *((u16 *) &buf[FILE_RECLEN_OFFSET]) = reclen;
+               len = min(count - copied, PAGE_SIZE - res);
+               if (copy_to_user(ubuf + copied, buf + res, len)) {
+                       rc = -EFAULT;
+                       goto fail;
+               }
+               res = 0;
+               copied += len;
+       } while (copied != count);
+
+       *offs += copied;
+       rc = copied;
+fail:
+       kfree(buf);
+       return rc;
+}
+
+static ssize_t ur_read(struct file *file, char __user *ubuf, size_t count,
+                      loff_t *offs)
+{
+       struct urdev *urd;
+       int rc;
+
+       TRACE("ur_read: count=%zu ppos=%li\n", count, (unsigned long) *offs);
+
+       if (count == 0)
+               return 0;
+
+       urd = ((struct urfile *) file->private_data)->urd;
+       rc = mutex_lock_interruptible(&urd->io_mutex);
+       if (rc)
+               return rc;
+       rc = diag14_read(file, ubuf, count, offs);
+       mutex_unlock(&urd->io_mutex);
+       return rc;
+}
+
+/*
+ * diagnose code 0x14 subcode 0x0fff - retrieve next file descriptor
+ * cc=0  normal completion
+ * cc=1  no files on reader queue or no subsequent file
+ * cc=2  spid specified is invalid
+ */
+static int diag_read_next_file_info(struct file_control_block *buf, int spid)
+{
+       int cc;
+
+       cc = do_diag_14((unsigned long) buf, spid, 0xfff);
+       switch (cc) {
+       case 0:
+               return 0;
+       default:
+               return -ENODATA;
+       }
+}
+
+static int verify_device(struct urdev *urd)
+{
+       struct file_control_block fcb;
+       char *buf;
+       int rc;
+
+       switch (urd->class) {
+       case DEV_CLASS_UR_O:
+               return 0; /* no check needed here */
+       case DEV_CLASS_UR_I:
+               /* check for empty reader device (beginning of chain) */
+               rc = diag_read_next_file_info(&fcb, 0);
+               if (rc)
+                       return rc;
+
+               /* open file on virtual reader  */
+               buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+               if (!buf)
+                       return -ENOMEM;
+               rc = diag_read_file(urd->dev_id.devno, buf);
+               kfree(buf);
+
+               if ((rc != 0) && (rc != -ENODATA)) /* EOF does not hurt */
+                       return rc;
+               return 0;
+       default:
+               return -ENOTSUPP;
+       }
+}
+
+static int get_file_reclen(struct urdev *urd)
+{
+       struct file_control_block fcb;
+       int rc;
+
+       switch (urd->class) {
+       case DEV_CLASS_UR_O:
+               return 0;
+       case DEV_CLASS_UR_I:
+               rc = diag_read_next_file_info(&fcb, 0);
+               if (rc)
+                       return rc;
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+       if (fcb.file_stat & FLG_CP_DUMP)
+               return 0;
+
+       return fcb.rec_len;
+}
+
+static int ur_open(struct inode *inode, struct file *file)
+{
+       u16 devno;
+       struct urdev *urd;
+       struct urfile *urf;
+       unsigned short accmode;
+       int rc;
+
+       accmode = file->f_flags & O_ACCMODE;
+
+       if (accmode == O_RDWR)
+               return -EACCES;
+
+       /*
+        * We treat the minor number as the devno of the ur device
+        * to find in the driver tree.
+        */
+       devno = MINOR(file->f_dentry->d_inode->i_rdev);
+
+       urd = urdev_get_from_devno(devno);
+       if (!urd)
+               return -ENXIO;
+
+       if (file->f_flags & O_NONBLOCK) {
+               if (!mutex_trylock(&urd->open_mutex)) {
+                       rc = -EBUSY;
+                       goto fail_put;
+               }
+       } else {
+               if (mutex_lock_interruptible(&urd->open_mutex)) {
+                       rc = -ERESTARTSYS;
+                       goto fail_put;
+               }
+       }
+
+       TRACE("ur_open\n");
+
+       if (((accmode == O_RDONLY) && (urd->class != DEV_CLASS_UR_I)) ||
+           ((accmode == O_WRONLY) && (urd->class != DEV_CLASS_UR_O))) {
+               TRACE("ur_open: unsupported dev class (%d)\n", urd->class);
+               rc = -EACCES;
+               goto fail_unlock;
+       }
+
+       rc = verify_device(urd);
+       if (rc)
+               goto fail_unlock;
+
+       urf = urfile_alloc(urd);
+       if (!urf) {
+               rc = -ENOMEM;
+               goto fail_unlock;
+       }
+
+       urf->dev_reclen = urd->reclen;
+       rc = get_file_reclen(urd);
+       if (rc < 0)
+               goto fail_urfile_free;
+       urf->file_reclen = rc;
+       file->private_data = urf;
+       return 0;
+
+fail_urfile_free:
+       urfile_free(urf);
+fail_unlock:
+       mutex_unlock(&urd->open_mutex);
+fail_put:
+       urdev_put(urd);
+       return rc;
+}
+
+static int ur_release(struct inode *inode, struct file *file)
+{
+       struct urfile *urf = file->private_data;
+
+       TRACE("ur_release\n");
+       mutex_unlock(&urf->urd->open_mutex);
+       urdev_put(urf->urd);
+       urfile_free(urf);
+       return 0;
+}
+
+static loff_t ur_llseek(struct file *file, loff_t offset, int whence)
+{
+       loff_t newpos;
+
+       if ((file->f_flags & O_ACCMODE) != O_RDONLY)
+               return -ESPIPE; /* seek allowed only for reader */
+       if (offset % PAGE_SIZE)
+               return -ESPIPE; /* only multiples of 4K allowed */
+       switch (whence) {
+       case 0: /* SEEK_SET */
+               newpos = offset;
+               break;
+       case 1: /* SEEK_CUR */
+               newpos = file->f_pos + offset;
+               break;
+       default:
+               return -EINVAL;
+       }
+       file->f_pos = newpos;
+       return newpos;
+}
+
+static struct file_operations ur_fops = {
+       .owner   = THIS_MODULE,
+       .open    = ur_open,
+       .release = ur_release,
+       .read    = ur_read,
+       .write   = ur_write,
+       .llseek  = ur_llseek,
+};
+
+/*
+ * ccw_device infrastructure:
+ *     ur_probe gets its own ref to the device (i.e. get_device),
+ *     creates the struct urdev, the device attributes, sets up
+ *     the interrupt handler and validates the virtual unit record device.
+ *     ur_remove removes the device attributes, frees the struct urdev
+ *     and drops (put_device) the ref to the device we got in ur_probe.
+ */
+static int ur_probe(struct ccw_device *cdev)
+{
+       struct urdev *urd;
+       int rc;
+
+       TRACE("ur_probe: cdev=%p state=%d\n", cdev, *(int *) cdev->private);
+
+       if (!get_device(&cdev->dev))
+               return -ENODEV;
+
+       urd = urdev_alloc(cdev);
+       if (!urd) {
+               rc = -ENOMEM;
+               goto fail;
+       }
+       rc = ur_create_attributes(&cdev->dev);
+       if (rc) {
+               rc = -ENOMEM;
+               goto fail;
+       }
+       cdev->dev.driver_data = urd;
+       cdev->handler = ur_int_handler;
+
+       /* validate virtual unit record device */
+       urd->class = get_urd_class(urd);
+       if (urd->class < 0) {
+               rc = urd->class;
+               goto fail;
+       }
+       if ((urd->class != DEV_CLASS_UR_I) && (urd->class != DEV_CLASS_UR_O)) {
+               rc = -ENOTSUPP;
+               goto fail;
+       }
+
+       return 0;
+
+fail:
+       urdev_free(urd);
+       put_device(&cdev->dev);
+       return rc;
+}
+
+static void ur_remove(struct ccw_device *cdev)
+{
+       struct urdev *urd = cdev->dev.driver_data;
+
+       TRACE("ur_remove\n");
+       if (cdev->online)
+               ur_set_offline(cdev);
+       ur_remove_attributes(&cdev->dev);
+       urdev_free(urd);
+       put_device(&cdev->dev);
+}
+
+static int ur_set_online(struct ccw_device *cdev)
+{
+       struct urdev *urd;
+       int minor, major, rc;
+       char node_id[16];
+
+       TRACE("ur_set_online: cdev=%p state=%d\n", cdev,
+             *(int *) cdev->private);
+
+       if (!try_module_get(ur_driver.owner))
+               return -EINVAL;
+
+       urd = (struct urdev *) cdev->dev.driver_data;
+       minor = urd->dev_id.devno;
+       major = MAJOR(ur_first_dev_maj_min);
+
+       urd->char_device = cdev_alloc();
+       if (!urd->char_device) {
+               rc = -ENOMEM;
+               goto fail_module_put;
+       }
+
+       cdev_init(urd->char_device, &ur_fops);
+       urd->char_device->dev = MKDEV(major, minor);
+       urd->char_device->owner = ur_fops.owner;
+
+       rc = cdev_add(urd->char_device, urd->char_device->dev, 1);
+       if (rc)
+               goto fail_free_cdev;
+       if (urd->cdev->id.cu_type == READER_PUNCH_DEVTYPE) {
+               if (urd->class == DEV_CLASS_UR_I)
+                       sprintf(node_id, "vmrdr-%s", cdev->dev.bus_id);
+               if (urd->class == DEV_CLASS_UR_O)
+                       sprintf(node_id, "vmpun-%s", cdev->dev.bus_id);
+       } else if (urd->cdev->id.cu_type == PRINTER_DEVTYPE) {
+               sprintf(node_id, "vmprt-%s", cdev->dev.bus_id);
+       } else {
+               rc = -ENOTSUPP;
+               goto fail_free_cdev;
+       }
+
+       urd->device = device_create(vmur_class, NULL, urd->char_device->dev,
+                                       "%s", node_id);
+       if (IS_ERR(urd->device)) {
+               rc = PTR_ERR(urd->device);
+               TRACE("ur_set_online: device_create rc=%d\n", rc);
+               goto fail_free_cdev;
+       }
+
+       return 0;
+
+fail_free_cdev:
+       cdev_del(urd->char_device);
+fail_module_put:
+       module_put(ur_driver.owner);
+
+       return rc;
+}
+
+static int ur_set_offline(struct ccw_device *cdev)
+{
+       struct urdev *urd;
+
+       TRACE("ur_set_offline: cdev=%p cdev->private=%p state=%d\n",
+               cdev, cdev->private, *(int *) cdev->private);
+       urd = (struct urdev *) cdev->dev.driver_data;
+       device_destroy(vmur_class, urd->char_device->dev);
+       cdev_del(urd->char_device);
+       module_put(ur_driver.owner);
+
+       return 0;
+}
+
+/*
+ * Module initialisation and cleanup
+ */
+static int __init ur_init(void)
+{
+       int rc;
+       dev_t dev;
+
+       if (!MACHINE_IS_VM) {
+               PRINT_ERR("%s is only available under z/VM.\n", ur_banner);
+               return -ENODEV;
+       }
+
+       vmur_dbf = debug_register("vmur", 4, 1, 4 * sizeof(long));
+       if (!vmur_dbf)
+               return -ENOMEM;
+       rc = debug_register_view(vmur_dbf, &debug_sprintf_view);
+       if (rc)
+               goto fail_free_dbf;
+
+       debug_set_level(vmur_dbf, 6);
+
+       rc = ccw_driver_register(&ur_driver);
+       if (rc)
+               goto fail_free_dbf;
+
+       rc = alloc_chrdev_region(&dev, 0, NUM_MINORS, "vmur");
+       if (rc) {
+               PRINT_ERR("alloc_chrdev_region failed: err = %d\n", rc);
+               goto fail_unregister_driver;
+       }
+       ur_first_dev_maj_min = MKDEV(MAJOR(dev), 0);
+
+       vmur_class = class_create(THIS_MODULE, "vmur");
+       if (IS_ERR(vmur_class)) {
+               rc = PTR_ERR(vmur_class);
+               goto fail_unregister_region;
+       }
+       PRINT_INFO("%s loaded.\n", ur_banner);
+       return 0;
+
+fail_unregister_region:
+       unregister_chrdev_region(ur_first_dev_maj_min, NUM_MINORS);
+fail_unregister_driver:
+       ccw_driver_unregister(&ur_driver);
+fail_free_dbf:
+       debug_unregister(vmur_dbf);
+       return rc;
+}
+
+static void __exit ur_exit(void)
+{
+       class_destroy(vmur_class);
+       unregister_chrdev_region(ur_first_dev_maj_min, NUM_MINORS);
+       ccw_driver_unregister(&ur_driver);
+       debug_unregister(vmur_dbf);
+       PRINT_INFO("%s unloaded.\n", ur_banner);
+}
+
+module_init(ur_init);
+module_exit(ur_exit);
diff --git a/drivers/s390/char/vmur.h b/drivers/s390/char/vmur.h
new file mode 100644 (file)
index 0000000..16d0a4e
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Linux driver for System z and s390 unit record devices
+ * (z/VM virtual punch, reader, printer)
+ *
+ * Copyright IBM Corp. 2001, 2007
+ * Authors: Malcolm Beattie <beattiem@uk.ibm.com>
+ *         Michael Holzheu <holzheu@de.ibm.com>
+ *         Frank Munzert <munzert@de.ibm.com>
+ */
+
+#ifndef _VMUR_H_
+#define _VMUR_H_
+
+#define DEV_CLASS_UR_I 0x20 /* diag210 unit record input device class */
+#define DEV_CLASS_UR_O 0x10 /* diag210 unit record output device class */
+/*
+ * we only support z/VM's default unit record devices:
+ * both in SPOOL directory control statement and in CP DEFINE statement
+ *     RDR defaults to 2540 reader
+ *     PUN defaults to 2540 punch
+ *     PRT defaults to 1403 printer
+ */
+#define READER_PUNCH_DEVTYPE   0x2540
+#define PRINTER_DEVTYPE                0x1403
+
+/* z/VM spool file control block SFBLOK */
+struct file_control_block {
+       char reserved_1[8];
+       char user_owner[8];
+       char user_orig[8];
+       __s32 data_recs;
+       __s16 rec_len;
+       __s16 file_num;
+       __u8  file_stat;
+       __u8  dev_type;
+       char  reserved_2[6];
+       char  file_name[12];
+       char  file_type[12];
+       char  create_date[8];
+       char  create_time[8];
+       char  reserved_3[6];
+       __u8  file_class;
+       __u8  sfb_lok;
+       __u64 distr_code;
+       __u32 reserved_4;
+       __u8  current_starting_copy_number;
+       __u8  sfblock_cntrl_flags;
+       __u8  reserved_5;
+       __u8  more_status_flags;
+       char  rest[200];
+} __attribute__ ((packed));
+
+#define FLG_CP_DUMP 0x10
+
+/*
+ * A struct urdev is created for each ur device that is made available
+ * via the ccw_device driver model.
+ */
+struct urdev {
+       struct ccw_device *cdev;        /* Backpointer to ccw device */
+       struct mutex io_mutex;          /* Serialises device IO */
+       struct mutex open_mutex;        /* Serialises access to device */
+       struct completion *io_done;     /* do_ur_io waits; irq completes */
+       struct device *device;
+       struct cdev *char_device;
+       struct ccw_dev_id dev_id;       /* device id */
+       size_t reclen;                  /* Record length for *write* CCWs */
+       int class;                      /* VM device class */
+       int io_request_rc;              /* return code from I/O request */
+};
+
+/*
+ * A struct urfile is allocated at open() time for each device and
+ * freed on release().
+ */
+struct urfile {
+       struct urdev *urd;
+       unsigned int flags;
+       size_t dev_reclen;
+       __u16 file_reclen;
+};
+
+/*
+ * Device major/minor definitions.
+ */
+
+#define UR_MAJOR 0     /* get dynamic major */
+/*
+ * We map minor numbers directly to device numbers (0-FFFF) for simplicity.
+ * This avoids having to allocate (and manage) slot numbers.
+ */
+#define NUM_MINORS 65536
+
+/* Limiting each I/O to 511 records limits chan prog to 4KB (511 r/w + 1 NOP) */
+#define MAX_RECS_PER_IO                511
+#define WRITE_CCW_CMD          0x01
+
+#define TRACE(x...) debug_sprintf_event(vmur_dbf, 1, x)
+#define CCWDEV_CU_DI(cutype, di) \
+               CCW_DEVICE(cutype, 0x00), .driver_info = (di)
+
+#define FILE_RECLEN_OFFSET     4064 /* reclen offset in spool data block */
+
+#endif /* _VMUR_H_ */
index 6b264bdb5bfb1c09097f5133a44becedda7c3865..001682e70f672dc1be7e73e4da5918eb708427ff 100644 (file)
@@ -272,7 +272,7 @@ modalias_show (struct device *dev, struct device_attribute *attr, char *buf)
        struct ccw_device_id *id = &(cdev->id);
        int len;
 
-       len = snprint_alias(buf, PAGE_SIZE, id, "\n") + 1;
+       len = snprint_alias(buf, PAGE_SIZE, id, "\n");
 
        return len > PAGE_SIZE ? PAGE_SIZE : len;
 }
index e70aeb7a378109ef1fa1f6a31d72ae6fe7009828..ed026a1dc3244e066091571a546b50f168967061 100644 (file)
@@ -166,9 +166,9 @@ qdio_check_ccq(struct qdio_q *q, unsigned int ccq)
 {
        char dbf_text[15];
 
-       if (ccq == 0 || ccq == 32 || ccq == 96)
+       if (ccq == 0 || ccq == 32)
                return 0;
-       if (ccq == 97)
+       if (ccq == 96 || ccq == 97)
                return 1;
        /*notify devices immediately*/
        sprintf(dbf_text,"%d", ccq);
@@ -2306,8 +2306,8 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr)
        if (!ssqd_area) {
                QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \
                                "SIGAs for sch x%x.\n", irq_ptr->schid.sch_no);
-               irq_ptr->qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY ||
-                                 CHSC_FLAG_SIGA_OUTPUT_NECESSARY ||
+               irq_ptr->qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |
+                                 CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
                                  CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */
                irq_ptr->is_qebsm = 0;
                irq_ptr->sch_token = 0;
@@ -2328,8 +2328,8 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr)
                QDIO_PRINT_WARN("CHSC returned cc %i. Using all " \
                                "SIGAs for sch 0.%x.%x.\n", result,
                                irq_ptr->schid.ssid, irq_ptr->schid.sch_no);
-               qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY ||
-                       CHSC_FLAG_SIGA_OUTPUT_NECESSARY ||
+               qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |
+                       CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
                        CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */
                irq_ptr->is_qebsm  = 0;
                goto out;
@@ -2340,8 +2340,8 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr)
                                "is 0x%x. Using all SIGAs for sch 0.%x.%x.\n",
                                ssqd_area->response.code,
                                irq_ptr->schid.ssid, irq_ptr->schid.sch_no);
-               qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY ||
-                       CHSC_FLAG_SIGA_OUTPUT_NECESSARY ||
+               qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |
+                       CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
                        CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */
                irq_ptr->is_qebsm  = 0;
                goto out;
index a54e4140683aea238d28e48f50621e801c7d9450..e821a155b6588c163041d31a795313ce6158d6c3 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/kthread.h>
 #include <linux/delay.h>
 #include <linux/kmod.h>
+#include <linux/reboot.h>
 #include <asm/oplib.h>
 #include <asm/ebus.h>
 
@@ -170,8 +171,6 @@ static void get_current_temps(struct bbc_cpu_temperature *tp)
 static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp)
 {
        static int shutting_down = 0;
-       static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
-       char *argv[] = { "/sbin/shutdown", "-h", "now", NULL };
        char *type = "???";
        s8 val = -1;
 
@@ -195,7 +194,7 @@ static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp)
        printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n");
 
        shutting_down = 1;
-       if (call_usermodehelper("/sbin/shutdown", argv, envp, 0) < 0)
+       if (orderly_poweroff(true) < 0)
                printk(KERN_CRIT "envctrl: shutdown execution failed\n");
 }
 
index 8328acab47fdd2feb6c425ba59c179081b27f425..dadabef116b60ea75d935b37254ca53eeff2e09a 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/ioport.h>
 #include <linux/miscdevice.h>
 #include <linux/kmod.h>
+#include <linux/reboot.h>
 
 #include <asm/ebus.h>
 #include <asm/uaccess.h>
@@ -966,10 +967,6 @@ static struct i2c_child_t *envctrl_get_i2c_child(unsigned char mon_type)
 static void envctrl_do_shutdown(void)
 {
        static int inprog = 0;
-       static char *envp[] = { 
-               "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
-       char *argv[] = { 
-               "/sbin/shutdown", "-h", "now", NULL };  
        int ret;
 
        if (inprog != 0)
@@ -977,7 +974,7 @@ static void envctrl_do_shutdown(void)
 
        inprog = 1;
        printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n");
-       ret = call_usermodehelper("/sbin/shutdown", argv, envp, 0);
+       ret = orderly_poweroff(true);
        if (ret < 0) {
                printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n"); 
                inprog = 0;  /* unlikely to succeed, but we could try again */
index 53e81a44c1a3917fece986bef143e38401ff6f7e..2cf0953fe0ecb6f29e8180305afc68af95a89e27 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 #include <linux/delay.h>
 #include <linux/dio.h>
 #include <linux/console.h>
index 7fa413ddccf598ad52cf16713176dc841f7f7002..18f6297064482864bad07b269bf8ebe2bab0db8f 100644 (file)
@@ -486,6 +486,36 @@ config SERIAL_DZ_CONSOLE
 
          If unsure, say Y.
 
+config SERIAL_ZS
+       tristate "DECstation Z85C30 serial support"
+       depends on MACH_DECSTATION
+       select SERIAL_CORE
+       default y
+       ---help---
+         Support for the Zilog 85C350 serial communications controller used
+         for serial ports in newer DECstation systems.  These include the
+         DECsystem 5900 and all models of the DECstation and DECsystem 5000
+         systems except from model 200.
+
+         If unsure, say Y.  To compile this driver as a module, choose M here:
+         the module will be called zs.
+
+config SERIAL_ZS_CONSOLE
+       bool "Support for console on a DECstation Z85C30 serial port"
+       depends on SERIAL_ZS=y
+       select SERIAL_CORE_CONSOLE
+       default y
+       ---help---
+         If you say Y here, it will be possible to use a serial port as the
+         system console (the system console is the device which receives all
+         kernel messages and warnings and which allows logins in single user
+         mode).
+
+         Note that the firmware uses ttyS1 as the serial console on the
+         Maxine and ttyS3 on the others using this driver.
+
+         If unsure, say Y.
+
 config SERIAL_21285
        tristate "DC21285 serial port support"
        depends on ARM && FOOTBRIDGE
index c48cdd61b7369ef397a1ccb11549da3f8acf814e..af6377d480d72a0d3c849c34ed44b89c89d98212 100644 (file)
@@ -43,6 +43,7 @@ obj-$(CONFIG_V850E_UART) += v850e_uart.o
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
 obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
 obj-$(CONFIG_SERIAL_DZ) += dz.o
+obj-$(CONFIG_SERIAL_ZS) += zs.o
 obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
 obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
 obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
diff --git a/drivers/serial/zs.c b/drivers/serial/zs.c
new file mode 100644 (file)
index 0000000..65f1294
--- /dev/null
@@ -0,0 +1,1287 @@
+/*
+ * zs.c: Serial port driver for IOASIC DECstations.
+ *
+ * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
+ * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
+ *
+ * DECstation changes
+ * Copyright (C) 1998-2000 Harald Koerfgen
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007  Maciej W. Rozycki
+ *
+ * For the rest of the code the original Copyright applies:
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ *
+ * Note: for IOASIC systems the wiring is as follows:
+ *
+ * mouse/keyboard:
+ * DIN-7 MJ-4  signal        SCC
+ * 2     1     TxD       <-  A.TxD
+ * 3     4     RxD       ->  A.RxD
+ *
+ * EIA-232/EIA-423:
+ * DB-25 MMJ-6 signal        SCC
+ * 2     2     TxD       <-  B.TxD
+ * 3     5     RxD       ->  B.RxD
+ * 4           RTS       <- ~A.RTS
+ * 5           CTS       -> ~B.CTS
+ * 6     6     DSR       -> ~A.SYNC
+ * 8           CD        -> ~B.DCD
+ * 12          DSRS(DCE) -> ~A.CTS  (*)
+ * 15          TxC       ->  B.TxC
+ * 17          RxC       ->  B.RxC
+ * 20    1     DTR       <- ~A.DTR
+ * 22          RI        -> ~A.DCD
+ * 23          DSRS(DTE) <- ~B.RTS
+ *
+ * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE)
+ *     is shared with DSRS(DTE) at pin 23.
+ *
+ * As you can immediately notice the wiring of the RTS, DTR and DSR signals
+ * is a bit odd.  This makes the handling of port B unnecessarily
+ * complicated and prevents the use of some automatic modes of operation.
+ */
+
+#if defined(CONFIG_SERIAL_ZS_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/bug.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irqflags.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/spinlock.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/types.h>
+
+#include <asm/atomic.h>
+#include <asm/system.h>
+
+#include <asm/dec/interrupts.h>
+#include <asm/dec/ioasic_addrs.h>
+#include <asm/dec/system.h>
+
+#include "zs.h"
+
+
+MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
+MODULE_DESCRIPTION("DECstation Z85C30 serial driver");
+MODULE_LICENSE("GPL");
+
+
+static char zs_name[] __initdata = "DECstation Z85C30 serial driver version ";
+static char zs_version[] __initdata = "0.10";
+
+/*
+ * It would be nice to dynamically allocate everything that
+ * depends on ZS_NUM_SCCS, so we could support any number of
+ * Z85C30s, but for now...
+ */
+#define ZS_NUM_SCCS    2               /* Max # of ZS chips supported.  */
+#define ZS_NUM_CHAN    2               /* 2 channels per chip.  */
+#define ZS_CHAN_A      0               /* Index of the channel A.  */
+#define ZS_CHAN_B      1               /* Index of the channel B.  */
+#define ZS_CHAN_IO_SIZE 8              /* IOMEM space size.  */
+#define ZS_CHAN_IO_STRIDE 4            /* Register alignment.  */
+#define ZS_CHAN_IO_OFFSET 1            /* The SCC resides on the high byte
+                                          of the 16-bit IOBUS.  */
+#define ZS_CLOCK        7372800        /* Z85C30 PCLK input clock rate.  */
+
+#define to_zport(uport) container_of(uport, struct zs_port, port)
+
+struct zs_parms {
+       resource_size_t scc[ZS_NUM_SCCS];
+       int irq[ZS_NUM_SCCS];
+};
+
+static struct zs_scc zs_sccs[ZS_NUM_SCCS];
+
+static u8 zs_init_regs[ZS_NUM_REGS] __initdata = {
+       0,                              /* write 0 */
+       PAR_SPEC,                       /* write 1 */
+       0,                              /* write 2 */
+       0,                              /* write 3 */
+       X16CLK | SB1,                   /* write 4 */
+       0,                              /* write 5 */
+       0, 0, 0,                        /* write 6, 7, 8 */
+       MIE | DLC | NV,                 /* write 9 */
+       NRZ,                            /* write 10 */
+       TCBR | RCBR,                    /* write 11 */
+       0, 0,                           /* BRG time constant, write 12 + 13 */
+       BRSRC | BRENABL,                /* write 14 */
+       0,                              /* write 15 */
+};
+
+/*
+ * Debugging.
+ */
+#undef ZS_DEBUG_REGS
+
+
+/*
+ * Reading and writing Z85C30 registers.
+ */
+static void recovery_delay(void)
+{
+       udelay(2);
+}
+
+static u8 read_zsreg(struct zs_port *zport, int reg)
+{
+       void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET;
+       u8 retval;
+
+       if (reg != 0) {
+               writeb(reg & 0xf, control);
+               fast_iob();
+               recovery_delay();
+       }
+       retval = readb(control);
+       recovery_delay();
+       return retval;
+}
+
+static void write_zsreg(struct zs_port *zport, int reg, u8 value)
+{
+       void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET;
+
+       if (reg != 0) {
+               writeb(reg & 0xf, control);
+               fast_iob(); recovery_delay();
+       }
+       writeb(value, control);
+       fast_iob();
+       recovery_delay();
+       return;
+}
+
+static u8 read_zsdata(struct zs_port *zport)
+{
+       void __iomem *data = zport->port.membase +
+                            ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET;
+       u8 retval;
+
+       retval = readb(data);
+       recovery_delay();
+       return retval;
+}
+
+static void write_zsdata(struct zs_port *zport, u8 value)
+{
+       void __iomem *data = zport->port.membase +
+                            ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET;
+
+       writeb(value, data);
+       fast_iob();
+       recovery_delay();
+       return;
+}
+
+#ifdef ZS_DEBUG_REGS
+void zs_dump(void)
+{
+       struct zs_port *zport;
+       int i, j;
+
+       for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
+               zport = &zs_sccs[i / ZS_NUM_CHAN].zport[i % ZS_NUM_CHAN];
+
+               if (!zport->scc)
+                       continue;
+
+               for (j = 0; j < 16; j++)
+                       printk("W%-2d = 0x%02x\t", j, zport->regs[j]);
+               printk("\n");
+               for (j = 0; j < 16; j++)
+                       printk("R%-2d = 0x%02x\t", j, read_zsreg(zport, j));
+               printk("\n\n");
+       }
+}
+#endif
+
+
+static void zs_spin_lock_cond_irq(spinlock_t *lock, int irq)
+{
+       if (irq)
+               spin_lock_irq(lock);
+       else
+               spin_lock(lock);
+}
+
+static void zs_spin_unlock_cond_irq(spinlock_t *lock, int irq)
+{
+       if (irq)
+               spin_unlock_irq(lock);
+       else
+               spin_unlock(lock);
+}
+
+static int zs_receive_drain(struct zs_port *zport)
+{
+       int loops = 10000;
+
+       while ((read_zsreg(zport, R0) & Rx_CH_AV) && loops--)
+               read_zsdata(zport);
+       return loops;
+}
+
+static int zs_transmit_drain(struct zs_port *zport, int irq)
+{
+       struct zs_scc *scc = zport->scc;
+       int loops = 10000;
+
+       while (!(read_zsreg(zport, R0) & Tx_BUF_EMP) && loops--) {
+               zs_spin_unlock_cond_irq(&scc->zlock, irq);
+               udelay(2);
+               zs_spin_lock_cond_irq(&scc->zlock, irq);
+       }
+       return loops;
+}
+
+static int zs_line_drain(struct zs_port *zport, int irq)
+{
+       struct zs_scc *scc = zport->scc;
+       int loops = 10000;
+
+       while (!(read_zsreg(zport, R1) & ALL_SNT) && loops--) {
+               zs_spin_unlock_cond_irq(&scc->zlock, irq);
+               udelay(2);
+               zs_spin_lock_cond_irq(&scc->zlock, irq);
+       }
+       return loops;
+}
+
+
+static void load_zsregs(struct zs_port *zport, u8 *regs, int irq)
+{
+       /* Let the current transmission finish.  */
+       zs_line_drain(zport, irq);
+       /* Load 'em up.  */
+       write_zsreg(zport, R3, regs[3] & ~RxENABLE);
+       write_zsreg(zport, R5, regs[5] & ~TxENAB);
+       write_zsreg(zport, R4, regs[4]);
+       write_zsreg(zport, R9, regs[9]);
+       write_zsreg(zport, R1, regs[1]);
+       write_zsreg(zport, R2, regs[2]);
+       write_zsreg(zport, R10, regs[10]);
+       write_zsreg(zport, R14, regs[14] & ~BRENABL);
+       write_zsreg(zport, R11, regs[11]);
+       write_zsreg(zport, R12, regs[12]);
+       write_zsreg(zport, R13, regs[13]);
+       write_zsreg(zport, R14, regs[14]);
+       write_zsreg(zport, R15, regs[15]);
+       if (regs[3] & RxENABLE)
+               write_zsreg(zport, R3, regs[3]);
+       if (regs[5] & TxENAB)
+               write_zsreg(zport, R5, regs[5]);
+       return;
+}
+
+
+/*
+ * Status handling routines.
+ */
+
+/*
+ * zs_tx_empty() -- get the transmitter empty status
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *         is emptied.  On bus types like RS485, the transmitter must
+ *         release the bus after transmitting.  This must be done when
+ *         the transmit shift register is empty, not be done when the
+ *         transmit holding register is empty.  This functionality
+ *         allows an RS485 driver to be written in user space.
+ */
+static unsigned int zs_tx_empty(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       unsigned long flags;
+       u8 status;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+       status = read_zsreg(zport, R1);
+       spin_unlock_irqrestore(&scc->zlock, flags);
+
+       return status & ALL_SNT ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int zs_raw_get_ab_mctrl(struct zs_port *zport_a,
+                                       struct zs_port *zport_b)
+{
+       u8 status_a, status_b;
+       unsigned int mctrl;
+
+       status_a = read_zsreg(zport_a, R0);
+       status_b = read_zsreg(zport_b, R0);
+
+       mctrl = ((status_b & CTS) ? TIOCM_CTS : 0) |
+               ((status_b & DCD) ? TIOCM_CAR : 0) |
+               ((status_a & DCD) ? TIOCM_RNG : 0) |
+               ((status_a & SYNC_HUNT) ? TIOCM_DSR : 0);
+
+       return mctrl;
+}
+
+static unsigned int zs_raw_get_mctrl(struct zs_port *zport)
+{
+       struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
+
+       return zport != zport_a ? zs_raw_get_ab_mctrl(zport_a, zport) : 0;
+}
+
+static unsigned int zs_raw_xor_mctrl(struct zs_port *zport)
+{
+       struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
+       unsigned int mmask, mctrl, delta;
+       u8 mask_a, mask_b;
+
+       if (zport == zport_a)
+               return 0;
+
+       mask_a = zport_a->regs[15];
+       mask_b = zport->regs[15];
+
+       mmask = ((mask_b & CTSIE) ? TIOCM_CTS : 0) |
+               ((mask_b & DCDIE) ? TIOCM_CAR : 0) |
+               ((mask_a & DCDIE) ? TIOCM_RNG : 0) |
+               ((mask_a & SYNCIE) ? TIOCM_DSR : 0);
+
+       mctrl = zport->mctrl;
+       if (mmask) {
+               mctrl &= ~mmask;
+               mctrl |= zs_raw_get_ab_mctrl(zport_a, zport) & mmask;
+       }
+
+       delta = mctrl ^ zport->mctrl;
+       if (delta)
+               zport->mctrl = mctrl;
+
+       return delta;
+}
+
+static unsigned int zs_get_mctrl(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       unsigned int mctrl;
+
+       spin_lock(&scc->zlock);
+       mctrl = zs_raw_get_mctrl(zport);
+       spin_unlock(&scc->zlock);
+
+       return mctrl;
+}
+
+static void zs_set_mctrl(struct uart_port *uport, unsigned int mctrl)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+       u8 oldloop, newloop;
+
+       spin_lock(&scc->zlock);
+       if (zport != zport_a) {
+               if (mctrl & TIOCM_DTR)
+                       zport_a->regs[5] |= DTR;
+               else
+                       zport_a->regs[5] &= ~DTR;
+               if (mctrl & TIOCM_RTS)
+                       zport_a->regs[5] |= RTS;
+               else
+                       zport_a->regs[5] &= ~RTS;
+               write_zsreg(zport_a, R5, zport_a->regs[5]);
+       }
+
+       /* Rarely modified, so don't poke at hardware unless necessary. */
+       oldloop = zport->regs[14];
+       newloop = oldloop;
+       if (mctrl & TIOCM_LOOP)
+               newloop |= LOOPBAK;
+       else
+               newloop &= ~LOOPBAK;
+       if (newloop != oldloop) {
+               zport->regs[14] = newloop;
+               write_zsreg(zport, R14, zport->regs[14]);
+       }
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_raw_stop_tx(struct zs_port *zport)
+{
+       write_zsreg(zport, R0, RES_Tx_P);
+       zport->tx_stopped = 1;
+}
+
+static void zs_stop_tx(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+
+       spin_lock(&scc->zlock);
+       zs_raw_stop_tx(zport);
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_raw_transmit_chars(struct zs_port *);
+
+static void zs_start_tx(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+
+       spin_lock(&scc->zlock);
+       if (zport->tx_stopped) {
+               zs_transmit_drain(zport, 0);
+               zport->tx_stopped = 0;
+               zs_raw_transmit_chars(zport);
+       }
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_stop_rx(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+
+       spin_lock(&scc->zlock);
+       zport->regs[15] &= ~BRKIE;
+       zport->regs[1] &= ~(RxINT_MASK | TxINT_ENAB);
+       zport->regs[1] |= RxINT_DISAB;
+
+       if (zport != zport_a) {
+               /* A-side DCD tracks RI and SYNC tracks DSR.  */
+               zport_a->regs[15] &= ~(DCDIE | SYNCIE);
+               write_zsreg(zport_a, R15, zport_a->regs[15]);
+               if (!(zport_a->regs[15] & BRKIE)) {
+                       zport_a->regs[1] &= ~EXT_INT_ENAB;
+                       write_zsreg(zport_a, R1, zport_a->regs[1]);
+               }
+
+               /* This-side DCD tracks DCD and CTS tracks CTS.  */
+               zport->regs[15] &= ~(DCDIE | CTSIE);
+               zport->regs[1] &= ~EXT_INT_ENAB;
+       } else {
+               /* DCD tracks RI and SYNC tracks DSR for the B side.  */
+               if (!(zport->regs[15] & (DCDIE | SYNCIE)))
+                       zport->regs[1] &= ~EXT_INT_ENAB;
+       }
+
+       write_zsreg(zport, R15, zport->regs[15]);
+       write_zsreg(zport, R1, zport->regs[1]);
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_enable_ms(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+
+       if (zport == zport_a)
+               return;
+
+       spin_lock(&scc->zlock);
+
+       /* Clear Ext interrupts if not being handled already.  */
+       if (!(zport_a->regs[1] & EXT_INT_ENAB))
+               write_zsreg(zport_a, R0, RES_EXT_INT);
+
+       /* A-side DCD tracks RI and SYNC tracks DSR.  */
+       zport_a->regs[1] |= EXT_INT_ENAB;
+       zport_a->regs[15] |= DCDIE | SYNCIE;
+
+       /* This-side DCD tracks DCD and CTS tracks CTS.  */
+       zport->regs[15] |= DCDIE | CTSIE;
+
+       zs_raw_xor_mctrl(zport);
+
+       write_zsreg(zport_a, R1, zport_a->regs[1]);
+       write_zsreg(zport_a, R15, zport_a->regs[15]);
+       write_zsreg(zport, R15, zport->regs[15]);
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_break_ctl(struct uart_port *uport, int break_state)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+       if (break_state == -1)
+               zport->regs[5] |= SND_BRK;
+       else
+               zport->regs[5] &= ~SND_BRK;
+       write_zsreg(zport, R5, zport->regs[5]);
+       spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+
+/*
+ * Interrupt handling routines.
+ */
+#define Rx_BRK 0x0100                  /* BREAK event software flag.  */
+#define Rx_SYS 0x0200                  /* SysRq event software flag.  */
+
+static void zs_receive_chars(struct zs_port *zport)
+{
+       struct uart_port *uport = &zport->port;
+       struct zs_scc *scc = zport->scc;
+       struct uart_icount *icount;
+       unsigned int avail, status, ch, flag;
+       int count;
+
+       for (count = 16; count; count--) {
+               spin_lock(&scc->zlock);
+               avail = read_zsreg(zport, R0) & Rx_CH_AV;
+               spin_unlock(&scc->zlock);
+               if (!avail)
+                       break;
+
+               spin_lock(&scc->zlock);
+               status = read_zsreg(zport, R1) & (Rx_OVR | FRM_ERR | PAR_ERR);
+               ch = read_zsdata(zport);
+               spin_unlock(&scc->zlock);
+
+               flag = TTY_NORMAL;
+
+               icount = &uport->icount;
+               icount->rx++;
+
+               /* Handle the null char got when BREAK is removed.  */
+               if (!ch)
+                       status |= zport->tty_break;
+               if (unlikely(status &
+                            (Rx_OVR | FRM_ERR | PAR_ERR | Rx_SYS | Rx_BRK))) {
+                       zport->tty_break = 0;
+
+                       /* Reset the error indication.  */
+                       if (status & (Rx_OVR | FRM_ERR | PAR_ERR)) {
+                               spin_lock(&scc->zlock);
+                               write_zsreg(zport, R0, ERR_RES);
+                               spin_unlock(&scc->zlock);
+                       }
+
+                       if (status & (Rx_SYS | Rx_BRK)) {
+                               icount->brk++;
+                               /* SysRq discards the null char.  */
+                               if (status & Rx_SYS)
+                                       continue;
+                       } else if (status & FRM_ERR)
+                               icount->frame++;
+                       else if (status & PAR_ERR)
+                               icount->parity++;
+                       if (status & Rx_OVR)
+                               icount->overrun++;
+
+                       status &= uport->read_status_mask;
+                       if (status & Rx_BRK)
+                               flag = TTY_BREAK;
+                       else if (status & FRM_ERR)
+                               flag = TTY_FRAME;
+                       else if (status & PAR_ERR)
+                               flag = TTY_PARITY;
+               }
+
+               if (uart_handle_sysrq_char(uport, ch))
+                       continue;
+
+               uart_insert_char(uport, status, Rx_OVR, ch, flag);
+       }
+
+       tty_flip_buffer_push(uport->info->tty);
+}
+
+static void zs_raw_transmit_chars(struct zs_port *zport)
+{
+       struct circ_buf *xmit = &zport->port.info->xmit;
+
+       /* XON/XOFF chars.  */
+       if (zport->port.x_char) {
+               write_zsdata(zport, zport->port.x_char);
+               zport->port.icount.tx++;
+               zport->port.x_char = 0;
+               return;
+       }
+
+       /* If nothing to do or stopped or hardware stopped.  */
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&zport->port)) {
+               zs_raw_stop_tx(zport);
+               return;
+       }
+
+       /* Send char.  */
+       write_zsdata(zport, xmit->buf[xmit->tail]);
+       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+       zport->port.icount.tx++;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&zport->port);
+
+       /* Are we are done?  */
+       if (uart_circ_empty(xmit))
+               zs_raw_stop_tx(zport);
+}
+
+static void zs_transmit_chars(struct zs_port *zport)
+{
+       struct zs_scc *scc = zport->scc;
+
+       spin_lock(&scc->zlock);
+       zs_raw_transmit_chars(zport);
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_status_handle(struct zs_port *zport, struct zs_port *zport_a)
+{
+       struct uart_port *uport = &zport->port;
+       struct zs_scc *scc = zport->scc;
+       unsigned int delta;
+       u8 status, brk;
+
+       spin_lock(&scc->zlock);
+
+       /* Get status from Read Register 0.  */
+       status = read_zsreg(zport, R0);
+
+       if (zport->regs[15] & BRKIE) {
+               brk = status & BRK_ABRT;
+               if (brk && !zport->brk) {
+                       spin_unlock(&scc->zlock);
+                       if (uart_handle_break(uport))
+                               zport->tty_break = Rx_SYS;
+                       else
+                               zport->tty_break = Rx_BRK;
+                       spin_lock(&scc->zlock);
+               }
+               zport->brk = brk;
+       }
+
+       if (zport != zport_a) {
+               delta = zs_raw_xor_mctrl(zport);
+               spin_unlock(&scc->zlock);
+
+               if (delta & TIOCM_CTS)
+                       uart_handle_cts_change(uport,
+                                              zport->mctrl & TIOCM_CTS);
+               if (delta & TIOCM_CAR)
+                       uart_handle_dcd_change(uport,
+                                              zport->mctrl & TIOCM_CAR);
+               if (delta & TIOCM_RNG)
+                       uport->icount.dsr++;
+               if (delta & TIOCM_DSR)
+                       uport->icount.rng++;
+
+               if (delta)
+                       wake_up_interruptible(&uport->info->delta_msr_wait);
+
+               spin_lock(&scc->zlock);
+       }
+
+       /* Clear the status condition...  */
+       write_zsreg(zport, R0, RES_EXT_INT);
+
+       spin_unlock(&scc->zlock);
+}
+
+/*
+ * This is the Z85C30 driver's generic interrupt routine.
+ */
+static irqreturn_t zs_interrupt(int irq, void *dev_id)
+{
+       struct zs_scc *scc = dev_id;
+       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+       struct zs_port *zport_b = &scc->zport[ZS_CHAN_B];
+       irqreturn_t status = IRQ_NONE;
+       u8 zs_intreg;
+       int count;
+
+       /*
+        * NOTE: The read register 3, which holds the irq status,
+        *       does so for both channels on each chip.  Although
+        *       the status value itself must be read from the A
+        *       channel and is only valid when read from channel A.
+        *       Yes... broken hardware...
+        */
+       for (count = 16; count; count--) {
+               spin_lock(&scc->zlock);
+               zs_intreg = read_zsreg(zport_a, R3);
+               spin_unlock(&scc->zlock);
+               if (!zs_intreg)
+                       break;
+
+               /*
+                * We do not like losing characters, so we prioritise
+                * interrupt sources a little bit differently than
+                * the SCC would, was it allowed to.
+                */
+               if (zs_intreg & CHBRxIP)
+                       zs_receive_chars(zport_b);
+               if (zs_intreg & CHARxIP)
+                       zs_receive_chars(zport_a);
+               if (zs_intreg & CHBEXT)
+                       zs_status_handle(zport_b, zport_a);
+               if (zs_intreg & CHAEXT)
+                       zs_status_handle(zport_a, zport_a);
+               if (zs_intreg & CHBTxIP)
+                       zs_transmit_chars(zport_b);
+               if (zs_intreg & CHATxIP)
+                       zs_transmit_chars(zport_a);
+
+               status = IRQ_HANDLED;
+       }
+
+       return status;
+}
+
+
+/*
+ * Finally, routines used to initialize the serial port.
+ */
+static int zs_startup(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       unsigned long flags;
+       int irq_guard;
+       int ret;
+
+       irq_guard = atomic_add_return(1, &scc->irq_guard);
+       if (irq_guard == 1) {
+               ret = request_irq(zport->port.irq, zs_interrupt,
+                                 IRQF_SHARED, "scc", scc);
+               if (ret) {
+                       atomic_add(-1, &scc->irq_guard);
+                       printk(KERN_ERR "zs: can't get irq %d\n",
+                              zport->port.irq);
+                       return ret;
+               }
+       }
+
+       spin_lock_irqsave(&scc->zlock, flags);
+
+       /* Clear the receive FIFO.  */
+       zs_receive_drain(zport);
+
+       /* Clear the interrupt registers.  */
+       write_zsreg(zport, R0, ERR_RES);
+       write_zsreg(zport, R0, RES_Tx_P);
+       /* But Ext only if not being handled already.  */
+       if (!(zport->regs[1] & EXT_INT_ENAB))
+               write_zsreg(zport, R0, RES_EXT_INT);
+
+       /* Finally, enable sequencing and interrupts.  */
+       zport->regs[1] &= ~RxINT_MASK;
+       zport->regs[1] |= RxINT_ALL | TxINT_ENAB | EXT_INT_ENAB;
+       zport->regs[3] |= RxENABLE;
+       zport->regs[5] |= TxENAB;
+       zport->regs[15] |= BRKIE;
+       write_zsreg(zport, R1, zport->regs[1]);
+       write_zsreg(zport, R3, zport->regs[3]);
+       write_zsreg(zport, R5, zport->regs[5]);
+       write_zsreg(zport, R15, zport->regs[15]);
+
+       /* Record the current state of RR0.  */
+       zport->mctrl = zs_raw_get_mctrl(zport);
+       zport->brk = read_zsreg(zport, R0) & BRK_ABRT;
+
+       zport->tx_stopped = 1;
+
+       spin_unlock_irqrestore(&scc->zlock, flags);
+
+       return 0;
+}
+
+static void zs_shutdown(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       unsigned long flags;
+       int irq_guard;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+
+       zport->regs[5] &= ~TxENAB;
+       zport->regs[3] &= ~RxENABLE;
+       write_zsreg(zport, R5, zport->regs[5]);
+       write_zsreg(zport, R3, zport->regs[3]);
+
+       spin_unlock_irqrestore(&scc->zlock, flags);
+
+       irq_guard = atomic_add_return(-1, &scc->irq_guard);
+       if (!irq_guard)
+               free_irq(zport->port.irq, scc);
+}
+
+
+static void zs_reset(struct zs_port *zport)
+{
+       struct zs_scc *scc = zport->scc;
+       int irq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+       irq = !irqs_disabled_flags(flags);
+       if (!scc->initialised) {
+               /* Reset the pointer first, just in case...  */
+               read_zsreg(zport, R0);
+               /* And let the current transmission finish.  */
+               zs_line_drain(zport, irq);
+               write_zsreg(zport, R9, FHWRES);
+               udelay(10);
+               write_zsreg(zport, R9, 0);
+               scc->initialised = 1;
+       }
+       load_zsregs(zport, zport->regs, irq);
+       spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+static void zs_set_termios(struct uart_port *uport, struct ktermios *termios,
+                          struct ktermios *old_termios)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+       int irq;
+       unsigned int baud, brg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+       irq = !irqs_disabled_flags(flags);
+
+       /* Byte size.  */
+       zport->regs[3] &= ~RxNBITS_MASK;
+       zport->regs[5] &= ~TxNBITS_MASK;
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               zport->regs[3] |= Rx5;
+               zport->regs[5] |= Tx5;
+               break;
+       case CS6:
+               zport->regs[3] |= Rx6;
+               zport->regs[5] |= Tx6;
+               break;
+       case CS7:
+               zport->regs[3] |= Rx7;
+               zport->regs[5] |= Tx7;
+               break;
+       case CS8:
+       default:
+               zport->regs[3] |= Rx8;
+               zport->regs[5] |= Tx8;
+               break;
+       }
+
+       /* Parity and stop bits.  */
+       zport->regs[4] &= ~(XCLK_MASK | SB_MASK | PAR_ENA | PAR_EVEN);
+       if (termios->c_cflag & CSTOPB)
+               zport->regs[4] |= SB2;
+       else
+               zport->regs[4] |= SB1;
+       if (termios->c_cflag & PARENB)
+               zport->regs[4] |= PAR_ENA;
+       if (!(termios->c_cflag & PARODD))
+               zport->regs[4] |= PAR_EVEN;
+       switch (zport->clk_mode) {
+       case 64:
+               zport->regs[4] |= X64CLK;
+               break;
+       case 32:
+               zport->regs[4] |= X32CLK;
+               break;
+       case 16:
+               zport->regs[4] |= X16CLK;
+               break;
+       case 1:
+               zport->regs[4] |= X1CLK;
+               break;
+       default:
+               BUG();
+       }
+
+       baud = uart_get_baud_rate(uport, termios, old_termios, 0,
+                                 uport->uartclk / zport->clk_mode / 4);
+
+       brg = ZS_BPS_TO_BRG(baud, uport->uartclk / zport->clk_mode);
+       zport->regs[12] = brg & 0xff;
+       zport->regs[13] = (brg >> 8) & 0xff;
+
+       uart_update_timeout(uport, termios->c_cflag, baud);
+
+       uport->read_status_mask = Rx_OVR;
+       if (termios->c_iflag & INPCK)
+               uport->read_status_mask |= FRM_ERR | PAR_ERR;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               uport->read_status_mask |= Rx_BRK;
+
+       uport->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               uport->ignore_status_mask |= FRM_ERR | PAR_ERR;
+       if (termios->c_iflag & IGNBRK) {
+               uport->ignore_status_mask |= Rx_BRK;
+               if (termios->c_iflag & IGNPAR)
+                       uport->ignore_status_mask |= Rx_OVR;
+       }
+
+       if (termios->c_cflag & CREAD)
+               zport->regs[3] |= RxENABLE;
+       else
+               zport->regs[3] &= ~RxENABLE;
+
+       if (zport != zport_a) {
+               if (!(termios->c_cflag & CLOCAL)) {
+                       zport->regs[15] |= DCDIE;
+               } else
+                       zport->regs[15] &= ~DCDIE;
+               if (termios->c_cflag & CRTSCTS) {
+                       zport->regs[15] |= CTSIE;
+               } else
+                       zport->regs[15] &= ~CTSIE;
+               zs_raw_xor_mctrl(zport);
+       }
+
+       /* Load up the new values.  */
+       load_zsregs(zport, zport->regs, irq);
+
+       spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+
+static const char *zs_type(struct uart_port *uport)
+{
+       return "Z85C30 SCC";
+}
+
+static void zs_release_port(struct uart_port *uport)
+{
+       iounmap(uport->membase);
+       uport->membase = 0;
+       release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE);
+}
+
+static int zs_map_port(struct uart_port *uport)
+{
+       if (!uport->membase)
+               uport->membase = ioremap_nocache(uport->mapbase,
+                                                ZS_CHAN_IO_SIZE);
+       if (!uport->membase) {
+               printk(KERN_ERR "zs: Cannot map MMIO\n");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static int zs_request_port(struct uart_port *uport)
+{
+       int ret;
+
+       if (!request_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE, "scc")) {
+               printk(KERN_ERR "zs: Unable to reserve MMIO resource\n");
+               return -EBUSY;
+       }
+       ret = zs_map_port(uport);
+       if (ret) {
+               release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE);
+               return ret;
+       }
+       return 0;
+}
+
+static void zs_config_port(struct uart_port *uport, int flags)
+{
+       struct zs_port *zport = to_zport(uport);
+
+       if (flags & UART_CONFIG_TYPE) {
+               if (zs_request_port(uport))
+                       return;
+
+               uport->type = PORT_ZS;
+
+               zs_reset(zport);
+       }
+}
+
+static int zs_verify_port(struct uart_port *uport, struct serial_struct *ser)
+{
+       struct zs_port *zport = to_zport(uport);
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_ZS)
+               ret = -EINVAL;
+       if (ser->irq != uport->irq)
+               ret = -EINVAL;
+       if (ser->baud_base != uport->uartclk / zport->clk_mode / 4)
+               ret = -EINVAL;
+       return ret;
+}
+
+
+static struct uart_ops zs_ops = {
+       .tx_empty       = zs_tx_empty,
+       .set_mctrl      = zs_set_mctrl,
+       .get_mctrl      = zs_get_mctrl,
+       .stop_tx        = zs_stop_tx,
+       .start_tx       = zs_start_tx,
+       .stop_rx        = zs_stop_rx,
+       .enable_ms      = zs_enable_ms,
+       .break_ctl      = zs_break_ctl,
+       .startup        = zs_startup,
+       .shutdown       = zs_shutdown,
+       .set_termios    = zs_set_termios,
+       .type           = zs_type,
+       .release_port   = zs_release_port,
+       .request_port   = zs_request_port,
+       .config_port    = zs_config_port,
+       .verify_port    = zs_verify_port,
+};
+
+/*
+ * Initialize Z85C30 port structures.
+ */
+static int __init zs_probe_sccs(void)
+{
+       static int probed;
+       struct zs_parms zs_parms;
+       int chip, side, irq;
+       int n_chips = 0;
+       int i;
+
+       if (probed)
+               return 0;
+
+       irq = dec_interrupt[DEC_IRQ_SCC0];
+       if (irq >= 0) {
+               zs_parms.scc[n_chips] = IOASIC_SCC0;
+               zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC0];
+               n_chips++;
+       }
+       irq = dec_interrupt[DEC_IRQ_SCC1];
+       if (irq >= 0) {
+               zs_parms.scc[n_chips] = IOASIC_SCC1;
+               zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC1];
+               n_chips++;
+       }
+       if (!n_chips)
+               return -ENXIO;
+
+       probed = 1;
+
+       for (chip = 0; chip < n_chips; chip++) {
+               spin_lock_init(&zs_sccs[chip].zlock);
+               for (side = 0; side < ZS_NUM_CHAN; side++) {
+                       struct zs_port *zport = &zs_sccs[chip].zport[side];
+                       struct uart_port *uport = &zport->port;
+
+                       zport->scc      = &zs_sccs[chip];
+                       zport->clk_mode = 16;
+
+                       uport->irq      = zs_parms.irq[chip];
+                       uport->uartclk  = ZS_CLOCK;
+                       uport->fifosize = 1;
+                       uport->iotype   = UPIO_MEM;
+                       uport->flags    = UPF_BOOT_AUTOCONF;
+                       uport->ops      = &zs_ops;
+                       uport->line     = chip * ZS_NUM_CHAN + side;
+                       uport->mapbase  = dec_kn_slot_base +
+                                         zs_parms.scc[chip] +
+                                         (side ^ ZS_CHAN_B) * ZS_CHAN_IO_SIZE;
+
+                       for (i = 0; i < ZS_NUM_REGS; i++)
+                               zport->regs[i] = zs_init_regs[i];
+               }
+       }
+
+       return 0;
+}
+
+
+#ifdef CONFIG_SERIAL_ZS_CONSOLE
+static void zs_console_putchar(struct uart_port *uport, int ch)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       int irq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+       irq = !irqs_disabled_flags(flags);
+       if (zs_transmit_drain(zport, irq))
+               write_zsdata(zport, ch);
+       spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ */
+static void zs_console_write(struct console *co, const char *s,
+                            unsigned int count)
+{
+       int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN;
+       struct zs_port *zport = &zs_sccs[chip].zport[side];
+       struct zs_scc *scc = zport->scc;
+       unsigned long flags;
+       u8 txint, txenb;
+       int irq;
+
+       /* Disable transmit interrupts and enable the transmitter. */
+       spin_lock_irqsave(&scc->zlock, flags);
+       txint = zport->regs[1];
+       txenb = zport->regs[5];
+       if (txint & TxINT_ENAB) {
+               zport->regs[1] = txint & ~TxINT_ENAB;
+               write_zsreg(zport, R1, zport->regs[1]);
+       }
+       if (!(txenb & TxENAB)) {
+               zport->regs[5] = txenb | TxENAB;
+               write_zsreg(zport, R5, zport->regs[5]);
+       }
+       spin_unlock_irqrestore(&scc->zlock, flags);
+
+       uart_console_write(&zport->port, s, count, zs_console_putchar);
+
+       /* Restore transmit interrupts and the transmitter enable. */
+       spin_lock_irqsave(&scc->zlock, flags);
+       irq = !irqs_disabled_flags(flags);
+       zs_line_drain(zport, irq);
+       if (!(txenb & TxENAB)) {
+               zport->regs[5] &= ~TxENAB;
+               write_zsreg(zport, R5, zport->regs[5]);
+       }
+       if (txint & TxINT_ENAB) {
+               zport->regs[1] |= TxINT_ENAB;
+               write_zsreg(zport, R1, zport->regs[1]);
+       }
+       spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+/*
+ * Setup serial console baud/bits/parity.  We do two things here:
+ * - construct a cflag setting for the first uart_open()
+ * - initialise the serial port
+ * Return non-zero if we didn't find a serial port.
+ */
+static int __init zs_console_setup(struct console *co, char *options)
+{
+       int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN;
+       struct zs_port *zport = &zs_sccs[chip].zport[side];
+       struct uart_port *uport = &zport->port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       int ret;
+
+       ret = zs_map_port(uport);
+       if (ret)
+               return ret;
+
+       zs_reset(zport);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       return uart_set_options(uport, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver zs_reg;
+static struct console zs_console = {
+       .name   = "ttyS",
+       .write  = zs_console_write,
+       .device = uart_console_device,
+       .setup  = zs_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+       .data   = &zs_reg,
+};
+
+/*
+ *     Register console.
+ */
+static int __init zs_serial_console_init(void)
+{
+       int ret;
+
+       ret = zs_probe_sccs();
+       if (ret)
+               return ret;
+       register_console(&zs_console);
+
+       return 0;
+}
+
+console_initcall(zs_serial_console_init);
+
+#define SERIAL_ZS_CONSOLE      &zs_console
+#else
+#define SERIAL_ZS_CONSOLE      NULL
+#endif /* CONFIG_SERIAL_ZS_CONSOLE */
+
+static struct uart_driver zs_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "serial",
+       .dev_name               = "ttyS",
+       .major                  = TTY_MAJOR,
+       .minor                  = 64,
+       .nr                     = ZS_NUM_SCCS * ZS_NUM_CHAN,
+       .cons                   = SERIAL_ZS_CONSOLE,
+};
+
+/* zs_init inits the driver. */
+static int __init zs_init(void)
+{
+       int i, ret;
+
+       pr_info("%s%s\n", zs_name, zs_version);
+
+       /* Find out how many Z85C30 SCCs we have.  */
+       ret = zs_probe_sccs();
+       if (ret)
+               return ret;
+
+       ret = uart_register_driver(&zs_reg);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
+               struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
+               struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
+               struct uart_port *uport = &zport->port;
+
+               if (zport->scc)
+                       uart_add_one_port(&zs_reg, uport);
+       }
+
+       return 0;
+}
+
+static void __exit zs_exit(void)
+{
+       int i;
+
+       for (i = ZS_NUM_SCCS * ZS_NUM_CHAN - 1; i >= 0; i--) {
+               struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
+               struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
+               struct uart_port *uport = &zport->port;
+
+               if (zport->scc)
+                       uart_remove_one_port(&zs_reg, uport);
+       }
+
+       uart_unregister_driver(&zs_reg);
+}
+
+module_init(zs_init);
+module_exit(zs_exit);
diff --git a/drivers/serial/zs.h b/drivers/serial/zs.h
new file mode 100644 (file)
index 0000000..aa921b5
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * zs.h: Definitions for the DECstation Z85C30 serial driver.
+ *
+ * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
+ * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 2004, 2005, 2007  Maciej W. Rozycki
+ */
+#ifndef _SERIAL_ZS_H
+#define _SERIAL_ZS_H
+
+#ifdef __KERNEL__
+
+#define ZS_NUM_REGS 16
+
+/*
+ * This is our internal structure for each serial port's state.
+ */
+struct zs_port {
+       struct zs_scc   *scc;                   /* Containing SCC.  */
+       struct uart_port port;                  /* Underlying UART.  */
+
+       int             clk_mode;               /* May be 1, 16, 32, or 64.  */
+
+       unsigned int    tty_break;              /* Set on BREAK condition.  */
+       int             tx_stopped;             /* Output is suspended.  */
+
+       unsigned int    mctrl;                  /* State of modem lines.  */
+       u8              brk;                    /* BREAK state from RR0.  */
+
+       u8              regs[ZS_NUM_REGS];      /* Channel write registers.  */
+};
+
+/*
+ * Per-SCC state for locking and the interrupt handler.
+ */
+struct zs_scc {
+       struct zs_port  zport[2];
+       spinlock_t      zlock;
+       atomic_t        irq_guard;
+       int             initialised;
+};
+
+#endif /* __KERNEL__ */
+
+/*
+ * Conversion routines to/from brg time constants from/to bits per second.
+ */
+#define ZS_BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define ZS_BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/*
+ * The Zilog register set.
+ */
+
+/* Write Register 0 (Command) */
+#define R0             0       /* Register selects */
+#define R1             1
+#define R2             2
+#define R3             3
+#define R4             4
+#define R5             5
+#define R6             6
+#define R7             7
+#define R8             8
+#define R9             9
+#define R10            10
+#define R11            11
+#define R12            12
+#define R13            13
+#define R14            14
+#define R15            15
+
+#define NULLCODE       0       /* Null Code */
+#define POINT_HIGH     0x8     /* Select upper half of registers */
+#define RES_EXT_INT    0x10    /* Reset Ext. Status Interrupts */
+#define SEND_ABORT     0x18    /* HDLC Abort */
+#define RES_RxINT_FC   0x20    /* Reset RxINT on First Character */
+#define RES_Tx_P       0x28    /* Reset TxINT Pending */
+#define ERR_RES                0x30    /* Error Reset */
+#define RES_H_IUS      0x38    /* Reset highest IUS */
+
+#define RES_Rx_CRC     0x40    /* Reset Rx CRC Checker */
+#define RES_Tx_CRC     0x80    /* Reset Tx CRC Checker */
+#define RES_EOM_L      0xC0    /* Reset EOM latch */
+
+/* Write Register 1 (Tx/Rx/Ext Int Enable and WAIT/DMA Commands) */
+#define EXT_INT_ENAB   0x1     /* Ext Int Enable */
+#define TxINT_ENAB     0x2     /* Tx Int Enable */
+#define PAR_SPEC       0x4     /* Parity is special condition */
+
+#define RxINT_DISAB    0       /* Rx Int Disable */
+#define RxINT_FCERR    0x8     /* Rx Int on First Character Only or Error */
+#define RxINT_ALL      0x10    /* Int on all Rx Characters or error */
+#define RxINT_ERR      0x18    /* Int on error only */
+#define RxINT_MASK     0x18
+
+#define WT_RDY_RT      0x20    /* Wait/Ready on R/T */
+#define WT_FN_RDYFN    0x40    /* Wait/FN/Ready FN */
+#define WT_RDY_ENAB    0x80    /* Wait/Ready Enable */
+
+/* Write Register 2 (Interrupt Vector) */
+
+/* Write Register 3 (Receive Parameters and Control) */
+#define RxENABLE       0x1     /* Rx Enable */
+#define SYNC_L_INH     0x2     /* Sync Character Load Inhibit */
+#define ADD_SM         0x4     /* Address Search Mode (SDLC) */
+#define RxCRC_ENAB     0x8     /* Rx CRC Enable */
+#define ENT_HM         0x10    /* Enter Hunt Mode */
+#define AUTO_ENAB      0x20    /* Auto Enables */
+#define Rx5            0x0     /* Rx 5 Bits/Character */
+#define Rx7            0x40    /* Rx 7 Bits/Character */
+#define Rx6            0x80    /* Rx 6 Bits/Character */
+#define Rx8            0xc0    /* Rx 8 Bits/Character */
+#define RxNBITS_MASK   0xc0
+
+/* Write Register 4 (Transmit/Receive Miscellaneous Parameters and Modes) */
+#define PAR_ENA                0x1     /* Parity Enable */
+#define PAR_EVEN       0x2     /* Parity Even/Odd* */
+
+#define SYNC_ENAB      0       /* Sync Modes Enable */
+#define SB1            0x4     /* 1 stop bit/char */
+#define SB15           0x8     /* 1.5 stop bits/char */
+#define SB2            0xc     /* 2 stop bits/char */
+#define SB_MASK                0xc
+
+#define MONSYNC                0       /* 8 Bit Sync character */
+#define BISYNC         0x10    /* 16 bit sync character */
+#define SDLC           0x20    /* SDLC Mode (01111110 Sync Flag) */
+#define EXTSYNC                0x30    /* External Sync Mode */
+
+#define X1CLK          0x0     /* x1 clock mode */
+#define X16CLK         0x40    /* x16 clock mode */
+#define X32CLK         0x80    /* x32 clock mode */
+#define X64CLK         0xc0    /* x64 clock mode */
+#define XCLK_MASK      0xc0
+
+/* Write Register 5 (Transmit Parameters and Controls) */
+#define TxCRC_ENAB     0x1     /* Tx CRC Enable */
+#define RTS            0x2     /* RTS */
+#define SDLC_CRC       0x4     /* SDLC/CRC-16 */
+#define TxENAB         0x8     /* Tx Enable */
+#define SND_BRK                0x10    /* Send Break */
+#define Tx5            0x0     /* Tx 5 bits (or less)/character */
+#define Tx7            0x20    /* Tx 7 bits/character */
+#define Tx6            0x40    /* Tx 6 bits/character */
+#define Tx8            0x60    /* Tx 8 bits/character */
+#define TxNBITS_MASK   0x60
+#define DTR            0x80    /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (Transmit Buffer) */
+
+/* Write Register 9 (Master Interrupt Control) */
+#define VIS            1       /* Vector Includes Status */
+#define NV             2       /* No Vector */
+#define DLC            4       /* Disable Lower Chain */
+#define MIE            8       /* Master Interrupt Enable */
+#define STATHI         0x10    /* Status high */
+#define SOFTACK                0x20    /* Software Interrupt Acknowledge */
+#define NORESET                0       /* No reset on write to R9 */
+#define CHRB           0x40    /* Reset channel B */
+#define CHRA           0x80    /* Reset channel A */
+#define FHWRES         0xc0    /* Force hardware reset */
+
+/* Write Register 10 (Miscellaneous Transmitter/Receiver Control Bits) */
+#define BIT6           1       /* 6 bit/8bit sync */
+#define LOOPMODE       2       /* SDLC Loop mode */
+#define ABUNDER                4       /* Abort/flag on SDLC xmit underrun */
+#define MARKIDLE       8       /* Mark/flag on idle */
+#define GAOP           0x10    /* Go active on poll */
+#define NRZ            0       /* NRZ mode */
+#define NRZI           0x20    /* NRZI mode */
+#define FM1            0x40    /* FM1 (transition = 1) */
+#define FM0            0x60    /* FM0 (transition = 0) */
+#define CRCPS          0x80    /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode Control) */
+#define TRxCXT         0       /* TRxC = Xtal output */
+#define TRxCTC         1       /* TRxC = Transmit clock */
+#define TRxCBR         2       /* TRxC = BR Generator Output */
+#define TRxCDP         3       /* TRxC = DPLL output */
+#define TRxCOI         4       /* TRxC O/I */
+#define TCRTxCP                0       /* Transmit clock = RTxC pin */
+#define TCTRxCP                8       /* Transmit clock = TRxC pin */
+#define TCBR           0x10    /* Transmit clock = BR Generator output */
+#define TCDPLL         0x18    /* Transmit clock = DPLL output */
+#define RCRTxCP                0       /* Receive clock = RTxC pin */
+#define RCTRxCP                0x20    /* Receive clock = TRxC pin */
+#define RCBR           0x40    /* Receive clock = BR Generator output */
+#define RCDPLL         0x60    /* Receive clock = DPLL output */
+#define RTxCX          0x80    /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (Lower Byte of Baud Rate Generator Time Constant) */
+
+/* Write Register 13 (Upper Byte of Baud Rate Generator Time Constant) */
+
+/* Write Register 14 (Miscellaneous Control Bits) */
+#define BRENABL                1       /* Baud rate generator enable */
+#define BRSRC          2       /* Baud rate generator source */
+#define DTRREQ         4       /* DTR/Request function */
+#define AUTOECHO       8       /* Auto Echo */
+#define LOOPBAK                0x10    /* Local loopback */
+#define SEARCH         0x20    /* Enter search mode */
+#define RMC            0x40    /* Reset missing clock */
+#define DISDPLL                0x60    /* Disable DPLL */
+#define SSBR           0x80    /* Set DPLL source = BR generator */
+#define SSRTxC         0xa0    /* Set DPLL source = RTxC */
+#define SFMM           0xc0    /* Set FM mode */
+#define SNRZI          0xe0    /* Set NRZI mode */
+
+/* Write Register 15 (External/Status Interrupt Control) */
+#define WR7P_EN                1       /* WR7 Prime SDLC Feature Enable */
+#define ZCIE           2       /* Zero count IE */
+#define DCDIE          8       /* DCD IE */
+#define SYNCIE         0x10    /* Sync/hunt IE */
+#define CTSIE          0x20    /* CTS IE */
+#define TxUIE          0x40    /* Tx Underrun/EOM IE */
+#define BRKIE          0x80    /* Break/Abort IE */
+
+
+/* Read Register 0 (Transmit/Receive Buffer Status and External Status) */
+#define Rx_CH_AV       0x1     /* Rx Character Available */
+#define ZCOUNT         0x2     /* Zero count */
+#define Tx_BUF_EMP     0x4     /* Tx Buffer empty */
+#define DCD            0x8     /* DCD */
+#define SYNC_HUNT      0x10    /* Sync/hunt */
+#define CTS            0x20    /* CTS */
+#define TxEOM          0x40    /* Tx underrun */
+#define BRK_ABRT       0x80    /* Break/Abort */
+
+/* Read Register 1 (Special Receive Condition Status) */
+#define ALL_SNT                0x1     /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define RES3           0x8     /* 0/3 */
+#define RES4           0x4     /* 0/4 */
+#define RES5           0xc     /* 0/5 */
+#define RES6           0x2     /* 0/6 */
+#define RES7           0xa     /* 0/7 */
+#define RES8           0x6     /* 0/8 */
+#define RES18          0xe     /* 1/8 */
+#define RES28          0x0     /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define PAR_ERR                0x10    /* Parity Error */
+#define Rx_OVR         0x20    /* Rx Overrun Error */
+#define FRM_ERR                0x40    /* CRC/Framing Error */
+#define END_FR         0x80    /* End of Frame (SDLC) */
+
+/* Read Register 2 (Interrupt Vector (WR2) -- channel A).  */
+
+/* Read Register 2 (Modified Interrupt Vector -- channel B).  */
+
+/* Read Register 3 (Interrupt Pending Bits -- channel A only).  */
+#define CHBEXT         0x1     /* Channel B Ext/Stat IP */
+#define CHBTxIP                0x2     /* Channel B Tx IP */
+#define CHBRxIP                0x4     /* Channel B Rx IP */
+#define CHAEXT         0x8     /* Channel A Ext/Stat IP */
+#define CHATxIP                0x10    /* Channel A Tx IP */
+#define CHARxIP                0x20    /* Channel A Rx IP */
+
+/* Read Register 6 (SDLC FIFO Status and Byte Count LSB) */
+
+/* Read Register 7 (SDLC FIFO Status and Byte Count MSB) */
+
+/* Read Register 8 (Receive Data) */
+
+/* Read Register 10 (Miscellaneous Status Bits) */
+#define ONLOOP         2       /* On loop */
+#define LOOPSEND       0x10    /* Loop sending */
+#define CLK2MIS                0x40    /* Two clocks missing */
+#define CLK1MIS                0x80    /* One clock missing */
+
+/* Read Register 12 (Lower Byte of Baud Rate Generator Constant (WR12)) */
+
+/* Read Register 13 (Upper Byte of Baud Rate Generator Constant (WR13) */
+
+/* Read Register 15 (External/Status Interrupt Control (WR15)) */
+
+#endif /* _SERIAL_ZS_H */
index 9673426922114cacb1c70dcdda0f565955711d84..c899246bd3627ffc991f28e9ff1e2aa90f720c65 100644 (file)
@@ -5,7 +5,6 @@
 # Object file lists.
 
 obj-$(CONFIG_TC) += tc.o tc-driver.o
-obj-$(CONFIG_ZS) += zs.o
 obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o
 
 $(obj)/lk201-map.o: $(obj)/lk201-map.c
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c
deleted file mode 100644 (file)
index ed979f1..0000000
+++ /dev/null
@@ -1,2203 +0,0 @@
-/*
- * decserial.c: Serial port driver for IOASIC DECstations.
- *
- * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
- * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
- *
- * DECstation changes
- * Copyright (C) 1998-2000 Harald Koerfgen
- * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005  Maciej W. Rozycki
- *
- * For the rest of the code the original Copyright applies:
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- *
- *
- * Note: for IOASIC systems the wiring is as follows:
- *
- * mouse/keyboard:
- * DIN-7 MJ-4  signal        SCC
- * 2     1     TxD       <-  A.TxD
- * 3     4     RxD       ->  A.RxD
- *
- * EIA-232/EIA-423:
- * DB-25 MMJ-6 signal        SCC
- * 2     2     TxD       <-  B.TxD
- * 3     5     RxD       ->  B.RxD
- * 4           RTS       <- ~A.RTS
- * 5           CTS       -> ~B.CTS
- * 6     6     DSR       -> ~A.SYNC
- * 8           CD        -> ~B.DCD
- * 12          DSRS(DCE) -> ~A.CTS  (*)
- * 15          TxC       ->  B.TxC
- * 17          RxC       ->  B.RxC
- * 20    1     DTR       <- ~A.DTR
- * 22          RI        -> ~A.DCD
- * 23          DSRS(DTE) <- ~B.RTS
- *
- * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE)
- *     is shared with DSRS(DTE) at pin 23.
- */
-
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#ifdef CONFIG_SERIAL_DEC_CONSOLE
-#include <linux/console.h>
-#endif
-
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/bootinfo.h>
-
-#include <asm/dec/interrupts.h>
-#include <asm/dec/ioasic_addrs.h>
-#include <asm/dec/machtype.h>
-#include <asm/dec/serial.h>
-#include <asm/dec/system.h>
-
-#ifdef CONFIG_KGDB
-#include <asm/kgdb.h>
-#endif
-#ifdef CONFIG_MAGIC_SYSRQ
-#include <linux/sysrq.h>
-#endif
-
-#include "zs.h"
-
-/*
- * It would be nice to dynamically allocate everything that
- * depends on NUM_SERIAL, so we could support any number of
- * Z8530s, but for now...
- */
-#define NUM_SERIAL     2               /* Max number of ZS chips supported */
-#define NUM_CHANNELS   (NUM_SERIAL * 2)        /* 2 channels per chip */
-#define CHANNEL_A_NR  (zs_parms->channel_a_offset > zs_parms->channel_b_offset)
-                                        /* Number of channel A in the chip */
-#define ZS_CHAN_IO_SIZE 8
-#define ZS_CLOCK        7372800        /* Z8530 RTxC input clock rate */
-
-#define RECOVERY_DELAY  udelay(2)
-
-struct zs_parms {
-       unsigned long scc0;
-       unsigned long scc1;
-       int channel_a_offset;
-       int channel_b_offset;
-       int irq0;
-       int irq1;
-       int clock;
-};
-
-static struct zs_parms *zs_parms;
-
-#ifdef CONFIG_MACH_DECSTATION
-static struct zs_parms ds_parms = {
-       scc0 : IOASIC_SCC0,
-       scc1 : IOASIC_SCC1,
-       channel_a_offset : 1,
-       channel_b_offset : 9,
-       irq0 : -1,
-       irq1 : -1,
-       clock : ZS_CLOCK
-};
-#endif
-
-#ifdef CONFIG_MACH_DECSTATION
-#define DS_BUS_PRESENT (IOASIC)
-#else
-#define DS_BUS_PRESENT 0
-#endif
-
-#define BUS_PRESENT (DS_BUS_PRESENT)
-
-DEFINE_SPINLOCK(zs_lock);
-
-struct dec_zschannel zs_channels[NUM_CHANNELS];
-struct dec_serial zs_soft[NUM_CHANNELS];
-int zs_channels_found;
-struct dec_serial *zs_chain;   /* list of all channels */
-
-struct tty_struct zs_ttys[NUM_CHANNELS];
-
-#ifdef CONFIG_SERIAL_DEC_CONSOLE
-static struct console zs_console;
-#endif
-#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
-   !defined(MODULE)
-static unsigned long break_pressed; /* break, really ... */
-#endif
-
-static unsigned char zs_init_regs[16] __initdata = {
-       0,                              /* write 0 */
-       0,                              /* write 1 */
-       0,                              /* write 2 */
-       0,                              /* write 3 */
-       (X16CLK),                       /* write 4 */
-       0,                              /* write 5 */
-       0, 0, 0,                        /* write 6, 7, 8 */
-       (MIE | DLC | NV),               /* write 9 */
-       (NRZ),                          /* write 10 */
-       (TCBR | RCBR),                  /* write 11 */
-       0, 0,                           /* BRG time constant, write 12 + 13 */
-       (BRSRC | BRENABL),              /* write 14 */
-       0                               /* write 15 */
-};
-
-static struct tty_driver *serial_driver;
-
-/* serial subtype definitions */
-#define SERIAL_TYPE_NORMAL     1
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/*
- * Debugging.
- */
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_THROTTLE
-#undef SERIAL_PARANOIA_CHECK
-
-#undef ZS_DEBUG_REGS
-
-#ifdef SERIAL_DEBUG_THROTTLE
-#define _tty_name(tty,buf) tty_name(tty,buf)
-#endif
-
-#define RS_STROBE_TIME 10
-#define RS_ISR_PASS_LIMIT 256
-
-static void probe_sccs(void);
-static void change_speed(struct dec_serial *info);
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
-
-static inline int serial_paranoia_check(struct dec_serial *info,
-                                       char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
-       static const char *badmagic =
-               "Warning: bad magic number for serial struct %s in %s\n";
-       static const char *badinfo =
-               "Warning: null mac_serial for %s in %s\n";
-
-       if (!info) {
-               printk(badinfo, name, routine);
-               return 1;
-       }
-       if (info->magic != SERIAL_MAGIC) {
-               printk(badmagic, name, routine);
-               return 1;
-       }
-#endif
-       return 0;
-}
-
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
-       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-       9600, 19200, 38400, 57600, 115200, 0 };
-
-/*
- * Reading and writing Z8530 registers.
- */
-static inline unsigned char read_zsreg(struct dec_zschannel *channel,
-                                      unsigned char reg)
-{
-       unsigned char retval;
-
-       if (reg != 0) {
-               *channel->control = reg & 0xf;
-               fast_iob(); RECOVERY_DELAY;
-       }
-       retval = *channel->control;
-       RECOVERY_DELAY;
-       return retval;
-}
-
-static inline void write_zsreg(struct dec_zschannel *channel,
-                              unsigned char reg, unsigned char value)
-{
-       if (reg != 0) {
-               *channel->control = reg & 0xf;
-               fast_iob(); RECOVERY_DELAY;
-       }
-       *channel->control = value;
-       fast_iob(); RECOVERY_DELAY;
-       return;
-}
-
-static inline unsigned char read_zsdata(struct dec_zschannel *channel)
-{
-       unsigned char retval;
-
-       retval = *channel->data;
-       RECOVERY_DELAY;
-       return retval;
-}
-
-static inline void write_zsdata(struct dec_zschannel *channel,
-                               unsigned char value)
-{
-       *channel->data = value;
-       fast_iob(); RECOVERY_DELAY;
-       return;
-}
-
-static inline void load_zsregs(struct dec_zschannel *channel,
-                              unsigned char *regs)
-{
-/*     ZS_CLEARERR(channel);
-       ZS_CLEARFIFO(channel); */
-       /* Load 'em up */
-       write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
-       write_zsreg(channel, R5, regs[R5] & ~TxENAB);
-       write_zsreg(channel, R4, regs[R4]);
-       write_zsreg(channel, R9, regs[R9]);
-       write_zsreg(channel, R1, regs[R1]);
-       write_zsreg(channel, R2, regs[R2]);
-       write_zsreg(channel, R10, regs[R10]);
-       write_zsreg(channel, R11, regs[R11]);
-       write_zsreg(channel, R12, regs[R12]);
-       write_zsreg(channel, R13, regs[R13]);
-       write_zsreg(channel, R14, regs[R14]);
-       write_zsreg(channel, R15, regs[R15]);
-       write_zsreg(channel, R3, regs[R3]);
-       write_zsreg(channel, R5, regs[R5]);
-       return;
-}
-
-/* Sets or clears DTR/RTS on the requested line */
-static inline void zs_rtsdtr(struct dec_serial *info, int which, int set)
-{
-        unsigned long flags;
-
-       spin_lock_irqsave(&zs_lock, flags);
-       if (info->zs_channel != info->zs_chan_a) {
-               if (set) {
-                       info->zs_chan_a->curregs[5] |= (which & (RTS | DTR));
-               } else {
-                       info->zs_chan_a->curregs[5] &= ~(which & (RTS | DTR));
-               }
-               write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
-       }
-       spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-/* Utility routines for the Zilog */
-static inline int get_zsbaud(struct dec_serial *ss)
-{
-       struct dec_zschannel *channel = ss->zs_channel;
-       int brg;
-
-       /* The baud rate is split up between two 8-bit registers in
-        * what is termed 'BRG time constant' format in my docs for
-        * the chip, it is a function of the clk rate the chip is
-        * receiving which happens to be constant.
-        */
-       brg = (read_zsreg(channel, 13) << 8);
-       brg |= read_zsreg(channel, 12);
-       return BRG_TO_BPS(brg, (zs_parms->clock/(ss->clk_divisor)));
-}
-
-/* On receive, this clears errors and the receiver interrupts */
-static inline void rs_recv_clear(struct dec_zschannel *zsc)
-{
-       write_zsreg(zsc, 0, ERR_RES);
-       write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines.  All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt().  They were separated out for readability's sake.
- *
- *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- */
-static void rs_sched_event(struct dec_serial *info, int event)
-{
-       info->event |= 1 << event;
-       tasklet_schedule(&info->tlet);
-}
-
-static void receive_chars(struct dec_serial *info)
-{
-       struct tty_struct *tty = info->tty;
-       unsigned char ch, stat, flag;
-
-       while ((read_zsreg(info->zs_channel, R0) & Rx_CH_AV) != 0) {
-
-               stat = read_zsreg(info->zs_channel, R1);
-               ch = read_zsdata(info->zs_channel);
-
-               if (!tty && (!info->hook || !info->hook->rx_char))
-                       continue;
-
-               flag = TTY_NORMAL;
-               if (info->tty_break) {
-                       info->tty_break = 0;
-                       flag = TTY_BREAK;
-                       if (info->flags & ZILOG_SAK)
-                               do_SAK(tty);
-                       /* Ignore the null char got when BREAK is removed.  */
-                       if (ch == 0)
-                               continue;
-               } else {
-                       if (stat & Rx_OVR) {
-                               flag = TTY_OVERRUN;
-                       } else if (stat & FRM_ERR) {
-                               flag = TTY_FRAME;
-                       } else if (stat & PAR_ERR) {
-                               flag = TTY_PARITY;
-                       }
-                       if (flag != TTY_NORMAL)
-                               /* reset the error indication */
-                               write_zsreg(info->zs_channel, R0, ERR_RES);
-               }
-
-#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
-   !defined(MODULE)
-               if (break_pressed && info->line == zs_console.index) {
-                       /* Ignore the null char got when BREAK is removed.  */
-                       if (ch == 0)
-                               continue;
-                       if (time_before(jiffies, break_pressed + HZ * 5)) {
-                               handle_sysrq(ch, NULL);
-                               break_pressed = 0;
-                               continue;
-                       }
-                       break_pressed = 0;
-               }
-#endif
-
-               if (info->hook && info->hook->rx_char) {
-                       (*info->hook->rx_char)(ch, flag);
-                       return;
-               }
-
-               tty_insert_flip_char(tty, ch, flag);
-       }
-       if (tty)
-               tty_flip_buffer_push(tty);
-}
-
-static void transmit_chars(struct dec_serial *info)
-{
-       if ((read_zsreg(info->zs_channel, R0) & Tx_BUF_EMP) == 0)
-               return;
-       info->tx_active = 0;
-
-       if (info->x_char) {
-               /* Send next char */
-               write_zsdata(info->zs_channel, info->x_char);
-               info->x_char = 0;
-               info->tx_active = 1;
-               return;
-       }
-
-       if ((info->xmit_cnt <= 0) || (info->tty && info->tty->stopped)
-           || info->tx_stopped) {
-               write_zsreg(info->zs_channel, R0, RES_Tx_P);
-               return;
-       }
-       /* Send char */
-       write_zsdata(info->zs_channel, info->xmit_buf[info->xmit_tail++]);
-       info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
-       info->xmit_cnt--;
-       info->tx_active = 1;
-
-       if (info->xmit_cnt < WAKEUP_CHARS)
-               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-}
-
-static void status_handle(struct dec_serial *info)
-{
-       unsigned char stat;
-
-       /* Get status from Read Register 0 */
-       stat = read_zsreg(info->zs_channel, R0);
-
-       if ((stat & BRK_ABRT) && !(info->read_reg_zero & BRK_ABRT)) {
-#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
-   !defined(MODULE)
-               if (info->line == zs_console.index) {
-                       if (!break_pressed)
-                               break_pressed = jiffies;
-               } else
-#endif
-                       info->tty_break = 1;
-       }
-
-       if (info->zs_channel != info->zs_chan_a) {
-
-               /* Check for DCD transitions */
-               if (info->tty && !C_CLOCAL(info->tty) &&
-                   ((stat ^ info->read_reg_zero) & DCD) != 0 ) {
-                       if (stat & DCD) {
-                               wake_up_interruptible(&info->open_wait);
-                       } else {
-                               tty_hangup(info->tty);
-                       }
-               }
-
-               /* Check for CTS transitions */
-               if (info->tty && C_CRTSCTS(info->tty)) {
-                       if ((stat & CTS) != 0) {
-                               if (info->tx_stopped) {
-                                       info->tx_stopped = 0;
-                                       if (!info->tx_active)
-                                               transmit_chars(info);
-                               }
-                       } else {
-                               info->tx_stopped = 1;
-                       }
-               }
-
-       }
-
-       /* Clear status condition... */
-       write_zsreg(info->zs_channel, R0, RES_EXT_INT);
-       info->read_reg_zero = stat;
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-static irqreturn_t rs_interrupt(int irq, void *dev_id)
-{
-       struct dec_serial *info = (struct dec_serial *) dev_id;
-       irqreturn_t status = IRQ_NONE;
-       unsigned char zs_intreg;
-       int shift;
-
-       /* NOTE: The read register 3, which holds the irq status,
-        *       does so for both channels on each chip.  Although
-        *       the status value itself must be read from the A
-        *       channel and is only valid when read from channel A.
-        *       Yes... broken hardware...
-        */
-#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
-
-       if (info->zs_chan_a == info->zs_channel)
-               shift = 3;      /* Channel A */
-       else
-               shift = 0;      /* Channel B */
-
-       for (;;) {
-               zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift;
-               if ((zs_intreg & CHAN_IRQMASK) == 0)
-                       break;
-
-               status = IRQ_HANDLED;
-
-               if (zs_intreg & CHBRxIP) {
-                       receive_chars(info);
-               }
-               if (zs_intreg & CHBTxIP) {
-                       transmit_chars(info);
-               }
-               if (zs_intreg & CHBEXT) {
-                       status_handle(info);
-               }
-       }
-
-       /* Why do we need this ? */
-       write_zsreg(info->zs_channel, 0, RES_H_IUS);
-
-       return status;
-}
-
-#ifdef ZS_DEBUG_REGS
-void zs_dump (void) {
-       int i, j;
-       for (i = 0; i < zs_channels_found; i++) {
-               struct dec_zschannel *ch = &zs_channels[i];
-               if ((long)ch->control == UNI_IO_BASE+UNI_SCC1A_CTRL) {
-                       for (j = 0; j < 15; j++) {
-                               printk("W%d = 0x%x\t",
-                                      j, (int)ch->curregs[j]);
-                       }
-                       for (j = 0; j < 15; j++) {
-                               printk("R%d = 0x%x\t",
-                                      j, (int)read_zsreg(ch,j));
-                       }
-                       printk("\n\n");
-               }
-       }
-}
-#endif
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * ------------------------------------------------------------
- */
-static void rs_stop(struct tty_struct *tty)
-{
-       struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_stop"))
-               return;
-
-#if 1
-       spin_lock_irqsave(&zs_lock, flags);
-       if (info->zs_channel->curregs[5] & TxENAB) {
-               info->zs_channel->curregs[5] &= ~TxENAB;
-               write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
-       }
-       spin_unlock_irqrestore(&zs_lock, flags);
-#endif
-}
-
-static void rs_start(struct tty_struct *tty)
-{
-       struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_start"))
-               return;
-
-       spin_lock_irqsave(&zs_lock, flags);
-#if 1
-       if (info->xmit_cnt && info->xmit_buf && !(info->zs_channel->curregs[5] & TxENAB)) {
-               info->zs_channel->curregs[5] |= TxENAB;
-               write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
-       }
-#else
-       if (info->xmit_cnt && info->xmit_buf && !info->tx_active) {
-               transmit_chars(info);
-       }
-#endif
-       spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using rs_sched_event(), and they get done here.
- */
-
-static void do_softint(unsigned long private_)
-{
-       struct dec_serial       *info = (struct dec_serial *) private_;
-       struct tty_struct       *tty;
-
-       tty = info->tty;
-       if (!tty)
-               return;
-
-       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
-               tty_wakeup(tty);
-}
-
-static int zs_startup(struct dec_serial * info)
-{
-       unsigned long flags;
-
-       if (info->flags & ZILOG_INITIALIZED)
-               return 0;
-
-       if (!info->xmit_buf) {
-               info->xmit_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
-               if (!info->xmit_buf)
-                       return -ENOMEM;
-       }
-
-       spin_lock_irqsave(&zs_lock, flags);
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
-#endif
-
-       /*
-        * Clear the receive FIFO.
-        */
-       ZS_CLEARFIFO(info->zs_channel);
-       info->xmit_fifo_size = 1;
-
-       /*
-        * Clear the interrupt registers.
-        */
-       write_zsreg(info->zs_channel, R0, ERR_RES);
-       write_zsreg(info->zs_channel, R0, RES_H_IUS);
-
-       /*
-        * Set the speed of the serial port
-        */
-       change_speed(info);
-
-       /*
-        * Turn on RTS and DTR.
-        */
-       zs_rtsdtr(info, RTS | DTR, 1);
-
-       /*
-        * Finally, enable sequencing and interrupts
-        */
-       info->zs_channel->curregs[R1] &= ~RxINT_MASK;
-       info->zs_channel->curregs[R1] |= (RxINT_ALL | TxINT_ENAB |
-                                         EXT_INT_ENAB);
-       info->zs_channel->curregs[R3] |= RxENABLE;
-       info->zs_channel->curregs[R5] |= TxENAB;
-       info->zs_channel->curregs[R15] |= (DCDIE | CTSIE | TxUIE | BRKIE);
-       write_zsreg(info->zs_channel, R1, info->zs_channel->curregs[R1]);
-       write_zsreg(info->zs_channel, R3, info->zs_channel->curregs[R3]);
-       write_zsreg(info->zs_channel, R5, info->zs_channel->curregs[R5]);
-       write_zsreg(info->zs_channel, R15, info->zs_channel->curregs[R15]);
-
-       /*
-        * And clear the interrupt registers again for luck.
-        */
-       write_zsreg(info->zs_channel, R0, ERR_RES);
-       write_zsreg(info->zs_channel, R0, RES_H_IUS);
-
-       /* Save the current value of RR0 */
-       info->read_reg_zero = read_zsreg(info->zs_channel, R0);
-
-       if (info->tty)
-               clear_bit(TTY_IO_ERROR, &info->tty->flags);
-       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
-       info->flags |= ZILOG_INITIALIZED;
-       spin_unlock_irqrestore(&zs_lock, flags);
-       return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(struct dec_serial * info)
-{
-       unsigned long   flags;
-
-       if (!(info->flags & ZILOG_INITIALIZED))
-               return;
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("Shutting down serial port %d (irq %d)....", info->line,
-              info->irq);
-#endif
-
-       spin_lock_irqsave(&zs_lock, flags);
-
-       if (info->xmit_buf) {
-               free_page((unsigned long) info->xmit_buf);
-               info->xmit_buf = 0;
-       }
-
-       info->zs_channel->curregs[1] = 0;
-       write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]); /* no interrupts */
-
-       info->zs_channel->curregs[3] &= ~RxENABLE;
-       write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
-
-       info->zs_channel->curregs[5] &= ~TxENAB;
-       write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
-       if (!info->tty || C_HUPCL(info->tty)) {
-               zs_rtsdtr(info, RTS | DTR, 0);
-       }
-
-       if (info->tty)
-               set_bit(TTY_IO_ERROR, &info->tty->flags);
-
-       info->flags &= ~ZILOG_INITIALIZED;
-       spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(struct dec_serial *info)
-{
-       unsigned cflag;
-       int     i;
-       int     brg, bits;
-       unsigned long flags;
-
-       if (!info->hook) {
-               if (!info->tty || !info->tty->termios)
-                       return;
-               cflag = info->tty->termios->c_cflag;
-               if (!info->port)
-                       return;
-       } else {
-               cflag = info->hook->cflags;
-       }
-
-       i = cflag & CBAUD;
-       if (i & CBAUDEX) {
-               i &= ~CBAUDEX;
-               if (i < 1 || i > 2) {
-                       if (!info->hook)
-                               info->tty->termios->c_cflag &= ~CBAUDEX;
-                       else
-                               info->hook->cflags &= ~CBAUDEX;
-               } else
-                       i += 15;
-       }
-
-       spin_lock_irqsave(&zs_lock, flags);
-       info->zs_baud = baud_table[i];
-       if (info->zs_baud) {
-               brg = BPS_TO_BRG(info->zs_baud, zs_parms->clock/info->clk_divisor);
-               info->zs_channel->curregs[12] = (brg & 255);
-               info->zs_channel->curregs[13] = ((brg >> 8) & 255);
-               zs_rtsdtr(info, DTR, 1);
-       } else {
-               zs_rtsdtr(info, RTS | DTR, 0);
-               return;
-       }
-
-       /* byte size and parity */
-       info->zs_channel->curregs[3] &= ~RxNBITS_MASK;
-       info->zs_channel->curregs[5] &= ~TxNBITS_MASK;
-       switch (cflag & CSIZE) {
-       case CS5:
-               bits = 7;
-               info->zs_channel->curregs[3] |= Rx5;
-               info->zs_channel->curregs[5] |= Tx5;
-               break;
-       case CS6:
-               bits = 8;
-               info->zs_channel->curregs[3] |= Rx6;
-               info->zs_channel->curregs[5] |= Tx6;
-               break;
-       case CS7:
-               bits = 9;
-               info->zs_channel->curregs[3] |= Rx7;
-               info->zs_channel->curregs[5] |= Tx7;
-               break;
-       case CS8:
-       default: /* defaults to 8 bits */
-               bits = 10;
-               info->zs_channel->curregs[3] |= Rx8;
-               info->zs_channel->curregs[5] |= Tx8;
-               break;
-       }
-
-       info->timeout = ((info->xmit_fifo_size*HZ*bits) / info->zs_baud);
-        info->timeout += HZ/50;         /* Add .02 seconds of slop */
-
-       info->zs_channel->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
-       if (cflag & CSTOPB) {
-               info->zs_channel->curregs[4] |= SB2;
-       } else {
-               info->zs_channel->curregs[4] |= SB1;
-       }
-       if (cflag & PARENB) {
-               info->zs_channel->curregs[4] |= PAR_ENA;
-       }
-       if (!(cflag & PARODD)) {
-               info->zs_channel->curregs[4] |= PAR_EVEN;
-       }
-
-       if (!(cflag & CLOCAL)) {
-               if (!(info->zs_channel->curregs[15] & DCDIE))
-                       info->read_reg_zero = read_zsreg(info->zs_channel, 0);
-               info->zs_channel->curregs[15] |= DCDIE;
-       } else
-               info->zs_channel->curregs[15] &= ~DCDIE;
-       if (cflag & CRTSCTS) {
-               info->zs_channel->curregs[15] |= CTSIE;
-               if ((read_zsreg(info->zs_channel, 0) & CTS) == 0)
-                       info->tx_stopped = 1;
-       } else {
-               info->zs_channel->curregs[15] &= ~CTSIE;
-               info->tx_stopped = 0;
-       }
-
-       /* Load up the new values */
-       load_zsregs(info->zs_channel, info->zs_channel->curregs);
-
-       spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
-       struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
-               return;
-
-       if (info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped ||
-           !info->xmit_buf)
-               return;
-
-       /* Enable transmitter */
-       spin_lock_irqsave(&zs_lock, flags);
-       transmit_chars(info);
-       spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-static int rs_write(struct tty_struct * tty,
-                   const unsigned char *buf, int count)
-{
-       int     c, total = 0;
-       struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_write"))
-               return 0;
-
-       if (!tty || !info->xmit_buf)
-               return 0;
-
-       while (1) {
-               spin_lock_irqsave(&zs_lock, flags);
-               c = min(count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                                  SERIAL_XMIT_SIZE - info->xmit_head));
-               if (c <= 0)
-                       break;
-
-               memcpy(info->xmit_buf + info->xmit_head, buf, c);
-               info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-               info->xmit_cnt += c;
-               spin_unlock_irqrestore(&zs_lock, flags);
-               buf += c;
-               count -= c;
-               total += c;
-       }
-
-       if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
-           && !info->tx_active)
-               transmit_chars(info);
-       spin_unlock_irqrestore(&zs_lock, flags);
-       return total;
-}
-
-static int rs_write_room(struct tty_struct *tty)
-{
-       struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-       int     ret;
-
-       if (serial_paranoia_check(info, tty->name, "rs_write_room"))
-               return 0;
-       ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
-       if (ret < 0)
-               ret = 0;
-       return ret;
-}
-
-static int rs_chars_in_buffer(struct tty_struct *tty)
-{
-       struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
-               return 0;
-       return info->xmit_cnt;
-}
-
-static void rs_flush_buffer(struct tty_struct *tty)
-{
-       struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
-               return;
-       spin_lock_irq(&zs_lock);
-       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-       spin_unlock_irq(&zs_lock);
-       tty_wakeup(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void rs_throttle(struct tty_struct * tty)
-{
-       struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-       unsigned long flags;
-
-#ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
-
-       printk("throttle %s: %d....\n", _tty_name(tty, buf),
-              tty->ldisc.chars_in_buffer(tty));
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "rs_throttle"))
-               return;
-
-       if (I_IXOFF(tty)) {
-               spin_lock_irqsave(&zs_lock, flags);
-               info->x_char = STOP_CHAR(tty);
-               if (!info->tx_active)
-                       transmit_chars(info);
-               spin_unlock_irqrestore(&zs_lock, flags);
-       }
-
-       if (C_CRTSCTS(tty)) {
-               zs_rtsdtr(info, RTS, 0);
-       }
-}
-
-static void rs_unthrottle(struct tty_struct * tty)
-{
-       struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-       unsigned long flags;
-
-#ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
-
-       printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
-              tty->ldisc.chars_in_buffer(tty));
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
-               return;
-
-       if (I_IXOFF(tty)) {
-               spin_lock_irqsave(&zs_lock, flags);
-               if (info->x_char)
-                       info->x_char = 0;
-               else {
-                       info->x_char = START_CHAR(tty);
-                       if (!info->tx_active)
-                               transmit_chars(info);
-               }
-               spin_unlock_irqrestore(&zs_lock, flags);
-       }
-
-       if (C_CRTSCTS(tty)) {
-               zs_rtsdtr(info, RTS, 1);
-       }
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct dec_serial * info,
-                          struct serial_struct * retinfo)
-{
-       struct serial_struct tmp;
-
-       if (!retinfo)
-               return -EFAULT;
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.type = info->type;
-       tmp.line = info->line;
-       tmp.port = info->port;
-       tmp.irq = info->irq;
-       tmp.flags = info->flags;
-       tmp.baud_base = info->baud_base;
-       tmp.close_delay = info->close_delay;
-       tmp.closing_wait = info->closing_wait;
-       tmp.custom_divisor = info->custom_divisor;
-       return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0;
-}
-
-static int set_serial_info(struct dec_serial * info,
-                          struct serial_struct * new_info)
-{
-       struct serial_struct new_serial;
-       struct dec_serial old_info;
-       int                     retval = 0;
-
-       if (!new_info)
-               return -EFAULT;
-       copy_from_user(&new_serial,new_info,sizeof(new_serial));
-       old_info = *info;
-
-       if (!capable(CAP_SYS_ADMIN)) {
-               if ((new_serial.baud_base != info->baud_base) ||
-                   (new_serial.type != info->type) ||
-                   (new_serial.close_delay != info->close_delay) ||
-                   ((new_serial.flags & ~ZILOG_USR_MASK) !=
-                    (info->flags & ~ZILOG_USR_MASK)))
-                       return -EPERM;
-               info->flags = ((info->flags & ~ZILOG_USR_MASK) |
-                              (new_serial.flags & ZILOG_USR_MASK));
-               info->custom_divisor = new_serial.custom_divisor;
-               goto check_and_exit;
-       }
-
-       if (info->count > 1)
-               return -EBUSY;
-
-       /*
-        * OK, past this point, all the error checking has been done.
-        * At this point, we start making changes.....
-        */
-
-       info->baud_base = new_serial.baud_base;
-       info->flags = ((info->flags & ~ZILOG_FLAGS) |
-                       (new_serial.flags & ZILOG_FLAGS));
-       info->type = new_serial.type;
-       info->close_delay = new_serial.close_delay;
-       info->closing_wait = new_serial.closing_wait;
-
-check_and_exit:
-       retval = zs_startup(info);
-       return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *         is emptied.  On bus types like RS485, the transmitter must
- *         release the bus after transmitting. This must be done when
- *         the transmit shift register is empty, not be done when the
- *         transmit holding register is empty.  This functionality
- *         allows an RS485 driver to be written in user space.
- */
-static int get_lsr_info(struct dec_serial * info, unsigned int *value)
-{
-       unsigned char status;
-
-       spin_lock(&zs_lock);
-       status = read_zsreg(info->zs_channel, 0);
-       spin_unlock_irq(&zs_lock);
-       put_user(status,value);
-       return 0;
-}
-
-static int rs_tiocmget(struct tty_struct *tty, struct file *file)
-{
-       struct dec_serial * info = (struct dec_serial *)tty->driver_data;
-       unsigned char control, status_a, status_b;
-       unsigned int result;
-
-       if (info->hook)
-               return -ENODEV;
-
-       if (serial_paranoia_check(info, tty->name, __FUNCTION__))
-               return -ENODEV;
-
-       if (tty->flags & (1 << TTY_IO_ERROR))
-               return -EIO;
-
-       if (info->zs_channel == info->zs_chan_a)
-               result = 0;
-       else {
-               spin_lock(&zs_lock);
-               control = info->zs_chan_a->curregs[5];
-               status_a = read_zsreg(info->zs_chan_a, 0);
-               status_b = read_zsreg(info->zs_channel, 0);
-               spin_unlock_irq(&zs_lock);
-               result =  ((control  & RTS) ? TIOCM_RTS: 0)
-                       | ((control  & DTR) ? TIOCM_DTR: 0)
-                       | ((status_b & DCD) ? TIOCM_CAR: 0)
-                       | ((status_a & DCD) ? TIOCM_RNG: 0)
-                       | ((status_a & SYNC_HUNT) ? TIOCM_DSR: 0)
-                       | ((status_b & CTS) ? TIOCM_CTS: 0);
-       }
-       return result;
-}
-
-static int rs_tiocmset(struct tty_struct *tty, struct file *file,
-                       unsigned int set, unsigned int clear)
-{
-       struct dec_serial * info = (struct dec_serial *)tty->driver_data;
-
-       if (info->hook)
-               return -ENODEV;
-
-       if (serial_paranoia_check(info, tty->name, __FUNCTION__))
-               return -ENODEV;
-
-       if (tty->flags & (1 << TTY_IO_ERROR))
-               return -EIO;
-
-       if (info->zs_channel == info->zs_chan_a)
-               return 0;
-
-       spin_lock(&zs_lock);
-       if (set & TIOCM_RTS)
-               info->zs_chan_a->curregs[5] |= RTS;
-       if (set & TIOCM_DTR)
-               info->zs_chan_a->curregs[5] |= DTR;
-       if (clear & TIOCM_RTS)
-               info->zs_chan_a->curregs[5] &= ~RTS;
-       if (clear & TIOCM_DTR)
-               info->zs_chan_a->curregs[5] &= ~DTR;
-       write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
-       spin_unlock_irq(&zs_lock);
-       return 0;
-}
-
-/*
- * rs_break - turn transmit break condition on/off
- */
-static void rs_break(struct tty_struct *tty, int break_state)
-{
-       struct dec_serial *info = (struct dec_serial *) tty->driver_data;
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_break"))
-               return;
-       if (!info->port)
-               return;
-
-       spin_lock_irqsave(&zs_lock, flags);
-       if (break_state == -1)
-               info->zs_channel->curregs[5] |= SND_BRK;
-       else
-               info->zs_channel->curregs[5] &= ~SND_BRK;
-       write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
-       spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-static int rs_ioctl(struct tty_struct *tty, struct file * file,
-                   unsigned int cmd, unsigned long arg)
-{
-       struct dec_serial * info = (struct dec_serial *)tty->driver_data;
-
-       if (info->hook)
-               return -ENODEV;
-
-       if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
-               return -ENODEV;
-
-       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
-           (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
-                   return -EIO;
-       }
-
-       switch (cmd) {
-       case TIOCGSERIAL:
-               if (!access_ok(VERIFY_WRITE, (void *)arg,
-                              sizeof(struct serial_struct)))
-                       return -EFAULT;
-               return get_serial_info(info, (struct serial_struct *)arg);
-
-       case TIOCSSERIAL:
-               return set_serial_info(info, (struct serial_struct *)arg);
-
-       case TIOCSERGETLSR:                     /* Get line status register */
-               if (!access_ok(VERIFY_WRITE, (void *)arg,
-                              sizeof(unsigned int)))
-                       return -EFAULT;
-               return get_lsr_info(info, (unsigned int *)arg);
-
-       case TIOCSERGSTRUCT:
-               if (!access_ok(VERIFY_WRITE, (void *)arg,
-                              sizeof(struct dec_serial)))
-                       return -EFAULT;
-               copy_from_user((struct dec_serial *)arg, info,
-                              sizeof(struct dec_serial));
-               return 0;
-
-       default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
-       struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-       int was_stopped;
-
-       if (tty->termios->c_cflag == old_termios->c_cflag)
-               return;
-       was_stopped = info->tx_stopped;
-
-       change_speed(info);
-
-       if (was_stopped && !info->tx_stopped)
-               rs_start(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- *
- * This routine is called when the serial port gets closed.
- * Wait for the last remaining data to be sent.
- * ------------------------------------------------------------
- */
-static void rs_close(struct tty_struct *tty, struct file * filp)
-{
-       struct dec_serial * info = (struct dec_serial *)tty->driver_data;
-       unsigned long flags;
-
-       if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
-               return;
-
-       spin_lock_irqsave(&zs_lock, flags);
-
-       if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&zs_lock, flags);
-               return;
-       }
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("rs_close ttyS%d, count = %d\n", info->line, info->count);
-#endif
-       if ((tty->count == 1) && (info->count != 1)) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  Info->count should always
-                * be one in these conditions.  If it's greater than
-                * one, we've got real problems, since it means the
-                * serial port won't be shutdown.
-                */
-               printk("rs_close: bad serial port count; tty->count is 1, "
-                      "info->count is %d\n", info->count);
-               info->count = 1;
-       }
-       if (--info->count < 0) {
-               printk("rs_close: bad serial port count for ttyS%d: %d\n",
-                      info->line, info->count);
-               info->count = 0;
-       }
-       if (info->count) {
-               spin_unlock_irqrestore(&zs_lock, flags);
-               return;
-       }
-       info->flags |= ZILOG_CLOSING;
-       /*
-        * Now we wait for the transmit buffer to clear; and we notify
-        * the line discipline to only process XON/XOFF characters.
-        */
-       tty->closing = 1;
-       if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->closing_wait);
-       /*
-        * At this point we stop accepting input.  To do this, we
-        * disable the receiver and receive interrupts.
-        */
-       info->zs_channel->curregs[3] &= ~RxENABLE;
-       write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
-       info->zs_channel->curregs[1] = 0;       /* disable any rx ints */
-       write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]);
-       ZS_CLEARFIFO(info->zs_channel);
-       if (info->flags & ZILOG_INITIALIZED) {
-               /*
-                * Before we drop DTR, make sure the SCC transmitter
-                * has completely drained.
-                */
-               rs_wait_until_sent(tty, info->timeout);
-       }
-
-       shutdown(info);
-       if (tty->driver->flush_buffer)
-               tty->driver->flush_buffer(tty);
-       tty_ldisc_flush(tty);
-       tty->closing = 0;
-       info->event = 0;
-       info->tty = 0;
-       if (info->blocked_open) {
-               if (info->close_delay) {
-                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
-               }
-               wake_up_interruptible(&info->open_wait);
-       }
-       info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING);
-       wake_up_interruptible(&info->close_wait);
-       spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-       struct dec_serial *info = (struct dec_serial *) tty->driver_data;
-       unsigned long orig_jiffies;
-       int char_time;
-
-       if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
-               return;
-
-       orig_jiffies = jiffies;
-       /*
-        * Set the check interval to be 1/5 of the estimated time to
-        * send a single character, and make it at least 1.  The check
-        * interval should also be less than the timeout.
-        */
-       char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
-       char_time = char_time / 5;
-       if (char_time == 0)
-               char_time = 1;
-       if (timeout)
-               char_time = min(char_time, timeout);
-       while ((read_zsreg(info->zs_channel, 1) & Tx_BUF_EMP) == 0) {
-               msleep_interruptible(jiffies_to_msecs(char_time));
-               if (signal_pending(current))
-                       break;
-               if (timeout && time_after(jiffies, orig_jiffies + timeout))
-                       break;
-       }
-       current->state = TASK_RUNNING;
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void rs_hangup(struct tty_struct *tty)
-{
-       struct dec_serial * info = (struct dec_serial *)tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "rs_hangup"))
-               return;
-
-       rs_flush_buffer(tty);
-       shutdown(info);
-       info->event = 0;
-       info->count = 0;
-       info->flags &= ~ZILOG_NORMAL_ACTIVE;
-       info->tty = 0;
-       wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
-                          struct dec_serial *info)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       int             retval;
-       int             do_clocal = 0;
-
-       /*
-        * If the device is in the middle of being closed, then block
-        * until it's done, and then try again.
-        */
-       if (info->flags & ZILOG_CLOSING) {
-               interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-               return ((info->flags & ZILOG_HUP_NOTIFY) ?
-                       -EAGAIN : -ERESTARTSYS);
-#else
-               return -EAGAIN;
-#endif
-       }
-
-       /*
-        * If non-blocking mode is set, or the port is not enabled,
-        * then make the check up front and then exit.
-        */
-       if ((filp->f_flags & O_NONBLOCK) ||
-           (tty->flags & (1 << TTY_IO_ERROR))) {
-               info->flags |= ZILOG_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (tty->termios->c_cflag & CLOCAL)
-               do_clocal = 1;
-
-       /*
-        * Block waiting for the carrier detect and the line to become
-        * free (i.e., not in use by the callout).  While we are in
-        * this loop, info->count is dropped by one, so that
-        * rs_close() knows when to free things.  We restore it upon
-        * exit, either normal or abnormal.
-        */
-       retval = 0;
-       add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
-       printk("block_til_ready before block: ttyS%d, count = %d\n",
-              info->line, info->count);
-#endif
-       spin_lock(&zs_lock);
-       if (!tty_hung_up_p(filp))
-               info->count--;
-       spin_unlock_irq(&zs_lock);
-       info->blocked_open++;
-       while (1) {
-               spin_lock(&zs_lock);
-               if (tty->termios->c_cflag & CBAUD)
-                       zs_rtsdtr(info, RTS | DTR, 1);
-               spin_unlock_irq(&zs_lock);
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) ||
-                   !(info->flags & ZILOG_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-                       if (info->flags & ZILOG_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;
-#else
-                       retval = -EAGAIN;
-#endif
-                       break;
-               }
-               if (!(info->flags & ZILOG_CLOSING) &&
-                   (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD)))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-#ifdef SERIAL_DEBUG_OPEN
-               printk("block_til_ready blocking: ttyS%d, count = %d\n",
-                      info->line, info->count);
-#endif
-               schedule();
-       }
-       current->state = TASK_RUNNING;
-       remove_wait_queue(&info->open_wait, &wait);
-       if (!tty_hung_up_p(filp))
-               info->count++;
-       info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
-       printk("block_til_ready after blocking: ttyS%d, count = %d\n",
-              info->line, info->count);
-#endif
-       if (retval)
-               return retval;
-       info->flags |= ZILOG_NORMAL_ACTIVE;
-       return 0;
-}
-
-/*
- * This routine is called whenever a serial port is opened.  It
- * enables interrupts for a serial port, linking in its ZILOG structure into
- * the IRQ chain.   It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int rs_open(struct tty_struct *tty, struct file * filp)
-{
-       struct dec_serial       *info;
-       int                     retval, line;
-
-       line = tty->index;
-       if ((line < 0) || (line >= zs_channels_found))
-               return -ENODEV;
-       info = zs_soft + line;
-
-       if (info->hook)
-               return -ENODEV;
-
-       if (serial_paranoia_check(info, tty->name, "rs_open"))
-               return -ENODEV;
-#ifdef SERIAL_DEBUG_OPEN
-       printk("rs_open %s, count = %d\n", tty->name, info->count);
-#endif
-
-       info->count++;
-       tty->driver_data = info;
-       info->tty = tty;
-
-       /*
-        * If the port is the middle of closing, bail out now
-        */
-       if (tty_hung_up_p(filp) ||
-           (info->flags & ZILOG_CLOSING)) {
-               if (info->flags & ZILOG_CLOSING)
-                       interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-               return ((info->flags & ZILOG_HUP_NOTIFY) ?
-                       -EAGAIN : -ERESTARTSYS);
-#else
-               return -EAGAIN;
-#endif
-       }
-
-       /*
-        * Start up serial port
-        */
-       retval = zs_startup(info);
-       if (retval)
-               return retval;
-
-       retval = block_til_ready(tty, filp, info);
-       if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-               printk("rs_open returning after block_til_ready with %d\n",
-                      retval);
-#endif
-               return retval;
-       }
-
-#ifdef CONFIG_SERIAL_DEC_CONSOLE
-       if (zs_console.cflag && zs_console.index == line) {
-               tty->termios->c_cflag = zs_console.cflag;
-               zs_console.cflag = 0;
-               change_speed(info);
-       }
-#endif
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("rs_open %s successful...", tty->name);
-#endif
-/* tty->low_latency = 1; */
-       return 0;
-}
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void __init show_serial_version(void)
-{
-       printk("DECstation Z8530 serial driver version 0.09\n");
-}
-
-/*  Initialize Z8530s zs_channels
- */
-
-static void __init probe_sccs(void)
-{
-       struct dec_serial **pp;
-       int i, n, n_chips = 0, n_channels, chip, channel;
-       unsigned long flags;
-
-       /*
-        * did we get here by accident?
-        */
-       if(!BUS_PRESENT) {
-               printk("Not on JUNKIO machine, skipping probe_sccs\n");
-               return;
-       }
-
-       switch(mips_machtype) {
-#ifdef CONFIG_MACH_DECSTATION
-       case MACH_DS5000_2X0:
-       case MACH_DS5900:
-               n_chips = 2;
-               zs_parms = &ds_parms;
-               zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
-               zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
-               break;
-       case MACH_DS5000_1XX:
-               n_chips = 2;
-               zs_parms = &ds_parms;
-               zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
-               zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
-               break;
-       case MACH_DS5000_XX:
-               n_chips = 1;
-               zs_parms = &ds_parms;
-               zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
-               break;
-#endif
-       default:
-               panic("zs: unsupported bus");
-       }
-       if (!zs_parms)
-               panic("zs: uninitialized parms");
-
-       pp = &zs_chain;
-
-       n_channels = 0;
-
-       for (chip = 0; chip < n_chips; chip++) {
-               for (channel = 0; channel <= 1; channel++) {
-                       /*
-                        * The sccs reside on the high byte of the 16 bit IOBUS
-                        */
-                       zs_channels[n_channels].control =
-                               (volatile void *)CKSEG1ADDR(dec_kn_slot_base +
-                         (0 == chip ? zs_parms->scc0 : zs_parms->scc1) +
-                         (0 == channel ? zs_parms->channel_a_offset :
-                                         zs_parms->channel_b_offset));
-                       zs_channels[n_channels].data =
-                               zs_channels[n_channels].control + 4;
-
-#ifndef CONFIG_SERIAL_DEC_CONSOLE
-                       /*
-                        * We're called early and memory managment isn't up, yet.
-                        * Thus request_region would fail.
-                        */
-                       if (!request_region((unsigned long)
-                                        zs_channels[n_channels].control,
-                                        ZS_CHAN_IO_SIZE, "SCC"))
-                               panic("SCC I/O region is not free");
-#endif
-                       zs_soft[n_channels].zs_channel = &zs_channels[n_channels];
-                       /* HACK alert! */
-                       if (!(chip & 1))
-                               zs_soft[n_channels].irq = zs_parms->irq0;
-                       else
-                               zs_soft[n_channels].irq = zs_parms->irq1;
-
-                       /*
-                        *  Identification of channel A. Location of channel A
-                         *  inside chip depends on mapping of internal address
-                        *  the chip decodes channels by.
-                        *  CHANNEL_A_NR returns either 0 (in case of
-                        *  DECstations) or 1 (in case of Baget).
-                        */
-                       if (CHANNEL_A_NR == channel)
-                               zs_soft[n_channels].zs_chan_a =
-                                   &zs_channels[n_channels+1-2*CHANNEL_A_NR];
-                       else
-                               zs_soft[n_channels].zs_chan_a =
-                                   &zs_channels[n_channels];
-
-                       *pp = &zs_soft[n_channels];
-                       pp = &zs_soft[n_channels].zs_next;
-                       n_channels++;
-               }
-       }
-
-       *pp = 0;
-       zs_channels_found = n_channels;
-
-       for (n = 0; n < zs_channels_found; n++) {
-               for (i = 0; i < 16; i++) {
-                       zs_soft[n].zs_channel->curregs[i] = zs_init_regs[i];
-               }
-       }
-
-       spin_lock_irqsave(&zs_lock, flags);
-       for (n = 0; n < zs_channels_found; n++) {
-               if (n % 2 == 0) {
-                       write_zsreg(zs_soft[n].zs_chan_a, R9, FHWRES);
-                       udelay(10);
-                       write_zsreg(zs_soft[n].zs_chan_a, R9, 0);
-               }
-               load_zsregs(zs_soft[n].zs_channel,
-                           zs_soft[n].zs_channel->curregs);
-       }
-       spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-static const struct tty_operations serial_ops = {
-       .open = rs_open,
-       .close = rs_close,
-       .write = rs_write,
-       .flush_chars = rs_flush_chars,
-       .write_room = rs_write_room,
-       .chars_in_buffer = rs_chars_in_buffer,
-       .flush_buffer = rs_flush_buffer,
-       .ioctl = rs_ioctl,
-       .throttle = rs_throttle,
-       .unthrottle = rs_unthrottle,
-       .set_termios = rs_set_termios,
-       .stop = rs_stop,
-       .start = rs_start,
-       .hangup = rs_hangup,
-       .break_ctl = rs_break,
-       .wait_until_sent = rs_wait_until_sent,
-       .tiocmget = rs_tiocmget,
-       .tiocmset = rs_tiocmset,
-};
-
-/* zs_init inits the driver */
-int __init zs_init(void)
-{
-       int channel, i;
-       struct dec_serial *info;
-
-       if(!BUS_PRESENT)
-               return -ENODEV;
-
-       /* Find out how many Z8530 SCCs we have */
-       if (zs_chain == 0)
-               probe_sccs();
-       serial_driver = alloc_tty_driver(zs_channels_found);
-       if (!serial_driver)
-               return -ENOMEM;
-
-       show_serial_version();
-
-       /* Initialize the tty_driver structure */
-       /* Not all of this is exactly right for us. */
-
-       serial_driver->owner = THIS_MODULE;
-       serial_driver->name = "ttyS";
-       serial_driver->major = TTY_MAJOR;
-       serial_driver->minor_start = 64;
-       serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
-       serial_driver->subtype = SERIAL_TYPE_NORMAL;
-       serial_driver->init_termios = tty_std_termios;
-       serial_driver->init_termios.c_cflag =
-               B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-       serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-       tty_set_operations(serial_driver, &serial_ops);
-
-       if (tty_register_driver(serial_driver))
-               panic("Couldn't register serial driver");
-
-       for (info = zs_chain, i = 0; info; info = info->zs_next, i++) {
-
-               /* Needed before interrupts are enabled. */
-               info->tty = 0;
-               info->x_char = 0;
-
-               if (info->hook && info->hook->init_info) {
-                       (*info->hook->init_info)(info);
-                       continue;
-               }
-
-               info->magic = SERIAL_MAGIC;
-               info->port = (int) info->zs_channel->control;
-               info->line = i;
-               info->custom_divisor = 16;
-               info->close_delay = 50;
-               info->closing_wait = 3000;
-               info->event = 0;
-               info->count = 0;
-               info->blocked_open = 0;
-               tasklet_init(&info->tlet, do_softint, (unsigned long)info);
-               init_waitqueue_head(&info->open_wait);
-               init_waitqueue_head(&info->close_wait);
-               printk("ttyS%02d at 0x%08x (irq = %d) is a Z85C30 SCC\n",
-                      info->line, info->port, info->irq);
-               tty_register_device(serial_driver, info->line, NULL);
-
-       }
-
-       for (channel = 0; channel < zs_channels_found; ++channel) {
-               zs_soft[channel].clk_divisor = 16;
-               zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
-
-               if (request_irq(zs_soft[channel].irq, rs_interrupt, IRQF_SHARED,
-                               "scc", &zs_soft[channel]))
-                       printk(KERN_ERR "decserial: can't get irq %d\n",
-                              zs_soft[channel].irq);
-
-               if (zs_soft[channel].hook) {
-                       zs_startup(&zs_soft[channel]);
-                       if (zs_soft[channel].hook->init_channel)
-                               (*zs_soft[channel].hook->init_channel)
-                                       (&zs_soft[channel]);
-               }
-       }
-
-       return 0;
-}
-
-/*
- * polling I/O routines
- */
-static int zs_poll_tx_char(void *handle, unsigned char ch)
-{
-       struct dec_serial *info = handle;
-       struct dec_zschannel *chan = info->zs_channel;
-       int    ret;
-
-       if(chan) {
-               int loops = 10000;
-
-               while (loops && !(read_zsreg(chan, 0) & Tx_BUF_EMP))
-                       loops--;
-
-               if (loops) {
-                       write_zsdata(chan, ch);
-                       ret = 0;
-               } else
-                       ret = -EAGAIN;
-
-               return ret;
-       } else
-               return -ENODEV;
-}
-
-static int zs_poll_rx_char(void *handle)
-{
-       struct dec_serial *info = handle;
-        struct dec_zschannel *chan = info->zs_channel;
-        int    ret;
-
-       if(chan) {
-                int loops = 10000;
-
-               while (loops && !(read_zsreg(chan, 0) & Rx_CH_AV))
-                       loops--;
-
-                if (loops)
-                        ret = read_zsdata(chan);
-                else
-                        ret = -EAGAIN;
-
-               return ret;
-       } else
-               return -ENODEV;
-}
-
-int register_zs_hook(unsigned int channel, struct dec_serial_hook *hook)
-{
-       struct dec_serial *info = &zs_soft[channel];
-
-       if (info->hook) {
-               printk("%s: line %d has already a hook registered\n",
-                      __FUNCTION__, channel);
-
-               return 0;
-       } else {
-               hook->poll_rx_char = zs_poll_rx_char;
-               hook->poll_tx_char = zs_poll_tx_char;
-               info->hook = hook;
-
-               return 1;
-       }
-}
-
-int unregister_zs_hook(unsigned int channel)
-{
-       struct dec_serial *info = &zs_soft[channel];
-
-        if (info->hook) {
-                info->hook = NULL;
-                return 1;
-        } else {
-                printk("%s: trying to unregister hook on line %d,"
-                       " but none is registered\n", __FUNCTION__, channel);
-                return 0;
-        }
-}
-
-/*
- * ------------------------------------------------------------
- * Serial console driver
- * ------------------------------------------------------------
- */
-#ifdef CONFIG_SERIAL_DEC_CONSOLE
-
-
-/*
- *     Print a string to the serial port trying not to disturb
- *     any possible real use of the port...
- */
-static void serial_console_write(struct console *co, const char *s,
-                                unsigned count)
-{
-       struct dec_serial *info;
-       int i;
-
-       info = zs_soft + co->index;
-
-       for (i = 0; i < count; i++, s++) {
-               if(*s == '\n')
-                       zs_poll_tx_char(info, '\r');
-               zs_poll_tx_char(info, *s);
-       }
-}
-
-static struct tty_driver *serial_console_device(struct console *c, int *index)
-{
-       *index = c->index;
-       return serial_driver;
-}
-
-/*
- *     Setup initial baud/bits/parity. We do two things here:
- *     - construct a cflag setting for the first rs_open()
- *     - initialize the serial port
- *     Return non-zero if we didn't find a serial port.
- */
-static int __init serial_console_setup(struct console *co, char *options)
-{
-       struct dec_serial *info;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int cflag = CREAD | HUPCL | CLOCAL;
-       int clk_divisor = 16;
-       int brg;
-       char *s;
-       unsigned long flags;
-
-       if(!BUS_PRESENT)
-               return -ENODEV;
-
-       info = zs_soft + co->index;
-
-       if (zs_chain == 0)
-               probe_sccs();
-
-       info->is_cons = 1;
-
-       if (options) {
-               baud = simple_strtoul(options, NULL, 10);
-               s = options;
-               while(*s >= '0' && *s <= '9')
-                       s++;
-               if (*s)
-                       parity = *s++;
-               if (*s)
-                       bits   = *s - '0';
-       }
-
-       /*
-        *      Now construct a cflag setting.
-        */
-       switch(baud) {
-       case 1200:
-               cflag |= B1200;
-               break;
-       case 2400:
-               cflag |= B2400;
-               break;
-       case 4800:
-               cflag |= B4800;
-               break;
-       case 19200:
-               cflag |= B19200;
-               break;
-       case 38400:
-               cflag |= B38400;
-               break;
-       case 57600:
-               cflag |= B57600;
-               break;
-       case 115200:
-               cflag |= B115200;
-               break;
-       case 9600:
-       default:
-               cflag |= B9600;
-               /*
-                * Set this to a sane value to prevent a divide error.
-                */
-               baud  = 9600;
-               break;
-       }
-       switch(bits) {
-       case 7:
-               cflag |= CS7;
-               break;
-       default:
-       case 8:
-               cflag |= CS8;
-               break;
-       }
-       switch(parity) {
-       case 'o': case 'O':
-               cflag |= PARODD;
-               break;
-       case 'e': case 'E':
-               cflag |= PARENB;
-               break;
-       }
-       co->cflag = cflag;
-
-       spin_lock_irqsave(&zs_lock, flags);
-
-       /*
-        * Set up the baud rate generator.
-        */
-       brg = BPS_TO_BRG(baud, zs_parms->clock / clk_divisor);
-       info->zs_channel->curregs[R12] = (brg & 255);
-       info->zs_channel->curregs[R13] = ((brg >> 8) & 255);
-
-       /*
-        * Set byte size and parity.
-        */
-       if (bits == 7) {
-               info->zs_channel->curregs[R3] |= Rx7;
-               info->zs_channel->curregs[R5] |= Tx7;
-       } else {
-               info->zs_channel->curregs[R3] |= Rx8;
-               info->zs_channel->curregs[R5] |= Tx8;
-       }
-       if (cflag & PARENB) {
-               info->zs_channel->curregs[R4] |= PAR_ENA;
-       }
-       if (!(cflag & PARODD)) {
-               info->zs_channel->curregs[R4] |= PAR_EVEN;
-       }
-       info->zs_channel->curregs[R4] |= SB1;
-
-       /*
-        * Turn on RTS and DTR.
-        */
-       zs_rtsdtr(info, RTS | DTR, 1);
-
-       /*
-        * Finally, enable sequencing.
-        */
-       info->zs_channel->curregs[R3] |= RxENABLE;
-       info->zs_channel->curregs[R5] |= TxENAB;
-
-       /*
-        * Clear the interrupt registers.
-        */
-       write_zsreg(info->zs_channel, R0, ERR_RES);
-       write_zsreg(info->zs_channel, R0, RES_H_IUS);
-
-       /*
-        * Load up the new values.
-        */
-       load_zsregs(info->zs_channel, info->zs_channel->curregs);
-
-       /* Save the current value of RR0 */
-       info->read_reg_zero = read_zsreg(info->zs_channel, R0);
-
-       zs_soft[co->index].clk_divisor = clk_divisor;
-       zs_soft[co->index].zs_baud = get_zsbaud(&zs_soft[co->index]);
-
-       spin_unlock_irqrestore(&zs_lock, flags);
-
-       return 0;
-}
-
-static struct console zs_console = {
-       .name           = "ttyS",
-       .write          = serial_console_write,
-       .device         = serial_console_device,
-       .setup          = serial_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-};
-
-/*
- *     Register console.
- */
-void __init zs_serial_console_init(void)
-{
-       register_console(&zs_console);
-}
-#endif /* ifdef CONFIG_SERIAL_DEC_CONSOLE */
-
-#ifdef CONFIG_KGDB
-struct dec_zschannel *zs_kgdbchan;
-static unsigned char scc_inittab[] = {
-       9,  0x80,       /* reset A side (CHRA) */
-       13, 0,          /* set baud rate divisor */
-       12, 1,
-       14, 1,          /* baud rate gen enable, src=rtxc (BRENABL) */
-       11, 0x50,       /* clocks = br gen (RCBR | TCBR) */
-       5,  0x6a,       /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
-       4,  0x44,       /* x16 clock, 1 stop (SB1 | X16CLK)*/
-       3,  0xc1,       /* rx enable, 8 bits (RxENABLE | Rx8)*/
-};
-
-/* These are for receiving and sending characters under the kgdb
- * source level kernel debugger.
- */
-void putDebugChar(char kgdb_char)
-{
-       struct dec_zschannel *chan = zs_kgdbchan;
-       while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
-               RECOVERY_DELAY;
-       write_zsdata(chan, kgdb_char);
-}
-char getDebugChar(void)
-{
-       struct dec_zschannel *chan = zs_kgdbchan;
-       while((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
-               eieio(); /*barrier();*/
-       return read_zsdata(chan);
-}
-void kgdb_interruptible(int yes)
-{
-       struct dec_zschannel *chan = zs_kgdbchan;
-       int one, nine;
-       nine = read_zsreg(chan, 9);
-       if (yes == 1) {
-               one = EXT_INT_ENAB|RxINT_ALL;
-               nine |= MIE;
-               printk("turning serial ints on\n");
-       } else {
-               one = RxINT_DISAB;
-               nine &= ~MIE;
-               printk("turning serial ints off\n");
-       }
-       write_zsreg(chan, 1, one);
-       write_zsreg(chan, 9, nine);
-}
-
-static int kgdbhook_init_channel(void *handle)
-{
-       return 0;
-}
-
-static void kgdbhook_init_info(void *handle)
-{
-}
-
-static void kgdbhook_rx_char(void *handle, unsigned char ch, unsigned char fl)
-{
-       struct dec_serial *info = handle;
-
-       if (fl != TTY_NORMAL)
-               return;
-       if (ch == 0x03 || ch == '$')
-               breakpoint();
-}
-
-/* This sets up the serial port we're using, and turns on
- * interrupts for that channel, so kgdb is usable once we're done.
- */
-static inline void kgdb_chaninit(struct dec_zschannel *ms, int intson, int bps)
-{
-       int brg;
-       int i, x;
-       volatile char *sccc = ms->control;
-       brg = BPS_TO_BRG(bps, zs_parms->clock/16);
-       printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg);
-       for (i = 20000; i != 0; --i) {
-               x = *sccc; eieio();
-       }
-       for (i = 0; i < sizeof(scc_inittab); ++i) {
-               write_zsreg(ms, scc_inittab[i], scc_inittab[i+1]);
-               i++;
-       }
-}
-/* This is called at boot time to prime the kgdb serial debugging
- * serial line.  The 'tty_num' argument is 0 for /dev/ttya and 1
- * for /dev/ttyb which is determined in setup_arch() from the
- * boot command line flags.
- */
-struct dec_serial_hook zs_kgdbhook = {
-       .init_channel   = kgdbhook_init_channel,
-       .init_info      = kgdbhook_init_info,
-       .rx_char        = kgdbhook_rx_char,
-       .cflags         = B38400 | CS8 | CLOCAL,
-};
-
-void __init zs_kgdb_hook(int tty_num)
-{
-       /* Find out how many Z8530 SCCs we have */
-       if (zs_chain == 0)
-               probe_sccs();
-       zs_soft[tty_num].zs_channel = &zs_channels[tty_num];
-       zs_kgdbchan = zs_soft[tty_num].zs_channel;
-       zs_soft[tty_num].change_needed = 0;
-       zs_soft[tty_num].clk_divisor = 16;
-       zs_soft[tty_num].zs_baud = 38400;
-       zs_soft[tty_num].hook = &zs_kgdbhook; /* This runs kgdb */
-       /* Turn on transmitter/receiver at 8-bits/char */
-        kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
-       printk("KGDB: on channel %d initialized\n", tty_num);
-       set_debug_traps(); /* init stub */
-}
-#endif /* ifdef CONFIG_KGDB */
diff --git a/drivers/tc/zs.h b/drivers/tc/zs.h
deleted file mode 100644 (file)
index 1351220..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * drivers/tc/zs.h: Definitions for the DECstation Z85C30 serial driver.
- *
- * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
- * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen.
- *
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 2004, 2005  Maciej W. Rozycki
- */
-#ifndef _DECSERIAL_H
-#define _DECSERIAL_H
-
-#include <asm/dec/serial.h>
-
-#define NUM_ZSREGS 16
-
-struct serial_struct {
-       int     type;
-       int     line;
-       int     port;
-       int     irq;
-       int     flags;
-       int     xmit_fifo_size;
-       int     custom_divisor;
-       int     baud_base;
-       unsigned short  close_delay;
-       char    reserved_char[2];
-       int     hub6;
-       unsigned short  closing_wait; /* time to wait before closing */
-       unsigned short  closing_wait2; /* no longer used... */
-       int     reserved[4];
-};
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output.  65535 means don't wait at all.
- */
-#define ZILOG_CLOSING_WAIT_INF 0
-#define ZILOG_CLOSING_WAIT_NONE        65535
-
-/*
- * Definitions for ZILOG_struct (and serial_struct) flags field
- */
-#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
-                                  on the callout port */
-#define ZILOG_FOURPORT  0x0002 /* Set OU1, OUT2 per AST Fourport settings */
-#define ZILOG_SAK      0x0004  /* Secure Attention Key (Orange book) */
-#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
-
-#define ZILOG_SPD_MASK 0x0030
-#define ZILOG_SPD_HI   0x0010  /* Use 56000 instead of 38400 bps */
-
-#define ZILOG_SPD_VHI  0x0020  /* Use 115200 instead of 38400 bps */
-#define ZILOG_SPD_CUST 0x0030  /* Use user-specified divisor */
-
-#define ZILOG_SKIP_TEST        0x0040 /* Skip UART test during autoconfiguration */
-#define ZILOG_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
-#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
-#define ZILOG_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
-#define ZILOG_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
-
-#define ZILOG_FLAGS    0x0FFF  /* Possible legal ZILOG flags */
-#define ZILOG_USR_MASK 0x0430  /* Legal flags that non-privileged
-                                * users can set or reset */
-
-/* Internal flags used only by kernel/chr_drv/serial.c */
-#define ZILOG_INITIALIZED      0x80000000 /* Serial port was initialized */
-#define ZILOG_CALLOUT_ACTIVE   0x40000000 /* Call out device is active */
-#define ZILOG_NORMAL_ACTIVE    0x20000000 /* Normal device is active */
-#define ZILOG_BOOT_AUTOCONF    0x10000000 /* Autoconfigure port on bootup */
-#define ZILOG_CLOSING          0x08000000 /* Serial port is closing */
-#define ZILOG_CTS_FLOW         0x04000000 /* Do CTS flow control */
-#define ZILOG_CHECK_CD         0x02000000 /* i.e., CLOCAL */
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-/*
- * This is our internal structure for each serial port's state.
- *
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-struct dec_zschannel {
-       volatile unsigned char *control;
-       volatile unsigned char *data;
-
-       /* Current write register values */
-       unsigned char curregs[NUM_ZSREGS];
-};
-
-struct dec_serial {
-       struct dec_serial       *zs_next;       /* For IRQ servicing chain.  */
-       struct dec_zschannel    *zs_channel;    /* Channel registers.  */
-       struct dec_zschannel    *zs_chan_a;     /* A side registers.  */
-       unsigned char           read_reg_zero;
-
-       struct dec_serial_hook  *hook;          /* Hook on this channel.  */
-       int                     tty_break;      /* Set on BREAK condition.  */
-       int                     is_cons;        /* Is this our console.  */
-       int                     tx_active;      /* Char is being xmitted.  */
-       int                     tx_stopped;     /* Output is suspended.  */
-
-       /*
-        * We need to know the current clock divisor
-        * to read the bps rate the chip has currently loaded.
-        */
-       int                     clk_divisor;    /* May be 1, 16, 32, or 64.  */
-       int                     zs_baud;
-
-       char                    change_needed;
-
-       int                     magic;
-       int                     baud_base;
-       int                     port;
-       int                     irq;
-       int                     flags;          /* Defined in tty.h.  */
-       int                     type;           /* UART type.  */
-       struct tty_struct       *tty;
-       int                     read_status_mask;
-       int                     ignore_status_mask;
-       int                     timeout;
-       int                     xmit_fifo_size;
-       int                     custom_divisor;
-       int                     x_char;         /* XON/XOFF character.  */
-       int                     close_delay;
-       unsigned short          closing_wait;
-       unsigned short          closing_wait2;
-       unsigned long           event;
-       unsigned long           last_active;
-       int                     line;
-       int                     count;          /* # of fds on device.  */
-       int                     blocked_open;   /* # of blocked opens.  */
-       unsigned char           *xmit_buf;
-       int                     xmit_head;
-       int                     xmit_tail;
-       int                     xmit_cnt;
-       struct tasklet_struct   tlet;
-       wait_queue_head_t       open_wait;
-       wait_queue_head_t       close_wait;
-};
-
-
-#define SERIAL_MAGIC 0x5301
-
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP  0
-
-#endif /* __KERNEL__ */
-
-/* Conversion routines to/from brg time constants from/to bits
- * per second.
- */
-#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
-#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-
-/* The Zilog register set */
-
-#define        FLAG    0x7e
-
-/* Write Register 0 */
-#define        R0      0               /* Register selects */
-#define        R1      1
-#define        R2      2
-#define        R3      3
-#define        R4      4
-#define        R5      5
-#define        R6      6
-#define        R7      7
-#define        R8      8
-#define        R9      9
-#define        R10     10
-#define        R11     11
-#define        R12     12
-#define        R13     13
-#define        R14     14
-#define        R15     15
-
-#define        NULLCODE        0       /* Null Code */
-#define        POINT_HIGH      0x8     /* Select upper half of registers */
-#define        RES_EXT_INT     0x10    /* Reset Ext. Status Interrupts */
-#define        SEND_ABORT      0x18    /* HDLC Abort */
-#define        RES_RxINT_FC    0x20    /* Reset RxINT on First Character */
-#define        RES_Tx_P        0x28    /* Reset TxINT Pending */
-#define        ERR_RES         0x30    /* Error Reset */
-#define        RES_H_IUS       0x38    /* Reset highest IUS */
-
-#define        RES_Rx_CRC      0x40    /* Reset Rx CRC Checker */
-#define        RES_Tx_CRC      0x80    /* Reset Tx CRC Checker */
-#define        RES_EOM_L       0xC0    /* Reset EOM latch */
-
-/* Write Register 1 */
-
-#define        EXT_INT_ENAB    0x1     /* Ext Int Enable */
-#define        TxINT_ENAB      0x2     /* Tx Int Enable */
-#define        PAR_SPEC        0x4     /* Parity is special condition */
-
-#define        RxINT_DISAB     0       /* Rx Int Disable */
-#define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
-#define        RxINT_ALL       0x10    /* Int on all Rx Characters or error */
-#define        RxINT_ERR       0x18    /* Int on error only */
-#define        RxINT_MASK      0x18
-
-#define        WT_RDY_RT       0x20    /* Wait/Ready on R/T */
-#define        WT_FN_RDYFN     0x40    /* Wait/FN/Ready FN */
-#define        WT_RDY_ENAB     0x80    /* Wait/Ready Enable */
-
-/* Write Register #2 (Interrupt Vector) */
-
-/* Write Register 3 */
-
-#define        RxENABLE        0x1     /* Rx Enable */
-#define        SYNC_L_INH      0x2     /* Sync Character Load Inhibit */
-#define        ADD_SM          0x4     /* Address Search Mode (SDLC) */
-#define        RxCRC_ENAB      0x8     /* Rx CRC Enable */
-#define        ENT_HM          0x10    /* Enter Hunt Mode */
-#define        AUTO_ENAB       0x20    /* Auto Enables */
-#define        Rx5             0x0     /* Rx 5 Bits/Character */
-#define        Rx7             0x40    /* Rx 7 Bits/Character */
-#define        Rx6             0x80    /* Rx 6 Bits/Character */
-#define        Rx8             0xc0    /* Rx 8 Bits/Character */
-#define RxNBITS_MASK   0xc0
-
-/* Write Register 4 */
-
-#define        PAR_ENA         0x1     /* Parity Enable */
-#define        PAR_EVEN        0x2     /* Parity Even/Odd* */
-
-#define        SYNC_ENAB       0       /* Sync Modes Enable */
-#define        SB1             0x4     /* 1 stop bit/char */
-#define        SB15            0x8     /* 1.5 stop bits/char */
-#define        SB2             0xc     /* 2 stop bits/char */
-#define SB_MASK                0xc
-
-#define        MONSYNC         0       /* 8 Bit Sync character */
-#define        BISYNC          0x10    /* 16 bit sync character */
-#define        SDLC            0x20    /* SDLC Mode (01111110 Sync Flag) */
-#define        EXTSYNC         0x30    /* External Sync Mode */
-
-#define        X1CLK           0x0     /* x1 clock mode */
-#define        X16CLK          0x40    /* x16 clock mode */
-#define        X32CLK          0x80    /* x32 clock mode */
-#define        X64CLK          0xC0    /* x64 clock mode */
-#define XCLK_MASK      0xC0
-
-/* Write Register 5 */
-
-#define        TxCRC_ENAB      0x1     /* Tx CRC Enable */
-#define        RTS             0x2     /* RTS */
-#define        SDLC_CRC        0x4     /* SDLC/CRC-16 */
-#define        TxENAB          0x8     /* Tx Enable */
-#define        SND_BRK         0x10    /* Send Break */
-#define        Tx5             0x0     /* Tx 5 bits (or less)/character */
-#define        Tx7             0x20    /* Tx 7 bits/character */
-#define        Tx6             0x40    /* Tx 6 bits/character */
-#define        Tx8             0x60    /* Tx 8 bits/character */
-#define TxNBITS_MASK   0x60
-#define        DTR             0x80    /* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 8 (transmit buffer) */
-
-/* Write Register 9 (Master interrupt control) */
-#define        VIS     1       /* Vector Includes Status */
-#define        NV      2       /* No Vector */
-#define        DLC     4       /* Disable Lower Chain */
-#define        MIE     8       /* Master Interrupt Enable */
-#define        STATHI  0x10    /* Status high */
-#define        SOFTACK 0x20    /* Software Interrupt Acknowledge */
-#define        NORESET 0       /* No reset on write to R9 */
-#define        CHRB    0x40    /* Reset channel B */
-#define        CHRA    0x80    /* Reset channel A */
-#define        FHWRES  0xc0    /* Force hardware reset */
-
-/* Write Register 10 (misc control bits) */
-#define        BIT6    1       /* 6 bit/8bit sync */
-#define        LOOPMODE 2      /* SDLC Loop mode */
-#define        ABUNDER 4       /* Abort/flag on SDLC xmit underrun */
-#define        MARKIDLE 8      /* Mark/flag on idle */
-#define        GAOP    0x10    /* Go active on poll */
-#define        NRZ     0       /* NRZ mode */
-#define        NRZI    0x20    /* NRZI mode */
-#define        FM1     0x40    /* FM1 (transition = 1) */
-#define        FM0     0x60    /* FM0 (transition = 0) */
-#define        CRCPS   0x80    /* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode control) */
-#define        TRxCXT  0       /* TRxC = Xtal output */
-#define        TRxCTC  1       /* TRxC = Transmit clock */
-#define        TRxCBR  2       /* TRxC = BR Generator Output */
-#define        TRxCDP  3       /* TRxC = DPLL output */
-#define        TRxCOI  4       /* TRxC O/I */
-#define        TCRTxCP 0       /* Transmit clock = RTxC pin */
-#define        TCTRxCP 8       /* Transmit clock = TRxC pin */
-#define        TCBR    0x10    /* Transmit clock = BR Generator output */
-#define        TCDPLL  0x18    /* Transmit clock = DPLL output */
-#define        RCRTxCP 0       /* Receive clock = RTxC pin */
-#define        RCTRxCP 0x20    /* Receive clock = TRxC pin */
-#define        RCBR    0x40    /* Receive clock = BR Generator output */
-#define        RCDPLL  0x60    /* Receive clock = DPLL output */
-#define        RTxCX   0x80    /* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (lower byte of baud rate generator time constant) */
-
-/* Write Register 13 (upper byte of baud rate generator time constant) */
-
-/* Write Register 14 (Misc control bits) */
-#define        BRENABL 1       /* Baud rate generator enable */
-#define        BRSRC   2       /* Baud rate generator source */
-#define        DTRREQ  4       /* DTR/Request function */
-#define        AUTOECHO 8      /* Auto Echo */
-#define        LOOPBAK 0x10    /* Local loopback */
-#define        SEARCH  0x20    /* Enter search mode */
-#define        RMC     0x40    /* Reset missing clock */
-#define        DISDPLL 0x60    /* Disable DPLL */
-#define        SSBR    0x80    /* Set DPLL source = BR generator */
-#define        SSRTxC  0xa0    /* Set DPLL source = RTxC */
-#define        SFMM    0xc0    /* Set FM mode */
-#define        SNRZI   0xe0    /* Set NRZI mode */
-
-/* Write Register 15 (external/status interrupt control) */
-#define        ZCIE    2       /* Zero count IE */
-#define        DCDIE   8       /* DCD IE */
-#define        SYNCIE  0x10    /* Sync/hunt IE */
-#define        CTSIE   0x20    /* CTS IE */
-#define        TxUIE   0x40    /* Tx Underrun/EOM IE */
-#define        BRKIE   0x80    /* Break/Abort IE */
-
-
-/* Read Register 0 */
-#define        Rx_CH_AV        0x1     /* Rx Character Available */
-#define        ZCOUNT          0x2     /* Zero count */
-#define        Tx_BUF_EMP      0x4     /* Tx Buffer empty */
-#define        DCD             0x8     /* DCD */
-#define        SYNC_HUNT       0x10    /* Sync/hunt */
-#define        CTS             0x20    /* CTS */
-#define        TxEOM           0x40    /* Tx underrun */
-#define        BRK_ABRT        0x80    /* Break/Abort */
-
-/* Read Register 1 */
-#define        ALL_SNT         0x1     /* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define        RES3            0x8     /* 0/3 */
-#define        RES4            0x4     /* 0/4 */
-#define        RES5            0xc     /* 0/5 */
-#define        RES6            0x2     /* 0/6 */
-#define        RES7            0xa     /* 0/7 */
-#define        RES8            0x6     /* 0/8 */
-#define        RES18           0xe     /* 1/8 */
-#define        RES28           0x0     /* 2/8 */
-/* Special Rx Condition Interrupts */
-#define        PAR_ERR         0x10    /* Parity error */
-#define        Rx_OVR          0x20    /* Rx Overrun Error */
-#define        FRM_ERR         0x40    /* CRC/Framing Error */
-#define        END_FR          0x80    /* End of Frame (SDLC) */
-
-/* Read Register 2 (channel b only) - Interrupt vector */
-
-/* Read Register 3 (interrupt pending register) ch a only */
-#define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
-#define        CHBTxIP 0x2             /* Channel B Tx IP */
-#define        CHBRxIP 0x4             /* Channel B Rx IP */
-#define        CHAEXT  0x8             /* Channel A Ext/Stat IP */
-#define        CHATxIP 0x10            /* Channel A Tx IP */
-#define        CHARxIP 0x20            /* Channel A Rx IP */
-
-/* Read Register 8 (receive data register) */
-
-/* Read Register 10  (misc status bits) */
-#define        ONLOOP  2               /* On loop */
-#define        LOOPSEND 0x10           /* Loop sending */
-#define        CLK2MIS 0x40            /* Two clocks missing */
-#define        CLK1MIS 0x80            /* One clock missing */
-
-/* Read Register 12 (lower byte of baud rate generator constant) */
-
-/* Read Register 13 (upper byte of baud rate generator constant) */
-
-/* Read Register 15 (value of WR 15) */
-
-/* Misc macros */
-#define ZS_CLEARERR(channel)   (write_zsreg(channel, 0, ERR_RES))
-#define ZS_CLEARFIFO(channel)  do { volatile unsigned char garbage; \
-                                    garbage = read_zsdata(channel); \
-                                    garbage = read_zsdata(channel); \
-                                    garbage = read_zsdata(channel); \
-                               } while(0)
-
-#endif /* !(_DECSERIAL_H) */
index 8f530e68263bd31fb8f80ce2be5660de6b2733a9..5f98f673f1b675002e57b31dfb25194e7e9ed002 100644 (file)
@@ -19,6 +19,7 @@ if PHONE
 
 config PHONE_IXJ
        tristate "QuickNet Internet LineJack/PhoneJack support"
+       depends ISA || PCI
        ---help---
          Say M if you have a telephony card manufactured by Quicknet
          Technologies, Inc.  These include the Internet PhoneJACK and
index c7b0a357b04a68f309cf0ef783c1d7406e99014b..49cd9793404f33c5165d5b77e0d9657c3f7c1b20 100644 (file)
@@ -3453,7 +3453,6 @@ static void ixj_write_frame(IXJ *j)
 {
        int cnt, frame_count, dly;
        IXJ_WORD dat;
-       BYTES blankword;
 
        frame_count = 0;
        if(j->flags.cidplay) {
@@ -3501,6 +3500,8 @@ static void ixj_write_frame(IXJ *j)
                }
                if (frame_count >= 1) {
                        if (j->ver.low == 0x12 && j->play_mode && j->flags.play_first_frame) {
+                               BYTES blankword;
+
                                switch (j->play_mode) {
                                case PLAYBACK_MODE_ULAW:
                                case PLAYBACK_MODE_ALAW:
@@ -3508,6 +3509,7 @@ static void ixj_write_frame(IXJ *j)
                                        break;
                                case PLAYBACK_MODE_8LINEAR:
                                case PLAYBACK_MODE_16LINEAR:
+                               default:
                                        blankword.low = blankword.high = 0x00;
                                        break;
                                case PLAYBACK_MODE_8LINEAR_WSS:
@@ -3531,6 +3533,8 @@ static void ixj_write_frame(IXJ *j)
                                j->flags.play_first_frame = 0;
                        } else  if (j->play_codec == G723_63 && j->flags.play_first_frame) {
                                for (cnt = 0; cnt < 24; cnt++) {
+                                       BYTES blankword;
+
                                        if(cnt == 12) {
                                                blankword.low = 0x02;
                                                blankword.high = 0x00;
@@ -4868,6 +4872,7 @@ static char daa_CR_read(IXJ *j, int cr)
                bytes.high = 0xB0 + cr;
                break;
        case SOP_PU_PULSEDIALING:
+       default:
                bytes.high = 0xF0 + cr;
                break;
        }
index 071b9675a7819dff38f5128c1d23f635f12b26a8..7dd73546bf43cb4541d68ad2393a07c3be5db121 100644 (file)
@@ -16,7 +16,7 @@ config USB_ARCH_HAS_HCD
        boolean
        default y if USB_ARCH_HAS_OHCI
        default y if USB_ARCH_HAS_EHCI
-       default y if PCMCIA                             # sl811_cs
+       default y if PCMCIA && !M32R                    # sl811_cs
        default y if ARM                                # SL-811
        default PCI
 
index 1fd5fc220cd7ee9ac81c08af66e10466e5bb3821..42d4e6454a77f3bfec9562bc41b44a85ab42afb8 100644 (file)
@@ -630,7 +630,7 @@ static int auerchain_start_wait_urb (pauerchain_t acp, struct urb *urb, int time
        } else
                status = urb->status;
 
-       if (actual_length)
+       if (status >= 0)
                *actual_length = urb->actual_length;
 
        return status;
@@ -664,7 +664,7 @@ static int auerchain_control_msg (pauerchain_t acp, struct usb_device *dev, unsi
        int ret;
        struct usb_ctrlrequest *dr;
        struct urb *urb;
-        int length;
+        int uninitialized_var(length);
 
         dbg ("auerchain_control_msg");
         dr = kmalloc (sizeof (struct usb_ctrlrequest), GFP_KERNEL);
index da219c043c9997a98d49bd894441e3f2304b9d0c..9de1c114f8092f095832ab520f01c48ce058f2ec 100644 (file)
@@ -12,7 +12,7 @@ if LOGO
 
 config FB_LOGO_EXTRA
        bool
-       depends on FB
+       depends on FB=y
        default y if SPU_BASE
 
 config LOGO_LINUX_MONO
index 5d29a26b8cdf39aadd6b59a27877b0e82b75e4e9..de0d755f901924fb439f54f8f964796ce80fa78c 100644 (file)
@@ -273,8 +273,11 @@ static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
                        }
                }
        }
+
+       /* if h2/post/in/feed have not been assigned, return zero (error) */
        if (besth2 < 2)
                return 0;
+
        dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant);
        return fxtal * (*feed) / (*in) * ctl->den;
 }
@@ -284,7 +287,7 @@ static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl,
                unsigned int* in, unsigned int* feed, unsigned int* post,
                unsigned int* htotal2) {
        unsigned int fvco;
-       unsigned int p;
+       unsigned int uninitialized_var(p);
 
        fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2);
        if (!fvco)
@@ -715,7 +718,9 @@ static int maven_find_exact_clocks(unsigned int ht, unsigned int vt,
        m->regs[0x82] = 0x81;
 
        for (x = 0; x < 8; x++) {
-               unsigned int a, b, c, h2;
+               unsigned int c;
+               unsigned int uninitialized_var(a), uninitialized_var(b),
+                            uninitialized_var(h2);
                unsigned int h = ht + 2 + x;
 
                if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
index 70bfd78eca819a873ee35932e650bafb58d4b423..13307703a9f04d421792a460b8b595c50ee776f6 100644 (file)
@@ -1223,6 +1223,8 @@ static int CalcVClock
         }
     }
     }
+
+    /* non-zero: M/N/P/clock values assigned.  zero: error (not set) */
     return (DeltaOld != 0xFFFFFFFF);
 }
 /*
@@ -1240,7 +1242,10 @@ int CalcStateExt
     int            dotClock
 )
 {
-    int pixelDepth, VClk, m, n, p;
+    int pixelDepth;
+    int uninitialized_var(VClk),uninitialized_var(m),
+        uninitialized_var(n),  uninitialized_var(p);
+
     /*
      * Save mode parameters.
      */
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
new file mode 100644 (file)
index 0000000..56592f0
--- /dev/null
@@ -0,0 +1,2 @@
+obj-y  += grant-table.o
+obj-y  += xenbus/
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
new file mode 100644 (file)
index 0000000..ea94dba
--- /dev/null
@@ -0,0 +1,582 @@
+/******************************************************************************
+ * grant_table.c
+ *
+ * Granting foreign access to our memory reservation.
+ *
+ * Copyright (c) 2005-2006, Christopher Clark
+ * Copyright (c) 2004-2005, K A Fraser
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+
+#include <xen/interface/xen.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+
+#include <asm/pgtable.h>
+#include <asm/sync_bitops.h>
+
+
+/* External tools reserve first few grant table entries. */
+#define NR_RESERVED_ENTRIES 8
+#define GNTTAB_LIST_END 0xffffffff
+#define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(struct grant_entry))
+
+static grant_ref_t **gnttab_list;
+static unsigned int nr_grant_frames;
+static unsigned int boot_max_nr_grant_frames;
+static int gnttab_free_count;
+static grant_ref_t gnttab_free_head;
+static DEFINE_SPINLOCK(gnttab_list_lock);
+
+static struct grant_entry *shared;
+
+static struct gnttab_free_callback *gnttab_free_callback_list;
+
+static int gnttab_expand(unsigned int req_entries);
+
+#define RPP (PAGE_SIZE / sizeof(grant_ref_t))
+
+static inline grant_ref_t *__gnttab_entry(grant_ref_t entry)
+{
+       return &gnttab_list[(entry) / RPP][(entry) % RPP];
+}
+/* This can be used as an l-value */
+#define gnttab_entry(entry) (*__gnttab_entry(entry))
+
+static int get_free_entries(unsigned count)
+{
+       unsigned long flags;
+       int ref, rc;
+       grant_ref_t head;
+
+       spin_lock_irqsave(&gnttab_list_lock, flags);
+
+       if ((gnttab_free_count < count) &&
+           ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) {
+               spin_unlock_irqrestore(&gnttab_list_lock, flags);
+               return rc;
+       }
+
+       ref = head = gnttab_free_head;
+       gnttab_free_count -= count;
+       while (count-- > 1)
+               head = gnttab_entry(head);
+       gnttab_free_head = gnttab_entry(head);
+       gnttab_entry(head) = GNTTAB_LIST_END;
+
+       spin_unlock_irqrestore(&gnttab_list_lock, flags);
+
+       return ref;
+}
+
+static void do_free_callbacks(void)
+{
+       struct gnttab_free_callback *callback, *next;
+
+       callback = gnttab_free_callback_list;
+       gnttab_free_callback_list = NULL;
+
+       while (callback != NULL) {
+               next = callback->next;
+               if (gnttab_free_count >= callback->count) {
+                       callback->next = NULL;
+                       callback->fn(callback->arg);
+               } else {
+                       callback->next = gnttab_free_callback_list;
+                       gnttab_free_callback_list = callback;
+               }
+               callback = next;
+       }
+}
+
+static inline void check_free_callbacks(void)
+{
+       if (unlikely(gnttab_free_callback_list))
+               do_free_callbacks();
+}
+
+static void put_free_entry(grant_ref_t ref)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&gnttab_list_lock, flags);
+       gnttab_entry(ref) = gnttab_free_head;
+       gnttab_free_head = ref;
+       gnttab_free_count++;
+       check_free_callbacks();
+       spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+
+static void update_grant_entry(grant_ref_t ref, domid_t domid,
+                              unsigned long frame, unsigned flags)
+{
+       /*
+        * Introducing a valid entry into the grant table:
+        *  1. Write ent->domid.
+        *  2. Write ent->frame:
+        *      GTF_permit_access:   Frame to which access is permitted.
+        *      GTF_accept_transfer: Pseudo-phys frame slot being filled by new
+        *                           frame, or zero if none.
+        *  3. Write memory barrier (WMB).
+        *  4. Write ent->flags, inc. valid type.
+        */
+       shared[ref].frame = frame;
+       shared[ref].domid = domid;
+       wmb();
+       shared[ref].flags = flags;
+}
+
+/*
+ * Public grant-issuing interface functions
+ */
+void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
+                                    unsigned long frame, int readonly)
+{
+       update_grant_entry(ref, domid, frame,
+                          GTF_permit_access | (readonly ? GTF_readonly : 0));
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);
+
+int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
+                               int readonly)
+{
+       int ref;
+
+       ref = get_free_entries(1);
+       if (unlikely(ref < 0))
+               return -ENOSPC;
+
+       gnttab_grant_foreign_access_ref(ref, domid, frame, readonly);
+
+       return ref;
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
+
+int gnttab_query_foreign_access(grant_ref_t ref)
+{
+       u16 nflags;
+
+       nflags = shared[ref].flags;
+
+       return (nflags & (GTF_reading|GTF_writing));
+}
+EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);
+
+int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
+{
+       u16 flags, nflags;
+
+       nflags = shared[ref].flags;
+       do {
+               flags = nflags;
+               if (flags & (GTF_reading|GTF_writing)) {
+                       printk(KERN_ALERT "WARNING: g.e. still in use!\n");
+                       return 0;
+               }
+       } while ((nflags = sync_cmpxchg(&shared[ref].flags, flags, 0)) != flags);
+
+       return 1;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
+
+void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
+                              unsigned long page)
+{
+       if (gnttab_end_foreign_access_ref(ref, readonly)) {
+               put_free_entry(ref);
+               if (page != 0)
+                       free_page(page);
+       } else {
+               /* XXX This needs to be fixed so that the ref and page are
+                  placed on a list to be freed up later. */
+               printk(KERN_WARNING
+                      "WARNING: leaking g.e. and page still in use!\n");
+       }
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
+
+int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
+{
+       int ref;
+
+       ref = get_free_entries(1);
+       if (unlikely(ref < 0))
+               return -ENOSPC;
+       gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
+
+       return ref;
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer);
+
+void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
+                                      unsigned long pfn)
+{
+       update_grant_entry(ref, domid, pfn, GTF_accept_transfer);
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref);
+
+unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
+{
+       unsigned long frame;
+       u16           flags;
+
+       /*
+        * If a transfer is not even yet started, try to reclaim the grant
+        * reference and return failure (== 0).
+        */
+       while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
+               if (sync_cmpxchg(&shared[ref].flags, flags, 0) == flags)
+                       return 0;
+               cpu_relax();
+       }
+
+       /* If a transfer is in progress then wait until it is completed. */
+       while (!(flags & GTF_transfer_completed)) {
+               flags = shared[ref].flags;
+               cpu_relax();
+       }
+
+       rmb();  /* Read the frame number /after/ reading completion status. */
+       frame = shared[ref].frame;
+       BUG_ON(frame == 0);
+
+       return frame;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref);
+
+unsigned long gnttab_end_foreign_transfer(grant_ref_t ref)
+{
+       unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
+       put_free_entry(ref);
+       return frame;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer);
+
+void gnttab_free_grant_reference(grant_ref_t ref)
+{
+       put_free_entry(ref);
+}
+EXPORT_SYMBOL_GPL(gnttab_free_grant_reference);
+
+void gnttab_free_grant_references(grant_ref_t head)
+{
+       grant_ref_t ref;
+       unsigned long flags;
+       int count = 1;
+       if (head == GNTTAB_LIST_END)
+               return;
+       spin_lock_irqsave(&gnttab_list_lock, flags);
+       ref = head;
+       while (gnttab_entry(ref) != GNTTAB_LIST_END) {
+               ref = gnttab_entry(ref);
+               count++;
+       }
+       gnttab_entry(ref) = gnttab_free_head;
+       gnttab_free_head = head;
+       gnttab_free_count += count;
+       check_free_callbacks();
+       spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_free_grant_references);
+
+int gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
+{
+       int h = get_free_entries(count);
+
+       if (h < 0)
+               return -ENOSPC;
+
+       *head = h;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(gnttab_alloc_grant_references);
+
+int gnttab_empty_grant_references(const grant_ref_t *private_head)
+{
+       return (*private_head == GNTTAB_LIST_END);
+}
+EXPORT_SYMBOL_GPL(gnttab_empty_grant_references);
+
+int gnttab_claim_grant_reference(grant_ref_t *private_head)
+{
+       grant_ref_t g = *private_head;
+       if (unlikely(g == GNTTAB_LIST_END))
+               return -ENOSPC;
+       *private_head = gnttab_entry(g);
+       return g;
+}
+EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
+
+void gnttab_release_grant_reference(grant_ref_t *private_head,
+                                   grant_ref_t release)
+{
+       gnttab_entry(release) = *private_head;
+       *private_head = release;
+}
+EXPORT_SYMBOL_GPL(gnttab_release_grant_reference);
+
+void gnttab_request_free_callback(struct gnttab_free_callback *callback,
+                                 void (*fn)(void *), void *arg, u16 count)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&gnttab_list_lock, flags);
+       if (callback->next)
+               goto out;
+       callback->fn = fn;
+       callback->arg = arg;
+       callback->count = count;
+       callback->next = gnttab_free_callback_list;
+       gnttab_free_callback_list = callback;
+       check_free_callbacks();
+out:
+       spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_request_free_callback);
+
+void gnttab_cancel_free_callback(struct gnttab_free_callback *callback)
+{
+       struct gnttab_free_callback **pcb;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gnttab_list_lock, flags);
+       for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) {
+               if (*pcb == callback) {
+                       *pcb = callback->next;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback);
+
+static int grow_gnttab_list(unsigned int more_frames)
+{
+       unsigned int new_nr_grant_frames, extra_entries, i;
+
+       new_nr_grant_frames = nr_grant_frames + more_frames;
+       extra_entries       = more_frames * GREFS_PER_GRANT_FRAME;
+
+       for (i = nr_grant_frames; i < new_nr_grant_frames; i++) {
+               gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC);
+               if (!gnttab_list[i])
+                       goto grow_nomem;
+       }
+
+
+       for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames;
+            i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++)
+               gnttab_entry(i) = i + 1;
+
+       gnttab_entry(i) = gnttab_free_head;
+       gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames;
+       gnttab_free_count += extra_entries;
+
+       nr_grant_frames = new_nr_grant_frames;
+
+       check_free_callbacks();
+
+       return 0;
+
+grow_nomem:
+       for ( ; i >= nr_grant_frames; i--)
+               free_page((unsigned long) gnttab_list[i]);
+       return -ENOMEM;
+}
+
+static unsigned int __max_nr_grant_frames(void)
+{
+       struct gnttab_query_size query;
+       int rc;
+
+       query.dom = DOMID_SELF;
+
+       rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1);
+       if ((rc < 0) || (query.status != GNTST_okay))
+               return 4; /* Legacy max supported number of frames */
+
+       return query.max_nr_frames;
+}
+
+static inline unsigned int max_nr_grant_frames(void)
+{
+       unsigned int xen_max = __max_nr_grant_frames();
+
+       if (xen_max > boot_max_nr_grant_frames)
+               return boot_max_nr_grant_frames;
+       return xen_max;
+}
+
+static int map_pte_fn(pte_t *pte, struct page *pmd_page,
+                     unsigned long addr, void *data)
+{
+       unsigned long **frames = (unsigned long **)data;
+
+       set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL));
+       (*frames)++;
+       return 0;
+}
+
+static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,
+                       unsigned long addr, void *data)
+{
+
+       set_pte_at(&init_mm, addr, pte, __pte(0));
+       return 0;
+}
+
+static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
+{
+       struct gnttab_setup_table setup;
+       unsigned long *frames;
+       unsigned int nr_gframes = end_idx + 1;
+       int rc;
+
+       frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC);
+       if (!frames)
+               return -ENOMEM;
+
+       setup.dom        = DOMID_SELF;
+       setup.nr_frames  = nr_gframes;
+       setup.frame_list = frames;
+
+       rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
+       if (rc == -ENOSYS) {
+               kfree(frames);
+               return -ENOSYS;
+       }
+
+       BUG_ON(rc || setup.status);
+
+       if (shared == NULL) {
+               struct vm_struct *area;
+               area = alloc_vm_area(PAGE_SIZE * max_nr_grant_frames());
+               BUG_ON(area == NULL);
+               shared = area->addr;
+       }
+       rc = apply_to_page_range(&init_mm, (unsigned long)shared,
+                                PAGE_SIZE * nr_gframes,
+                                map_pte_fn, &frames);
+       BUG_ON(rc);
+       frames -= nr_gframes; /* adjust after map_pte_fn() */
+
+       kfree(frames);
+
+       return 0;
+}
+
+static int gnttab_resume(void)
+{
+       if (max_nr_grant_frames() < nr_grant_frames)
+               return -ENOSYS;
+       return gnttab_map(0, nr_grant_frames - 1);
+}
+
+static int gnttab_suspend(void)
+{
+       apply_to_page_range(&init_mm, (unsigned long)shared,
+                           PAGE_SIZE * nr_grant_frames,
+                           unmap_pte_fn, NULL);
+
+       return 0;
+}
+
+static int gnttab_expand(unsigned int req_entries)
+{
+       int rc;
+       unsigned int cur, extra;
+
+       cur = nr_grant_frames;
+       extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) /
+                GREFS_PER_GRANT_FRAME);
+       if (cur + extra > max_nr_grant_frames())
+               return -ENOSPC;
+
+       rc = gnttab_map(cur, cur + extra - 1);
+       if (rc == 0)
+               rc = grow_gnttab_list(extra);
+
+       return rc;
+}
+
+static int __devinit gnttab_init(void)
+{
+       int i;
+       unsigned int max_nr_glist_frames;
+       unsigned int nr_init_grefs;
+
+       if (!is_running_on_xen())
+               return -ENODEV;
+
+       nr_grant_frames = 1;
+       boot_max_nr_grant_frames = __max_nr_grant_frames();
+
+       /* Determine the maximum number of frames required for the
+        * grant reference free list on the current hypervisor.
+        */
+       max_nr_glist_frames = (boot_max_nr_grant_frames *
+                              GREFS_PER_GRANT_FRAME /
+                              (PAGE_SIZE / sizeof(grant_ref_t)));
+
+       gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *),
+                             GFP_KERNEL);
+       if (gnttab_list == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < nr_grant_frames; i++) {
+               gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL);
+               if (gnttab_list[i] == NULL)
+                       goto ini_nomem;
+       }
+
+       if (gnttab_resume() < 0)
+               return -ENODEV;
+
+       nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME;
+
+       for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
+               gnttab_entry(i) = i + 1;
+
+       gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END;
+       gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
+       gnttab_free_head  = NR_RESERVED_ENTRIES;
+
+       printk("Grant table initialized\n");
+       return 0;
+
+ ini_nomem:
+       for (i--; i >= 0; i--)
+               free_page((unsigned long)gnttab_list[i]);
+       kfree(gnttab_list);
+       return -ENOMEM;
+}
+
+core_initcall(gnttab_init);
diff --git a/drivers/xen/xenbus/Makefile b/drivers/xen/xenbus/Makefile
new file mode 100644 (file)
index 0000000..5571f5b
--- /dev/null
@@ -0,0 +1,7 @@
+obj-y  += xenbus.o
+
+xenbus-objs =
+xenbus-objs += xenbus_client.o
+xenbus-objs += xenbus_comms.o
+xenbus-objs += xenbus_xs.o
+xenbus-objs += xenbus_probe.o
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
new file mode 100644 (file)
index 0000000..9fd2f70
--- /dev/null
@@ -0,0 +1,569 @@
+/******************************************************************************
+ * Client-facing interface for the Xenbus driver.  In other words, the
+ * interface between the Xenbus and the device-specific code, be it the
+ * frontend or the backend of that driver.
+ *
+ * Copyright (C) 2005 XenSource Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/event_channel.h>
+#include <xen/events.h>
+#include <xen/grant_table.h>
+#include <xen/xenbus.h>
+
+const char *xenbus_strstate(enum xenbus_state state)
+{
+       static const char *const name[] = {
+               [ XenbusStateUnknown      ] = "Unknown",
+               [ XenbusStateInitialising ] = "Initialising",
+               [ XenbusStateInitWait     ] = "InitWait",
+               [ XenbusStateInitialised  ] = "Initialised",
+               [ XenbusStateConnected    ] = "Connected",
+               [ XenbusStateClosing      ] = "Closing",
+               [ XenbusStateClosed       ] = "Closed",
+       };
+       return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
+}
+EXPORT_SYMBOL_GPL(xenbus_strstate);
+
+/**
+ * xenbus_watch_path - register a watch
+ * @dev: xenbus device
+ * @path: path to watch
+ * @watch: watch to register
+ * @callback: callback to register
+ *
+ * Register a @watch on the given path, using the given xenbus_watch structure
+ * for storage, and the given @callback function as the callback.  Return 0 on
+ * success, or -errno on error.  On success, the given @path will be saved as
+ * @watch->node, and remains the caller's to free.  On error, @watch->node will
+ * be NULL, the device will switch to %XenbusStateClosing, and the error will
+ * be saved in the store.
+ */
+int xenbus_watch_path(struct xenbus_device *dev, const char *path,
+                     struct xenbus_watch *watch,
+                     void (*callback)(struct xenbus_watch *,
+                                      const char **, unsigned int))
+{
+       int err;
+
+       watch->node = path;
+       watch->callback = callback;
+
+       err = register_xenbus_watch(watch);
+
+       if (err) {
+               watch->node = NULL;
+               watch->callback = NULL;
+               xenbus_dev_fatal(dev, err, "adding watch on %s", path);
+       }
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_watch_path);
+
+
+/**
+ * xenbus_watch_pathfmt - register a watch on a sprintf-formatted path
+ * @dev: xenbus device
+ * @watch: watch to register
+ * @callback: callback to register
+ * @pathfmt: format of path to watch
+ *
+ * Register a watch on the given @path, using the given xenbus_watch
+ * structure for storage, and the given @callback function as the callback.
+ * Return 0 on success, or -errno on error.  On success, the watched path
+ * (@path/@path2) will be saved as @watch->node, and becomes the caller's to
+ * kfree().  On error, watch->node will be NULL, so the caller has nothing to
+ * free, the device will switch to %XenbusStateClosing, and the error will be
+ * saved in the store.
+ */
+int xenbus_watch_pathfmt(struct xenbus_device *dev,
+                        struct xenbus_watch *watch,
+                        void (*callback)(struct xenbus_watch *,
+                                       const char **, unsigned int),
+                        const char *pathfmt, ...)
+{
+       int err;
+       va_list ap;
+       char *path;
+
+       va_start(ap, pathfmt);
+       path = kvasprintf(GFP_KERNEL, pathfmt, ap);
+       va_end(ap);
+
+       if (!path) {
+               xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch");
+               return -ENOMEM;
+       }
+       err = xenbus_watch_path(dev, path, watch, callback);
+
+       if (err)
+               kfree(path);
+       return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_watch_pathfmt);
+
+
+/**
+ * xenbus_switch_state
+ * @dev: xenbus device
+ * @xbt: transaction handle
+ * @state: new state
+ *
+ * Advertise in the store a change of the given driver to the given new_state.
+ * Return 0 on success, or -errno on error.  On error, the device will switch
+ * to XenbusStateClosing, and the error will be saved in the store.
+ */
+int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state)
+{
+       /* We check whether the state is currently set to the given value, and
+          if not, then the state is set.  We don't want to unconditionally
+          write the given state, because we don't want to fire watches
+          unnecessarily.  Furthermore, if the node has gone, we don't write
+          to it, as the device will be tearing down, and we don't want to
+          resurrect that directory.
+
+          Note that, because of this cached value of our state, this function
+          will not work inside a Xenstore transaction (something it was
+          trying to in the past) because dev->state would not get reset if
+          the transaction was aborted.
+
+        */
+
+       int current_state;
+       int err;
+
+       if (state == dev->state)
+               return 0;
+
+       err = xenbus_scanf(XBT_NIL, dev->nodename, "state", "%d",
+                          &current_state);
+       if (err != 1)
+               return 0;
+
+       err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%d", state);
+       if (err) {
+               if (state != XenbusStateClosing) /* Avoid looping */
+                       xenbus_dev_fatal(dev, err, "writing new state");
+               return err;
+       }
+
+       dev->state = state;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_switch_state);
+
+int xenbus_frontend_closed(struct xenbus_device *dev)
+{
+       xenbus_switch_state(dev, XenbusStateClosed);
+       complete(&dev->down);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_frontend_closed);
+
+/**
+ * Return the path to the error node for the given device, or NULL on failure.
+ * If the value returned is non-NULL, then it is the caller's to kfree.
+ */
+static char *error_path(struct xenbus_device *dev)
+{
+       return kasprintf(GFP_KERNEL, "error/%s", dev->nodename);
+}
+
+
+static void xenbus_va_dev_error(struct xenbus_device *dev, int err,
+                               const char *fmt, va_list ap)
+{
+       int ret;
+       unsigned int len;
+       char *printf_buffer = NULL;
+       char *path_buffer = NULL;
+
+#define PRINTF_BUFFER_SIZE 4096
+       printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
+       if (printf_buffer == NULL)
+               goto fail;
+
+       len = sprintf(printf_buffer, "%i ", -err);
+       ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap);
+
+       BUG_ON(len + ret > PRINTF_BUFFER_SIZE-1);
+
+       dev_err(&dev->dev, "%s\n", printf_buffer);
+
+       path_buffer = error_path(dev);
+
+       if (path_buffer == NULL) {
+               dev_err(&dev->dev, "failed to write error node for %s (%s)\n",
+                      dev->nodename, printf_buffer);
+               goto fail;
+       }
+
+       if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) {
+               dev_err(&dev->dev, "failed to write error node for %s (%s)\n",
+                      dev->nodename, printf_buffer);
+               goto fail;
+       }
+
+fail:
+       kfree(printf_buffer);
+       kfree(path_buffer);
+}
+
+
+/**
+ * xenbus_dev_error
+ * @dev: xenbus device
+ * @err: error to report
+ * @fmt: error message format
+ *
+ * Report the given negative errno into the store, along with the given
+ * formatted message.
+ */
+void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       xenbus_va_dev_error(dev, err, fmt, ap);
+       va_end(ap);
+}
+EXPORT_SYMBOL_GPL(xenbus_dev_error);
+
+/**
+ * xenbus_dev_fatal
+ * @dev: xenbus device
+ * @err: error to report
+ * @fmt: error message format
+ *
+ * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by
+ * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly
+ * closedown of this driver and its peer.
+ */
+
+void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       xenbus_va_dev_error(dev, err, fmt, ap);
+       va_end(ap);
+
+       xenbus_switch_state(dev, XenbusStateClosing);
+}
+EXPORT_SYMBOL_GPL(xenbus_dev_fatal);
+
+/**
+ * xenbus_grant_ring
+ * @dev: xenbus device
+ * @ring_mfn: mfn of ring to grant
+
+ * Grant access to the given @ring_mfn to the peer of the given device.  Return
+ * 0 on success, or -errno on error.  On error, the device will switch to
+ * XenbusStateClosing, and the error will be saved in the store.
+ */
+int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn)
+{
+       int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0);
+       if (err < 0)
+               xenbus_dev_fatal(dev, err, "granting access to ring page");
+       return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_grant_ring);
+
+
+/**
+ * Allocate an event channel for the given xenbus_device, assigning the newly
+ * created local port to *port.  Return 0 on success, or -errno on error.  On
+ * error, the device will switch to XenbusStateClosing, and the error will be
+ * saved in the store.
+ */
+int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port)
+{
+       struct evtchn_alloc_unbound alloc_unbound;
+       int err;
+
+       alloc_unbound.dom = DOMID_SELF;
+       alloc_unbound.remote_dom = dev->otherend_id;
+
+       err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
+                                         &alloc_unbound);
+       if (err)
+               xenbus_dev_fatal(dev, err, "allocating event channel");
+       else
+               *port = alloc_unbound.port;
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_alloc_evtchn);
+
+
+/**
+ * Bind to an existing interdomain event channel in another domain. Returns 0
+ * on success and stores the local port in *port. On error, returns -errno,
+ * switches the device to XenbusStateClosing, and saves the error in XenStore.
+ */
+int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port)
+{
+       struct evtchn_bind_interdomain bind_interdomain;
+       int err;
+
+       bind_interdomain.remote_dom = dev->otherend_id;
+       bind_interdomain.remote_port = remote_port;
+
+       err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
+                                         &bind_interdomain);
+       if (err)
+               xenbus_dev_fatal(dev, err,
+                                "binding to event channel %d from domain %d",
+                                remote_port, dev->otherend_id);
+       else
+               *port = bind_interdomain.local_port;
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_bind_evtchn);
+
+
+/**
+ * Free an existing event channel. Returns 0 on success or -errno on error.
+ */
+int xenbus_free_evtchn(struct xenbus_device *dev, int port)
+{
+       struct evtchn_close close;
+       int err;
+
+       close.port = port;
+
+       err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
+       if (err)
+               xenbus_dev_error(dev, err, "freeing event channel %d", port);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_free_evtchn);
+
+
+/**
+ * xenbus_map_ring_valloc
+ * @dev: xenbus device
+ * @gnt_ref: grant reference
+ * @vaddr: pointer to address to be filled out by mapping
+ *
+ * Based on Rusty Russell's skeleton driver's map_page.
+ * Map a page of memory into this domain from another domain's grant table.
+ * xenbus_map_ring_valloc allocates a page of virtual address space, maps the
+ * page to that address, and sets *vaddr to that address.
+ * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h)
+ * or -ENOMEM on error. If an error is returned, device will switch to
+ * XenbusStateClosing and the error message will be saved in XenStore.
+ */
+int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr)
+{
+       struct gnttab_map_grant_ref op = {
+               .flags = GNTMAP_host_map,
+               .ref   = gnt_ref,
+               .dom   = dev->otherend_id,
+       };
+       struct vm_struct *area;
+
+       *vaddr = NULL;
+
+       area = alloc_vm_area(PAGE_SIZE);
+       if (!area)
+               return -ENOMEM;
+
+       op.host_addr = (unsigned long)area->addr;
+
+       if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+               BUG();
+
+       if (op.status != GNTST_okay) {
+               free_vm_area(area);
+               xenbus_dev_fatal(dev, op.status,
+                                "mapping in shared page %d from domain %d",
+                                gnt_ref, dev->otherend_id);
+               return op.status;
+       }
+
+       /* Stuff the handle in an unused field */
+       area->phys_addr = (unsigned long)op.handle;
+
+       *vaddr = area->addr;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc);
+
+
+/**
+ * xenbus_map_ring
+ * @dev: xenbus device
+ * @gnt_ref: grant reference
+ * @handle: pointer to grant handle to be filled
+ * @vaddr: address to be mapped to
+ *
+ * Map a page of memory into this domain from another domain's grant table.
+ * xenbus_map_ring does not allocate the virtual address space (you must do
+ * this yourself!). It only maps in the page to the specified address.
+ * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h)
+ * or -ENOMEM on error. If an error is returned, device will switch to
+ * XenbusStateClosing and the error message will be saved in XenStore.
+ */
+int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref,
+                   grant_handle_t *handle, void *vaddr)
+{
+       struct gnttab_map_grant_ref op = {
+               .host_addr = (unsigned long)vaddr,
+               .flags     = GNTMAP_host_map,
+               .ref       = gnt_ref,
+               .dom       = dev->otherend_id,
+       };
+
+       if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+               BUG();
+
+       if (op.status != GNTST_okay) {
+               xenbus_dev_fatal(dev, op.status,
+                                "mapping in shared page %d from domain %d",
+                                gnt_ref, dev->otherend_id);
+       } else
+               *handle = op.handle;
+
+       return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_map_ring);
+
+
+/**
+ * xenbus_unmap_ring_vfree
+ * @dev: xenbus device
+ * @vaddr: addr to unmap
+ *
+ * Based on Rusty Russell's skeleton driver's unmap_page.
+ * Unmap a page of memory in this domain that was imported from another domain.
+ * Use xenbus_unmap_ring_vfree if you mapped in your memory with
+ * xenbus_map_ring_valloc (it will free the virtual address space).
+ * Returns 0 on success and returns GNTST_* on error
+ * (see xen/include/interface/grant_table.h).
+ */
+int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr)
+{
+       struct vm_struct *area;
+       struct gnttab_unmap_grant_ref op = {
+               .host_addr = (unsigned long)vaddr,
+       };
+
+       /* It'd be nice if linux/vmalloc.h provided a find_vm_area(void *addr)
+        * method so that we don't have to muck with vmalloc internals here.
+        * We could force the user to hang on to their struct vm_struct from
+        * xenbus_map_ring_valloc, but these 6 lines considerably simplify
+        * this API.
+        */
+       read_lock(&vmlist_lock);
+       for (area = vmlist; area != NULL; area = area->next) {
+               if (area->addr == vaddr)
+                       break;
+       }
+       read_unlock(&vmlist_lock);
+
+       if (!area) {
+               xenbus_dev_error(dev, -ENOENT,
+                                "can't find mapped virtual address %p", vaddr);
+               return GNTST_bad_virt_addr;
+       }
+
+       op.handle = (grant_handle_t)area->phys_addr;
+
+       if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+               BUG();
+
+       if (op.status == GNTST_okay)
+               free_vm_area(area);
+       else
+               xenbus_dev_error(dev, op.status,
+                                "unmapping page at handle %d error %d",
+                                (int16_t)area->phys_addr, op.status);
+
+       return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree);
+
+
+/**
+ * xenbus_unmap_ring
+ * @dev: xenbus device
+ * @handle: grant handle
+ * @vaddr: addr to unmap
+ *
+ * Unmap a page of memory in this domain that was imported from another domain.
+ * Returns 0 on success and returns GNTST_* on error
+ * (see xen/include/interface/grant_table.h).
+ */
+int xenbus_unmap_ring(struct xenbus_device *dev,
+                     grant_handle_t handle, void *vaddr)
+{
+       struct gnttab_unmap_grant_ref op = {
+               .host_addr = (unsigned long)vaddr,
+               .handle    = handle,
+       };
+
+       if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+               BUG();
+
+       if (op.status != GNTST_okay)
+               xenbus_dev_error(dev, op.status,
+                                "unmapping page at handle %d error %d",
+                                handle, op.status);
+
+       return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_unmap_ring);
+
+
+/**
+ * xenbus_read_driver_state
+ * @path: path for driver
+ *
+ * Return the state of the driver rooted at the given store path, or
+ * XenbusStateUnknown if no state can be read.
+ */
+enum xenbus_state xenbus_read_driver_state(const char *path)
+{
+       enum xenbus_state result;
+       int err = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL);
+       if (err)
+               result = XenbusStateUnknown;
+
+       return result;
+}
+EXPORT_SYMBOL_GPL(xenbus_read_driver_state);
diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c
new file mode 100644 (file)
index 0000000..6efbe3f
--- /dev/null
@@ -0,0 +1,233 @@
+/******************************************************************************
+ * xenbus_comms.c
+ *
+ * Low level code to talks to Xen Store: ringbuffer and event channel.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <xen/xenbus.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/events.h>
+#include <xen/page.h>
+#include "xenbus_comms.h"
+
+static int xenbus_irq;
+
+static DECLARE_WORK(probe_work, xenbus_probe);
+
+static DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
+
+static irqreturn_t wake_waiting(int irq, void *unused)
+{
+       if (unlikely(xenstored_ready == 0)) {
+               xenstored_ready = 1;
+               schedule_work(&probe_work);
+       }
+
+       wake_up(&xb_waitq);
+       return IRQ_HANDLED;
+}
+
+static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
+{
+       return ((prod - cons) <= XENSTORE_RING_SIZE);
+}
+
+static void *get_output_chunk(XENSTORE_RING_IDX cons,
+                             XENSTORE_RING_IDX prod,
+                             char *buf, uint32_t *len)
+{
+       *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
+       if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
+               *len = XENSTORE_RING_SIZE - (prod - cons);
+       return buf + MASK_XENSTORE_IDX(prod);
+}
+
+static const void *get_input_chunk(XENSTORE_RING_IDX cons,
+                                  XENSTORE_RING_IDX prod,
+                                  const char *buf, uint32_t *len)
+{
+       *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
+       if ((prod - cons) < *len)
+               *len = prod - cons;
+       return buf + MASK_XENSTORE_IDX(cons);
+}
+
+/**
+ * xb_write - low level write
+ * @data: buffer to send
+ * @len: length of buffer
+ *
+ * Returns 0 on success, error otherwise.
+ */
+int xb_write(const void *data, unsigned len)
+{
+       struct xenstore_domain_interface *intf = xen_store_interface;
+       XENSTORE_RING_IDX cons, prod;
+       int rc;
+
+       while (len != 0) {
+               void *dst;
+               unsigned int avail;
+
+               rc = wait_event_interruptible(
+                       xb_waitq,
+                       (intf->req_prod - intf->req_cons) !=
+                       XENSTORE_RING_SIZE);
+               if (rc < 0)
+                       return rc;
+
+               /* Read indexes, then verify. */
+               cons = intf->req_cons;
+               prod = intf->req_prod;
+               if (!check_indexes(cons, prod)) {
+                       intf->req_cons = intf->req_prod = 0;
+                       return -EIO;
+               }
+
+               dst = get_output_chunk(cons, prod, intf->req, &avail);
+               if (avail == 0)
+                       continue;
+               if (avail > len)
+                       avail = len;
+
+               /* Must write data /after/ reading the consumer index. */
+               mb();
+
+               memcpy(dst, data, avail);
+               data += avail;
+               len -= avail;
+
+               /* Other side must not see new producer until data is there. */
+               wmb();
+               intf->req_prod += avail;
+
+               /* Implies mb(): other side will see the updated producer. */
+               notify_remote_via_evtchn(xen_store_evtchn);
+       }
+
+       return 0;
+}
+
+int xb_data_to_read(void)
+{
+       struct xenstore_domain_interface *intf = xen_store_interface;
+       return (intf->rsp_cons != intf->rsp_prod);
+}
+
+int xb_wait_for_data_to_read(void)
+{
+       return wait_event_interruptible(xb_waitq, xb_data_to_read());
+}
+
+int xb_read(void *data, unsigned len)
+{
+       struct xenstore_domain_interface *intf = xen_store_interface;
+       XENSTORE_RING_IDX cons, prod;
+       int rc;
+
+       while (len != 0) {
+               unsigned int avail;
+               const char *src;
+
+               rc = xb_wait_for_data_to_read();
+               if (rc < 0)
+                       return rc;
+
+               /* Read indexes, then verify. */
+               cons = intf->rsp_cons;
+               prod = intf->rsp_prod;
+               if (!check_indexes(cons, prod)) {
+                       intf->rsp_cons = intf->rsp_prod = 0;
+                       return -EIO;
+               }
+
+               src = get_input_chunk(cons, prod, intf->rsp, &avail);
+               if (avail == 0)
+                       continue;
+               if (avail > len)
+                       avail = len;
+
+               /* Must read data /after/ reading the producer index. */
+               rmb();
+
+               memcpy(data, src, avail);
+               data += avail;
+               len -= avail;
+
+               /* Other side must not see free space until we've copied out */
+               mb();
+               intf->rsp_cons += avail;
+
+               pr_debug("Finished read of %i bytes (%i to go)\n", avail, len);
+
+               /* Implies mb(): other side will see the updated consumer. */
+               notify_remote_via_evtchn(xen_store_evtchn);
+       }
+
+       return 0;
+}
+
+/**
+ * xb_init_comms - Set up interrupt handler off store event channel.
+ */
+int xb_init_comms(void)
+{
+       struct xenstore_domain_interface *intf = xen_store_interface;
+       int err;
+
+       if (intf->req_prod != intf->req_cons)
+               printk(KERN_ERR "XENBUS request ring is not quiescent "
+                      "(%08x:%08x)!\n", intf->req_cons, intf->req_prod);
+
+       if (intf->rsp_prod != intf->rsp_cons) {
+               printk(KERN_WARNING "XENBUS response ring is not quiescent "
+                      "(%08x:%08x): fixing up\n",
+                      intf->rsp_cons, intf->rsp_prod);
+               intf->rsp_cons = intf->rsp_prod;
+       }
+
+       if (xenbus_irq)
+               unbind_from_irqhandler(xenbus_irq, &xb_waitq);
+
+       err = bind_evtchn_to_irqhandler(
+               xen_store_evtchn, wake_waiting,
+               0, "xenbus", &xb_waitq);
+       if (err <= 0) {
+               printk(KERN_ERR "XENBUS request irq failed %i\n", err);
+               return err;
+       }
+
+       xenbus_irq = err;
+
+       return 0;
+}
diff --git a/drivers/xen/xenbus/xenbus_comms.h b/drivers/xen/xenbus/xenbus_comms.h
new file mode 100644 (file)
index 0000000..c21db75
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Private include for xenbus communications.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _XENBUS_COMMS_H
+#define _XENBUS_COMMS_H
+
+int xs_init(void);
+int xb_init_comms(void);
+
+/* Low level routines. */
+int xb_write(const void *data, unsigned len);
+int xb_read(void *data, unsigned len);
+int xb_data_to_read(void);
+int xb_wait_for_data_to_read(void);
+int xs_input_avail(void);
+extern struct xenstore_domain_interface *xen_store_interface;
+extern int xen_store_evtchn;
+
+#endif /* _XENBUS_COMMS_H */
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
new file mode 100644 (file)
index 0000000..0b769f7
--- /dev/null
@@ -0,0 +1,935 @@
+/******************************************************************************
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 Mike Wray, Hewlett-Packard
+ * Copyright (C) 2005, 2006 XenSource Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#define DPRINTK(fmt, args...)                          \
+       pr_debug("xenbus_probe (%s:%d) " fmt ".\n",     \
+                __func__, __LINE__, ##args)
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/notifier.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/xenbus.h>
+#include <xen/events.h>
+#include <xen/page.h>
+
+#include "xenbus_comms.h"
+#include "xenbus_probe.h"
+
+int xen_store_evtchn;
+struct xenstore_domain_interface *xen_store_interface;
+static unsigned long xen_store_mfn;
+
+static BLOCKING_NOTIFIER_HEAD(xenstore_chain);
+
+static void wait_for_devices(struct xenbus_driver *xendrv);
+
+static int xenbus_probe_frontend(const char *type, const char *name);
+
+static void xenbus_dev_shutdown(struct device *_dev);
+
+/* If something in array of ids matches this device, return it. */
+static const struct xenbus_device_id *
+match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
+{
+       for (; *arr->devicetype != '\0'; arr++) {
+               if (!strcmp(arr->devicetype, dev->devicetype))
+                       return arr;
+       }
+       return NULL;
+}
+
+int xenbus_match(struct device *_dev, struct device_driver *_drv)
+{
+       struct xenbus_driver *drv = to_xenbus_driver(_drv);
+
+       if (!drv->ids)
+               return 0;
+
+       return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
+}
+
+/* device/<type>/<id> => <type>-<id> */
+static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
+{
+       nodename = strchr(nodename, '/');
+       if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) {
+               printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename);
+               return -EINVAL;
+       }
+
+       strlcpy(bus_id, nodename + 1, BUS_ID_SIZE);
+       if (!strchr(bus_id, '/')) {
+               printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id);
+               return -EINVAL;
+       }
+       *strchr(bus_id, '/') = '-';
+       return 0;
+}
+
+
+static void free_otherend_details(struct xenbus_device *dev)
+{
+       kfree(dev->otherend);
+       dev->otherend = NULL;
+}
+
+
+static void free_otherend_watch(struct xenbus_device *dev)
+{
+       if (dev->otherend_watch.node) {
+               unregister_xenbus_watch(&dev->otherend_watch);
+               kfree(dev->otherend_watch.node);
+               dev->otherend_watch.node = NULL;
+       }
+}
+
+
+int read_otherend_details(struct xenbus_device *xendev,
+                                char *id_node, char *path_node)
+{
+       int err = xenbus_gather(XBT_NIL, xendev->nodename,
+                               id_node, "%i", &xendev->otherend_id,
+                               path_node, NULL, &xendev->otherend,
+                               NULL);
+       if (err) {
+               xenbus_dev_fatal(xendev, err,
+                                "reading other end details from %s",
+                                xendev->nodename);
+               return err;
+       }
+       if (strlen(xendev->otherend) == 0 ||
+           !xenbus_exists(XBT_NIL, xendev->otherend, "")) {
+               xenbus_dev_fatal(xendev, -ENOENT,
+                                "unable to read other end from %s.  "
+                                "missing or inaccessible.",
+                                xendev->nodename);
+               free_otherend_details(xendev);
+               return -ENOENT;
+       }
+
+       return 0;
+}
+
+
+static int read_backend_details(struct xenbus_device *xendev)
+{
+       return read_otherend_details(xendev, "backend-id", "backend");
+}
+
+
+/* Bus type for frontend drivers. */
+static struct xen_bus_type xenbus_frontend = {
+       .root = "device",
+       .levels = 2,            /* device/type/<id> */
+       .get_bus_id = frontend_bus_id,
+       .probe = xenbus_probe_frontend,
+       .bus = {
+               .name     = "xen",
+               .match    = xenbus_match,
+               .probe    = xenbus_dev_probe,
+               .remove   = xenbus_dev_remove,
+               .shutdown = xenbus_dev_shutdown,
+       },
+};
+
+static void otherend_changed(struct xenbus_watch *watch,
+                            const char **vec, unsigned int len)
+{
+       struct xenbus_device *dev =
+               container_of(watch, struct xenbus_device, otherend_watch);
+       struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
+       enum xenbus_state state;
+
+       /* Protect us against watches firing on old details when the otherend
+          details change, say immediately after a resume. */
+       if (!dev->otherend ||
+           strncmp(dev->otherend, vec[XS_WATCH_PATH],
+                   strlen(dev->otherend))) {
+               dev_dbg(&dev->dev, "Ignoring watch at %s", vec[XS_WATCH_PATH]);
+               return;
+       }
+
+       state = xenbus_read_driver_state(dev->otherend);
+
+       dev_dbg(&dev->dev, "state is %d, (%s), %s, %s",
+               state, xenbus_strstate(state), dev->otherend_watch.node,
+               vec[XS_WATCH_PATH]);
+
+       /*
+        * Ignore xenbus transitions during shutdown. This prevents us doing
+        * work that can fail e.g., when the rootfs is gone.
+        */
+       if (system_state > SYSTEM_RUNNING) {
+               struct xen_bus_type *bus = bus;
+               bus = container_of(dev->dev.bus, struct xen_bus_type, bus);
+               /* If we're frontend, drive the state machine to Closed. */
+               /* This should cause the backend to release our resources. */
+               if ((bus == &xenbus_frontend) && (state == XenbusStateClosing))
+                       xenbus_frontend_closed(dev);
+               return;
+       }
+
+       if (drv->otherend_changed)
+               drv->otherend_changed(dev, state);
+}
+
+
+static int talk_to_otherend(struct xenbus_device *dev)
+{
+       struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
+
+       free_otherend_watch(dev);
+       free_otherend_details(dev);
+
+       return drv->read_otherend_details(dev);
+}
+
+
+static int watch_otherend(struct xenbus_device *dev)
+{
+       return xenbus_watch_pathfmt(dev, &dev->otherend_watch, otherend_changed,
+                                   "%s/%s", dev->otherend, "state");
+}
+
+
+int xenbus_dev_probe(struct device *_dev)
+{
+       struct xenbus_device *dev = to_xenbus_device(_dev);
+       struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
+       const struct xenbus_device_id *id;
+       int err;
+
+       DPRINTK("%s", dev->nodename);
+
+       if (!drv->probe) {
+               err = -ENODEV;
+               goto fail;
+       }
+
+       id = match_device(drv->ids, dev);
+       if (!id) {
+               err = -ENODEV;
+               goto fail;
+       }
+
+       err = talk_to_otherend(dev);
+       if (err) {
+               dev_warn(&dev->dev, "talk_to_otherend on %s failed.\n",
+                        dev->nodename);
+               return err;
+       }
+
+       err = drv->probe(dev, id);
+       if (err)
+               goto fail;
+
+       err = watch_otherend(dev);
+       if (err) {
+               dev_warn(&dev->dev, "watch_otherend on %s failed.\n",
+                      dev->nodename);
+               return err;
+       }
+
+       return 0;
+fail:
+       xenbus_dev_error(dev, err, "xenbus_dev_probe on %s", dev->nodename);
+       xenbus_switch_state(dev, XenbusStateClosed);
+       return -ENODEV;
+}
+
+int xenbus_dev_remove(struct device *_dev)
+{
+       struct xenbus_device *dev = to_xenbus_device(_dev);
+       struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
+
+       DPRINTK("%s", dev->nodename);
+
+       free_otherend_watch(dev);
+       free_otherend_details(dev);
+
+       if (drv->remove)
+               drv->remove(dev);
+
+       xenbus_switch_state(dev, XenbusStateClosed);
+       return 0;
+}
+
+static void xenbus_dev_shutdown(struct device *_dev)
+{
+       struct xenbus_device *dev = to_xenbus_device(_dev);
+       unsigned long timeout = 5*HZ;
+
+       DPRINTK("%s", dev->nodename);
+
+       get_device(&dev->dev);
+       if (dev->state != XenbusStateConnected) {
+               printk(KERN_INFO "%s: %s: %s != Connected, skipping\n", __func__,
+                      dev->nodename, xenbus_strstate(dev->state));
+               goto out;
+       }
+       xenbus_switch_state(dev, XenbusStateClosing);
+       timeout = wait_for_completion_timeout(&dev->down, timeout);
+       if (!timeout)
+               printk(KERN_INFO "%s: %s timeout closing device\n",
+                      __func__, dev->nodename);
+ out:
+       put_device(&dev->dev);
+}
+
+int xenbus_register_driver_common(struct xenbus_driver *drv,
+                                 struct xen_bus_type *bus,
+                                 struct module *owner,
+                                 const char *mod_name)
+{
+       drv->driver.name = drv->name;
+       drv->driver.bus = &bus->bus;
+       drv->driver.owner = owner;
+       drv->driver.mod_name = mod_name;
+
+       return driver_register(&drv->driver);
+}
+
+int __xenbus_register_frontend(struct xenbus_driver *drv,
+                              struct module *owner, const char *mod_name)
+{
+       int ret;
+
+       drv->read_otherend_details = read_backend_details;
+
+       ret = xenbus_register_driver_common(drv, &xenbus_frontend,
+                                           owner, mod_name);
+       if (ret)
+               return ret;
+
+       /* If this driver is loaded as a module wait for devices to attach. */
+       wait_for_devices(drv);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(__xenbus_register_frontend);
+
+void xenbus_unregister_driver(struct xenbus_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(xenbus_unregister_driver);
+
+struct xb_find_info
+{
+       struct xenbus_device *dev;
+       const char *nodename;
+};
+
+static int cmp_dev(struct device *dev, void *data)
+{
+       struct xenbus_device *xendev = to_xenbus_device(dev);
+       struct xb_find_info *info = data;
+
+       if (!strcmp(xendev->nodename, info->nodename)) {
+               info->dev = xendev;
+               get_device(dev);
+               return 1;
+       }
+       return 0;
+}
+
+struct xenbus_device *xenbus_device_find(const char *nodename,
+                                        struct bus_type *bus)
+{
+       struct xb_find_info info = { .dev = NULL, .nodename = nodename };
+
+       bus_for_each_dev(bus, NULL, &info, cmp_dev);
+       return info.dev;
+}
+
+static int cleanup_dev(struct device *dev, void *data)
+{
+       struct xenbus_device *xendev = to_xenbus_device(dev);
+       struct xb_find_info *info = data;
+       int len = strlen(info->nodename);
+
+       DPRINTK("%s", info->nodename);
+
+       /* Match the info->nodename path, or any subdirectory of that path. */
+       if (strncmp(xendev->nodename, info->nodename, len))
+               return 0;
+
+       /* If the node name is longer, ensure it really is a subdirectory. */
+       if ((strlen(xendev->nodename) > len) && (xendev->nodename[len] != '/'))
+               return 0;
+
+       info->dev = xendev;
+       get_device(dev);
+       return 1;
+}
+
+static void xenbus_cleanup_devices(const char *path, struct bus_type *bus)
+{
+       struct xb_find_info info = { .nodename = path };
+
+       do {
+               info.dev = NULL;
+               bus_for_each_dev(bus, NULL, &info, cleanup_dev);
+               if (info.dev) {
+                       device_unregister(&info.dev->dev);
+                       put_device(&info.dev->dev);
+               }
+       } while (info.dev);
+}
+
+static void xenbus_dev_release(struct device *dev)
+{
+       if (dev)
+               kfree(to_xenbus_device(dev));
+}
+
+static ssize_t xendev_show_nodename(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename);
+}
+DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL);
+
+static ssize_t xendev_show_devtype(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype);
+}
+DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL);
+
+
+int xenbus_probe_node(struct xen_bus_type *bus,
+                     const char *type,
+                     const char *nodename)
+{
+       int err;
+       struct xenbus_device *xendev;
+       size_t stringlen;
+       char *tmpstring;
+
+       enum xenbus_state state = xenbus_read_driver_state(nodename);
+
+       if (state != XenbusStateInitialising) {
+               /* Device is not new, so ignore it.  This can happen if a
+                  device is going away after switching to Closed.  */
+               return 0;
+       }
+
+       stringlen = strlen(nodename) + 1 + strlen(type) + 1;
+       xendev = kzalloc(sizeof(*xendev) + stringlen, GFP_KERNEL);
+       if (!xendev)
+               return -ENOMEM;
+
+       xendev->state = XenbusStateInitialising;
+
+       /* Copy the strings into the extra space. */
+
+       tmpstring = (char *)(xendev + 1);
+       strcpy(tmpstring, nodename);
+       xendev->nodename = tmpstring;
+
+       tmpstring += strlen(tmpstring) + 1;
+       strcpy(tmpstring, type);
+       xendev->devicetype = tmpstring;
+       init_completion(&xendev->down);
+
+       xendev->dev.bus = &bus->bus;
+       xendev->dev.release = xenbus_dev_release;
+
+       err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename);
+       if (err)
+               goto fail;
+
+       /* Register with generic device framework. */
+       err = device_register(&xendev->dev);
+       if (err)
+               goto fail;
+
+       err = device_create_file(&xendev->dev, &dev_attr_nodename);
+       if (err)
+               goto fail_unregister;
+
+       err = device_create_file(&xendev->dev, &dev_attr_devtype);
+       if (err)
+               goto fail_remove_file;
+
+       return 0;
+fail_remove_file:
+       device_remove_file(&xendev->dev, &dev_attr_nodename);
+fail_unregister:
+       device_unregister(&xendev->dev);
+fail:
+       kfree(xendev);
+       return err;
+}
+
+/* device/<typename>/<name> */
+static int xenbus_probe_frontend(const char *type, const char *name)
+{
+       char *nodename;
+       int err;
+
+       nodename = kasprintf(GFP_KERNEL, "%s/%s/%s",
+                            xenbus_frontend.root, type, name);
+       if (!nodename)
+               return -ENOMEM;
+
+       DPRINTK("%s", nodename);
+
+       err = xenbus_probe_node(&xenbus_frontend, type, nodename);
+       kfree(nodename);
+       return err;
+}
+
+static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
+{
+       int err = 0;
+       char **dir;
+       unsigned int dir_n = 0;
+       int i;
+
+       dir = xenbus_directory(XBT_NIL, bus->root, type, &dir_n);
+       if (IS_ERR(dir))
+               return PTR_ERR(dir);
+
+       for (i = 0; i < dir_n; i++) {
+               err = bus->probe(type, dir[i]);
+               if (err)
+                       break;
+       }
+       kfree(dir);
+       return err;
+}
+
+int xenbus_probe_devices(struct xen_bus_type *bus)
+{
+       int err = 0;
+       char **dir;
+       unsigned int i, dir_n;
+
+       dir = xenbus_directory(XBT_NIL, bus->root, "", &dir_n);
+       if (IS_ERR(dir))
+               return PTR_ERR(dir);
+
+       for (i = 0; i < dir_n; i++) {
+               err = xenbus_probe_device_type(bus, dir[i]);
+               if (err)
+                       break;
+       }
+       kfree(dir);
+       return err;
+}
+
+static unsigned int char_count(const char *str, char c)
+{
+       unsigned int i, ret = 0;
+
+       for (i = 0; str[i]; i++)
+               if (str[i] == c)
+                       ret++;
+       return ret;
+}
+
+static int strsep_len(const char *str, char c, unsigned int len)
+{
+       unsigned int i;
+
+       for (i = 0; str[i]; i++)
+               if (str[i] == c) {
+                       if (len == 0)
+                               return i;
+                       len--;
+               }
+       return (len == 0) ? i : -ERANGE;
+}
+
+void xenbus_dev_changed(const char *node, struct xen_bus_type *bus)
+{
+       int exists, rootlen;
+       struct xenbus_device *dev;
+       char type[BUS_ID_SIZE];
+       const char *p, *root;
+
+       if (char_count(node, '/') < 2)
+               return;
+
+       exists = xenbus_exists(XBT_NIL, node, "");
+       if (!exists) {
+               xenbus_cleanup_devices(node, &bus->bus);
+               return;
+       }
+
+       /* backend/<type>/... or device/<type>/... */
+       p = strchr(node, '/') + 1;
+       snprintf(type, BUS_ID_SIZE, "%.*s", (int)strcspn(p, "/"), p);
+       type[BUS_ID_SIZE-1] = '\0';
+
+       rootlen = strsep_len(node, '/', bus->levels);
+       if (rootlen < 0)
+               return;
+       root = kasprintf(GFP_KERNEL, "%.*s", rootlen, node);
+       if (!root)
+               return;
+
+       dev = xenbus_device_find(root, &bus->bus);
+       if (!dev)
+               xenbus_probe_node(bus, type, root);
+       else
+               put_device(&dev->dev);
+
+       kfree(root);
+}
+
+static void frontend_changed(struct xenbus_watch *watch,
+                            const char **vec, unsigned int len)
+{
+       DPRINTK("");
+
+       xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend);
+}
+
+/* We watch for devices appearing and vanishing. */
+static struct xenbus_watch fe_watch = {
+       .node = "device",
+       .callback = frontend_changed,
+};
+
+static int suspend_dev(struct device *dev, void *data)
+{
+       int err = 0;
+       struct xenbus_driver *drv;
+       struct xenbus_device *xdev;
+
+       DPRINTK("");
+
+       if (dev->driver == NULL)
+               return 0;
+       drv = to_xenbus_driver(dev->driver);
+       xdev = container_of(dev, struct xenbus_device, dev);
+       if (drv->suspend)
+               err = drv->suspend(xdev);
+       if (err)
+               printk(KERN_WARNING
+                      "xenbus: suspend %s failed: %i\n", dev->bus_id, err);
+       return 0;
+}
+
+static int suspend_cancel_dev(struct device *dev, void *data)
+{
+       int err = 0;
+       struct xenbus_driver *drv;
+       struct xenbus_device *xdev;
+
+       DPRINTK("");
+
+       if (dev->driver == NULL)
+               return 0;
+       drv = to_xenbus_driver(dev->driver);
+       xdev = container_of(dev, struct xenbus_device, dev);
+       if (drv->suspend_cancel)
+               err = drv->suspend_cancel(xdev);
+       if (err)
+               printk(KERN_WARNING
+                      "xenbus: suspend_cancel %s failed: %i\n",
+                      dev->bus_id, err);
+       return 0;
+}
+
+static int resume_dev(struct device *dev, void *data)
+{
+       int err;
+       struct xenbus_driver *drv;
+       struct xenbus_device *xdev;
+
+       DPRINTK("");
+
+       if (dev->driver == NULL)
+               return 0;
+
+       drv = to_xenbus_driver(dev->driver);
+       xdev = container_of(dev, struct xenbus_device, dev);
+
+       err = talk_to_otherend(xdev);
+       if (err) {
+               printk(KERN_WARNING
+                      "xenbus: resume (talk_to_otherend) %s failed: %i\n",
+                      dev->bus_id, err);
+               return err;
+       }
+
+       xdev->state = XenbusStateInitialising;
+
+       if (drv->resume) {
+               err = drv->resume(xdev);
+               if (err) {
+                       printk(KERN_WARNING
+                              "xenbus: resume %s failed: %i\n",
+                              dev->bus_id, err);
+                       return err;
+               }
+       }
+
+       err = watch_otherend(xdev);
+       if (err) {
+               printk(KERN_WARNING
+                      "xenbus_probe: resume (watch_otherend) %s failed: "
+                      "%d.\n", dev->bus_id, err);
+               return err;
+       }
+
+       return 0;
+}
+
+void xenbus_suspend(void)
+{
+       DPRINTK("");
+
+       bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
+       xenbus_backend_suspend(suspend_dev);
+       xs_suspend();
+}
+EXPORT_SYMBOL_GPL(xenbus_suspend);
+
+void xenbus_resume(void)
+{
+       xb_init_comms();
+       xs_resume();
+       bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
+       xenbus_backend_resume(resume_dev);
+}
+EXPORT_SYMBOL_GPL(xenbus_resume);
+
+void xenbus_suspend_cancel(void)
+{
+       xs_suspend_cancel();
+       bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_cancel_dev);
+       xenbus_backend_resume(suspend_cancel_dev);
+}
+EXPORT_SYMBOL_GPL(xenbus_suspend_cancel);
+
+/* A flag to determine if xenstored is 'ready' (i.e. has started) */
+int xenstored_ready = 0;
+
+
+int register_xenstore_notifier(struct notifier_block *nb)
+{
+       int ret = 0;
+
+       if (xenstored_ready > 0)
+               ret = nb->notifier_call(nb, 0, NULL);
+       else
+               blocking_notifier_chain_register(&xenstore_chain, nb);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(register_xenstore_notifier);
+
+void unregister_xenstore_notifier(struct notifier_block *nb)
+{
+       blocking_notifier_chain_unregister(&xenstore_chain, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_xenstore_notifier);
+
+void xenbus_probe(struct work_struct *unused)
+{
+       BUG_ON((xenstored_ready <= 0));
+
+       /* Enumerate devices in xenstore and watch for changes. */
+       xenbus_probe_devices(&xenbus_frontend);
+       register_xenbus_watch(&fe_watch);
+       xenbus_backend_probe_and_watch();
+
+       /* Notify others that xenstore is up */
+       blocking_notifier_call_chain(&xenstore_chain, 0, NULL);
+}
+
+static int __init xenbus_probe_init(void)
+{
+       int err = 0;
+
+       DPRINTK("");
+
+       err = -ENODEV;
+       if (!is_running_on_xen())
+               goto out_error;
+
+       /* Register ourselves with the kernel bus subsystem */
+       err = bus_register(&xenbus_frontend.bus);
+       if (err)
+               goto out_error;
+
+       err = xenbus_backend_bus_register();
+       if (err)
+               goto out_unreg_front;
+
+       /*
+        * Domain0 doesn't have a store_evtchn or store_mfn yet.
+        */
+       if (is_initial_xendomain()) {
+               /* dom0 not yet supported */
+       } else {
+               xenstored_ready = 1;
+               xen_store_evtchn = xen_start_info->store_evtchn;
+               xen_store_mfn = xen_start_info->store_mfn;
+       }
+       xen_store_interface = mfn_to_virt(xen_store_mfn);
+
+       /* Initialize the interface to xenstore. */
+       err = xs_init();
+       if (err) {
+               printk(KERN_WARNING
+                      "XENBUS: Error initializing xenstore comms: %i\n", err);
+               goto out_unreg_back;
+       }
+
+       if (!is_initial_xendomain())
+               xenbus_probe(NULL);
+
+       return 0;
+
+  out_unreg_back:
+       xenbus_backend_bus_unregister();
+
+  out_unreg_front:
+       bus_unregister(&xenbus_frontend.bus);
+
+  out_error:
+       return err;
+}
+
+postcore_initcall(xenbus_probe_init);
+
+MODULE_LICENSE("GPL");
+
+static int is_disconnected_device(struct device *dev, void *data)
+{
+       struct xenbus_device *xendev = to_xenbus_device(dev);
+       struct device_driver *drv = data;
+
+       /*
+        * A device with no driver will never connect. We care only about
+        * devices which should currently be in the process of connecting.
+        */
+       if (!dev->driver)
+               return 0;
+
+       /* Is this search limited to a particular driver? */
+       if (drv && (dev->driver != drv))
+               return 0;
+
+       return (xendev->state != XenbusStateConnected);
+}
+
+static int exists_disconnected_device(struct device_driver *drv)
+{
+       return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
+                               is_disconnected_device);
+}
+
+static int print_device_status(struct device *dev, void *data)
+{
+       struct xenbus_device *xendev = to_xenbus_device(dev);
+       struct device_driver *drv = data;
+
+       /* Is this operation limited to a particular driver? */
+       if (drv && (dev->driver != drv))
+               return 0;
+
+       if (!dev->driver) {
+               /* Information only: is this too noisy? */
+               printk(KERN_INFO "XENBUS: Device with no driver: %s\n",
+                      xendev->nodename);
+       } else if (xendev->state != XenbusStateConnected) {
+               printk(KERN_WARNING "XENBUS: Timeout connecting "
+                      "to device: %s (state %d)\n",
+                      xendev->nodename, xendev->state);
+       }
+
+       return 0;
+}
+
+/* We only wait for device setup after most initcalls have run. */
+static int ready_to_wait_for_devices;
+
+/*
+ * On a 10 second timeout, wait for all devices currently configured.  We need
+ * to do this to guarantee that the filesystems and / or network devices
+ * needed for boot are available, before we can allow the boot to proceed.
+ *
+ * This needs to be on a late_initcall, to happen after the frontend device
+ * drivers have been initialised, but before the root fs is mounted.
+ *
+ * A possible improvement here would be to have the tools add a per-device
+ * flag to the store entry, indicating whether it is needed at boot time.
+ * This would allow people who knew what they were doing to accelerate their
+ * boot slightly, but of course needs tools or manual intervention to set up
+ * those flags correctly.
+ */
+static void wait_for_devices(struct xenbus_driver *xendrv)
+{
+       unsigned long timeout = jiffies + 10*HZ;
+       struct device_driver *drv = xendrv ? &xendrv->driver : NULL;
+
+       if (!ready_to_wait_for_devices || !is_running_on_xen())
+               return;
+
+       while (exists_disconnected_device(drv)) {
+               if (time_after(jiffies, timeout))
+                       break;
+               schedule_timeout_interruptible(HZ/10);
+       }
+
+       bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
+                        print_device_status);
+}
+
+#ifndef MODULE
+static int __init boot_wait_for_devices(void)
+{
+       ready_to_wait_for_devices = 1;
+       wait_for_devices(NULL);
+       return 0;
+}
+
+late_initcall(boot_wait_for_devices);
+#endif
diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h
new file mode 100644 (file)
index 0000000..e09b194
--- /dev/null
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * xenbus_probe.h
+ *
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 XenSource Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _XENBUS_PROBE_H
+#define _XENBUS_PROBE_H
+
+#ifdef CONFIG_XEN_BACKEND
+extern void xenbus_backend_suspend(int (*fn)(struct device *, void *));
+extern void xenbus_backend_resume(int (*fn)(struct device *, void *));
+extern void xenbus_backend_probe_and_watch(void);
+extern int xenbus_backend_bus_register(void);
+extern void xenbus_backend_bus_unregister(void);
+#else
+static inline void xenbus_backend_suspend(int (*fn)(struct device *, void *)) {}
+static inline void xenbus_backend_resume(int (*fn)(struct device *, void *)) {}
+static inline void xenbus_backend_probe_and_watch(void) {}
+static inline int xenbus_backend_bus_register(void) { return 0; }
+static inline void xenbus_backend_bus_unregister(void) {}
+#endif
+
+struct xen_bus_type
+{
+       char *root;
+       unsigned int levels;
+       int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);
+       int (*probe)(const char *type, const char *dir);
+       struct bus_type bus;
+};
+
+extern int xenbus_match(struct device *_dev, struct device_driver *_drv);
+extern int xenbus_dev_probe(struct device *_dev);
+extern int xenbus_dev_remove(struct device *_dev);
+extern int xenbus_register_driver_common(struct xenbus_driver *drv,
+                                        struct xen_bus_type *bus,
+                                        struct module *owner,
+                                        const char *mod_name);
+extern int xenbus_probe_node(struct xen_bus_type *bus,
+                            const char *type,
+                            const char *nodename);
+extern int xenbus_probe_devices(struct xen_bus_type *bus);
+
+extern void xenbus_dev_changed(const char *node, struct xen_bus_type *bus);
+
+#endif
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c
new file mode 100644 (file)
index 0000000..9e943fb
--- /dev/null
@@ -0,0 +1,861 @@
+/******************************************************************************
+ * xenbus_xs.c
+ *
+ * This is the kernel equivalent of the "xs" library.  We don't need everything
+ * and we use xenbus_comms for communication.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/unistd.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/uio.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/kthread.h>
+#include <linux/rwsem.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <xen/xenbus.h>
+#include "xenbus_comms.h"
+
+struct xs_stored_msg {
+       struct list_head list;
+
+       struct xsd_sockmsg hdr;
+
+       union {
+               /* Queued replies. */
+               struct {
+                       char *body;
+               } reply;
+
+               /* Queued watch events. */
+               struct {
+                       struct xenbus_watch *handle;
+                       char **vec;
+                       unsigned int vec_size;
+               } watch;
+       } u;
+};
+
+struct xs_handle {
+       /* A list of replies. Currently only one will ever be outstanding. */
+       struct list_head reply_list;
+       spinlock_t reply_lock;
+       wait_queue_head_t reply_waitq;
+
+       /*
+        * Mutex ordering: transaction_mutex -> watch_mutex -> request_mutex.
+        * response_mutex is never taken simultaneously with the other three.
+        */
+
+       /* One request at a time. */
+       struct mutex request_mutex;
+
+       /* Protect xenbus reader thread against save/restore. */
+       struct mutex response_mutex;
+
+       /* Protect transactions against save/restore. */
+       struct rw_semaphore transaction_mutex;
+
+       /* Protect watch (de)register against save/restore. */
+       struct rw_semaphore watch_mutex;
+};
+
+static struct xs_handle xs_state;
+
+/* List of registered watches, and a lock to protect it. */
+static LIST_HEAD(watches);
+static DEFINE_SPINLOCK(watches_lock);
+
+/* List of pending watch callback events, and a lock to protect it. */
+static LIST_HEAD(watch_events);
+static DEFINE_SPINLOCK(watch_events_lock);
+
+/*
+ * Details of the xenwatch callback kernel thread. The thread waits on the
+ * watch_events_waitq for work to do (queued on watch_events list). When it
+ * wakes up it acquires the xenwatch_mutex before reading the list and
+ * carrying out work.
+ */
+static pid_t xenwatch_pid;
+static DEFINE_MUTEX(xenwatch_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq);
+
+static int get_error(const char *errorstring)
+{
+       unsigned int i;
+
+       for (i = 0; strcmp(errorstring, xsd_errors[i].errstring) != 0; i++) {
+               if (i == ARRAY_SIZE(xsd_errors) - 1) {
+                       printk(KERN_WARNING
+                              "XENBUS xen store gave: unknown error %s",
+                              errorstring);
+                       return EINVAL;
+               }
+       }
+       return xsd_errors[i].errnum;
+}
+
+static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
+{
+       struct xs_stored_msg *msg;
+       char *body;
+
+       spin_lock(&xs_state.reply_lock);
+
+       while (list_empty(&xs_state.reply_list)) {
+               spin_unlock(&xs_state.reply_lock);
+               /* XXX FIXME: Avoid synchronous wait for response here. */
+               wait_event(xs_state.reply_waitq,
+                          !list_empty(&xs_state.reply_list));
+               spin_lock(&xs_state.reply_lock);
+       }
+
+       msg = list_entry(xs_state.reply_list.next,
+                        struct xs_stored_msg, list);
+       list_del(&msg->list);
+
+       spin_unlock(&xs_state.reply_lock);
+
+       *type = msg->hdr.type;
+       if (len)
+               *len = msg->hdr.len;
+       body = msg->u.reply.body;
+
+       kfree(msg);
+
+       return body;
+}
+
+void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
+{
+       void *ret;
+       struct xsd_sockmsg req_msg = *msg;
+       int err;
+
+       if (req_msg.type == XS_TRANSACTION_START)
+               down_read(&xs_state.transaction_mutex);
+
+       mutex_lock(&xs_state.request_mutex);
+
+       err = xb_write(msg, sizeof(*msg) + msg->len);
+       if (err) {
+               msg->type = XS_ERROR;
+               ret = ERR_PTR(err);
+       } else
+               ret = read_reply(&msg->type, &msg->len);
+
+       mutex_unlock(&xs_state.request_mutex);
+
+       if ((msg->type == XS_TRANSACTION_END) ||
+           ((req_msg.type == XS_TRANSACTION_START) &&
+            (msg->type == XS_ERROR)))
+               up_read(&xs_state.transaction_mutex);
+
+       return ret;
+}
+
+/* Send message to xs, get kmalloc'ed reply.  ERR_PTR() on error. */
+static void *xs_talkv(struct xenbus_transaction t,
+                     enum xsd_sockmsg_type type,
+                     const struct kvec *iovec,
+                     unsigned int num_vecs,
+                     unsigned int *len)
+{
+       struct xsd_sockmsg msg;
+       void *ret = NULL;
+       unsigned int i;
+       int err;
+
+       msg.tx_id = t.id;
+       msg.req_id = 0;
+       msg.type = type;
+       msg.len = 0;
+       for (i = 0; i < num_vecs; i++)
+               msg.len += iovec[i].iov_len;
+
+       mutex_lock(&xs_state.request_mutex);
+
+       err = xb_write(&msg, sizeof(msg));
+       if (err) {
+               mutex_unlock(&xs_state.request_mutex);
+               return ERR_PTR(err);
+       }
+
+       for (i = 0; i < num_vecs; i++) {
+               err = xb_write(iovec[i].iov_base, iovec[i].iov_len);
+               if (err) {
+                       mutex_unlock(&xs_state.request_mutex);
+                       return ERR_PTR(err);
+               }
+       }
+
+       ret = read_reply(&msg.type, len);
+
+       mutex_unlock(&xs_state.request_mutex);
+
+       if (IS_ERR(ret))
+               return ret;
+
+       if (msg.type == XS_ERROR) {
+               err = get_error(ret);
+               kfree(ret);
+               return ERR_PTR(-err);
+       }
+
+       if (msg.type != type) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING
+                              "XENBUS unexpected type [%d], expected [%d]\n",
+                              msg.type, type);
+               kfree(ret);
+               return ERR_PTR(-EINVAL);
+       }
+       return ret;
+}
+
+/* Simplified version of xs_talkv: single message. */
+static void *xs_single(struct xenbus_transaction t,
+                      enum xsd_sockmsg_type type,
+                      const char *string,
+                      unsigned int *len)
+{
+       struct kvec iovec;
+
+       iovec.iov_base = (void *)string;
+       iovec.iov_len = strlen(string) + 1;
+       return xs_talkv(t, type, &iovec, 1, len);
+}
+
+/* Many commands only need an ack, don't care what it says. */
+static int xs_error(char *reply)
+{
+       if (IS_ERR(reply))
+               return PTR_ERR(reply);
+       kfree(reply);
+       return 0;
+}
+
+static unsigned int count_strings(const char *strings, unsigned int len)
+{
+       unsigned int num;
+       const char *p;
+
+       for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1)
+               num++;
+
+       return num;
+}
+
+/* Return the path to dir with /name appended. Buffer must be kfree()'ed. */
+static char *join(const char *dir, const char *name)
+{
+       char *buffer;
+
+       if (strlen(name) == 0)
+               buffer = kasprintf(GFP_KERNEL, "%s", dir);
+       else
+               buffer = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
+       return (!buffer) ? ERR_PTR(-ENOMEM) : buffer;
+}
+
+static char **split(char *strings, unsigned int len, unsigned int *num)
+{
+       char *p, **ret;
+
+       /* Count the strings. */
+       *num = count_strings(strings, len);
+
+       /* Transfer to one big alloc for easy freeing. */
+       ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL);
+       if (!ret) {
+               kfree(strings);
+               return ERR_PTR(-ENOMEM);
+       }
+       memcpy(&ret[*num], strings, len);
+       kfree(strings);
+
+       strings = (char *)&ret[*num];
+       for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
+               ret[(*num)++] = p;
+
+       return ret;
+}
+
+char **xenbus_directory(struct xenbus_transaction t,
+                       const char *dir, const char *node, unsigned int *num)
+{
+       char *strings, *path;
+       unsigned int len;
+
+       path = join(dir, node);
+       if (IS_ERR(path))
+               return (char **)path;
+
+       strings = xs_single(t, XS_DIRECTORY, path, &len);
+       kfree(path);
+       if (IS_ERR(strings))
+               return (char **)strings;
+
+       return split(strings, len, num);
+}
+EXPORT_SYMBOL_GPL(xenbus_directory);
+
+/* Check if a path exists. Return 1 if it does. */
+int xenbus_exists(struct xenbus_transaction t,
+                 const char *dir, const char *node)
+{
+       char **d;
+       int dir_n;
+
+       d = xenbus_directory(t, dir, node, &dir_n);
+       if (IS_ERR(d))
+               return 0;
+       kfree(d);
+       return 1;
+}
+EXPORT_SYMBOL_GPL(xenbus_exists);
+
+/* Get the value of a single file.
+ * Returns a kmalloced value: call free() on it after use.
+ * len indicates length in bytes.
+ */
+void *xenbus_read(struct xenbus_transaction t,
+                 const char *dir, const char *node, unsigned int *len)
+{
+       char *path;
+       void *ret;
+
+       path = join(dir, node);
+       if (IS_ERR(path))
+               return (void *)path;
+
+       ret = xs_single(t, XS_READ, path, len);
+       kfree(path);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_read);
+
+/* Write the value of a single file.
+ * Returns -err on failure.
+ */
+int xenbus_write(struct xenbus_transaction t,
+                const char *dir, const char *node, const char *string)
+{
+       const char *path;
+       struct kvec iovec[2];
+       int ret;
+
+       path = join(dir, node);
+       if (IS_ERR(path))
+               return PTR_ERR(path);
+
+       iovec[0].iov_base = (void *)path;
+       iovec[0].iov_len = strlen(path) + 1;
+       iovec[1].iov_base = (void *)string;
+       iovec[1].iov_len = strlen(string);
+
+       ret = xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));
+       kfree(path);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_write);
+
+/* Create a new directory. */
+int xenbus_mkdir(struct xenbus_transaction t,
+                const char *dir, const char *node)
+{
+       char *path;
+       int ret;
+
+       path = join(dir, node);
+       if (IS_ERR(path))
+               return PTR_ERR(path);
+
+       ret = xs_error(xs_single(t, XS_MKDIR, path, NULL));
+       kfree(path);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_mkdir);
+
+/* Destroy a file or directory (directories must be empty). */
+int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node)
+{
+       char *path;
+       int ret;
+
+       path = join(dir, node);
+       if (IS_ERR(path))
+               return PTR_ERR(path);
+
+       ret = xs_error(xs_single(t, XS_RM, path, NULL));
+       kfree(path);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_rm);
+
+/* Start a transaction: changes by others will not be seen during this
+ * transaction, and changes will not be visible to others until end.
+ */
+int xenbus_transaction_start(struct xenbus_transaction *t)
+{
+       char *id_str;
+
+       down_read(&xs_state.transaction_mutex);
+
+       id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL);
+       if (IS_ERR(id_str)) {
+               up_read(&xs_state.transaction_mutex);
+               return PTR_ERR(id_str);
+       }
+
+       t->id = simple_strtoul(id_str, NULL, 0);
+       kfree(id_str);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_transaction_start);
+
+/* End a transaction.
+ * If abandon is true, transaction is discarded instead of committed.
+ */
+int xenbus_transaction_end(struct xenbus_transaction t, int abort)
+{
+       char abortstr[2];
+       int err;
+
+       if (abort)
+               strcpy(abortstr, "F");
+       else
+               strcpy(abortstr, "T");
+
+       err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL));
+
+       up_read(&xs_state.transaction_mutex);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_transaction_end);
+
+/* Single read and scanf: returns -errno or num scanned. */
+int xenbus_scanf(struct xenbus_transaction t,
+                const char *dir, const char *node, const char *fmt, ...)
+{
+       va_list ap;
+       int ret;
+       char *val;
+
+       val = xenbus_read(t, dir, node, NULL);
+       if (IS_ERR(val))
+               return PTR_ERR(val);
+
+       va_start(ap, fmt);
+       ret = vsscanf(val, fmt, ap);
+       va_end(ap);
+       kfree(val);
+       /* Distinctive errno. */
+       if (ret == 0)
+               return -ERANGE;
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_scanf);
+
+/* Single printf and write: returns -errno or 0. */
+int xenbus_printf(struct xenbus_transaction t,
+                 const char *dir, const char *node, const char *fmt, ...)
+{
+       va_list ap;
+       int ret;
+#define PRINTF_BUFFER_SIZE 4096
+       char *printf_buffer;
+
+       printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
+       if (printf_buffer == NULL)
+               return -ENOMEM;
+
+       va_start(ap, fmt);
+       ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap);
+       va_end(ap);
+
+       BUG_ON(ret > PRINTF_BUFFER_SIZE-1);
+       ret = xenbus_write(t, dir, node, printf_buffer);
+
+       kfree(printf_buffer);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_printf);
+
+/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
+int xenbus_gather(struct xenbus_transaction t, const char *dir, ...)
+{
+       va_list ap;
+       const char *name;
+       int ret = 0;
+
+       va_start(ap, dir);
+       while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
+               const char *fmt = va_arg(ap, char *);
+               void *result = va_arg(ap, void *);
+               char *p;
+
+               p = xenbus_read(t, dir, name, NULL);
+               if (IS_ERR(p)) {
+                       ret = PTR_ERR(p);
+                       break;
+               }
+               if (fmt) {
+                       if (sscanf(p, fmt, result) == 0)
+                               ret = -EINVAL;
+                       kfree(p);
+               } else
+                       *(char **)result = p;
+       }
+       va_end(ap);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_gather);
+
+static int xs_watch(const char *path, const char *token)
+{
+       struct kvec iov[2];
+
+       iov[0].iov_base = (void *)path;
+       iov[0].iov_len = strlen(path) + 1;
+       iov[1].iov_base = (void *)token;
+       iov[1].iov_len = strlen(token) + 1;
+
+       return xs_error(xs_talkv(XBT_NIL, XS_WATCH, iov,
+                                ARRAY_SIZE(iov), NULL));
+}
+
+static int xs_unwatch(const char *path, const char *token)
+{
+       struct kvec iov[2];
+
+       iov[0].iov_base = (char *)path;
+       iov[0].iov_len = strlen(path) + 1;
+       iov[1].iov_base = (char *)token;
+       iov[1].iov_len = strlen(token) + 1;
+
+       return xs_error(xs_talkv(XBT_NIL, XS_UNWATCH, iov,
+                                ARRAY_SIZE(iov), NULL));
+}
+
+static struct xenbus_watch *find_watch(const char *token)
+{
+       struct xenbus_watch *i, *cmp;
+
+       cmp = (void *)simple_strtoul(token, NULL, 16);
+
+       list_for_each_entry(i, &watches, list)
+               if (i == cmp)
+                       return i;
+
+       return NULL;
+}
+
+/* Register callback to watch this node. */
+int register_xenbus_watch(struct xenbus_watch *watch)
+{
+       /* Pointer in ascii is the token. */
+       char token[sizeof(watch) * 2 + 1];
+       int err;
+
+       sprintf(token, "%lX", (long)watch);
+
+       down_read(&xs_state.watch_mutex);
+
+       spin_lock(&watches_lock);
+       BUG_ON(find_watch(token));
+       list_add(&watch->list, &watches);
+       spin_unlock(&watches_lock);
+
+       err = xs_watch(watch->node, token);
+
+       /* Ignore errors due to multiple registration. */
+       if ((err != 0) && (err != -EEXIST)) {
+               spin_lock(&watches_lock);
+               list_del(&watch->list);
+               spin_unlock(&watches_lock);
+       }
+
+       up_read(&xs_state.watch_mutex);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(register_xenbus_watch);
+
+void unregister_xenbus_watch(struct xenbus_watch *watch)
+{
+       struct xs_stored_msg *msg, *tmp;
+       char token[sizeof(watch) * 2 + 1];
+       int err;
+
+       sprintf(token, "%lX", (long)watch);
+
+       down_read(&xs_state.watch_mutex);
+
+       spin_lock(&watches_lock);
+       BUG_ON(!find_watch(token));
+       list_del(&watch->list);
+       spin_unlock(&watches_lock);
+
+       err = xs_unwatch(watch->node, token);
+       if (err)
+               printk(KERN_WARNING
+                      "XENBUS Failed to release watch %s: %i\n",
+                      watch->node, err);
+
+       up_read(&xs_state.watch_mutex);
+
+       /* Make sure there are no callbacks running currently (unless
+          its us) */
+       if (current->pid != xenwatch_pid)
+               mutex_lock(&xenwatch_mutex);
+
+       /* Cancel pending watch events. */
+       spin_lock(&watch_events_lock);
+       list_for_each_entry_safe(msg, tmp, &watch_events, list) {
+               if (msg->u.watch.handle != watch)
+                       continue;
+               list_del(&msg->list);
+               kfree(msg->u.watch.vec);
+               kfree(msg);
+       }
+       spin_unlock(&watch_events_lock);
+
+       if (current->pid != xenwatch_pid)
+               mutex_unlock(&xenwatch_mutex);
+}
+EXPORT_SYMBOL_GPL(unregister_xenbus_watch);
+
+void xs_suspend(void)
+{
+       down_write(&xs_state.transaction_mutex);
+       down_write(&xs_state.watch_mutex);
+       mutex_lock(&xs_state.request_mutex);
+       mutex_lock(&xs_state.response_mutex);
+}
+
+void xs_resume(void)
+{
+       struct xenbus_watch *watch;
+       char token[sizeof(watch) * 2 + 1];
+
+       mutex_unlock(&xs_state.response_mutex);
+       mutex_unlock(&xs_state.request_mutex);
+       up_write(&xs_state.transaction_mutex);
+
+       /* No need for watches_lock: the watch_mutex is sufficient. */
+       list_for_each_entry(watch, &watches, list) {
+               sprintf(token, "%lX", (long)watch);
+               xs_watch(watch->node, token);
+       }
+
+       up_write(&xs_state.watch_mutex);
+}
+
+void xs_suspend_cancel(void)
+{
+       mutex_unlock(&xs_state.response_mutex);
+       mutex_unlock(&xs_state.request_mutex);
+       up_write(&xs_state.watch_mutex);
+       up_write(&xs_state.transaction_mutex);
+}
+
+static int xenwatch_thread(void *unused)
+{
+       struct list_head *ent;
+       struct xs_stored_msg *msg;
+
+       for (;;) {
+               wait_event_interruptible(watch_events_waitq,
+                                        !list_empty(&watch_events));
+
+               if (kthread_should_stop())
+                       break;
+
+               mutex_lock(&xenwatch_mutex);
+
+               spin_lock(&watch_events_lock);
+               ent = watch_events.next;
+               if (ent != &watch_events)
+                       list_del(ent);
+               spin_unlock(&watch_events_lock);
+
+               if (ent != &watch_events) {
+                       msg = list_entry(ent, struct xs_stored_msg, list);
+                       msg->u.watch.handle->callback(
+                               msg->u.watch.handle,
+                               (const char **)msg->u.watch.vec,
+                               msg->u.watch.vec_size);
+                       kfree(msg->u.watch.vec);
+                       kfree(msg);
+               }
+
+               mutex_unlock(&xenwatch_mutex);
+       }
+
+       return 0;
+}
+
+static int process_msg(void)
+{
+       struct xs_stored_msg *msg;
+       char *body;
+       int err;
+
+       /*
+        * We must disallow save/restore while reading a xenstore message.
+        * A partial read across s/r leaves us out of sync with xenstored.
+        */
+       for (;;) {
+               err = xb_wait_for_data_to_read();
+               if (err)
+                       return err;
+               mutex_lock(&xs_state.response_mutex);
+               if (xb_data_to_read())
+                       break;
+               /* We raced with save/restore: pending data 'disappeared'. */
+               mutex_unlock(&xs_state.response_mutex);
+       }
+
+
+       msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+       if (msg == NULL) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = xb_read(&msg->hdr, sizeof(msg->hdr));
+       if (err) {
+               kfree(msg);
+               goto out;
+       }
+
+       body = kmalloc(msg->hdr.len + 1, GFP_KERNEL);
+       if (body == NULL) {
+               kfree(msg);
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = xb_read(body, msg->hdr.len);
+       if (err) {
+               kfree(body);
+               kfree(msg);
+               goto out;
+       }
+       body[msg->hdr.len] = '\0';
+
+       if (msg->hdr.type == XS_WATCH_EVENT) {
+               msg->u.watch.vec = split(body, msg->hdr.len,
+                                        &msg->u.watch.vec_size);
+               if (IS_ERR(msg->u.watch.vec)) {
+                       kfree(msg);
+                       err = PTR_ERR(msg->u.watch.vec);
+                       goto out;
+               }
+
+               spin_lock(&watches_lock);
+               msg->u.watch.handle = find_watch(
+                       msg->u.watch.vec[XS_WATCH_TOKEN]);
+               if (msg->u.watch.handle != NULL) {
+                       spin_lock(&watch_events_lock);
+                       list_add_tail(&msg->list, &watch_events);
+                       wake_up(&watch_events_waitq);
+                       spin_unlock(&watch_events_lock);
+               } else {
+                       kfree(msg->u.watch.vec);
+                       kfree(msg);
+               }
+               spin_unlock(&watches_lock);
+       } else {
+               msg->u.reply.body = body;
+               spin_lock(&xs_state.reply_lock);
+               list_add_tail(&msg->list, &xs_state.reply_list);
+               spin_unlock(&xs_state.reply_lock);
+               wake_up(&xs_state.reply_waitq);
+       }
+
+ out:
+       mutex_unlock(&xs_state.response_mutex);
+       return err;
+}
+
+static int xenbus_thread(void *unused)
+{
+       int err;
+
+       for (;;) {
+               err = process_msg();
+               if (err)
+                       printk(KERN_WARNING "XENBUS error %d while reading "
+                              "message\n", err);
+               if (kthread_should_stop())
+                       break;
+       }
+
+       return 0;
+}
+
+int xs_init(void)
+{
+       int err;
+       struct task_struct *task;
+
+       INIT_LIST_HEAD(&xs_state.reply_list);
+       spin_lock_init(&xs_state.reply_lock);
+       init_waitqueue_head(&xs_state.reply_waitq);
+
+       mutex_init(&xs_state.request_mutex);
+       mutex_init(&xs_state.response_mutex);
+       init_rwsem(&xs_state.transaction_mutex);
+       init_rwsem(&xs_state.watch_mutex);
+
+       /* Initialize the shared memory rings to talk to xenstored */
+       err = xb_init_comms();
+       if (err)
+               return err;
+
+       task = kthread_run(xenwatch_thread, NULL, "xenwatch");
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+       xenwatch_pid = task->pid;
+
+       task = kthread_run(xenbus_thread, NULL, "xenbus");
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+
+       return 0;
+}
index 45c35986d49f41c4fc8a52e6fd5c94d3dfe1a94e..0a7068e30ecb6212c3f1d07c1679b4573a5cb90f 100644 (file)
@@ -131,7 +131,9 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses)
                switch (token) {
                case Opt_debug:
                        v9ses->debug = option;
+#ifdef CONFIG_NET_9P_DEBUG
                        p9_debug_level = option;
+#endif
                        break;
                case Opt_port:
                        v9ses->port = option;
index 613df554728d0b27b2c84e61d1eb42582ea11a19..6a649902c5acc966b83959b7b8ffb9ad13a52911 100644 (file)
@@ -251,7 +251,7 @@ config JBD2
 
 config JBD2_DEBUG
        bool "JBD2 (ext4dev/ext4) debugging support"
-       depends on JBD2
+       depends on JBD2 && DEBUG_FS
        help
          If you are using the ext4dev/ext4 journaled file system (or
          potentially any other filesystem/device using JBD2), this option
@@ -260,10 +260,10 @@ config JBD2_DEBUG
          By default, the debugging output will be turned off.
 
          If you select Y here, then you will be able to turn on debugging
-         with "echo N > /proc/sys/fs/jbd2-debug", where N is a number between
-         1 and 5. The higher the number, the more debugging output is
-         generated.  To turn debugging off again, do
-         "echo 0 > /proc/sys/fs/jbd2-debug".
+         with "echo N > /sys/kernel/debug/jbd2/jbd2-debug", where N is a
+         number between 1 and 5. The higher the number, the more debugging
+         output is generated.  To turn debugging off again, do
+         "echo 0 > /sys/kernel/debug/jbd2/jbd2-debug".
 
 config FS_MBCACHE
 # Meta block cache for Extended Attributes (ext2/ext3/ext4)
index a260198306c21d589b9bc1bc237c9d6f8833ff14..b4a75880f6fd175b2f1f07d4c97c3a95024e5bfb 100644 (file)
@@ -139,6 +139,7 @@ err_put_filp:
        put_filp(file);
        return error;
 }
+EXPORT_SYMBOL_GPL(anon_inode_getfd);
 
 /*
  * A single inode exists for all anon_inode files. Contrary to pipes,
index a0a0c7b07ba3908379d311931254cc5ba9b2d014..f8dfc2269d85634aa61ebb19a761e986ea0bbc93 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -42,7 +42,7 @@ int inode_change_ok(struct inode *inode, struct iattr *attr)
 
        /* Make sure a caller can chmod. */
        if (ia_valid & ATTR_MODE) {
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        goto error;
                /* Also check the setgid bit! */
                if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
@@ -52,7 +52,7 @@ int inode_change_ok(struct inode *inode, struct iattr *attr)
 
        /* Check for setting the inode time. */
        if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) {
-               if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        goto error;
        }
 fine:
index 7c420b800c3438fd02ab669368f48fb9a6f01c5a..e58669e1b87c6bab0e0a0ac8677713b5b2f3fbb8 100644 (file)
@@ -464,7 +464,7 @@ ext2_xattr_set_acl(struct inode *inode, int type, const void *value,
 
        if (!test_opt(inode->i_sb, POSIX_ACL))
                return -EOPNOTSUPP;
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                return -EPERM;
 
        if (value) {
index e85c48218239b604948bfad7f41889df2dfbba1e..3bcd25422ee4879781a2785ec92a0f512e0c2567 100644 (file)
@@ -36,7 +36,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                if (IS_RDONLY(inode))
                        return -EROFS;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EACCES;
 
                if (get_user(flags, (int __user *) arg))
@@ -74,7 +74,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
        case EXT2_IOC_GETVERSION:
                return put_user(inode->i_generation, (int __user *) arg);
        case EXT2_IOC_SETVERSION:
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EPERM;
                if (IS_RDONLY(inode))
                        return -EROFS;
index 1e5038d9a01b9f469015b83f8ee7eb07a9abf8f8..d34e9967430a5ff28bebf278faef1882e188252f 100644 (file)
@@ -489,7 +489,7 @@ ext3_xattr_set_acl(struct inode *inode, int type, const void *value,
 
        if (!test_opt(inode->i_sb, POSIX_ACL))
                return -EOPNOTSUPP;
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                return -EPERM;
 
        if (value) {
index 965006dba6be8d22715dff9f52c2c5038c072c01..4a2a02c95bf94b98fc4534d870f3546a45442c8e 100644 (file)
@@ -41,7 +41,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                if (IS_RDONLY(inode))
                        return -EROFS;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EACCES;
 
                if (get_user(flags, (int __user *) arg))
@@ -122,7 +122,7 @@ flags_err:
                __u32 generation;
                int err;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EPERM;
                if (IS_RDONLY(inode))
                        return -EROFS;
@@ -181,7 +181,7 @@ flags_err:
                if (IS_RDONLY(inode))
                        return -EROFS;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EACCES;
 
                if (get_user(rsv_window_size, (int __user *)arg))
index 9e882546d91a098a01b409301f9baa2e00d4fce1..a8bae8cd1d5de707c9a8772464ca4ecaa93044ed 100644 (file)
@@ -489,7 +489,7 @@ ext4_xattr_set_acl(struct inode *inode, int type, const void *value,
 
        if (!test_opt(inode->i_sb, POSIX_ACL))
                return -EOPNOTSUPP;
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                return -EPERM;
 
        if (value) {
index 9de54ae48dee6a2d569fbbfb99d28179ec68ba73..e53b4af52f1119ddf54b6b8c316c62ca429edc65 100644 (file)
@@ -517,7 +517,7 @@ do_more:
                /*
                 * An HJ special.  This is expensive...
                 */
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
                jbd_unlock_bh_state(bitmap_bh);
                {
                        struct buffer_head *debug_bh;
@@ -1597,7 +1597,7 @@ allocated:
 
        performed_allocation = 1;
 
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
        {
                struct buffer_head *debug_bh;
 
index b9ce24129070bff5cee547a333139d9a4645d2c7..750c46f7d89345ab7a35742ec528612b7a2192ad 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/quotaops.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <linux/falloc.h>
 #include <linux/ext4_fs_extents.h>
 #include <asm/uaccess.h>
 
@@ -91,36 +92,6 @@ static void ext4_idx_store_pblock(struct ext4_extent_idx *ix, ext4_fsblk_t pb)
        ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff);
 }
 
-static int ext4_ext_check_header(const char *function, struct inode *inode,
-                               struct ext4_extent_header *eh)
-{
-       const char *error_msg = NULL;
-
-       if (unlikely(eh->eh_magic != EXT4_EXT_MAGIC)) {
-               error_msg = "invalid magic";
-               goto corrupted;
-       }
-       if (unlikely(eh->eh_max == 0)) {
-               error_msg = "invalid eh_max";
-               goto corrupted;
-       }
-       if (unlikely(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max))) {
-               error_msg = "invalid eh_entries";
-               goto corrupted;
-       }
-       return 0;
-
-corrupted:
-       ext4_error(inode->i_sb, function,
-                       "bad header in inode #%lu: %s - magic %x, "
-                       "entries %u, max %u, depth %u",
-                       inode->i_ino, error_msg, le16_to_cpu(eh->eh_magic),
-                       le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),
-                       le16_to_cpu(eh->eh_depth));
-
-       return -EIO;
-}
-
 static handle_t *ext4_ext_journal_restart(handle_t *handle, int needed)
 {
        int err;
@@ -269,6 +240,70 @@ static int ext4_ext_space_root_idx(struct inode *inode)
        return size;
 }
 
+static int
+ext4_ext_max_entries(struct inode *inode, int depth)
+{
+       int max;
+
+       if (depth == ext_depth(inode)) {
+               if (depth == 0)
+                       max = ext4_ext_space_root(inode);
+               else
+                       max = ext4_ext_space_root_idx(inode);
+       } else {
+               if (depth == 0)
+                       max = ext4_ext_space_block(inode);
+               else
+                       max = ext4_ext_space_block_idx(inode);
+       }
+
+       return max;
+}
+
+static int __ext4_ext_check_header(const char *function, struct inode *inode,
+                                       struct ext4_extent_header *eh,
+                                       int depth)
+{
+       const char *error_msg;
+       int max = 0;
+
+       if (unlikely(eh->eh_magic != EXT4_EXT_MAGIC)) {
+               error_msg = "invalid magic";
+               goto corrupted;
+       }
+       if (unlikely(le16_to_cpu(eh->eh_depth) != depth)) {
+               error_msg = "unexpected eh_depth";
+               goto corrupted;
+       }
+       if (unlikely(eh->eh_max == 0)) {
+               error_msg = "invalid eh_max";
+               goto corrupted;
+       }
+       max = ext4_ext_max_entries(inode, depth);
+       if (unlikely(le16_to_cpu(eh->eh_max) > max)) {
+               error_msg = "too large eh_max";
+               goto corrupted;
+       }
+       if (unlikely(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max))) {
+               error_msg = "invalid eh_entries";
+               goto corrupted;
+       }
+       return 0;
+
+corrupted:
+       ext4_error(inode->i_sb, function,
+                       "bad header in inode #%lu: %s - magic %x, "
+                       "entries %u, max %u(%u), depth %u(%u)",
+                       inode->i_ino, error_msg, le16_to_cpu(eh->eh_magic),
+                       le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),
+                       max, le16_to_cpu(eh->eh_depth), depth);
+
+       return -EIO;
+}
+
+#define ext4_ext_check_header(inode, eh, depth)        \
+       __ext4_ext_check_header(__FUNCTION__, inode, eh, depth)
+
 #ifdef EXT_DEBUG
 static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
 {
@@ -282,7 +317,7 @@ static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
                } else if (path->p_ext) {
                        ext_debug("  %d:%d:%llu ",
                                  le32_to_cpu(path->p_ext->ee_block),
-                                 le16_to_cpu(path->p_ext->ee_len),
+                                 ext4_ext_get_actual_len(path->p_ext),
                                  ext_pblock(path->p_ext));
                } else
                        ext_debug("  []");
@@ -305,7 +340,7 @@ static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path)
 
        for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) {
                ext_debug("%d:%d:%llu ", le32_to_cpu(ex->ee_block),
-                         le16_to_cpu(ex->ee_len), ext_pblock(ex));
+                         ext4_ext_get_actual_len(ex), ext_pblock(ex));
        }
        ext_debug("\n");
 }
@@ -329,6 +364,7 @@ static void ext4_ext_drop_refs(struct ext4_ext_path *path)
 /*
  * ext4_ext_binsearch_idx:
  * binary search for the closest index of the given block
+ * the header must be checked before calling this
  */
 static void
 ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int block)
@@ -336,27 +372,25 @@ ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int bloc
        struct ext4_extent_header *eh = path->p_hdr;
        struct ext4_extent_idx *r, *l, *m;
 
-       BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
-       BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
-       BUG_ON(le16_to_cpu(eh->eh_entries) <= 0);
 
        ext_debug("binsearch for %d(idx):  ", block);
 
        l = EXT_FIRST_INDEX(eh) + 1;
-       r = EXT_FIRST_INDEX(eh) + le16_to_cpu(eh->eh_entries) - 1;
+       r = EXT_LAST_INDEX(eh);
        while (l <= r) {
                m = l + (r - l) / 2;
                if (block < le32_to_cpu(m->ei_block))
                        r = m - 1;
                else
                        l = m + 1;
-               ext_debug("%p(%u):%p(%u):%p(%u) ", l, l->ei_block,
-                               m, m->ei_block, r, r->ei_block);
+               ext_debug("%p(%u):%p(%u):%p(%u) ", l, le32_to_cpu(l->ei_block),
+                               m, le32_to_cpu(m->ei_block),
+                               r, le32_to_cpu(r->ei_block));
        }
 
        path->p_idx = l - 1;
        ext_debug("  -> %d->%lld ", le32_to_cpu(path->p_idx->ei_block),
-                 idx_block(path->p_idx));
+                 idx_pblock(path->p_idx));
 
 #ifdef CHECK_BINSEARCH
        {
@@ -388,6 +422,7 @@ ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int bloc
 /*
  * ext4_ext_binsearch:
  * binary search for closest extent of the given block
+ * the header must be checked before calling this
  */
 static void
 ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
@@ -395,9 +430,6 @@ ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
        struct ext4_extent_header *eh = path->p_hdr;
        struct ext4_extent *r, *l, *m;
 
-       BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
-       BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
-
        if (eh->eh_entries == 0) {
                /*
                 * this leaf is empty:
@@ -409,7 +441,7 @@ ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
        ext_debug("binsearch for %d:  ", block);
 
        l = EXT_FIRST_EXTENT(eh) + 1;
-       r = EXT_FIRST_EXTENT(eh) + le16_to_cpu(eh->eh_entries) - 1;
+       r = EXT_LAST_EXTENT(eh);
 
        while (l <= r) {
                m = l + (r - l) / 2;
@@ -417,15 +449,16 @@ ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
                        r = m - 1;
                else
                        l = m + 1;
-               ext_debug("%p(%u):%p(%u):%p(%u) ", l, l->ee_block,
-                               m, m->ee_block, r, r->ee_block);
+               ext_debug("%p(%u):%p(%u):%p(%u) ", l, le32_to_cpu(l->ee_block),
+                               m, le32_to_cpu(m->ee_block),
+                               r, le32_to_cpu(r->ee_block));
        }
 
        path->p_ext = l - 1;
        ext_debug("  -> %d:%llu:%d ",
                        le32_to_cpu(path->p_ext->ee_block),
                        ext_pblock(path->p_ext),
-                       le16_to_cpu(path->p_ext->ee_len));
+                       ext4_ext_get_actual_len(path->p_ext));
 
 #ifdef CHECK_BINSEARCH
        {
@@ -468,11 +501,10 @@ ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path)
        short int depth, i, ppos = 0, alloc = 0;
 
        eh = ext_inode_hdr(inode);
-       BUG_ON(eh == NULL);
-       if (ext4_ext_check_header(__FUNCTION__, inode, eh))
+       depth = ext_depth(inode);
+       if (ext4_ext_check_header(inode, eh, depth))
                return ERR_PTR(-EIO);
 
-       i = depth = ext_depth(inode);
 
        /* account possible depth increase */
        if (!path) {
@@ -484,10 +516,12 @@ ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path)
        }
        path[0].p_hdr = eh;
 
+       i = depth;
        /* walk through the tree */
        while (i) {
                ext_debug("depth %d: num %d, max %d\n",
                          ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
+
                ext4_ext_binsearch_idx(inode, path + ppos, block);
                path[ppos].p_block = idx_pblock(path[ppos].p_idx);
                path[ppos].p_depth = i;
@@ -504,7 +538,7 @@ ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path)
                path[ppos].p_hdr = eh;
                i--;
 
-               if (ext4_ext_check_header(__FUNCTION__, inode, eh))
+               if (ext4_ext_check_header(inode, eh, i))
                        goto err;
        }
 
@@ -513,9 +547,6 @@ ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path)
        path[ppos].p_ext = NULL;
        path[ppos].p_idx = NULL;
 
-       if (ext4_ext_check_header(__FUNCTION__, inode, eh))
-               goto err;
-
        /* find extent */
        ext4_ext_binsearch(inode, path + ppos, block);
 
@@ -553,7 +584,7 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
                if (curp->p_idx != EXT_LAST_INDEX(curp->p_hdr)) {
                        len = (len - 1) * sizeof(struct ext4_extent_idx);
                        len = len < 0 ? 0 : len;
-                       ext_debug("insert new index %d after: %d. "
+                       ext_debug("insert new index %d after: %llu. "
                                        "move %d from 0x%p to 0x%p\n",
                                        logical, ptr, len,
                                        (curp->p_idx + 1), (curp->p_idx + 2));
@@ -564,7 +595,7 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
                /* insert before */
                len = len * sizeof(struct ext4_extent_idx);
                len = len < 0 ? 0 : len;
-               ext_debug("insert new index %d before: %d. "
+               ext_debug("insert new index %d before: %llu. "
                                "move %d from 0x%p to 0x%p\n",
                                logical, ptr, len,
                                curp->p_idx, (curp->p_idx + 1));
@@ -686,7 +717,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
                ext_debug("move %d:%llu:%d in new leaf %llu\n",
                                le32_to_cpu(path[depth].p_ext->ee_block),
                                ext_pblock(path[depth].p_ext),
-                               le16_to_cpu(path[depth].p_ext->ee_len),
+                               ext4_ext_get_actual_len(path[depth].p_ext),
                                newblock);
                /*memmove(ex++, path[depth].p_ext++,
                                sizeof(struct ext4_extent));
@@ -764,7 +795,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
                BUG_ON(EXT_MAX_INDEX(path[i].p_hdr) !=
                                EXT_LAST_INDEX(path[i].p_hdr));
                while (path[i].p_idx <= EXT_MAX_INDEX(path[i].p_hdr)) {
-                       ext_debug("%d: move %d:%d in new index %llu\n", i,
+                       ext_debug("%d: move %d:%llu in new index %llu\n", i,
                                        le32_to_cpu(path[i].p_idx->ei_block),
                                        idx_pblock(path[i].p_idx),
                                        newblock);
@@ -893,8 +924,13 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
        curp->p_hdr->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode));
        curp->p_hdr->eh_entries = cpu_to_le16(1);
        curp->p_idx = EXT_FIRST_INDEX(curp->p_hdr);
-       /* FIXME: it works, but actually path[0] can be index */
-       curp->p_idx->ei_block = EXT_FIRST_EXTENT(path[0].p_hdr)->ee_block;
+
+       if (path[0].p_hdr->eh_depth)
+               curp->p_idx->ei_block =
+                       EXT_FIRST_INDEX(path[0].p_hdr)->ei_block;
+       else
+               curp->p_idx->ei_block =
+                       EXT_FIRST_EXTENT(path[0].p_hdr)->ee_block;
        ext4_idx_store_pblock(curp->p_idx, newblock);
 
        neh = ext_inode_hdr(inode);
@@ -1106,7 +1142,24 @@ static int
 ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
                                struct ext4_extent *ex2)
 {
-       if (le32_to_cpu(ex1->ee_block) + le16_to_cpu(ex1->ee_len) !=
+       unsigned short ext1_ee_len, ext2_ee_len, max_len;
+
+       /*
+        * Make sure that either both extents are uninitialized, or
+        * both are _not_.
+        */
+       if (ext4_ext_is_uninitialized(ex1) ^ ext4_ext_is_uninitialized(ex2))
+               return 0;
+
+       if (ext4_ext_is_uninitialized(ex1))
+               max_len = EXT_UNINIT_MAX_LEN;
+       else
+               max_len = EXT_INIT_MAX_LEN;
+
+       ext1_ee_len = ext4_ext_get_actual_len(ex1);
+       ext2_ee_len = ext4_ext_get_actual_len(ex2);
+
+       if (le32_to_cpu(ex1->ee_block) + ext1_ee_len !=
                        le32_to_cpu(ex2->ee_block))
                return 0;
 
@@ -1115,18 +1168,65 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
         * as an RO_COMPAT feature, refuse to merge to extents if
         * this can result in the top bit of ee_len being set.
         */
-       if (le16_to_cpu(ex1->ee_len) + le16_to_cpu(ex2->ee_len) > EXT_MAX_LEN)
+       if (ext1_ee_len + ext2_ee_len > max_len)
                return 0;
 #ifdef AGGRESSIVE_TEST
        if (le16_to_cpu(ex1->ee_len) >= 4)
                return 0;
 #endif
 
-       if (ext_pblock(ex1) + le16_to_cpu(ex1->ee_len) == ext_pblock(ex2))
+       if (ext_pblock(ex1) + ext1_ee_len == ext_pblock(ex2))
                return 1;
        return 0;
 }
 
+/*
+ * This function tries to merge the "ex" extent to the next extent in the tree.
+ * It always tries to merge towards right. If you want to merge towards
+ * left, pass "ex - 1" as argument instead of "ex".
+ * Returns 0 if the extents (ex and ex+1) were _not_ merged and returns
+ * 1 if they got merged.
+ */
+int ext4_ext_try_to_merge(struct inode *inode,
+                         struct ext4_ext_path *path,
+                         struct ext4_extent *ex)
+{
+       struct ext4_extent_header *eh;
+       unsigned int depth, len;
+       int merge_done = 0;
+       int uninitialized = 0;
+
+       depth = ext_depth(inode);
+       BUG_ON(path[depth].p_hdr == NULL);
+       eh = path[depth].p_hdr;
+
+       while (ex < EXT_LAST_EXTENT(eh)) {
+               if (!ext4_can_extents_be_merged(inode, ex, ex + 1))
+                       break;
+               /* merge with next extent! */
+               if (ext4_ext_is_uninitialized(ex))
+                       uninitialized = 1;
+               ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
+                               + ext4_ext_get_actual_len(ex + 1));
+               if (uninitialized)
+                       ext4_ext_mark_uninitialized(ex);
+
+               if (ex + 1 < EXT_LAST_EXTENT(eh)) {
+                       len = (EXT_LAST_EXTENT(eh) - ex - 1)
+                               * sizeof(struct ext4_extent);
+                       memmove(ex + 1, ex + 2, len);
+               }
+               eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries) - 1);
+               merge_done = 1;
+               WARN_ON(eh->eh_entries == 0);
+               if (!eh->eh_entries)
+                       ext4_error(inode->i_sb, "ext4_ext_try_to_merge",
+                          "inode#%lu, eh->eh_entries = 0!", inode->i_ino);
+       }
+
+       return merge_done;
+}
+
 /*
  * check if a portion of the "newext" extent overlaps with an
  * existing extent.
@@ -1144,7 +1244,7 @@ unsigned int ext4_ext_check_overlap(struct inode *inode,
        unsigned int ret = 0;
 
        b1 = le32_to_cpu(newext->ee_block);
-       len1 = le16_to_cpu(newext->ee_len);
+       len1 = ext4_ext_get_actual_len(newext);
        depth = ext_depth(inode);
        if (!path[depth].p_ext)
                goto out;
@@ -1191,8 +1291,9 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
        struct ext4_extent *nearex; /* nearest extent */
        struct ext4_ext_path *npath = NULL;
        int depth, len, err, next;
+       unsigned uninitialized = 0;
 
-       BUG_ON(newext->ee_len == 0);
+       BUG_ON(ext4_ext_get_actual_len(newext) == 0);
        depth = ext_depth(inode);
        ex = path[depth].p_ext;
        BUG_ON(path[depth].p_hdr == NULL);
@@ -1200,14 +1301,24 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
        /* try to insert block into found extent and return */
        if (ex && ext4_can_extents_be_merged(inode, ex, newext)) {
                ext_debug("append %d block to %d:%d (from %llu)\n",
-                               le16_to_cpu(newext->ee_len),
+                               ext4_ext_get_actual_len(newext),
                                le32_to_cpu(ex->ee_block),
-                               le16_to_cpu(ex->ee_len), ext_pblock(ex));
+                               ext4_ext_get_actual_len(ex), ext_pblock(ex));
                err = ext4_ext_get_access(handle, inode, path + depth);
                if (err)
                        return err;
-               ex->ee_len = cpu_to_le16(le16_to_cpu(ex->ee_len)
-                                        + le16_to_cpu(newext->ee_len));
+
+               /*
+                * ext4_can_extents_be_merged should have checked that either
+                * both extents are uninitialized, or both aren't. Thus we
+                * need to check only one of them here.
+                */
+               if (ext4_ext_is_uninitialized(ex))
+                       uninitialized = 1;
+               ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
+                                       + ext4_ext_get_actual_len(newext));
+               if (uninitialized)
+                       ext4_ext_mark_uninitialized(ex);
                eh = path[depth].p_hdr;
                nearex = ex;
                goto merge;
@@ -1263,7 +1374,7 @@ has_space:
                ext_debug("first extent in the leaf: %d:%llu:%d\n",
                                le32_to_cpu(newext->ee_block),
                                ext_pblock(newext),
-                               le16_to_cpu(newext->ee_len));
+                               ext4_ext_get_actual_len(newext));
                path[depth].p_ext = EXT_FIRST_EXTENT(eh);
        } else if (le32_to_cpu(newext->ee_block)
                           > le32_to_cpu(nearex->ee_block)) {
@@ -1276,7 +1387,7 @@ has_space:
                                        "move %d from 0x%p to 0x%p\n",
                                        le32_to_cpu(newext->ee_block),
                                        ext_pblock(newext),
-                                       le16_to_cpu(newext->ee_len),
+                                       ext4_ext_get_actual_len(newext),
                                        nearex, len, nearex + 1, nearex + 2);
                        memmove(nearex + 2, nearex + 1, len);
                }
@@ -1289,7 +1400,7 @@ has_space:
                                "move %d from 0x%p to 0x%p\n",
                                le32_to_cpu(newext->ee_block),
                                ext_pblock(newext),
-                               le16_to_cpu(newext->ee_len),
+                               ext4_ext_get_actual_len(newext),
                                nearex, len, nearex + 1, nearex + 2);
                memmove(nearex + 1, nearex, len);
                path[depth].p_ext = nearex;
@@ -1304,20 +1415,7 @@ has_space:
 
 merge:
        /* try to merge extents to the right */
-       while (nearex < EXT_LAST_EXTENT(eh)) {
-               if (!ext4_can_extents_be_merged(inode, nearex, nearex + 1))
-                       break;
-               /* merge with next extent! */
-               nearex->ee_len = cpu_to_le16(le16_to_cpu(nearex->ee_len)
-                                            + le16_to_cpu(nearex[1].ee_len));
-               if (nearex + 1 < EXT_LAST_EXTENT(eh)) {
-                       len = (EXT_LAST_EXTENT(eh) - nearex - 1)
-                                       * sizeof(struct ext4_extent);
-                       memmove(nearex + 1, nearex + 2, len);
-               }
-               eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1);
-               BUG_ON(eh->eh_entries == 0);
-       }
+       ext4_ext_try_to_merge(inode, path, nearex);
 
        /* try to merge extents to the left */
 
@@ -1379,8 +1477,8 @@ int ext4_ext_walk_space(struct inode *inode, unsigned long block,
                        end = le32_to_cpu(ex->ee_block);
                        if (block + num < end)
                                end = block + num;
-               } else if (block >=
-                            le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len)) {
+               } else if (block >= le32_to_cpu(ex->ee_block)
+                                       + ext4_ext_get_actual_len(ex)) {
                        /* need to allocate space after found extent */
                        start = block;
                        end = block + num;
@@ -1392,7 +1490,8 @@ int ext4_ext_walk_space(struct inode *inode, unsigned long block,
                         * by found extent
                         */
                        start = block;
-                       end = le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len);
+                       end = le32_to_cpu(ex->ee_block)
+                               + ext4_ext_get_actual_len(ex);
                        if (block + num < end)
                                end = block + num;
                        exists = 1;
@@ -1408,7 +1507,7 @@ int ext4_ext_walk_space(struct inode *inode, unsigned long block,
                        cbex.ec_type = EXT4_EXT_CACHE_GAP;
                } else {
                        cbex.ec_block = le32_to_cpu(ex->ee_block);
-                       cbex.ec_len = le16_to_cpu(ex->ee_len);
+                       cbex.ec_len = ext4_ext_get_actual_len(ex);
                        cbex.ec_start = ext_pblock(ex);
                        cbex.ec_type = EXT4_EXT_CACHE_EXTENT;
                }
@@ -1481,15 +1580,15 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
                ext_debug("cache gap(before): %lu [%lu:%lu]",
                                (unsigned long) block,
                                (unsigned long) le32_to_cpu(ex->ee_block),
-                               (unsigned long) le16_to_cpu(ex->ee_len));
+                               (unsigned long) ext4_ext_get_actual_len(ex));
        } else if (block >= le32_to_cpu(ex->ee_block)
-                           + le16_to_cpu(ex->ee_len)) {
+                       + ext4_ext_get_actual_len(ex)) {
                lblock = le32_to_cpu(ex->ee_block)
-                        + le16_to_cpu(ex->ee_len);
+                       + ext4_ext_get_actual_len(ex);
                len = ext4_ext_next_allocated_block(path);
                ext_debug("cache gap(after): [%lu:%lu] %lu",
                                (unsigned long) le32_to_cpu(ex->ee_block),
-                               (unsigned long) le16_to_cpu(ex->ee_len),
+                               (unsigned long) ext4_ext_get_actual_len(ex),
                                (unsigned long) block);
                BUG_ON(len == lblock);
                len = len - lblock;
@@ -1619,12 +1718,12 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
                                unsigned long from, unsigned long to)
 {
        struct buffer_head *bh;
+       unsigned short ee_len =  ext4_ext_get_actual_len(ex);
        int i;
 
 #ifdef EXTENTS_STATS
        {
                struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
-               unsigned short ee_len =  le16_to_cpu(ex->ee_len);
                spin_lock(&sbi->s_ext_stats_lock);
                sbi->s_ext_blocks += ee_len;
                sbi->s_ext_extents++;
@@ -1638,12 +1737,12 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
        }
 #endif
        if (from >= le32_to_cpu(ex->ee_block)
-           && to == le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - 1) {
+           && to == le32_to_cpu(ex->ee_block) + ee_len - 1) {
                /* tail removal */
                unsigned long num;
                ext4_fsblk_t start;
-               num = le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - from;
-               start = ext_pblock(ex) + le16_to_cpu(ex->ee_len) - num;
+               num = le32_to_cpu(ex->ee_block) + ee_len - from;
+               start = ext_pblock(ex) + ee_len - num;
                ext_debug("free last %lu blocks starting %llu\n", num, start);
                for (i = 0; i < num; i++) {
                        bh = sb_find_get_block(inode->i_sb, start + i);
@@ -1651,12 +1750,12 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
                }
                ext4_free_blocks(handle, inode, start, num);
        } else if (from == le32_to_cpu(ex->ee_block)
-                  && to <= le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - 1) {
+                  && to <= le32_to_cpu(ex->ee_block) + ee_len - 1) {
                printk("strange request: removal %lu-%lu from %u:%u\n",
-                      from, to, le32_to_cpu(ex->ee_block), le16_to_cpu(ex->ee_len));
+                       from, to, le32_to_cpu(ex->ee_block), ee_len);
        } else {
                printk("strange request: removal(2) %lu-%lu from %u:%u\n",
-                      from, to, le32_to_cpu(ex->ee_block), le16_to_cpu(ex->ee_len));
+                       from, to, le32_to_cpu(ex->ee_block), ee_len);
        }
        return 0;
 }
@@ -1671,21 +1770,23 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
        unsigned a, b, block, num;
        unsigned long ex_ee_block;
        unsigned short ex_ee_len;
+       unsigned uninitialized = 0;
        struct ext4_extent *ex;
 
+       /* the header must be checked already in ext4_ext_remove_space() */
        ext_debug("truncate since %lu in leaf\n", start);
        if (!path[depth].p_hdr)
                path[depth].p_hdr = ext_block_hdr(path[depth].p_bh);
        eh = path[depth].p_hdr;
        BUG_ON(eh == NULL);
-       BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
-       BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
 
        /* find where to start removing */
        ex = EXT_LAST_EXTENT(eh);
 
        ex_ee_block = le32_to_cpu(ex->ee_block);
-       ex_ee_len = le16_to_cpu(ex->ee_len);
+       if (ext4_ext_is_uninitialized(ex))
+               uninitialized = 1;
+       ex_ee_len = ext4_ext_get_actual_len(ex);
 
        while (ex >= EXT_FIRST_EXTENT(eh) &&
                        ex_ee_block + ex_ee_len > start) {
@@ -1753,6 +1854,12 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
 
                ex->ee_block = cpu_to_le32(block);
                ex->ee_len = cpu_to_le16(num);
+               /*
+                * Do not mark uninitialized if all the blocks in the
+                * extent have been removed.
+                */
+               if (uninitialized && num)
+                       ext4_ext_mark_uninitialized(ex);
 
                err = ext4_ext_dirty(handle, inode, path + depth);
                if (err)
@@ -1762,7 +1869,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
                                ext_pblock(ex));
                ex--;
                ex_ee_block = le32_to_cpu(ex->ee_block);
-               ex_ee_len = le16_to_cpu(ex->ee_len);
+               ex_ee_len = ext4_ext_get_actual_len(ex);
        }
 
        if (correct_index && eh->eh_entries)
@@ -1825,7 +1932,7 @@ int ext4_ext_remove_space(struct inode *inode, unsigned long start)
                return -ENOMEM;
        }
        path[0].p_hdr = ext_inode_hdr(inode);
-       if (ext4_ext_check_header(__FUNCTION__, inode, path[0].p_hdr)) {
+       if (ext4_ext_check_header(inode, path[0].p_hdr, depth)) {
                err = -EIO;
                goto out;
        }
@@ -1846,17 +1953,8 @@ int ext4_ext_remove_space(struct inode *inode, unsigned long start)
                if (!path[i].p_hdr) {
                        ext_debug("initialize header\n");
                        path[i].p_hdr = ext_block_hdr(path[i].p_bh);
-                       if (ext4_ext_check_header(__FUNCTION__, inode,
-                                                       path[i].p_hdr)) {
-                               err = -EIO;
-                               goto out;
-                       }
                }
 
-               BUG_ON(le16_to_cpu(path[i].p_hdr->eh_entries)
-                          > le16_to_cpu(path[i].p_hdr->eh_max));
-               BUG_ON(path[i].p_hdr->eh_magic != EXT4_EXT_MAGIC);
-
                if (!path[i].p_idx) {
                        /* this level hasn't been touched yet */
                        path[i].p_idx = EXT_LAST_INDEX(path[i].p_hdr);
@@ -1873,17 +1971,27 @@ int ext4_ext_remove_space(struct inode *inode, unsigned long start)
                                i, EXT_FIRST_INDEX(path[i].p_hdr),
                                path[i].p_idx);
                if (ext4_ext_more_to_rm(path + i)) {
+                       struct buffer_head *bh;
                        /* go to the next level */
                        ext_debug("move to level %d (block %llu)\n",
                                  i + 1, idx_pblock(path[i].p_idx));
                        memset(path + i + 1, 0, sizeof(*path));
-                       path[i+1].p_bh =
-                               sb_bread(sb, idx_pblock(path[i].p_idx));
-                       if (!path[i+1].p_bh) {
+                       bh = sb_bread(sb, idx_pblock(path[i].p_idx));
+                       if (!bh) {
                                /* should we reset i_size? */
                                err = -EIO;
                                break;
                        }
+                       if (WARN_ON(i + 1 > depth)) {
+                               err = -EIO;
+                               break;
+                       }
+                       if (ext4_ext_check_header(inode, ext_block_hdr(bh),
+                                                       depth - i - 1)) {
+                               err = -EIO;
+                               break;
+                       }
+                       path[i + 1].p_bh = bh;
 
                        /* save actual number of indexes since this
                         * number is changed at the next iteration */
@@ -1977,15 +2085,158 @@ void ext4_ext_release(struct super_block *sb)
 #endif
 }
 
+/*
+ * This function is called by ext4_ext_get_blocks() if someone tries to write
+ * to an uninitialized extent. It may result in splitting the uninitialized
+ * extent into multiple extents (upto three - one initialized and two
+ * uninitialized).
+ * There are three possibilities:
+ *   a> There is no split required: Entire extent should be initialized
+ *   b> Splits in two extents: Write is happening at either end of the extent
+ *   c> Splits in three extents: Somone is writing in middle of the extent
+ */
+int ext4_ext_convert_to_initialized(handle_t *handle, struct inode *inode,
+                                       struct ext4_ext_path *path,
+                                       ext4_fsblk_t iblock,
+                                       unsigned long max_blocks)
+{
+       struct ext4_extent *ex, newex;
+       struct ext4_extent *ex1 = NULL;
+       struct ext4_extent *ex2 = NULL;
+       struct ext4_extent *ex3 = NULL;
+       struct ext4_extent_header *eh;
+       unsigned int allocated, ee_block, ee_len, depth;
+       ext4_fsblk_t newblock;
+       int err = 0;
+       int ret = 0;
+
+       depth = ext_depth(inode);
+       eh = path[depth].p_hdr;
+       ex = path[depth].p_ext;
+       ee_block = le32_to_cpu(ex->ee_block);
+       ee_len = ext4_ext_get_actual_len(ex);
+       allocated = ee_len - (iblock - ee_block);
+       newblock = iblock - ee_block + ext_pblock(ex);
+       ex2 = ex;
+
+       /* ex1: ee_block to iblock - 1 : uninitialized */
+       if (iblock > ee_block) {
+               ex1 = ex;
+               ex1->ee_len = cpu_to_le16(iblock - ee_block);
+               ext4_ext_mark_uninitialized(ex1);
+               ex2 = &newex;
+       }
+       /*
+        * for sanity, update the length of the ex2 extent before
+        * we insert ex3, if ex1 is NULL. This is to avoid temporary
+        * overlap of blocks.
+        */
+       if (!ex1 && allocated > max_blocks)
+               ex2->ee_len = cpu_to_le16(max_blocks);
+       /* ex3: to ee_block + ee_len : uninitialised */
+       if (allocated > max_blocks) {
+               unsigned int newdepth;
+               ex3 = &newex;
+               ex3->ee_block = cpu_to_le32(iblock + max_blocks);
+               ext4_ext_store_pblock(ex3, newblock + max_blocks);
+               ex3->ee_len = cpu_to_le16(allocated - max_blocks);
+               ext4_ext_mark_uninitialized(ex3);
+               err = ext4_ext_insert_extent(handle, inode, path, ex3);
+               if (err)
+                       goto out;
+               /*
+                * The depth, and hence eh & ex might change
+                * as part of the insert above.
+                */
+               newdepth = ext_depth(inode);
+               if (newdepth != depth) {
+                       depth = newdepth;
+                       path = ext4_ext_find_extent(inode, iblock, NULL);
+                       if (IS_ERR(path)) {
+                               err = PTR_ERR(path);
+                               path = NULL;
+                               goto out;
+                       }
+                       eh = path[depth].p_hdr;
+                       ex = path[depth].p_ext;
+                       if (ex2 != &newex)
+                               ex2 = ex;
+               }
+               allocated = max_blocks;
+       }
+       /*
+        * If there was a change of depth as part of the
+        * insertion of ex3 above, we need to update the length
+        * of the ex1 extent again here
+        */
+       if (ex1 && ex1 != ex) {
+               ex1 = ex;
+               ex1->ee_len = cpu_to_le16(iblock - ee_block);
+               ext4_ext_mark_uninitialized(ex1);
+               ex2 = &newex;
+       }
+       /* ex2: iblock to iblock + maxblocks-1 : initialised */
+       ex2->ee_block = cpu_to_le32(iblock);
+       ex2->ee_start = cpu_to_le32(newblock);
+       ext4_ext_store_pblock(ex2, newblock);
+       ex2->ee_len = cpu_to_le16(allocated);
+       if (ex2 != ex)
+               goto insert;
+       err = ext4_ext_get_access(handle, inode, path + depth);
+       if (err)
+               goto out;
+       /*
+        * New (initialized) extent starts from the first block
+        * in the current extent. i.e., ex2 == ex
+        * We have to see if it can be merged with the extent
+        * on the left.
+        */
+       if (ex2 > EXT_FIRST_EXTENT(eh)) {
+               /*
+                * To merge left, pass "ex2 - 1" to try_to_merge(),
+                * since it merges towards right _only_.
+                */
+               ret = ext4_ext_try_to_merge(inode, path, ex2 - 1);
+               if (ret) {
+                       err = ext4_ext_correct_indexes(handle, inode, path);
+                       if (err)
+                               goto out;
+                       depth = ext_depth(inode);
+                       ex2--;
+               }
+       }
+       /*
+        * Try to Merge towards right. This might be required
+        * only when the whole extent is being written to.
+        * i.e. ex2 == ex and ex3 == NULL.
+        */
+       if (!ex3) {
+               ret = ext4_ext_try_to_merge(inode, path, ex2);
+               if (ret) {
+                       err = ext4_ext_correct_indexes(handle, inode, path);
+                       if (err)
+                               goto out;
+               }
+       }
+       /* Mark modified extent as dirty */
+       err = ext4_ext_dirty(handle, inode, path + depth);
+       goto out;
+insert:
+       err = ext4_ext_insert_extent(handle, inode, path, &newex);
+out:
+       return err ? err : allocated;
+}
+
 int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                        ext4_fsblk_t iblock,
                        unsigned long max_blocks, struct buffer_head *bh_result,
                        int create, int extend_disksize)
 {
        struct ext4_ext_path *path = NULL;
+       struct ext4_extent_header *eh;
        struct ext4_extent newex, *ex;
        ext4_fsblk_t goal, newblock;
-       int err = 0, depth;
+       int err = 0, depth, ret;
        unsigned long allocated = 0;
 
        __clear_bit(BH_New, &bh_result->b_state);
@@ -1998,8 +2249,10 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        if (goal) {
                if (goal == EXT4_EXT_CACHE_GAP) {
                        if (!create) {
-                               /* block isn't allocated yet and
-                                * user doesn't want to allocate it */
+                               /*
+                                * block isn't allocated yet and
+                                * user doesn't want to allocate it
+                                */
                                goto out2;
                        }
                        /* we should allocate requested block */
@@ -2033,21 +2286,19 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
         * this is why assert can't be put in ext4_ext_find_extent()
         */
        BUG_ON(path[depth].p_ext == NULL && depth != 0);
+       eh = path[depth].p_hdr;
 
        ex = path[depth].p_ext;
        if (ex) {
                unsigned long ee_block = le32_to_cpu(ex->ee_block);
                ext4_fsblk_t ee_start = ext_pblock(ex);
-               unsigned short ee_len  = le16_to_cpu(ex->ee_len);
+               unsigned short ee_len;
 
                /*
-                * Allow future support for preallocated extents to be added
-                * as an RO_COMPAT feature:
                 * Uninitialized extents are treated as holes, except that
-                * we avoid (fail) allocating new blocks during a write.
+                * we split out initialized portions during a write.
                 */
-               if (ee_len > EXT_MAX_LEN)
-                       goto out2;
+               ee_len = ext4_ext_get_actual_len(ex);
                /* if found extent covers block, simply return it */
                if (iblock >= ee_block && iblock < ee_block + ee_len) {
                        newblock = iblock - ee_block + ee_start;
@@ -2055,9 +2306,27 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                        allocated = ee_len - (iblock - ee_block);
                        ext_debug("%d fit into %lu:%d -> %llu\n", (int) iblock,
                                        ee_block, ee_len, newblock);
-                       ext4_ext_put_in_cache(inode, ee_block, ee_len,
-                                               ee_start, EXT4_EXT_CACHE_EXTENT);
-                       goto out;
+
+                       /* Do not put uninitialized extent in the cache */
+                       if (!ext4_ext_is_uninitialized(ex)) {
+                               ext4_ext_put_in_cache(inode, ee_block,
+                                                       ee_len, ee_start,
+                                                       EXT4_EXT_CACHE_EXTENT);
+                               goto out;
+                       }
+                       if (create == EXT4_CREATE_UNINITIALIZED_EXT)
+                               goto out;
+                       if (!create)
+                               goto out2;
+
+                       ret = ext4_ext_convert_to_initialized(handle, inode,
+                                                               path, iblock,
+                                                               max_blocks);
+                       if (ret <= 0)
+                               goto out2;
+                       else
+                               allocated = ret;
+                       goto outnew;
                }
        }
 
@@ -2066,8 +2335,10 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
         * we couldn't try to create block if create flag is zero
         */
        if (!create) {
-               /* put just found gap into cache to speed up
-                * subsequent requests */
+               /*
+                * put just found gap into cache to speed up
+                * subsequent requests
+                */
                ext4_ext_put_gap_in_cache(inode, path, iblock);
                goto out2;
        }
@@ -2081,6 +2352,19 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        /* allocate new block */
        goal = ext4_ext_find_goal(inode, path, iblock);
 
+       /*
+        * See if request is beyond maximum number of blocks we can have in
+        * a single extent. For an initialized extent this limit is
+        * EXT_INIT_MAX_LEN and for an uninitialized extent this limit is
+        * EXT_UNINIT_MAX_LEN.
+        */
+       if (max_blocks > EXT_INIT_MAX_LEN &&
+           create != EXT4_CREATE_UNINITIALIZED_EXT)
+               max_blocks = EXT_INIT_MAX_LEN;
+       else if (max_blocks > EXT_UNINIT_MAX_LEN &&
+                create == EXT4_CREATE_UNINITIALIZED_EXT)
+               max_blocks = EXT_UNINIT_MAX_LEN;
+
        /* Check if we can really insert (iblock)::(iblock+max_blocks) extent */
        newex.ee_block = cpu_to_le32(iblock);
        newex.ee_len = cpu_to_le16(max_blocks);
@@ -2098,6 +2382,8 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        /* try to insert new extent into found leaf and return */
        ext4_ext_store_pblock(&newex, newblock);
        newex.ee_len = cpu_to_le16(allocated);
+       if (create == EXT4_CREATE_UNINITIALIZED_EXT)  /* Mark uninitialized */
+               ext4_ext_mark_uninitialized(&newex);
        err = ext4_ext_insert_extent(handle, inode, path, &newex);
        if (err) {
                /* free data blocks we just allocated */
@@ -2111,10 +2397,13 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
 
        /* previous routine could use block we allocated */
        newblock = ext_pblock(&newex);
+outnew:
        __set_bit(BH_New, &bh_result->b_state);
 
-       ext4_ext_put_in_cache(inode, iblock, allocated, newblock,
-                               EXT4_EXT_CACHE_EXTENT);
+       /* Cache only when it is _not_ an uninitialized extent */
+       if (create != EXT4_CREATE_UNINITIALIZED_EXT)
+               ext4_ext_put_in_cache(inode, iblock, allocated, newblock,
+                                               EXT4_EXT_CACHE_EXTENT);
 out:
        if (allocated > max_blocks)
                allocated = max_blocks;
@@ -2178,7 +2467,8 @@ void ext4_ext_truncate(struct inode * inode, struct page *page)
        err = ext4_ext_remove_space(inode, last_block);
 
        /* In a multi-transaction truncate, we only make the final
-        * transaction synchronous. */
+        * transaction synchronous.
+        */
        if (IS_SYNC(inode))
                handle->h_sync = 1;
 
@@ -2217,3 +2507,127 @@ int ext4_ext_writepage_trans_blocks(struct inode *inode, int num)
 
        return needed;
 }
+
+/*
+ * preallocate space for a file. This implements ext4's fallocate inode
+ * operation, which gets called from sys_fallocate system call.
+ * For block-mapped files, posix_fallocate should fall back to the method
+ * of writing zeroes to the required new blocks (the same behavior which is
+ * expected for file systems which do not support fallocate() system call).
+ */
+long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
+{
+       handle_t *handle;
+       ext4_fsblk_t block, max_blocks;
+       ext4_fsblk_t nblocks = 0;
+       int ret = 0;
+       int ret2 = 0;
+       int retries = 0;
+       struct buffer_head map_bh;
+       unsigned int credits, blkbits = inode->i_blkbits;
+
+       /*
+        * currently supporting (pre)allocate mode for extent-based
+        * files _only_
+        */
+       if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
+               return -EOPNOTSUPP;
+
+       /* preallocation to directories is currently not supported */
+       if (S_ISDIR(inode->i_mode))
+               return -ENODEV;
+
+       block = offset >> blkbits;
+       max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits)
+                       - block;
+
+       /*
+        * credits to insert 1 extent into extent tree + buffers to be able to
+        * modify 1 super block, 1 block bitmap and 1 group descriptor.
+        */
+       credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + 3;
+retry:
+       while (ret >= 0 && ret < max_blocks) {
+               block = block + ret;
+               max_blocks = max_blocks - ret;
+               handle = ext4_journal_start(inode, credits);
+               if (IS_ERR(handle)) {
+                       ret = PTR_ERR(handle);
+                       break;
+               }
+
+               ret = ext4_ext_get_blocks(handle, inode, block,
+                                         max_blocks, &map_bh,
+                                         EXT4_CREATE_UNINITIALIZED_EXT, 0);
+               WARN_ON(!ret);
+               if (!ret) {
+                       ext4_error(inode->i_sb, "ext4_fallocate",
+                                  "ext4_ext_get_blocks returned 0! inode#%lu"
+                                  ", block=%llu, max_blocks=%llu",
+                                  inode->i_ino, block, max_blocks);
+                       ret = -EIO;
+                       ext4_mark_inode_dirty(handle, inode);
+                       ret2 = ext4_journal_stop(handle);
+                       break;
+               }
+               if (ret > 0) {
+                       /* check wrap through sign-bit/zero here */
+                       if ((block + ret) < 0 || (block + ret) < block) {
+                               ret = -EIO;
+                               ext4_mark_inode_dirty(handle, inode);
+                               ret2 = ext4_journal_stop(handle);
+                               break;
+                       }
+                       if (buffer_new(&map_bh) && ((block + ret) >
+                           (EXT4_BLOCK_ALIGN(i_size_read(inode), blkbits)
+                           >> blkbits)))
+                                       nblocks = nblocks + ret;
+               }
+
+               /* Update ctime if new blocks get allocated */
+               if (nblocks) {
+                       struct timespec now;
+
+                       now = current_fs_time(inode->i_sb);
+                       if (!timespec_equal(&inode->i_ctime, &now))
+                               inode->i_ctime = now;
+               }
+
+               ext4_mark_inode_dirty(handle, inode);
+               ret2 = ext4_journal_stop(handle);
+               if (ret2)
+                       break;
+       }
+
+       if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
+               goto retry;
+
+       /*
+        * Time to update the file size.
+        * Update only when preallocation was requested beyond the file size.
+        */
+       if (!(mode & FALLOC_FL_KEEP_SIZE) &&
+           (offset + len) > i_size_read(inode)) {
+               if (ret > 0) {
+                       /*
+                        * if no error, we assume preallocation succeeded
+                        * completely
+                        */
+                       mutex_lock(&inode->i_mutex);
+                       i_size_write(inode, offset + len);
+                       EXT4_I(inode)->i_disksize = i_size_read(inode);
+                       mutex_unlock(&inode->i_mutex);
+               } else if (ret < 0 && nblocks) {
+                       /* Handle partial allocation scenario */
+                       loff_t newsize;
+
+                       mutex_lock(&inode->i_mutex);
+                       newsize  = (nblocks << blkbits) + i_size_read(inode);
+                       i_size_write(inode, EXT4_BLOCK_ALIGN(newsize, blkbits));
+                       EXT4_I(inode)->i_disksize = i_size_read(inode);
+                       mutex_unlock(&inode->i_mutex);
+               }
+       }
+
+       return ret > 0 ? ret2 : ret;
+}
index d4c8186aed646f6a4439b17d0b0cda9655aadf55..1a81cd66d63b2b2371e4c35025f004657ca66adf 100644 (file)
@@ -134,5 +134,6 @@ const struct inode_operations ext4_file_inode_operations = {
        .removexattr    = generic_removexattr,
 #endif
        .permission     = ext4_permission,
+       .fallocate      = ext4_fallocate,
 };
 
index c88b439ba5cd5838d264450746c450cc45245c16..427f83066a0da425b75757c68430768bba7428ea 100644 (file)
@@ -563,7 +563,8 @@ got:
        inode->i_ino = ino;
        /* This is the optimal IO size (for stat), not the fs block size */
        inode->i_blocks = 0;
-       inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+       inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
+                                                      ext4_current_time(inode);
 
        memset(ei->i_data, 0, sizeof(ei->i_data));
        ei->i_dir_start_lookup = 0;
@@ -595,9 +596,8 @@ got:
        spin_unlock(&sbi->s_next_gen_lock);
 
        ei->i_state = EXT4_STATE_NEW;
-       ei->i_extra_isize =
-               (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) ?
-               sizeof(struct ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE : 0;
+
+       ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize;
 
        ret = inode;
        if(DQUOT_ALLOC_INODE(inode)) {
index 8416fa28c422b2d8dc8369aebba51a5b8462afdc..de26c25d6a181081cdf715ac2a44e78017ba0a16 100644 (file)
@@ -726,7 +726,7 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
 
        /* We are done with atomic stuff, now do the rest of housekeeping */
 
-       inode->i_ctime = CURRENT_TIME_SEC;
+       inode->i_ctime = ext4_current_time(inode);
        ext4_mark_inode_dirty(handle, inode);
 
        /* had we spliced it onto indirect block? */
@@ -1766,7 +1766,6 @@ int ext4_block_truncate_page(handle_t *handle, struct page *page,
        struct inode *inode = mapping->host;
        struct buffer_head *bh;
        int err = 0;
-       void *kaddr;
 
        blocksize = inode->i_sb->s_blocksize;
        length = blocksize - (offset & (blocksize - 1));
@@ -1778,10 +1777,7 @@ int ext4_block_truncate_page(handle_t *handle, struct page *page,
         */
        if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
             ext4_should_writeback_data(inode) && PageUptodate(page)) {
-               kaddr = kmap_atomic(page, KM_USER0);
-               memset(kaddr + offset, 0, length);
-               flush_dcache_page(page);
-               kunmap_atomic(kaddr, KM_USER0);
+               zero_user_page(page, offset, length, KM_USER0);
                set_page_dirty(page);
                goto unlock;
        }
@@ -1834,10 +1830,7 @@ int ext4_block_truncate_page(handle_t *handle, struct page *page,
                        goto unlock;
        }
 
-       kaddr = kmap_atomic(page, KM_USER0);
-       memset(kaddr + offset, 0, length);
-       flush_dcache_page(page);
-       kunmap_atomic(kaddr, KM_USER0);
+       zero_user_page(page, offset, length, KM_USER0);
 
        BUFFER_TRACE(bh, "zeroed end of block");
 
@@ -2375,7 +2368,7 @@ do_indirects:
        ext4_discard_reservation(inode);
 
        mutex_unlock(&ei->truncate_mutex);
-       inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
+       inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
        ext4_mark_inode_dirty(handle, inode);
 
        /*
@@ -2583,6 +2576,25 @@ void ext4_set_inode_flags(struct inode *inode)
                inode->i_flags |= S_DIRSYNC;
 }
 
+/* Propagate flags from i_flags to EXT4_I(inode)->i_flags */
+void ext4_get_inode_flags(struct ext4_inode_info *ei)
+{
+       unsigned int flags = ei->vfs_inode.i_flags;
+
+       ei->i_flags &= ~(EXT4_SYNC_FL|EXT4_APPEND_FL|
+                       EXT4_IMMUTABLE_FL|EXT4_NOATIME_FL|EXT4_DIRSYNC_FL);
+       if (flags & S_SYNC)
+               ei->i_flags |= EXT4_SYNC_FL;
+       if (flags & S_APPEND)
+               ei->i_flags |= EXT4_APPEND_FL;
+       if (flags & S_IMMUTABLE)
+               ei->i_flags |= EXT4_IMMUTABLE_FL;
+       if (flags & S_NOATIME)
+               ei->i_flags |= EXT4_NOATIME_FL;
+       if (flags & S_DIRSYNC)
+               ei->i_flags |= EXT4_DIRSYNC_FL;
+}
+
 void ext4_read_inode(struct inode * inode)
 {
        struct ext4_iloc iloc;
@@ -2610,10 +2622,6 @@ void ext4_read_inode(struct inode * inode)
        }
        inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
        inode->i_size = le32_to_cpu(raw_inode->i_size);
-       inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
-       inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime);
-       inode->i_mtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_mtime);
-       inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0;
 
        ei->i_state = 0;
        ei->i_dir_start_lookup = 0;
@@ -2691,6 +2699,11 @@ void ext4_read_inode(struct inode * inode)
        } else
                ei->i_extra_isize = 0;
 
+       EXT4_INODE_GET_XTIME(i_ctime, inode, raw_inode);
+       EXT4_INODE_GET_XTIME(i_mtime, inode, raw_inode);
+       EXT4_INODE_GET_XTIME(i_atime, inode, raw_inode);
+       EXT4_EINODE_GET_XTIME(i_crtime, ei, raw_inode);
+
        if (S_ISREG(inode->i_mode)) {
                inode->i_op = &ext4_file_inode_operations;
                inode->i_fop = &ext4_file_operations;
@@ -2744,6 +2757,7 @@ static int ext4_do_update_inode(handle_t *handle,
        if (ei->i_state & EXT4_STATE_NEW)
                memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size);
 
+       ext4_get_inode_flags(ei);
        raw_inode->i_mode = cpu_to_le16(inode->i_mode);
        if(!(test_opt(inode->i_sb, NO_UID32))) {
                raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
@@ -2771,9 +2785,12 @@ static int ext4_do_update_inode(handle_t *handle,
        }
        raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
        raw_inode->i_size = cpu_to_le32(ei->i_disksize);
-       raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
-       raw_inode->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec);
-       raw_inode->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec);
+
+       EXT4_INODE_SET_XTIME(i_ctime, inode, raw_inode);
+       EXT4_INODE_SET_XTIME(i_mtime, inode, raw_inode);
+       EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode);
+       EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode);
+
        raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
        raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
        raw_inode->i_flags = cpu_to_le32(ei->i_flags);
@@ -3081,6 +3098,39 @@ ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
        return err;
 }
 
+/*
+ * Expand an inode by new_extra_isize bytes.
+ * Returns 0 on success or negative error number on failure.
+ */
+int ext4_expand_extra_isize(struct inode *inode, unsigned int new_extra_isize,
+                       struct ext4_iloc iloc, handle_t *handle)
+{
+       struct ext4_inode *raw_inode;
+       struct ext4_xattr_ibody_header *header;
+       struct ext4_xattr_entry *entry;
+
+       if (EXT4_I(inode)->i_extra_isize >= new_extra_isize)
+               return 0;
+
+       raw_inode = ext4_raw_inode(&iloc);
+
+       header = IHDR(inode, raw_inode);
+       entry = IFIRST(header);
+
+       /* No extended attributes present */
+       if (!(EXT4_I(inode)->i_state & EXT4_STATE_XATTR) ||
+               header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) {
+               memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE, 0,
+                       new_extra_isize);
+               EXT4_I(inode)->i_extra_isize = new_extra_isize;
+               return 0;
+       }
+
+       /* try to expand with EAs present */
+       return ext4_expand_extra_isize_ea(inode, new_extra_isize,
+                                         raw_inode, handle);
+}
+
 /*
  * What we do here is to mark the in-core inode as clean with respect to inode
  * dirtiness (it may still be data-dirty).
@@ -3105,10 +3155,38 @@ ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
 int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
 {
        struct ext4_iloc iloc;
-       int err;
+       struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+       static unsigned int mnt_count;
+       int err, ret;
 
        might_sleep();
        err = ext4_reserve_inode_write(handle, inode, &iloc);
+       if (EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize &&
+           !(EXT4_I(inode)->i_state & EXT4_STATE_NO_EXPAND)) {
+               /*
+                * We need extra buffer credits since we may write into EA block
+                * with this same handle. If journal_extend fails, then it will
+                * only result in a minor loss of functionality for that inode.
+                * If this is felt to be critical, then e2fsck should be run to
+                * force a large enough s_min_extra_isize.
+                */
+               if ((jbd2_journal_extend(handle,
+                            EXT4_DATA_TRANS_BLOCKS(inode->i_sb))) == 0) {
+                       ret = ext4_expand_extra_isize(inode,
+                                                     sbi->s_want_extra_isize,
+                                                     iloc, handle);
+                       if (ret) {
+                               EXT4_I(inode)->i_state |= EXT4_STATE_NO_EXPAND;
+                               if (mnt_count != sbi->s_es->s_mnt_count) {
+                                       ext4_warning(inode->i_sb, __FUNCTION__,
+                                       "Unable to expand inode %lu. Delete"
+                                       " some EAs or run e2fsck.",
+                                       inode->i_ino);
+                                       mnt_count = sbi->s_es->s_mnt_count;
+                               }
+                       }
+               }
+       }
        if (!err)
                err = ext4_mark_iloc_dirty(handle, inode, &iloc);
        return err;
@@ -3197,7 +3275,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
         */
 
        journal = EXT4_JOURNAL(inode);
-       if (is_journal_aborted(journal) || IS_RDONLY(inode))
+       if (is_journal_aborted(journal))
                return -EROFS;
 
        jbd2_journal_lock_updates(journal);
index 500567dd53b6fd9752096c014162927a730748f0..c04c7ccba9e3f140ed5243a6ccdcc58d6afcaa15 100644 (file)
@@ -28,6 +28,7 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
 
        switch (cmd) {
        case EXT4_IOC_GETFLAGS:
+               ext4_get_inode_flags(ei);
                flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
                return put_user(flags, (int __user *) arg);
        case EXT4_IOC_SETFLAGS: {
@@ -40,7 +41,7 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                if (IS_RDONLY(inode))
                        return -EROFS;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EACCES;
 
                if (get_user(flags, (int __user *) arg))
@@ -96,7 +97,7 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                ei->i_flags = flags;
 
                ext4_set_inode_flags(inode);
-               inode->i_ctime = CURRENT_TIME_SEC;
+               inode->i_ctime = ext4_current_time(inode);
 
                err = ext4_mark_iloc_dirty(handle, inode, &iloc);
 flags_err:
@@ -121,7 +122,7 @@ flags_err:
                __u32 generation;
                int err;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EPERM;
                if (IS_RDONLY(inode))
                        return -EROFS;
@@ -133,14 +134,14 @@ flags_err:
                        return PTR_ERR(handle);
                err = ext4_reserve_inode_write(handle, inode, &iloc);
                if (err == 0) {
-                       inode->i_ctime = CURRENT_TIME_SEC;
+                       inode->i_ctime = ext4_current_time(inode);
                        inode->i_generation = generation;
                        err = ext4_mark_iloc_dirty(handle, inode, &iloc);
                }
                ext4_journal_stop(handle);
                return err;
        }
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
        case EXT4_IOC_WAIT_FOR_READONLY:
                /*
                 * This is racy - by the time we're woken up and running,
@@ -180,7 +181,7 @@ flags_err:
                if (IS_RDONLY(inode))
                        return -EROFS;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EACCES;
 
                if (get_user(rsv_window_size, (int __user *)arg))
@@ -282,7 +283,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case EXT4_IOC32_SETVERSION_OLD:
                cmd = EXT4_IOC_SETVERSION_OLD;
                break;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
        case EXT4_IOC32_WAIT_FOR_READONLY:
                cmd = EXT4_IOC_WAIT_FOR_READONLY;
                break;
index 2de339dd755431fdde691de2f299d5fe62a4d28a..da224974af7861efeab66cdd0de475e0679f9432 100644 (file)
@@ -1295,7 +1295,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
         * happen is that the times are slightly out of date
         * and/or different from the directory change time.
         */
-       dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+       dir->i_mtime = dir->i_ctime = ext4_current_time(dir);
        ext4_update_dx_flag(dir);
        dir->i_version++;
        ext4_mark_inode_dirty(handle, dir);
@@ -1629,6 +1629,35 @@ static int ext4_delete_entry (handle_t *handle,
        return -ENOENT;
 }
 
+/*
+ * DIR_NLINK feature is set if 1) nlinks > EXT4_LINK_MAX or 2) nlinks == 2,
+ * since this indicates that nlinks count was previously 1.
+ */
+static void ext4_inc_count(handle_t *handle, struct inode *inode)
+{
+       inc_nlink(inode);
+       if (is_dx(inode) && inode->i_nlink > 1) {
+               /* limit is 16-bit i_links_count */
+               if (inode->i_nlink >= EXT4_LINK_MAX || inode->i_nlink == 2) {
+                       inode->i_nlink = 1;
+                       EXT4_SET_RO_COMPAT_FEATURE(inode->i_sb,
+                                             EXT4_FEATURE_RO_COMPAT_DIR_NLINK);
+               }
+       }
+}
+
+/*
+ * If a directory had nlink == 1, then we should let it be 1. This indicates
+ * directory has >EXT4_LINK_MAX subdirs.
+ */
+static void ext4_dec_count(handle_t *handle, struct inode *inode)
+{
+       drop_nlink(inode);
+       if (S_ISDIR(inode->i_mode) && inode->i_nlink == 0)
+               inc_nlink(inode);
+}
+
+
 static int ext4_add_nondir(handle_t *handle,
                struct dentry *dentry, struct inode *inode)
 {
@@ -1725,7 +1754,7 @@ static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode)
        struct ext4_dir_entry_2 * de;
        int err, retries = 0;
 
-       if (dir->i_nlink >= EXT4_LINK_MAX)
+       if (EXT4_DIR_LINK_MAX(dir))
                return -EMLINK;
 
 retry:
@@ -1748,7 +1777,7 @@ retry:
        inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
        dir_block = ext4_bread (handle, inode, 0, 1, &err);
        if (!dir_block) {
-               drop_nlink(inode); /* is this nlink == 0? */
+               ext4_dec_count(handle, inode); /* is this nlink == 0? */
                ext4_mark_inode_dirty(handle, inode);
                iput (inode);
                goto out_stop;
@@ -1780,7 +1809,7 @@ retry:
                iput (inode);
                goto out_stop;
        }
-       inc_nlink(dir);
+       ext4_inc_count(handle, dir);
        ext4_update_dx_flag(dir);
        ext4_mark_inode_dirty(handle, dir);
        d_instantiate(dentry, inode);
@@ -2045,9 +2074,9 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
        retval = ext4_delete_entry(handle, dir, de, bh);
        if (retval)
                goto end_rmdir;
-       if (inode->i_nlink != 2)
+       if (!EXT4_DIR_LINK_EMPTY(inode))
                ext4_warning (inode->i_sb, "ext4_rmdir",
-                             "empty directory has nlink!=2 (%d)",
+                             "empty directory has too many links (%d)",
                              inode->i_nlink);
        inode->i_version++;
        clear_nlink(inode);
@@ -2056,9 +2085,9 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
         * recovery. */
        inode->i_size = 0;
        ext4_orphan_add(handle, inode);
-       inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+       inode->i_ctime = dir->i_ctime = dir->i_mtime = ext4_current_time(inode);
        ext4_mark_inode_dirty(handle, inode);
-       drop_nlink(dir);
+       ext4_dec_count(handle, dir);
        ext4_update_dx_flag(dir);
        ext4_mark_inode_dirty(handle, dir);
 
@@ -2106,13 +2135,13 @@ static int ext4_unlink(struct inode * dir, struct dentry *dentry)
        retval = ext4_delete_entry(handle, dir, de, bh);
        if (retval)
                goto end_unlink;
-       dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+       dir->i_ctime = dir->i_mtime = ext4_current_time(dir);
        ext4_update_dx_flag(dir);
        ext4_mark_inode_dirty(handle, dir);
-       drop_nlink(inode);
+       ext4_dec_count(handle, inode);
        if (!inode->i_nlink)
                ext4_orphan_add(handle, inode);
-       inode->i_ctime = dir->i_ctime;
+       inode->i_ctime = ext4_current_time(inode);
        ext4_mark_inode_dirty(handle, inode);
        retval = 0;
 
@@ -2159,7 +2188,7 @@ retry:
                err = __page_symlink(inode, symname, l,
                                mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
                if (err) {
-                       drop_nlink(inode);
+                       ext4_dec_count(handle, inode);
                        ext4_mark_inode_dirty(handle, inode);
                        iput (inode);
                        goto out_stop;
@@ -2185,8 +2214,9 @@ static int ext4_link (struct dentry * old_dentry,
        struct inode *inode = old_dentry->d_inode;
        int err, retries = 0;
 
-       if (inode->i_nlink >= EXT4_LINK_MAX)
+       if (EXT4_DIR_LINK_MAX(inode))
                return -EMLINK;
+
        /*
         * Return -ENOENT if we've raced with unlink and i_nlink is 0.  Doing
         * otherwise has the potential to corrupt the orphan inode list.
@@ -2203,8 +2233,8 @@ retry:
        if (IS_DIRSYNC(dir))
                handle->h_sync = 1;
 
-       inode->i_ctime = CURRENT_TIME_SEC;
-       inc_nlink(inode);
+       inode->i_ctime = ext4_current_time(inode);
+       ext4_inc_count(handle, inode);
        atomic_inc(&inode->i_count);
 
        err = ext4_add_nondir(handle, dentry, inode);
@@ -2305,7 +2335,7 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
         * Like most other Unix systems, set the ctime for inodes on a
         * rename.
         */
-       old_inode->i_ctime = CURRENT_TIME_SEC;
+       old_inode->i_ctime = ext4_current_time(old_inode);
        ext4_mark_inode_dirty(handle, old_inode);
 
        /*
@@ -2337,10 +2367,10 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
        }
 
        if (new_inode) {
-               drop_nlink(new_inode);
-               new_inode->i_ctime = CURRENT_TIME_SEC;
+               ext4_dec_count(handle, new_inode);
+               new_inode->i_ctime = ext4_current_time(new_inode);
        }
-       old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
+       old_dir->i_ctime = old_dir->i_mtime = ext4_current_time(old_dir);
        ext4_update_dx_flag(old_dir);
        if (dir_bh) {
                BUFFER_TRACE(dir_bh, "get_write_access");
@@ -2348,11 +2378,13 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
                PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino);
                BUFFER_TRACE(dir_bh, "call ext4_journal_dirty_metadata");
                ext4_journal_dirty_metadata(handle, dir_bh);
-               drop_nlink(old_dir);
+               ext4_dec_count(handle, old_dir);
                if (new_inode) {
-                       drop_nlink(new_inode);
+                       /* checked empty_dir above, can't have another parent,
+                        * ext3_dec_count() won't work for many-linked dirs */
+                       new_inode->i_nlink = 0;
                } else {
-                       inc_nlink(new_dir);
+                       ext4_inc_count(handle, new_dir);
                        ext4_update_dx_flag(new_dir);
                        ext4_mark_inode_dirty(handle, new_dir);
                }
index b806e689c4aaead29f46af349e0b957dbed4113b..6dcbb28dc06d73edd841d6ecb8a1e93570ef4c29 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/namei.h>
 #include <linux/quotaops.h>
 #include <linux/seq_file.h>
+#include <linux/log2.h>
 
 #include <asm/uaccess.h>
 
@@ -734,7 +735,7 @@ enum {
        Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
        Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
        Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
-       Opt_grpquota, Opt_extents,
+       Opt_grpquota, Opt_extents, Opt_noextents,
 };
 
 static match_table_t tokens = {
@@ -785,6 +786,7 @@ static match_table_t tokens = {
        {Opt_usrquota, "usrquota"},
        {Opt_barrier, "barrier=%u"},
        {Opt_extents, "extents"},
+       {Opt_noextents, "noextents"},
        {Opt_err, NULL},
        {Opt_resize, "resize"},
 };
@@ -1120,6 +1122,9 @@ clear_qf_name:
                case Opt_extents:
                        set_opt (sbi->s_mount_opt, EXTENTS);
                        break;
+               case Opt_noextents:
+                       clear_opt (sbi->s_mount_opt, EXTENTS);
+                       break;
                default:
                        printk (KERN_ERR
                                "EXT4-fs: Unrecognized mount option \"%s\" "
@@ -1551,6 +1556,12 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
 
        set_opt(sbi->s_mount_opt, RESERVATION);
 
+       /*
+        * turn on extents feature by default in ext4 filesystem
+        * User -o noextents to turn it off
+        */
+       set_opt(sbi->s_mount_opt, EXTENTS);
+
        if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum,
                            NULL, 0))
                goto failed_mount;
@@ -1634,13 +1645,15 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
                sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
                sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
                if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) ||
-                   (sbi->s_inode_size & (sbi->s_inode_size - 1)) ||
+                   (!is_power_of_2(sbi->s_inode_size)) ||
                    (sbi->s_inode_size > blocksize)) {
                        printk (KERN_ERR
                                "EXT4-fs: unsupported inode size: %d\n",
                                sbi->s_inode_size);
                        goto failed_mount;
                }
+               if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE)
+                       sb->s_time_gran = 1 << (EXT4_EPOCH_BITS - 2);
        }
        sbi->s_frag_size = EXT4_MIN_FRAG_SIZE <<
                                   le32_to_cpu(es->s_log_frag_size);
@@ -1803,6 +1816,13 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
                goto failed_mount3;
        }
 
+       if (ext4_blocks_count(es) > 0xffffffffULL &&
+           !jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0,
+                                      JBD2_FEATURE_INCOMPAT_64BIT)) {
+               printk(KERN_ERR "ext4: Failed to set 64-bit journal feature\n");
+               goto failed_mount4;
+       }
+
        /* We have now updated the journal if required, so we can
         * validate the data journaling mode. */
        switch (test_opt(sb, DATA_FLAGS)) {
@@ -1857,6 +1877,32 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
        }
 
        ext4_setup_super (sb, es, sb->s_flags & MS_RDONLY);
+
+       /* determine the minimum size of new large inodes, if present */
+       if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) {
+               sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
+                                                    EXT4_GOOD_OLD_INODE_SIZE;
+               if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
+                                      EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)) {
+                       if (sbi->s_want_extra_isize <
+                           le16_to_cpu(es->s_want_extra_isize))
+                               sbi->s_want_extra_isize =
+                                       le16_to_cpu(es->s_want_extra_isize);
+                       if (sbi->s_want_extra_isize <
+                           le16_to_cpu(es->s_min_extra_isize))
+                               sbi->s_want_extra_isize =
+                                       le16_to_cpu(es->s_min_extra_isize);
+               }
+       }
+       /* Check if enough inode space is available */
+       if (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize >
+                                                       sbi->s_inode_size) {
+               sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
+                                                      EXT4_GOOD_OLD_INODE_SIZE;
+               printk(KERN_INFO "EXT4-fs: required extra inode space not"
+                       "available.\n");
+       }
+
        /*
         * akpm: core read_super() calls in here with the superblock locked.
         * That deadlocks, because orphan cleanup needs to lock the superblock
index e832e96095b33c177e880db6370e1686153439f6..b10d68fffb551d7b70b8797bfcd41b6de3bfaed4 100644 (file)
 #define BFIRST(bh) ENTRY(BHDR(bh)+1)
 #define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
 
-#define IHDR(inode, raw_inode) \
-       ((struct ext4_xattr_ibody_header *) \
-               ((void *)raw_inode + \
-                EXT4_GOOD_OLD_INODE_SIZE + \
-                EXT4_I(inode)->i_extra_isize))
-#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
-
 #ifdef EXT4_XATTR_DEBUG
 # define ea_idebug(inode, f...) do { \
                printk(KERN_DEBUG "inode %s:%lu: ", \
@@ -508,6 +501,24 @@ out:
        return;
 }
 
+/*
+ * Find the available free space for EAs. This also returns the total number of
+ * bytes used by EA entries.
+ */
+static size_t ext4_xattr_free_space(struct ext4_xattr_entry *last,
+                                   size_t *min_offs, void *base, int *total)
+{
+       for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+               *total += EXT4_XATTR_LEN(last->e_name_len);
+               if (!last->e_value_block && last->e_value_size) {
+                       size_t offs = le16_to_cpu(last->e_value_offs);
+                       if (offs < *min_offs)
+                               *min_offs = offs;
+               }
+       }
+       return (*min_offs - ((void *)last - base) - sizeof(__u32));
+}
+
 struct ext4_xattr_info {
        int name_index;
        const char *name;
@@ -1013,7 +1024,9 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
        }
        if (!error) {
                ext4_xattr_update_super_block(handle, inode->i_sb);
-               inode->i_ctime = CURRENT_TIME_SEC;
+               inode->i_ctime = ext4_current_time(inode);
+               if (!value)
+                       EXT4_I(inode)->i_state &= ~EXT4_STATE_NO_EXPAND;
                error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
                /*
                 * The bh is consumed by ext4_mark_iloc_dirty, even with
@@ -1066,6 +1079,253 @@ retry:
        return error;
 }
 
+/*
+ * Shift the EA entries in the inode to create space for the increased
+ * i_extra_isize.
+ */
+static void ext4_xattr_shift_entries(struct ext4_xattr_entry *entry,
+                                    int value_offs_shift, void *to,
+                                    void *from, size_t n, int blocksize)
+{
+       struct ext4_xattr_entry *last = entry;
+       int new_offs;
+
+       /* Adjust the value offsets of the entries */
+       for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+               if (!last->e_value_block && last->e_value_size) {
+                       new_offs = le16_to_cpu(last->e_value_offs) +
+                                                       value_offs_shift;
+                       BUG_ON(new_offs + le32_to_cpu(last->e_value_size)
+                                > blocksize);
+                       last->e_value_offs = cpu_to_le16(new_offs);
+               }
+       }
+       /* Shift the entries by n bytes */
+       memmove(to, from, n);
+}
+
+/*
+ * Expand an inode by new_extra_isize bytes when EAs are present.
+ * Returns 0 on success or negative error number on failure.
+ */
+int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
+                              struct ext4_inode *raw_inode, handle_t *handle)
+{
+       struct ext4_xattr_ibody_header *header;
+       struct ext4_xattr_entry *entry, *last, *first;
+       struct buffer_head *bh = NULL;
+       struct ext4_xattr_ibody_find *is = NULL;
+       struct ext4_xattr_block_find *bs = NULL;
+       char *buffer = NULL, *b_entry_name = NULL;
+       size_t min_offs, free;
+       int total_ino, total_blk;
+       void *base, *start, *end;
+       int extra_isize = 0, error = 0, tried_min_extra_isize = 0;
+       int s_min_extra_isize = EXT4_SB(inode->i_sb)->s_es->s_min_extra_isize;
+
+       down_write(&EXT4_I(inode)->xattr_sem);
+retry:
+       if (EXT4_I(inode)->i_extra_isize >= new_extra_isize) {
+               up_write(&EXT4_I(inode)->xattr_sem);
+               return 0;
+       }
+
+       header = IHDR(inode, raw_inode);
+       entry = IFIRST(header);
+
+       /*
+        * Check if enough free space is available in the inode to shift the
+        * entries ahead by new_extra_isize.
+        */
+
+       base = start = entry;
+       end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
+       min_offs = end - base;
+       last = entry;
+       total_ino = sizeof(struct ext4_xattr_ibody_header);
+
+       free = ext4_xattr_free_space(last, &min_offs, base, &total_ino);
+       if (free >= new_extra_isize) {
+               entry = IFIRST(header);
+               ext4_xattr_shift_entries(entry, EXT4_I(inode)->i_extra_isize
+                               - new_extra_isize, (void *)raw_inode +
+                               EXT4_GOOD_OLD_INODE_SIZE + new_extra_isize,
+                               (void *)header, total_ino,
+                               inode->i_sb->s_blocksize);
+               EXT4_I(inode)->i_extra_isize = new_extra_isize;
+               error = 0;
+               goto cleanup;
+       }
+
+       /*
+        * Enough free space isn't available in the inode, check if
+        * EA block can hold new_extra_isize bytes.
+        */
+       if (EXT4_I(inode)->i_file_acl) {
+               bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
+               error = -EIO;
+               if (!bh)
+                       goto cleanup;
+               if (ext4_xattr_check_block(bh)) {
+                       ext4_error(inode->i_sb, __FUNCTION__,
+                               "inode %lu: bad block %llu", inode->i_ino,
+                               EXT4_I(inode)->i_file_acl);
+                       error = -EIO;
+                       goto cleanup;
+               }
+               base = BHDR(bh);
+               first = BFIRST(bh);
+               end = bh->b_data + bh->b_size;
+               min_offs = end - base;
+               free = ext4_xattr_free_space(first, &min_offs, base,
+                                            &total_blk);
+               if (free < new_extra_isize) {
+                       if (!tried_min_extra_isize && s_min_extra_isize) {
+                               tried_min_extra_isize++;
+                               new_extra_isize = s_min_extra_isize;
+                               brelse(bh);
+                               goto retry;
+                       }
+                       error = -1;
+                       goto cleanup;
+               }
+       } else {
+               free = inode->i_sb->s_blocksize;
+       }
+
+       while (new_extra_isize > 0) {
+               size_t offs, size, entry_size;
+               struct ext4_xattr_entry *small_entry = NULL;
+               struct ext4_xattr_info i = {
+                       .value = NULL,
+                       .value_len = 0,
+               };
+               unsigned int total_size;  /* EA entry size + value size */
+               unsigned int shift_bytes; /* No. of bytes to shift EAs by? */
+               unsigned int min_total_size = ~0U;
+
+               is = kzalloc(sizeof(struct ext4_xattr_ibody_find), GFP_NOFS);
+               bs = kzalloc(sizeof(struct ext4_xattr_block_find), GFP_NOFS);
+               if (!is || !bs) {
+                       error = -ENOMEM;
+                       goto cleanup;
+               }
+
+               is->s.not_found = -ENODATA;
+               bs->s.not_found = -ENODATA;
+               is->iloc.bh = NULL;
+               bs->bh = NULL;
+
+               last = IFIRST(header);
+               /* Find the entry best suited to be pushed into EA block */
+               entry = NULL;
+               for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+                       total_size =
+                       EXT4_XATTR_SIZE(le32_to_cpu(last->e_value_size)) +
+                                       EXT4_XATTR_LEN(last->e_name_len);
+                       if (total_size <= free && total_size < min_total_size) {
+                               if (total_size < new_extra_isize) {
+                                       small_entry = last;
+                               } else {
+                                       entry = last;
+                                       min_total_size = total_size;
+                               }
+                       }
+               }
+
+               if (entry == NULL) {
+                       if (small_entry) {
+                               entry = small_entry;
+                       } else {
+                               if (!tried_min_extra_isize &&
+                                   s_min_extra_isize) {
+                                       tried_min_extra_isize++;
+                                       new_extra_isize = s_min_extra_isize;
+                                       goto retry;
+                               }
+                               error = -1;
+                               goto cleanup;
+                       }
+               }
+               offs = le16_to_cpu(entry->e_value_offs);
+               size = le32_to_cpu(entry->e_value_size);
+               entry_size = EXT4_XATTR_LEN(entry->e_name_len);
+               i.name_index = entry->e_name_index,
+               buffer = kmalloc(EXT4_XATTR_SIZE(size), GFP_NOFS);
+               b_entry_name = kmalloc(entry->e_name_len + 1, GFP_NOFS);
+               if (!buffer || !b_entry_name) {
+                       error = -ENOMEM;
+                       goto cleanup;
+               }
+               /* Save the entry name and the entry value */
+               memcpy(buffer, (void *)IFIRST(header) + offs,
+                      EXT4_XATTR_SIZE(size));
+               memcpy(b_entry_name, entry->e_name, entry->e_name_len);
+               b_entry_name[entry->e_name_len] = '\0';
+               i.name = b_entry_name;
+
+               error = ext4_get_inode_loc(inode, &is->iloc);
+               if (error)
+                       goto cleanup;
+
+               error = ext4_xattr_ibody_find(inode, &i, is);
+               if (error)
+                       goto cleanup;
+
+               /* Remove the chosen entry from the inode */
+               error = ext4_xattr_ibody_set(handle, inode, &i, is);
+
+               entry = IFIRST(header);
+               if (entry_size + EXT4_XATTR_SIZE(size) >= new_extra_isize)
+                       shift_bytes = new_extra_isize;
+               else
+                       shift_bytes = entry_size + size;
+               /* Adjust the offsets and shift the remaining entries ahead */
+               ext4_xattr_shift_entries(entry, EXT4_I(inode)->i_extra_isize -
+                       shift_bytes, (void *)raw_inode +
+                       EXT4_GOOD_OLD_INODE_SIZE + extra_isize + shift_bytes,
+                       (void *)header, total_ino - entry_size,
+                       inode->i_sb->s_blocksize);
+
+               extra_isize += shift_bytes;
+               new_extra_isize -= shift_bytes;
+               EXT4_I(inode)->i_extra_isize = extra_isize;
+
+               i.name = b_entry_name;
+               i.value = buffer;
+               i.value_len = cpu_to_le32(size);
+               error = ext4_xattr_block_find(inode, &i, bs);
+               if (error)
+                       goto cleanup;
+
+               /* Add entry which was removed from the inode into the block */
+               error = ext4_xattr_block_set(handle, inode, &i, bs);
+               if (error)
+                       goto cleanup;
+               kfree(b_entry_name);
+               kfree(buffer);
+               brelse(is->iloc.bh);
+               kfree(is);
+               kfree(bs);
+       }
+       brelse(bh);
+       up_write(&EXT4_I(inode)->xattr_sem);
+       return 0;
+
+cleanup:
+       kfree(b_entry_name);
+       kfree(buffer);
+       if (is)
+               brelse(is->iloc.bh);
+       kfree(is);
+       kfree(bs);
+       brelse(bh);
+       up_write(&EXT4_I(inode)->xattr_sem);
+       return error;
+}
+
+
+
 /*
  * ext4_xattr_delete_inode()
  *
index 79432b35398ff92f7cd9a24de3c787c47f1edf9a..d7f5d6a126511e7f65c63793512732d6e31813bb 100644 (file)
@@ -56,6 +56,13 @@ struct ext4_xattr_entry {
 #define EXT4_XATTR_SIZE(size) \
        (((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND)
 
+#define IHDR(inode, raw_inode) \
+       ((struct ext4_xattr_ibody_header *) \
+               ((void *)raw_inode + \
+               EXT4_GOOD_OLD_INODE_SIZE + \
+               EXT4_I(inode)->i_extra_isize))
+#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
+
 # ifdef CONFIG_EXT4DEV_FS_XATTR
 
 extern struct xattr_handler ext4_xattr_user_handler;
@@ -74,6 +81,9 @@ extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *,
 extern void ext4_xattr_delete_inode(handle_t *, struct inode *);
 extern void ext4_xattr_put_super(struct super_block *);
 
+extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
+                           struct ext4_inode *raw_inode, handle_t *handle);
+
 extern int init_ext4_xattr(void);
 extern void exit_ext4_xattr(void);
 
@@ -129,6 +139,13 @@ exit_ext4_xattr(void)
 {
 }
 
+static inline int
+ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
+                           struct ext4_inode *raw_inode, handle_t *handle)
+{
+       return -EOPNOTSUPP;
+}
+
 #define ext4_xattr_handlers    NULL
 
 # endif  /* CONFIG_EXT4DEV_FS_XATTR */
index 8e382a5d51bd6f757bd694344465de0711d4afb2..3f22e9f4f691ae3cb44312921c0aaf3a6b382086 100644 (file)
@@ -215,7 +215,7 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
 
        /* O_NOATIME can only be set by the owner or superuser */
        if ((arg & O_NOATIME) && !(filp->f_flags & O_NOATIME))
-               if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EPERM;
 
        /* required for strict SunOS emulation */
index 9ccb789471713dc94a6768c4cd459bf973166ee3..995d63b2e747556c879c52be194375196995b58a 100644 (file)
@@ -78,7 +78,7 @@ generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
 
        if (S_ISLNK(inode->i_mode))
                return -EOPNOTSUPP;
-       if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                return -EPERM;
        if (value) {
                acl = posix_acl_from_xattr(value, size);
index 6e80844367ee9b5edd81143bc659ab14834809a5..1047a8c7226afb56c8a13c5493c2ac66de741cbb 100644 (file)
@@ -74,7 +74,7 @@ int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access)
 {
        if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl)
                return -EOPNOTSUPP;
-       if (current->fsuid != ip->i_inode.i_uid && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(&ip->i_inode))
                return -EPERM;
        if (S_ISLNK(ip->i_inode.i_mode))
                return -EOPNOTSUPP;
index 79fd10402ea3479d3aaad8b7f6b780fa6a362216..b60c0affbec58af68e45fd063692a933949ad457 100644 (file)
@@ -38,7 +38,7 @@ int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                if (IS_RDONLY(inode))
                        return -EROFS;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EACCES;
 
                if (get_user(flags, (int __user *)arg))
index 78d63b818f0b2daac94a2432396577480522ee84..f290cb7cb83454e5e2814b0746c0e2a9507b7aed 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/kthread.h>
 #include <linux/poison.h>
 #include <linux/proc_fs.h>
+#include <linux/debugfs.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -528,7 +529,7 @@ int jbd2_log_wait_commit(journal_t *journal, tid_t tid)
 {
        int err = 0;
 
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
        spin_lock(&journal->j_state_lock);
        if (!tid_geq(journal->j_commit_request, tid)) {
                printk(KERN_EMERG
@@ -1709,7 +1710,7 @@ void jbd2_slab_free(void *ptr,  size_t size)
  * Journal_head storage management
  */
 static struct kmem_cache *jbd2_journal_head_cache;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
 static atomic_t nr_journal_heads = ATOMIC_INIT(0);
 #endif
 
@@ -1747,7 +1748,7 @@ static struct journal_head *journal_alloc_journal_head(void)
        struct journal_head *ret;
        static unsigned long last_warning;
 
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
        atomic_inc(&nr_journal_heads);
 #endif
        ret = kmem_cache_alloc(jbd2_journal_head_cache, GFP_NOFS);
@@ -1768,7 +1769,7 @@ static struct journal_head *journal_alloc_journal_head(void)
 
 static void journal_free_journal_head(struct journal_head *jh)
 {
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
        atomic_dec(&nr_journal_heads);
        memset(jh, JBD_POISON_FREE, sizeof(*jh));
 #endif
@@ -1951,64 +1952,50 @@ void jbd2_journal_put_journal_head(struct journal_head *jh)
 }
 
 /*
- * /proc tunables
+ * debugfs tunables
  */
-#if defined(CONFIG_JBD_DEBUG)
-int jbd2_journal_enable_debug;
+#if defined(CONFIG_JBD2_DEBUG)
+u8 jbd2_journal_enable_debug;
 EXPORT_SYMBOL(jbd2_journal_enable_debug);
 #endif
 
-#if defined(CONFIG_JBD_DEBUG) && defined(CONFIG_PROC_FS)
+#if defined(CONFIG_JBD2_DEBUG) && defined(CONFIG_DEBUG_FS)
 
-static struct proc_dir_entry *proc_jbd_debug;
+#define JBD2_DEBUG_NAME "jbd2-debug"
 
-static int read_jbd_debug(char *page, char **start, off_t off,
-                         int count, int *eof, void *data)
-{
-       int ret;
+struct dentry *jbd2_debugfs_dir, *jbd2_debug;
 
-       ret = sprintf(page + off, "%d\n", jbd2_journal_enable_debug);
-       *eof = 1;
-       return ret;
+static void __init jbd2_create_debugfs_entry(void)
+{
+       jbd2_debugfs_dir = debugfs_create_dir("jbd2", NULL);
+       if (jbd2_debugfs_dir)
+               jbd2_debug = debugfs_create_u8(JBD2_DEBUG_NAME, S_IRUGO,
+                                              jbd2_debugfs_dir,
+                                              &jbd2_journal_enable_debug);
 }
 
-static int write_jbd_debug(struct file *file, const char __user *buffer,
-                          unsigned long count, void *data)
+static void __exit jbd2_remove_debugfs_entry(void)
 {
-       char buf[32];
-
-       if (count > ARRAY_SIZE(buf) - 1)
-               count = ARRAY_SIZE(buf) - 1;
-       if (copy_from_user(buf, buffer, count))
-               return -EFAULT;
-       buf[ARRAY_SIZE(buf) - 1] = '\0';
-       jbd2_journal_enable_debug = simple_strtoul(buf, NULL, 10);
-       return count;
+       if (jbd2_debug)
+               debugfs_remove(jbd2_debug);
+       if (jbd2_debugfs_dir)
+               debugfs_remove(jbd2_debugfs_dir);
 }
 
-#define JBD_PROC_NAME "sys/fs/jbd2-debug"
+#else
 
-static void __init create_jbd_proc_entry(void)
+static void __init jbd2_create_debugfs_entry(void)
 {
-       proc_jbd_debug = create_proc_entry(JBD_PROC_NAME, 0644, NULL);
-       if (proc_jbd_debug) {
-               /* Why is this so hard? */
-               proc_jbd_debug->read_proc = read_jbd_debug;
-               proc_jbd_debug->write_proc = write_jbd_debug;
-       }
+       do {
+       } while (0);
 }
 
-static void __exit jbd2_remove_jbd_proc_entry(void)
+static void __exit jbd2_remove_debugfs_entry(void)
 {
-       if (proc_jbd_debug)
-               remove_proc_entry(JBD_PROC_NAME, NULL);
+       do {
+       } while (0);
 }
 
-#else
-
-#define create_jbd_proc_entry() do {} while (0)
-#define jbd2_remove_jbd_proc_entry() do {} while (0)
-
 #endif
 
 struct kmem_cache *jbd2_handle_cache;
@@ -2067,18 +2054,18 @@ static int __init journal_init(void)
        ret = journal_init_caches();
        if (ret != 0)
                jbd2_journal_destroy_caches();
-       create_jbd_proc_entry();
+       jbd2_create_debugfs_entry();
        return ret;
 }
 
 static void __exit journal_exit(void)
 {
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
        int n = atomic_read(&nr_journal_heads);
        if (n)
                printk(KERN_EMERG "JBD: leaked %d journal_heads!\n", n);
 #endif
-       jbd2_remove_jbd_proc_entry();
+       jbd2_remove_debugfs_entry();
        jbd2_journal_destroy_caches();
 }
 
index 395c92a04ac93beea84b4c456c65670c6fe2e250..e7730a045b931b330e5bb0fa7bb74df8679f338a 100644 (file)
@@ -295,7 +295,7 @@ int jbd2_journal_skip_recovery(journal_t *journal)
                printk(KERN_ERR "JBD: error %d scanning journal\n", err);
                ++journal->j_transaction_sequence;
        } else {
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
                int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence);
 #endif
                jbd_debug(0,
index a46101ee867afa22e5ee94f8161610433fffc00f..65b3a1b5b88dd0fc009ee4fc425f65d1ceda803e 100644 (file)
@@ -435,7 +435,7 @@ static int jffs2_acl_setxattr(struct inode *inode, int type, const void *value,
        struct posix_acl *acl;
        int rc;
 
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                return -EPERM;
 
        if (value) {
index fe063af6fd2fb216538d6c4bb0cc82e7ba024d2a..3c8663bea98ca3bf373f3ea83260b33d67548f3a 100644 (file)
@@ -69,7 +69,7 @@ int jfs_ioctl(struct inode * inode, struct file * filp, unsigned int cmd,
                if (IS_RDONLY(inode))
                        return -EROFS;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EACCES;
 
                if (get_user(flags, (int __user *) arg))
index b2375f0774b72c89cb602358735a0fed289206f7..9b7f2cdaae0a6655538066e104bff5e10bbcab70 100644 (file)
@@ -697,7 +697,7 @@ static int can_set_system_xattr(struct inode *inode, const char *name,
        struct posix_acl *acl;
        int rc;
 
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                return -EPERM;
 
        /*
index 5e2d98d10c5d79220a7daa95be76a8ac0616df93..defaa47c11d4e7a1de0d926bc659fd8a03df2d27 100644 (file)
@@ -1576,7 +1576,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
 
        /* O_NOATIME can only be set by the owner or superuser */
        if (flag & O_NOATIME)
-               if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EPERM;
 
        /*
index f04c7aa834cb838b1efd98196ccce2eba8312b95..004c2abbc7323280c0ad1df75f34f17a88352110 100644 (file)
@@ -1867,7 +1867,8 @@ static ssize_t ocfs2_file_buffered_write(struct file *file, loff_t *ppos,
        loff_t pos;
        const struct iovec *cur_iov = iov;
        struct page *user_page, *page;
-       char *buf, *dst;
+       char * uninitialized_var(buf);
+       char *dst;
        void *fsdata;
 
        /*
index 352eb4a13f9828717cbe68e2b626227b73c55a22..c4c36171240d0555d5db10d0edb341c2a52627c9 100644 (file)
@@ -209,7 +209,7 @@ void ocfs2_stop_heartbeat(struct ocfs2_super *osb)
        envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
        envp[2] = NULL;
 
-       ret = call_usermodehelper(argv[0], argv, envp, 1);
+       ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
        if (ret < 0)
                mlog_errno(ret);
 }
index bd68c3f2afbeab67a05c32eda336266db7cd7406..87dcece7e1b5cc1d0439da96c7fffe5199af1311 100644 (file)
@@ -63,7 +63,7 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
                goto bail_unlock;
 
        status = -EACCES;
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                goto bail_unlock;
 
        if (!S_ISDIR(inode->i_mode))
index be6a457f4226374b9d462cd8ee4332326ea22097..a6b054edacba7c4cffa127ceb413120ddd5fe101 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -26,6 +26,7 @@
 #include <linux/syscalls.h>
 #include <linux/rcupdate.h>
 #include <linux/audit.h>
+#include <linux/falloc.h>
 
 int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
@@ -352,6 +353,64 @@ asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length)
 }
 #endif
 
+asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len)
+{
+       struct file *file;
+       struct inode *inode;
+       long ret = -EINVAL;
+
+       if (offset < 0 || len <= 0)
+               goto out;
+
+       /* Return error if mode is not supported */
+       ret = -EOPNOTSUPP;
+       if (mode && !(mode & FALLOC_FL_KEEP_SIZE))
+               goto out;
+
+       ret = -EBADF;
+       file = fget(fd);
+       if (!file)
+               goto out;
+       if (!(file->f_mode & FMODE_WRITE))
+               goto out_fput;
+       /*
+        * Revalidate the write permissions, in case security policy has
+        * changed since the files were opened.
+        */
+       ret = security_file_permission(file, MAY_WRITE);
+       if (ret)
+               goto out_fput;
+
+       inode = file->f_path.dentry->d_inode;
+
+       ret = -ESPIPE;
+       if (S_ISFIFO(inode->i_mode))
+               goto out_fput;
+
+       ret = -ENODEV;
+       /*
+        * Let individual file system decide if it supports preallocation
+        * for directories or not.
+        */
+       if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
+               goto out_fput;
+
+       ret = -EFBIG;
+       /* Check for wrap through zero too */
+       if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0))
+               goto out_fput;
+
+       if (inode->i_op && inode->i_op->fallocate)
+               ret = inode->i_op->fallocate(inode, mode, offset, len);
+       else
+               ret = -ENOSYS;
+
+out_fput:
+       fput(file);
+out:
+       return ret;
+}
+
 /*
  * access() needs to use the real uid/gid, not the effective uid/gid.
  * We do this by temporarily clearing all FS-related capabilities and
index b484d2913c0dc18389fe242fd9c1568d578dd82f..11a0fcc2d402c23ec2c426c00d4181ee89188bb3 100644 (file)
@@ -51,8 +51,7 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                        if (IS_RDONLY(inode))
                                return -EROFS;
 
-                       if ((current->fsuid != inode->i_uid)
-                           && !capable(CAP_FOWNER))
+                       if (!is_owner_or_cap(inode))
                                return -EPERM;
 
                        if (get_user(flags, (int __user *)arg))
@@ -81,7 +80,7 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
        case REISERFS_IOC_GETVERSION:
                return put_user(inode->i_generation, (int __user *)arg);
        case REISERFS_IOC_SETVERSION:
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EPERM;
                if (IS_RDONLY(inode))
                        return -EROFS;
index 5296a29cc5eb51779169525a149a98b3206ed0ad..b7e4fa4539deeb9155e97affef199cbacb729f70 100644 (file)
@@ -21,7 +21,7 @@ xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
 
        if (!reiserfs_posixacl(inode->i_sb))
                return -EOPNOTSUPP;
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                return -EPERM;
 
        if (value) {
index 6658afb41cc7564ffeced0d42e0b35b0421baf0e..d6a504f5d758fb0ecfabead59258ac5b9ff63be6 100644 (file)
@@ -1356,7 +1356,7 @@ udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
                        case UDF_VIRTUAL_MAP15:
                        case UDF_VIRTUAL_MAP20:
                        {
-                               kernel_lb_addr ino;
+                               kernel_lb_addr uninitialized_var(ino);
 
                                if (!UDF_SB_LASTBLOCK(sb))
                                {
index 83a7e69e706caeaf576616eeae53d6d5bcfadac6..682eb63b20ad3c4c7452870c3d9e6e832aea21e0 100644 (file)
@@ -106,7 +106,7 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags
                 if (IS_IMMUTABLE(inode))
                         goto dput_and_out;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) {
+               if (!is_owner_or_cap(inode)) {
                        if (f) {
                                if (!(f->f_mode & FMODE_WRITE))
                                        goto dput_and_out;
index 4523aca79659c24f5d2ca3b8ee415ddd9588b73f..a44fd92caca31c72aba82e61ec6b321d7ebf5a7d 100644 (file)
@@ -60,8 +60,7 @@ xattr_permission(struct inode *inode, const char *name, int mask)
                if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
                        return -EPERM;
                if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
-                   (mask & MAY_WRITE) && (current->fsuid != inode->i_uid) &&
-                   !capable(CAP_FOWNER))
+                   (mask & MAY_WRITE) && !is_owner_or_cap(inode))
                        return -EPERM;
        }
 
index 39e492c3bfa3fe33c78c20aa796c89888d6b702e..fa13716a11c3b214fbb7494242d34e0f30096f63 100644 (file)
@@ -81,7 +81,7 @@ struct termio {
 
 #define user_termio_to_kernel_termios(a_termios, u_termio)                     \
 ({                                                                             \
-       struct termios *k_termios = (a_termios);                                \
+       struct ktermios *k_termios = (a_termios);                               \
        struct termio k_termio;                                                 \
        int canon, ret;                                                         \
                                                                                \
@@ -113,7 +113,7 @@ struct termio {
  */
 #define kernel_termios_to_user_termio(u_termio, a_termios)             \
 ({                                                                     \
-       struct termios *k_termios = (a_termios);                        \
+       struct ktermios *k_termios = (a_termios);                       \
        struct termio k_termio;                                         \
        int canon;                                                      \
                                                                        \
index 9744804388494aec75a26ac8ecc54c71c1183d28..0215965dc586d4db7037299ef56e735e9cb5a0b4 100644 (file)
@@ -36,4 +36,18 @@ struct platform_device *
 at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
                     unsigned long fbmem_start, unsigned long fbmem_len);
 
+/* depending on what's hooked up, not all SSC pins will be used */
+#define        ATMEL_SSC_TK            0x01
+#define        ATMEL_SSC_TF            0x02
+#define        ATMEL_SSC_TD            0x04
+#define        ATMEL_SSC_TX            (ATMEL_SSC_TK | ATMEL_SSC_TF | ATMEL_SSC_TD)
+
+#define        ATMEL_SSC_RK            0x10
+#define        ATMEL_SSC_RF            0x20
+#define        ATMEL_SSC_RD            0x40
+#define        ATMEL_SSC_RX            (ATMEL_SSC_RK | ATMEL_SSC_RF | ATMEL_SSC_RD)
+
+struct platform_device *
+at32_add_device_ssc(unsigned int id, unsigned int flags);
+
 #endif /* __ASM_ARCH_BOARD_H */
diff --git a/include/asm-avr32/arch-at32ap/sm.h b/include/asm-avr32/arch-at32ap/sm.h
deleted file mode 100644 (file)
index 265a9ea..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * AT32 System Manager interface.
- *
- * Copyright (C) 2006 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef __ASM_AVR32_AT32_SM_H__
-#define __ASM_AVR32_AT32_SM_H__
-
-struct irq_chip;
-struct platform_device;
-
-struct at32_sm {
-       spinlock_t lock;
-       void __iomem *regs;
-       struct irq_chip *eim_chip;
-       unsigned int eim_first_irq;
-       struct platform_device *pdev;
-};
-
-extern struct platform_device at32_sm_device;
-extern struct at32_sm system_manager;
-
-#endif /* __ASM_AVR32_AT32_SM_H__ */
index b9c2548a52f33d0807add5872424f88cc6342967..7ef3862a73d02443d95eaf6520ff45417f3f00d5 100644 (file)
@@ -101,7 +101,7 @@ static inline int atomic_sub_unless(atomic_t *v, int a, int u)
                "       mov     %1, 1\n"
                "1:"
                : "=&r"(tmp), "=&r"(result), "=o"(v->counter)
-               : "m"(v->counter), "rKs21"(a), "rKs21"(u)
+               : "m"(v->counter), "rKs21"(a), "rKs21"(u), "1"(result)
                : "cc", "memory");
 
        return result;
@@ -137,7 +137,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
                        "       mov     %1, 1\n"
                        "1:"
                        : "=&r"(tmp), "=&r"(result), "=o"(v->counter)
-                       : "m"(v->counter), "r"(a), "ir"(u)
+                       : "m"(v->counter), "r"(a), "ir"(u), "1"(result)
                        : "cc", "memory");
        }
 
index 3042723fcbfd69b267ba8e8216be5d7090cb771c..36f5fd430543ec5d088335f52d357d58e7c75ea7 100644 (file)
@@ -7,19 +7,10 @@
  * words, but halfwords must be halfword-aligned, and doublewords must
  * be word-aligned.
  *
- * TODO: Make all this CPU-specific and optimize.
+ * However, swapped word loads must be word-aligned so we can't
+ * optimize word loads in general.
  */
 
-#include <linux/string.h>
-
-/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
-
-#define get_unaligned(ptr) \
-  ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
-
-#define put_unaligned(val, ptr)                                \
-  ({ __typeof__(*(ptr)) __tmp = (val);                 \
-     memmove((ptr), &__tmp, sizeof(*(ptr)));           \
-     (void)0; })
+#include <asm-generic/unaligned.h>
 
 #endif /* __ASM_AVR32_UNALIGNED_H */
index 09ec447fe2af5de7cb67b142257f28fadb805413..16a466e50681bf5e6cc8a58f3a47a4b3c2c8acf8 100644 (file)
@@ -18,7 +18,8 @@
 #define get_unaligned(ptr) \
        __get_unaligned((ptr), sizeof(*(ptr)))
 #define put_unaligned(x,ptr) \
-       __put_unaligned((__u64)(x), (ptr), sizeof(*(ptr)))
+       ((void)sizeof(*(ptr)=(x)),\
+       __put_unaligned((__force __u64)(x), (ptr), sizeof(*(ptr))))
 
 /*
  * This function doesn't actually exist.  The idea is that when
@@ -95,21 +96,21 @@ static inline void __ustw(__u16 val, __u16 *addr)
        default:                                \
                bad_unaligned_access_length();  \
        };                                      \
-       (__typeof__(*(ptr)))val;                \
+       (__force __typeof__(*(ptr)))val;        \
 })
 
 #define __put_unaligned(val, ptr, size)                \
-do {                                           \
+({                                             \
        void *__gu_p = ptr;                     \
        switch (size) {                         \
        case 1:                                 \
-               *(__u8 *)__gu_p = val;          \
+               *(__u8 *)__gu_p = (__force __u8)val;            \
                break;                          \
        case 2:                                 \
-               __ustw(val, __gu_p);            \
+               __ustw((__force __u16)val, __gu_p);             \
                break;                          \
        case 4:                                 \
-               __ustl(val, __gu_p);            \
+               __ustl((__force __u32)val, __gu_p);             \
                break;                          \
        case 8:                                 \
                __ustq(val, __gu_p);            \
@@ -117,6 +118,7 @@ do {                                                \
        default:                                \
                bad_unaligned_access_length();  \
        };                                      \
-} while(0)
+       (void)0;                                \
+})
 
 #endif /* _ASM_GENERIC_UNALIGNED_H */
index 9e15ce0006ebd53b6f3fe888cde3155e549fbd14..36f310632c49a8bdc174f04a70c92841f7276f79 100644 (file)
@@ -41,6 +41,7 @@ extern int irqbalance_disable(char *str);
 extern void fixup_irqs(cpumask_t map);
 #endif
 
+unsigned int do_IRQ(struct pt_regs *regs);
 void init_IRQ(void);
 void __init native_init_IRQ(void);
 
index 7f161e760be6670879fa5eaa78b0fbc8e97c5a7b..a90c7a60109f67f6f6a26b2e9cce19aa32b64fb7 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _ASM_IRQ_VECTORS_LIMITS_H
 #define _ASM_IRQ_VECTORS_LIMITS_H
 
-#ifdef CONFIG_X86_IO_APIC
+#if defined(CONFIG_X86_IO_APIC) || defined(CONFIG_PARAVIRT)
 #define NR_IRQS 224
 # if (224 >= 32 * NR_CPUS)
 # define NR_IRQ_VECTORS NR_IRQS
index 8198d1cca1f31264dc6b0ee4da90cdd0c13cd323..7eb0b0b1fb3c3e24899eaa3ba0fa378857f77e62 100644 (file)
@@ -32,6 +32,8 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 #endif
 }
 
+void leave_mm(unsigned long cpu);
+
 static inline void switch_mm(struct mm_struct *prev,
                             struct mm_struct *next,
                             struct task_struct *tsk)
index 7f846a7d6bcc080c634314d61759a9e691a6eac1..7df88be2dd9ed28a200e0e55682dab611419f2e1 100644 (file)
@@ -52,6 +52,8 @@ struct paravirt_ops
        /* Basic arch-specific setup */
        void (*arch_setup)(void);
        char *(*memory_setup)(void);
+       void (*post_allocator_init)(void);
+
        void (*init_IRQ)(void);
        void (*time_init)(void);
 
@@ -116,7 +118,7 @@ struct paravirt_ops
 
        u64 (*read_tsc)(void);
        u64 (*read_pmc)(void);
-       u64 (*get_scheduled_cycles)(void);
+       unsigned long long (*sched_clock)(void);
        unsigned long (*get_cpu_khz)(void);
 
        /* Segment descriptor handling */
@@ -173,7 +175,7 @@ struct paravirt_ops
                                 unsigned long va);
 
        /* Hooks for allocating/releasing pagetable pages */
-       void (*alloc_pt)(u32 pfn);
+       void (*alloc_pt)(struct mm_struct *mm, u32 pfn);
        void (*alloc_pd)(u32 pfn);
        void (*alloc_pd_clone)(u32 pfn, u32 clonepfn, u32 start, u32 count);
        void (*release_pt)(u32 pfn);
@@ -260,6 +262,7 @@ unsigned paravirt_patch_default(u8 type, u16 clobbers, void *site, unsigned len)
 unsigned paravirt_patch_insns(void *site, unsigned len,
                              const char *start, const char *end);
 
+int paravirt_disable_iospace(void);
 
 /*
  * This generates an indirect call based on the operation type number.
@@ -563,7 +566,10 @@ static inline u64 paravirt_read_tsc(void)
 
 #define rdtscll(val) (val = paravirt_read_tsc())
 
-#define get_scheduled_cycles(val) (val = paravirt_ops.get_scheduled_cycles())
+static inline unsigned long long paravirt_sched_clock(void)
+{
+       return PVOP_CALL0(unsigned long long, sched_clock);
+}
 #define calculate_cpu_khz() (paravirt_ops.get_cpu_khz())
 
 #define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
@@ -669,6 +675,12 @@ static inline void setup_secondary_clock(void)
 }
 #endif
 
+static inline void paravirt_post_allocator_init(void)
+{
+       if (paravirt_ops.post_allocator_init)
+               (*paravirt_ops.post_allocator_init)();
+}
+
 static inline void paravirt_pagetable_setup_start(pgd_t *base)
 {
        if (paravirt_ops.pagetable_setup_start)
@@ -725,9 +737,9 @@ static inline void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
        PVOP_VCALL3(flush_tlb_others, &cpumask, mm, va);
 }
 
-static inline void paravirt_alloc_pt(unsigned pfn)
+static inline void paravirt_alloc_pt(struct mm_struct *mm, unsigned pfn)
 {
-       PVOP_VCALL1(alloc_pt, pfn);
+       PVOP_VCALL2(alloc_pt, mm, pfn);
 }
 static inline void paravirt_release_pt(unsigned pfn)
 {
index d07b7afc26922dc61d441853faa277428dd51863..f2fc33ceb9f21419121a4bfbdf8093f73ca5dad7 100644 (file)
@@ -7,7 +7,7 @@
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else
-#define paravirt_alloc_pt(pfn) do { } while (0)
+#define paravirt_alloc_pt(mm, pfn) do { } while (0)
 #define paravirt_alloc_pd(pfn) do { } while (0)
 #define paravirt_alloc_pd(pfn) do { } while (0)
 #define paravirt_alloc_pd_clone(pfn, clonepfn, start, count) do { } while (0)
 
 #define pmd_populate_kernel(mm, pmd, pte)                      \
 do {                                                           \
-       paravirt_alloc_pt(__pa(pte) >> PAGE_SHIFT);             \
+       paravirt_alloc_pt(mm, __pa(pte) >> PAGE_SHIFT);         \
        set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)));           \
 } while (0)
 
 #define pmd_populate(mm, pmd, pte)                             \
 do {                                                           \
-       paravirt_alloc_pt(page_to_pfn(pte));                    \
+       paravirt_alloc_pt(mm, page_to_pfn(pte));                \
        set_pmd(pmd, __pmd(_PAGE_TABLE +                        \
                ((unsigned long long)page_to_pfn(pte) <<        \
                        (unsigned long long) PAGE_SHIFT)));     \
index 0d5bff9dc4a5e2133ef7d29bf7287e9381368ae3..7862fe858a9ef8e5e92e15e36cc2fcdf31c200d6 100644 (file)
@@ -81,6 +81,10 @@ void __init add_memory_region(unsigned long long start,
 
 extern unsigned long init_pg_tables_end;
 
+#ifndef CONFIG_PARAVIRT
+#define paravirt_post_allocator_init() do {} while (0)
+#endif
+
 #endif /* __ASSEMBLY__ */
 
 #endif  /*  __KERNEL__  */
index 0c713278706262e60abaa34229ccedfa4e9a45d9..1f73bde165b166759b1a4f1331f3058673716738 100644 (file)
@@ -43,9 +43,12 @@ extern u8 x86_cpu_to_apicid[];
 
 #define cpu_physical_id(cpu)   x86_cpu_to_apicid[cpu]
 
+extern void set_cpu_sibling_map(int cpu);
+
 #ifdef CONFIG_HOTPLUG_CPU
 extern void cpu_exit_clear(void);
 extern void cpu_uninit(void);
+extern void remove_siblinginfo(int cpu);
 #endif
 
 struct smp_ops
@@ -129,6 +132,8 @@ extern int __cpu_disable(void);
 extern void __cpu_die(unsigned int cpu);
 extern unsigned int num_processors;
 
+void __cpuinit smp_store_cpu_info(int id);
+
 #endif /* !__ASSEMBLY__ */
 
 #else /* CONFIG_SMP */
index 153770e25faaac62f525aaa86ae93e7f60b96cbd..51a713e33a9ee8d590e4729657521601588a6a8b 100644 (file)
@@ -15,8 +15,38 @@ extern int no_sync_cmos_clock;
 extern int recalibrate_cpu_khz(void);
 
 #ifndef CONFIG_PARAVIRT
-#define get_scheduled_cycles(val) rdtscll(val)
 #define calculate_cpu_khz() native_calculate_cpu_khz()
 #endif
 
+/* Accellerators for sched_clock()
+ * convert from cycles(64bits) => nanoseconds (64bits)
+ *  basic equation:
+ *             ns = cycles / (freq / ns_per_sec)
+ *             ns = cycles * (ns_per_sec / freq)
+ *             ns = cycles * (10^9 / (cpu_khz * 10^3))
+ *             ns = cycles * (10^6 / cpu_khz)
+ *
+ *     Then we use scaling math (suggested by george@mvista.com) to get:
+ *             ns = cycles * (10^6 * SC / cpu_khz) / SC
+ *             ns = cycles * cyc2ns_scale / SC
+ *
+ *     And since SC is a constant power of two, we can convert the div
+ *  into a shift.
+ *
+ *  We can use khz divisor instead of mhz to keep a better percision, since
+ *  cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits.
+ *  (mathieu.desnoyers@polymtl.ca)
+ *
+ *                     -johnstul@us.ibm.com "math is hard, lets go shopping!"
+ */
+extern unsigned long cyc2ns_scale __read_mostly;
+
+#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
+
+static inline unsigned long long cycles_2_ns(unsigned long long cyc)
+{
+       return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
+}
+
+
 #endif
index e84ace1ec8bfae787d16c944aa7d8f10e0ed874b..9b15545eb9b5bd7d330f7ee0ccc240f7f6e06dec 100644 (file)
 #define __NR_signalfd          321
 #define __NR_timerfd           322
 #define __NR_eventfd           323
+#define __NR_fallocate         324
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 324
+#define NR_syscalls 325
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 213930b995cbcfd59043c707581043acc94bae84..4781881303285f73455e64249a2d56a44cea3729 100644 (file)
@@ -49,7 +49,7 @@ extern struct vmi_timer_ops {
 extern void __init vmi_time_init(void);
 extern unsigned long vmi_get_wallclock(void);
 extern int vmi_set_wallclock(unsigned long now);
-extern unsigned long long vmi_get_sched_cycles(void);
+extern unsigned long long vmi_sched_clock(void);
 extern unsigned long vmi_cpu_khz(void);
 
 #ifdef CONFIG_X86_LOCAL_APIC
diff --git a/include/asm-i386/xen/hypercall.h b/include/asm-i386/xen/hypercall.h
new file mode 100644 (file)
index 0000000..bc0ee7d
--- /dev/null
@@ -0,0 +1,413 @@
+/******************************************************************************
+ * hypercall.h
+ *
+ * Linux-specific hypervisor handling.
+ *
+ * Copyright (c) 2002-2004, K A Fraser
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __HYPERCALL_H__
+#define __HYPERCALL_H__
+
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/sched.h>
+#include <xen/interface/physdev.h>
+
+extern struct { char _entry[32]; } hypercall_page[];
+
+#define _hypercall0(type, name)                                                \
+({                                                                     \
+       long __res;                                                     \
+       asm volatile (                                                  \
+               "call %[call]"                                          \
+               : "=a" (__res)                                          \
+               : [call] "m" (hypercall_page[__HYPERVISOR_##name])      \
+               : "memory" );                                           \
+       (type)__res;                                                    \
+})
+
+#define _hypercall1(type, name, a1)                                    \
+({                                                                     \
+       long __res, __ign1;                                             \
+       asm volatile (                                                  \
+               "call %[call]"                                          \
+               : "=a" (__res), "=b" (__ign1)                           \
+               : "1" ((long)(a1)),                                     \
+                 [call] "m" (hypercall_page[__HYPERVISOR_##name])      \
+               : "memory" );                                           \
+       (type)__res;                                                    \
+})
+
+#define _hypercall2(type, name, a1, a2)                                        \
+({                                                                     \
+       long __res, __ign1, __ign2;                                     \
+       asm volatile (                                                  \
+               "call %[call]"                                          \
+               : "=a" (__res), "=b" (__ign1), "=c" (__ign2)            \
+               : "1" ((long)(a1)), "2" ((long)(a2)),                   \
+                 [call] "m" (hypercall_page[__HYPERVISOR_##name])      \
+               : "memory" );                                           \
+       (type)__res;                                                    \
+})
+
+#define _hypercall3(type, name, a1, a2, a3)                            \
+({                                                                     \
+       long __res, __ign1, __ign2, __ign3;                             \
+       asm volatile (                                                  \
+               "call %[call]"                                          \
+               : "=a" (__res), "=b" (__ign1), "=c" (__ign2),           \
+               "=d" (__ign3)                                           \
+               : "1" ((long)(a1)), "2" ((long)(a2)),                   \
+                 "3" ((long)(a3)),                                     \
+                 [call] "m" (hypercall_page[__HYPERVISOR_##name])      \
+               : "memory" );                                           \
+       (type)__res;                                                    \
+})
+
+#define _hypercall4(type, name, a1, a2, a3, a4)                                \
+({                                                                     \
+       long __res, __ign1, __ign2, __ign3, __ign4;                     \
+       asm volatile (                                                  \
+               "call %[call]"                                          \
+               : "=a" (__res), "=b" (__ign1), "=c" (__ign2),           \
+               "=d" (__ign3), "=S" (__ign4)                            \
+               : "1" ((long)(a1)), "2" ((long)(a2)),                   \
+                 "3" ((long)(a3)), "4" ((long)(a4)),                   \
+                 [call] "m" (hypercall_page[__HYPERVISOR_##name])      \
+               : "memory" );                                           \
+       (type)__res;                                                    \
+})
+
+#define _hypercall5(type, name, a1, a2, a3, a4, a5)                    \
+({                                                                     \
+       long __res, __ign1, __ign2, __ign3, __ign4, __ign5;             \
+       asm volatile (                                                  \
+               "call %[call]"                                          \
+               : "=a" (__res), "=b" (__ign1), "=c" (__ign2),           \
+               "=d" (__ign3), "=S" (__ign4), "=D" (__ign5)             \
+               : "1" ((long)(a1)), "2" ((long)(a2)),                   \
+                 "3" ((long)(a3)), "4" ((long)(a4)),                   \
+                 "5" ((long)(a5)),                                     \
+                 [call] "m" (hypercall_page[__HYPERVISOR_##name])      \
+               : "memory" );                                           \
+       (type)__res;                                                    \
+})
+
+static inline int
+HYPERVISOR_set_trap_table(struct trap_info *table)
+{
+       return _hypercall1(int, set_trap_table, table);
+}
+
+static inline int
+HYPERVISOR_mmu_update(struct mmu_update *req, int count,
+                     int *success_count, domid_t domid)
+{
+       return _hypercall4(int, mmu_update, req, count, success_count, domid);
+}
+
+static inline int
+HYPERVISOR_mmuext_op(struct mmuext_op *op, int count,
+                    int *success_count, domid_t domid)
+{
+       return _hypercall4(int, mmuext_op, op, count, success_count, domid);
+}
+
+static inline int
+HYPERVISOR_set_gdt(unsigned long *frame_list, int entries)
+{
+       return _hypercall2(int, set_gdt, frame_list, entries);
+}
+
+static inline int
+HYPERVISOR_stack_switch(unsigned long ss, unsigned long esp)
+{
+       return _hypercall2(int, stack_switch, ss, esp);
+}
+
+static inline int
+HYPERVISOR_set_callbacks(unsigned long event_selector,
+                        unsigned long event_address,
+                        unsigned long failsafe_selector,
+                        unsigned long failsafe_address)
+{
+       return _hypercall4(int, set_callbacks,
+                          event_selector, event_address,
+                          failsafe_selector, failsafe_address);
+}
+
+static inline int
+HYPERVISOR_fpu_taskswitch(int set)
+{
+       return _hypercall1(int, fpu_taskswitch, set);
+}
+
+static inline int
+HYPERVISOR_sched_op(int cmd, unsigned long arg)
+{
+       return _hypercall2(int, sched_op, cmd, arg);
+}
+
+static inline long
+HYPERVISOR_set_timer_op(u64 timeout)
+{
+       unsigned long timeout_hi = (unsigned long)(timeout>>32);
+       unsigned long timeout_lo = (unsigned long)timeout;
+       return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi);
+}
+
+static inline int
+HYPERVISOR_set_debugreg(int reg, unsigned long value)
+{
+       return _hypercall2(int, set_debugreg, reg, value);
+}
+
+static inline unsigned long
+HYPERVISOR_get_debugreg(int reg)
+{
+       return _hypercall1(unsigned long, get_debugreg, reg);
+}
+
+static inline int
+HYPERVISOR_update_descriptor(u64 ma, u64 desc)
+{
+       return _hypercall4(int, update_descriptor, ma, ma>>32, desc, desc>>32);
+}
+
+static inline int
+HYPERVISOR_memory_op(unsigned int cmd, void *arg)
+{
+       return _hypercall2(int, memory_op, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_multicall(void *call_list, int nr_calls)
+{
+       return _hypercall2(int, multicall, call_list, nr_calls);
+}
+
+static inline int
+HYPERVISOR_update_va_mapping(unsigned long va, pte_t new_val,
+                            unsigned long flags)
+{
+       unsigned long pte_hi = 0;
+#ifdef CONFIG_X86_PAE
+       pte_hi = new_val.pte_high;
+#endif
+       return _hypercall4(int, update_va_mapping, va,
+                          new_val.pte_low, pte_hi, flags);
+}
+
+static inline int
+HYPERVISOR_event_channel_op(int cmd, void *arg)
+{
+       int rc = _hypercall2(int, event_channel_op, cmd, arg);
+       if (unlikely(rc == -ENOSYS)) {
+               struct evtchn_op op;
+               op.cmd = cmd;
+               memcpy(&op.u, arg, sizeof(op.u));
+               rc = _hypercall1(int, event_channel_op_compat, &op);
+               memcpy(arg, &op.u, sizeof(op.u));
+       }
+       return rc;
+}
+
+static inline int
+HYPERVISOR_xen_version(int cmd, void *arg)
+{
+       return _hypercall2(int, xen_version, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_console_io(int cmd, int count, char *str)
+{
+       return _hypercall3(int, console_io, cmd, count, str);
+}
+
+static inline int
+HYPERVISOR_physdev_op(int cmd, void *arg)
+{
+       int rc = _hypercall2(int, physdev_op, cmd, arg);
+       if (unlikely(rc == -ENOSYS)) {
+               struct physdev_op op;
+               op.cmd = cmd;
+               memcpy(&op.u, arg, sizeof(op.u));
+               rc = _hypercall1(int, physdev_op_compat, &op);
+               memcpy(arg, &op.u, sizeof(op.u));
+       }
+       return rc;
+}
+
+static inline int
+HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count)
+{
+       return _hypercall3(int, grant_table_op, cmd, uop, count);
+}
+
+static inline int
+HYPERVISOR_update_va_mapping_otherdomain(unsigned long va, pte_t new_val,
+                                        unsigned long flags, domid_t domid)
+{
+       unsigned long pte_hi = 0;
+#ifdef CONFIG_X86_PAE
+       pte_hi = new_val.pte_high;
+#endif
+       return _hypercall5(int, update_va_mapping_otherdomain, va,
+                          new_val.pte_low, pte_hi, flags, domid);
+}
+
+static inline int
+HYPERVISOR_vm_assist(unsigned int cmd, unsigned int type)
+{
+       return _hypercall2(int, vm_assist, cmd, type);
+}
+
+static inline int
+HYPERVISOR_vcpu_op(int cmd, int vcpuid, void *extra_args)
+{
+       return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args);
+}
+
+static inline int
+HYPERVISOR_suspend(unsigned long srec)
+{
+       return _hypercall3(int, sched_op, SCHEDOP_shutdown,
+                          SHUTDOWN_suspend, srec);
+}
+
+static inline int
+HYPERVISOR_nmi_op(unsigned long op, unsigned long arg)
+{
+       return _hypercall2(int, nmi_op, op, arg);
+}
+
+static inline void
+MULTI_update_va_mapping(struct multicall_entry *mcl, unsigned long va,
+                       pte_t new_val, unsigned long flags)
+{
+       mcl->op = __HYPERVISOR_update_va_mapping;
+       mcl->args[0] = va;
+#ifdef CONFIG_X86_PAE
+       mcl->args[1] = new_val.pte_low;
+       mcl->args[2] = new_val.pte_high;
+#else
+       mcl->args[1] = new_val.pte_low;
+       mcl->args[2] = 0;
+#endif
+       mcl->args[3] = flags;
+}
+
+static inline void
+MULTI_grant_table_op(struct multicall_entry *mcl, unsigned int cmd,
+                    void *uop, unsigned int count)
+{
+       mcl->op = __HYPERVISOR_grant_table_op;
+       mcl->args[0] = cmd;
+       mcl->args[1] = (unsigned long)uop;
+       mcl->args[2] = count;
+}
+
+static inline void
+MULTI_update_va_mapping_otherdomain(struct multicall_entry *mcl, unsigned long va,
+                                   pte_t new_val, unsigned long flags,
+                                   domid_t domid)
+{
+       mcl->op = __HYPERVISOR_update_va_mapping_otherdomain;
+       mcl->args[0] = va;
+#ifdef CONFIG_X86_PAE
+       mcl->args[1] = new_val.pte_low;
+       mcl->args[2] = new_val.pte_high;
+#else
+       mcl->args[1] = new_val.pte_low;
+       mcl->args[2] = 0;
+#endif
+       mcl->args[3] = flags;
+       mcl->args[4] = domid;
+}
+
+static inline void
+MULTI_update_descriptor(struct multicall_entry *mcl, u64 maddr,
+                       struct desc_struct desc)
+{
+       mcl->op = __HYPERVISOR_update_descriptor;
+       mcl->args[0] = maddr;
+       mcl->args[1] = maddr >> 32;
+       mcl->args[2] = desc.a;
+       mcl->args[3] = desc.b;
+}
+
+static inline void
+MULTI_memory_op(struct multicall_entry *mcl, unsigned int cmd, void *arg)
+{
+       mcl->op = __HYPERVISOR_memory_op;
+       mcl->args[0] = cmd;
+       mcl->args[1] = (unsigned long)arg;
+}
+
+static inline void
+MULTI_mmu_update(struct multicall_entry *mcl, struct mmu_update *req,
+                int count, int *success_count, domid_t domid)
+{
+       mcl->op = __HYPERVISOR_mmu_update;
+       mcl->args[0] = (unsigned long)req;
+       mcl->args[1] = count;
+       mcl->args[2] = (unsigned long)success_count;
+       mcl->args[3] = domid;
+}
+
+static inline void
+MULTI_mmuext_op(struct multicall_entry *mcl, struct mmuext_op *op, int count,
+               int *success_count, domid_t domid)
+{
+       mcl->op = __HYPERVISOR_mmuext_op;
+       mcl->args[0] = (unsigned long)op;
+       mcl->args[1] = count;
+       mcl->args[2] = (unsigned long)success_count;
+       mcl->args[3] = domid;
+}
+
+static inline void
+MULTI_set_gdt(struct multicall_entry *mcl, unsigned long *frames, int entries)
+{
+       mcl->op = __HYPERVISOR_set_gdt;
+       mcl->args[0] = (unsigned long)frames;
+       mcl->args[1] = entries;
+}
+
+static inline void
+MULTI_stack_switch(struct multicall_entry *mcl,
+                  unsigned long ss, unsigned long esp)
+{
+       mcl->op = __HYPERVISOR_stack_switch;
+       mcl->args[0] = ss;
+       mcl->args[1] = esp;
+}
+
+#endif /* __HYPERCALL_H__ */
diff --git a/include/asm-i386/xen/hypervisor.h b/include/asm-i386/xen/hypervisor.h
new file mode 100644 (file)
index 0000000..8e15dd2
--- /dev/null
@@ -0,0 +1,73 @@
+/******************************************************************************
+ * hypervisor.h
+ *
+ * Linux-specific hypervisor handling.
+ *
+ * Copyright (c) 2002-2004, K A Fraser
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __HYPERVISOR_H__
+#define __HYPERVISOR_H__
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/version.h>
+
+#include <asm/ptrace.h>
+#include <asm/page.h>
+#include <asm/desc.h>
+#if defined(__i386__)
+#  ifdef CONFIG_X86_PAE
+#   include <asm-generic/pgtable-nopud.h>
+#  else
+#   include <asm-generic/pgtable-nopmd.h>
+#  endif
+#endif
+#include <asm/xen/hypercall.h>
+
+/* arch/i386/kernel/setup.c */
+extern struct shared_info *HYPERVISOR_shared_info;
+extern struct start_info *xen_start_info;
+#define is_initial_xendomain() (xen_start_info->flags & SIF_INITDOMAIN)
+
+/* arch/i386/mach-xen/evtchn.c */
+/* Force a proper event-channel callback from Xen. */
+extern void force_evtchn_callback(void);
+
+/* Turn jiffies into Xen system time. */
+u64 jiffies_to_st(unsigned long jiffies);
+
+
+#define MULTI_UVMFLAGS_INDEX 3
+#define MULTI_UVMDOMID_INDEX 4
+
+#define is_running_on_xen()    (xen_start_info ? 1 : 0)
+
+#endif /* __HYPERVISOR_H__ */
diff --git a/include/asm-i386/xen/interface.h b/include/asm-i386/xen/interface.h
new file mode 100644 (file)
index 0000000..165c396
--- /dev/null
@@ -0,0 +1,188 @@
+/******************************************************************************
+ * arch-x86_32.h
+ *
+ * Guest OS interface to x86 32-bit Xen.
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __XEN_PUBLIC_ARCH_X86_32_H__
+#define __XEN_PUBLIC_ARCH_X86_32_H__
+
+#ifdef __XEN__
+#define __DEFINE_GUEST_HANDLE(name, type) \
+    typedef struct { type *p; } __guest_handle_ ## name
+#else
+#define __DEFINE_GUEST_HANDLE(name, type) \
+    typedef type * __guest_handle_ ## name
+#endif
+
+#define DEFINE_GUEST_HANDLE_STRUCT(name) \
+       __DEFINE_GUEST_HANDLE(name, struct name)
+#define DEFINE_GUEST_HANDLE(name) __DEFINE_GUEST_HANDLE(name, name)
+#define GUEST_HANDLE(name)        __guest_handle_ ## name
+
+#ifndef __ASSEMBLY__
+/* Guest handles for primitive C types. */
+__DEFINE_GUEST_HANDLE(uchar, unsigned char);
+__DEFINE_GUEST_HANDLE(uint,  unsigned int);
+__DEFINE_GUEST_HANDLE(ulong, unsigned long);
+DEFINE_GUEST_HANDLE(char);
+DEFINE_GUEST_HANDLE(int);
+DEFINE_GUEST_HANDLE(long);
+DEFINE_GUEST_HANDLE(void);
+#endif
+
+/*
+ * SEGMENT DESCRIPTOR TABLES
+ */
+/*
+ * A number of GDT entries are reserved by Xen. These are not situated at the
+ * start of the GDT because some stupid OSes export hard-coded selector values
+ * in their ABI. These hard-coded values are always near the start of the GDT,
+ * so Xen places itself out of the way, at the far end of the GDT.
+ */
+#define FIRST_RESERVED_GDT_PAGE  14
+#define FIRST_RESERVED_GDT_BYTE  (FIRST_RESERVED_GDT_PAGE * 4096)
+#define FIRST_RESERVED_GDT_ENTRY (FIRST_RESERVED_GDT_BYTE / 8)
+
+/*
+ * These flat segments are in the Xen-private section of every GDT. Since these
+ * are also present in the initial GDT, many OSes will be able to avoid
+ * installing their own GDT.
+ */
+#define FLAT_RING1_CS 0xe019    /* GDT index 259 */
+#define FLAT_RING1_DS 0xe021    /* GDT index 260 */
+#define FLAT_RING1_SS 0xe021    /* GDT index 260 */
+#define FLAT_RING3_CS 0xe02b    /* GDT index 261 */
+#define FLAT_RING3_DS 0xe033    /* GDT index 262 */
+#define FLAT_RING3_SS 0xe033    /* GDT index 262 */
+
+#define FLAT_KERNEL_CS FLAT_RING1_CS
+#define FLAT_KERNEL_DS FLAT_RING1_DS
+#define FLAT_KERNEL_SS FLAT_RING1_SS
+#define FLAT_USER_CS    FLAT_RING3_CS
+#define FLAT_USER_DS    FLAT_RING3_DS
+#define FLAT_USER_SS    FLAT_RING3_SS
+
+/* And the trap vector is... */
+#define TRAP_INSTR "int $0x82"
+
+/*
+ * Virtual addresses beyond this are not modifiable by guest OSes. The
+ * machine->physical mapping table starts at this address, read-only.
+ */
+#ifdef CONFIG_X86_PAE
+#define __HYPERVISOR_VIRT_START 0xF5800000
+#else
+#define __HYPERVISOR_VIRT_START 0xFC000000
+#endif
+
+#ifndef HYPERVISOR_VIRT_START
+#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
+#endif
+
+#ifndef machine_to_phys_mapping
+#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
+#endif
+
+/* Maximum number of virtual CPUs in multi-processor guests. */
+#define MAX_VIRT_CPUS 32
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Send an array of these to HYPERVISOR_set_trap_table()
+ */
+#define TI_GET_DPL(_ti)                ((_ti)->flags & 3)
+#define TI_GET_IF(_ti)         ((_ti)->flags & 4)
+#define TI_SET_DPL(_ti, _dpl)  ((_ti)->flags |= (_dpl))
+#define TI_SET_IF(_ti, _if)    ((_ti)->flags |= ((!!(_if))<<2))
+
+struct trap_info {
+    uint8_t       vector;  /* exception vector                              */
+    uint8_t       flags;   /* 0-3: privilege level; 4: clear event enable?  */
+    uint16_t      cs;      /* code selector                                 */
+    unsigned long address; /* code offset                                   */
+};
+DEFINE_GUEST_HANDLE_STRUCT(trap_info);
+
+struct cpu_user_regs {
+    uint32_t ebx;
+    uint32_t ecx;
+    uint32_t edx;
+    uint32_t esi;
+    uint32_t edi;
+    uint32_t ebp;
+    uint32_t eax;
+    uint16_t error_code;    /* private */
+    uint16_t entry_vector;  /* private */
+    uint32_t eip;
+    uint16_t cs;
+    uint8_t  saved_upcall_mask;
+    uint8_t  _pad0;
+    uint32_t eflags;        /* eflags.IF == !saved_upcall_mask */
+    uint32_t esp;
+    uint16_t ss, _pad1;
+    uint16_t es, _pad2;
+    uint16_t ds, _pad3;
+    uint16_t fs, _pad4;
+    uint16_t gs, _pad5;
+};
+DEFINE_GUEST_HANDLE_STRUCT(cpu_user_regs);
+
+typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */
+
+/*
+ * The following is all CPU context. Note that the fpu_ctxt block is filled
+ * in by FXSAVE if the CPU has feature FXSR; otherwise FSAVE is used.
+ */
+struct vcpu_guest_context {
+    /* FPU registers come first so they can be aligned for FXSAVE/FXRSTOR. */
+    struct { char x[512]; } fpu_ctxt;       /* User-level FPU registers     */
+#define VGCF_I387_VALID (1<<0)
+#define VGCF_HVM_GUEST  (1<<1)
+#define VGCF_IN_KERNEL  (1<<2)
+    unsigned long flags;                    /* VGCF_* flags                 */
+    struct cpu_user_regs user_regs;         /* User-level CPU registers     */
+    struct trap_info trap_ctxt[256];        /* Virtual IDT                  */
+    unsigned long ldt_base, ldt_ents;       /* LDT (linear address, # ents) */
+    unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */
+    unsigned long kernel_ss, kernel_sp;     /* Virtual TSS (only SS1/SP1)   */
+    unsigned long ctrlreg[8];               /* CR0-CR7 (control registers)  */
+    unsigned long debugreg[8];              /* DB0-DB7 (debug registers)    */
+    unsigned long event_callback_cs;        /* CS:EIP of event callback     */
+    unsigned long event_callback_eip;
+    unsigned long failsafe_callback_cs;     /* CS:EIP of failsafe callback  */
+    unsigned long failsafe_callback_eip;
+    unsigned long vm_assist;                /* VMASST_TYPE_* bitmap */
+};
+DEFINE_GUEST_HANDLE_STRUCT(vcpu_guest_context);
+
+struct arch_shared_info {
+    unsigned long max_pfn;                  /* max pfn that appears in table */
+    /* Frame containing list of mfns containing list of mfns containing p2m. */
+    unsigned long pfn_to_mfn_frame_list_list;
+    unsigned long nmi_reason;
+};
+
+struct arch_vcpu_info {
+    unsigned long cr2;
+    unsigned long pad[5]; /* sizeof(struct vcpu_info) == 64 */
+};
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * Prefix forces emulation of some non-trapping instructions.
+ * Currently only CPUID.
+ */
+#ifdef __ASSEMBLY__
+#define XEN_EMULATE_PREFIX .byte 0x0f,0x0b,0x78,0x65,0x6e ;
+#define XEN_CPUID          XEN_EMULATE_PREFIX cpuid
+#else
+#define XEN_EMULATE_PREFIX ".byte 0x0f,0x0b,0x78,0x65,0x6e ; "
+#define XEN_CPUID          XEN_EMULATE_PREFIX "cpuid"
+#endif
+
+#endif
index 31ee521aeb7af631dcff9b34c2af7354db1a8c5c..f41b636a0bf6d726820f76cea1233018022ac55b 100644 (file)
 #define TIOCSBRK       0x5427  /* BSD compatibility */
 #define TIOCCBRK       0x5428  /* BSD compatibility */
 #define TIOCGSID       0x5429  /* Return the session ID of FD */
+#define TCGETS2                _IOR('T',0x2A, struct termios2)
+#define TCSETS2                _IOW('T',0x2B, struct termios2)
+#define TCSETSW2       _IOW('T',0x2C, struct termios2)
+#define TCSETSF2       _IOW('T',0x2D, struct termios2)
 #define TIOCGPTN       _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK     _IOW('T',0x31, int)  /* Lock/unlock Pty */
 
index 7fae3109ef47d1d368f8263cd85ac5543e30f2cd..9f162e0089ade2f66abf0d78cfe5456e0b6d3805 100644 (file)
@@ -149,6 +149,7 @@ struct ktermios {
 #define HUPCL  0002000
 #define CLOCAL 0004000
 #define CBAUDEX 0010000
+#define    BOTHER 0010000
 #define    B57600 0010001
 #define   B115200 0010002
 #define   B230400 0010003
@@ -164,10 +165,12 @@ struct ktermios {
 #define  B3000000 0010015
 #define  B3500000 0010016
 #define  B4000000 0010017
-#define CIBAUD   002003600000  /* input baud rate (not used) */
+#define CIBAUD   002003600000          /* input baud rate */
 #define CMSPAR   010000000000          /* mark or space (stick) parity */
 #define CRTSCTS          020000000000          /* flow control */
 
+#define IBSHIFT        16              /* Shift from CBAUD to CIBAUD */
+
 /* c_lflag bits */
 #define ISIG   0000001
 #define ICANON 0000002
index 08750c2d3607b0f479e978cac60627d3dc7e0262..689d218c0c285c4d0be89fa216882e8bd78a34bd 100644 (file)
@@ -87,8 +87,10 @@ struct termio {
        copy_to_user((termio)->c_cc, (termios)->c_cc, NCC);     \
 })
 
-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
+#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
 
 # endif /* __KERNEL__ */
 
diff --git a/include/asm-mips/dec/serial.h b/include/asm-mips/dec/serial.h
deleted file mode 100644 (file)
index acad758..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- *     include/asm-mips/dec/serial.h
- *
- *     Definitions common to all DECstation serial devices.
- *
- *     Copyright (C) 2004  Maciej W. Rozycki
- *
- *     Based on bits extracted from drivers/tc/zs.h for which
- *     the following copyrights apply:
- *
- *     Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
- *     Copyright (C) 1996  Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- *     Copyright (C)       Harald Koerfgen
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- */
-#ifndef __ASM_MIPS_DEC_SERIAL_H
-#define __ASM_MIPS_DEC_SERIAL_H
-
-struct dec_serial_hook {
-       int (*init_channel)(void *handle);
-       void (*init_info)(void *handle);
-       void (*rx_char)(unsigned char ch, unsigned char fl);
-       int (*poll_rx_char)(void *handle);
-       int (*poll_tx_char)(void *handle, unsigned char ch);
-       unsigned int cflags;
-};
-
-extern int register_dec_serial_hook(unsigned int channel,
-                                   struct dec_serial_hook *hook);
-extern int unregister_dec_serial_hook(unsigned int channel);
-
-#endif /* __ASM_MIPS_DEC_SERIAL_H */
index 1cc3f9cb6f4e104db5e16cb2f2ad56e90c483c8c..cc6d8722825882f33ed2cb9d85805bdcd6a7fed7 100644 (file)
@@ -308,6 +308,7 @@ COMPAT_SYS_SPU(move_pages)
 SYSCALL_SPU(getcpu)
 COMPAT_SYS(epoll_pwait)
 COMPAT_SYS_SPU(utimensat)
+COMPAT_SYS(fallocate)
 COMPAT_SYS_SPU(signalfd)
 COMPAT_SYS_SPU(timerfd)
 SYSCALL_SPU(eventfd)
index f71c6061f1ec8c16fcedfab05ea7d6c68daf06de..97d82b6a940609f8fa58e66cf22b268241715cdf 100644 (file)
 #define __NR_timerfd           306
 #define __NR_eventfd           307
 #define __NR_sync_file_range2  308
+#define __NR_fallocate         309
 
 #ifdef __KERNEL__
 
-#define __NR_syscalls          309
+#define __NR_syscalls          310
 
 #define __NR__exit __NR_exit
 #define NR_syscalls    __NR_syscalls
index ad595b67984232eb9535254de225d486a36068d4..9565a892801e440c2051302973e6fc817c1a1659 100644 (file)
 #define __SLOW_DOWN_IO do { } while (0)
 #define SLOW_DOWN_IO   do { } while (0)
 
-extern unsigned long virt_to_bus_not_defined_use_pci_map(volatile void *addr);
-#define virt_to_bus virt_to_bus_not_defined_use_pci_map
-extern unsigned long bus_to_virt_not_defined_use_pci_map(volatile void *addr);
-#define bus_to_virt bus_to_virt_not_defined_use_pci_map
-
 /* BIO layer definitions. */
 extern unsigned long kern_base, kern_size;
 #define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
index e97c43133752ad3b6258cf5ada95adbe574f06e0..1acc7272e537bca1bfe095ea24e518b32d837a9b 100644 (file)
@@ -61,6 +61,16 @@ extern u64 mdesc_arc_target(struct mdesc_handle *hp, u64 arc);
 
 extern void mdesc_update(void);
 
+struct mdesc_notifier_client {
+       void (*add)(struct mdesc_handle *handle, u64 node);
+       void (*remove)(struct mdesc_handle *handle, u64 node);
+
+       const char                      *node_name;
+       struct mdesc_notifier_client    *next;
+};
+
+extern void mdesc_register_notifier(struct mdesc_notifier_client *client);
+
 extern void mdesc_fill_in_cpu_data(cpumask_t mask);
 
 extern void sun4v_mdesc_init(void);
index 83c96422e9d61deba94a0cb9ee446b81d1b7a266..c0a8d4ed5bcb33669d808b4f1105c1913fe1dfac 100644 (file)
@@ -264,7 +264,7 @@ static inline u32 vio_dring_avail(struct vio_dring_state *dr,
                ((dr->prod - dr->cons) & (ring_size - 1)));
 }
 
-#define VIO_MAX_TYPE_LEN       64
+#define VIO_MAX_TYPE_LEN       32
 #define VIO_MAX_COMPAT_LEN     64
 
 struct vio_dev {
index 8696f8ad401ef128f8f96e219bc7581ff75f2ed5..fc4e73f5f1fa72c46cda757c99d2d98fead4a4cc 100644 (file)
@@ -630,6 +630,8 @@ __SYSCALL(__NR_signalfd, sys_signalfd)
 __SYSCALL(__NR_timerfd, sys_timerfd)
 #define __NR_eventfd           284
 __SYSCALL(__NR_eventfd, sys_eventfd)
+#define __NR_fallocate         285
+__SYSCALL(__NR_fallocate, sys_fallocate)
 
 #ifndef __NO_STUBS
 #define __ARCH_WANT_OLD_READDIR
index bd998ca6cb2e310f49bbfaaac3dc0bde928a2f0a..8547b10c388b5fedae1da1982a7f17e947f90708 100644 (file)
@@ -60,7 +60,6 @@ struct bsg_class_device {
 extern int bsg_register_queue(struct request_queue *, const char *);
 extern void bsg_unregister_queue(struct request_queue *);
 #else
-struct bsg_class_device { };
 #define bsg_register_queue(disk, name)         (0)
 #define bsg_unregister_queue(disk)     do { } while (0)
 #endif
index 9a1e0674e56ce6760d5088718d468981687f3c08..e831759b2fb5f971cfabdb94dfa9863b4f57cc4b 100644 (file)
  * e.g. ELFNOTE(XYZCo, 42, .asciz, "forty-two")
  *      ELFNOTE(XYZCo, 12, .long, 0xdeadbeef)
  */
-#define ELFNOTE(name, type, desctype, descdata)        \
-.pushsection .note.name, "",@note      ;       \
-  .align 4                             ;       \
+#define ELFNOTE_START(name, type, flags)       \
+.pushsection .note.name, flags,@note   ;       \
+  .balign 4                            ;       \
   .long 2f - 1f                /* namesz */    ;       \
-  .long 4f - 3f                /* descsz */    ;       \
+  .long 4484f - 3f     /* descsz */    ;       \
   .long type                           ;       \
 1:.asciz #name                         ;       \
-2:.align 4                             ;       \
-3:desctype descdata                    ;       \
-4:.align 4                             ;       \
+2:.balign 4                            ;       \
+3:
+
+#define ELFNOTE_END                            \
+4484:.balign 4                         ;       \
 .popsection                            ;
+
+#define ELFNOTE(name, type, desc)              \
+       ELFNOTE_START(name, type, "")           \
+               desc                    ;       \
+       ELFNOTE_END
+
 #else  /* !__ASSEMBLER__ */
 #include <linux/elf.h>
 /*
index de1f9f78625a3279bf5ddb580d57cc1003eef152..cdee7aaa57aa60952281c54320f7a9bf0fa936fb 100644 (file)
@@ -71,7 +71,7 @@
 /*
  * Maximal count of links to a file
  */
-#define EXT4_LINK_MAX          32000
+#define EXT4_LINK_MAX          65000
 
 /*
  * Macro-instructions used to manage several block sizes
                                 EXT4_GOOD_OLD_FIRST_INO : \
                                 (s)->s_first_ino)
 #endif
+#define EXT4_BLOCK_ALIGN(size, blkbits)                ALIGN((size), (1 << (blkbits)))
 
 /*
  * Macro-instructions used to manage fragments
@@ -201,6 +202,7 @@ struct ext4_group_desc
 #define EXT4_STATE_JDATA               0x00000001 /* journaled data exists */
 #define EXT4_STATE_NEW                 0x00000002 /* inode is newly created */
 #define EXT4_STATE_XATTR               0x00000004 /* has in-inode xattrs */
+#define EXT4_STATE_NO_EXPAND           0x00000008 /* No space for expansion */
 
 /* Used to pass group descriptor data when online resize is done */
 struct ext4_new_group_input {
@@ -225,6 +227,11 @@ struct ext4_new_group_data {
        __u32 free_blocks_count;
 };
 
+/*
+ * Following is used by preallocation code to tell get_blocks() that we
+ * want uninitialzed extents.
+ */
+#define EXT4_CREATE_UNINITIALIZED_EXT          2
 
 /*
  * ioctl commands
@@ -237,7 +244,7 @@ struct ext4_new_group_data {
 #define EXT4_IOC_GROUP_ADD             _IOW('f', 8,struct ext4_new_group_input)
 #define        EXT4_IOC_GETVERSION_OLD         FS_IOC_GETVERSION
 #define        EXT4_IOC_SETVERSION_OLD         FS_IOC_SETVERSION
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
 #define EXT4_IOC_WAIT_FOR_READONLY     _IOR('f', 99, long)
 #endif
 #define EXT4_IOC_GETRSVSZ              _IOR('f', 5, long)
@@ -253,7 +260,7 @@ struct ext4_new_group_data {
 #define EXT4_IOC32_GETRSVSZ            _IOR('f', 5, int)
 #define EXT4_IOC32_SETRSVSZ            _IOW('f', 6, int)
 #define EXT4_IOC32_GROUP_EXTEND                _IOW('f', 7, unsigned int)
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
 #define EXT4_IOC32_WAIT_FOR_READONLY   _IOR('f', 99, int)
 #endif
 #define EXT4_IOC32_GETVERSION_OLD      FS_IOC32_GETVERSION
@@ -282,7 +289,7 @@ struct ext4_inode {
        __le16  i_uid;          /* Low 16 bits of Owner Uid */
        __le32  i_size;         /* Size in bytes */
        __le32  i_atime;        /* Access time */
-       __le32  i_ctime;        /* Creation time */
+       __le32  i_ctime;        /* Inode Change time */
        __le32  i_mtime;        /* Modification time */
        __le32  i_dtime;        /* Deletion Time */
        __le16  i_gid;          /* Low 16 bits of Group Id */
@@ -331,10 +338,85 @@ struct ext4_inode {
        } osd2;                         /* OS dependent 2 */
        __le16  i_extra_isize;
        __le16  i_pad1;
+       __le32  i_ctime_extra;  /* extra Change time      (nsec << 2 | epoch) */
+       __le32  i_mtime_extra;  /* extra Modification time(nsec << 2 | epoch) */
+       __le32  i_atime_extra;  /* extra Access time      (nsec << 2 | epoch) */
+       __le32  i_crtime;       /* File Creation time */
+       __le32  i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
 };
 
 #define i_size_high    i_dir_acl
 
+#define EXT4_EPOCH_BITS 2
+#define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
+#define EXT4_NSEC_MASK  (~0UL << EXT4_EPOCH_BITS)
+
+/*
+ * Extended fields will fit into an inode if the filesystem was formatted
+ * with large inodes (-I 256 or larger) and there are not currently any EAs
+ * consuming all of the available space. For new inodes we always reserve
+ * enough space for the kernel's known extended fields, but for inodes
+ * created with an old kernel this might not have been the case. None of
+ * the extended inode fields is critical for correct filesystem operation.
+ * This macro checks if a certain field fits in the inode. Note that
+ * inode-size = GOOD_OLD_INODE_SIZE + i_extra_isize
+ */
+#define EXT4_FITS_IN_INODE(ext4_inode, einode, field)  \
+       ((offsetof(typeof(*ext4_inode), field) +        \
+         sizeof((ext4_inode)->field))                  \
+       <= (EXT4_GOOD_OLD_INODE_SIZE +                  \
+           (einode)->i_extra_isize))                   \
+
+static inline __le32 ext4_encode_extra_time(struct timespec *time)
+{
+       return cpu_to_le32((sizeof(time->tv_sec) > 4 ?
+                          time->tv_sec >> 32 : 0) |
+                          ((time->tv_nsec << 2) & EXT4_NSEC_MASK));
+}
+
+static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra)
+{
+       if (sizeof(time->tv_sec) > 4)
+              time->tv_sec |= (__u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK)
+                              << 32;
+       time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> 2;
+}
+
+#define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode)                         \
+do {                                                                          \
+       (raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec);               \
+       if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra))     \
+               (raw_inode)->xtime ## _extra =                                 \
+                               ext4_encode_extra_time(&(inode)->xtime);       \
+} while (0)
+
+#define EXT4_EINODE_SET_XTIME(xtime, einode, raw_inode)                               \
+do {                                                                          \
+       if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime))                      \
+               (raw_inode)->xtime = cpu_to_le32((einode)->xtime.tv_sec);      \
+       if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra))            \
+               (raw_inode)->xtime ## _extra =                                 \
+                               ext4_encode_extra_time(&(einode)->xtime);      \
+} while (0)
+
+#define EXT4_INODE_GET_XTIME(xtime, inode, raw_inode)                         \
+do {                                                                          \
+       (inode)->xtime.tv_sec = (signed)le32_to_cpu((raw_inode)->xtime);       \
+       if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra))     \
+               ext4_decode_extra_time(&(inode)->xtime,                        \
+                                      raw_inode->xtime ## _extra);            \
+} while (0)
+
+#define EXT4_EINODE_GET_XTIME(xtime, einode, raw_inode)                               \
+do {                                                                          \
+       if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime))                      \
+               (einode)->xtime.tv_sec =                                       \
+                       (signed)le32_to_cpu((raw_inode)->xtime);               \
+       if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra))            \
+               ext4_decode_extra_time(&(einode)->xtime,                       \
+                                      raw_inode->xtime ## _extra);            \
+} while (0)
+
 #if defined(__KERNEL__) || defined(__linux__)
 #define i_reserved1    osd1.linux1.l_i_reserved1
 #define i_frag         osd2.linux2.l_i_frag
@@ -533,6 +615,13 @@ static inline struct ext4_inode_info *EXT4_I(struct inode *inode)
        return container_of(inode, struct ext4_inode_info, vfs_inode);
 }
 
+static inline struct timespec ext4_current_time(struct inode *inode)
+{
+       return (inode->i_sb->s_time_gran < NSEC_PER_SEC) ?
+               current_fs_time(inode->i_sb) : CURRENT_TIME_SEC;
+}
+
+
 static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
 {
        return ino == EXT4_ROOT_INO ||
@@ -603,6 +692,8 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
 #define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER    0x0001
 #define EXT4_FEATURE_RO_COMPAT_LARGE_FILE      0x0002
 #define EXT4_FEATURE_RO_COMPAT_BTREE_DIR       0x0004
+#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK       0x0020
+#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE     0x0040
 
 #define EXT4_FEATURE_INCOMPAT_COMPRESSION      0x0001
 #define EXT4_FEATURE_INCOMPAT_FILETYPE         0x0002
@@ -620,6 +711,8 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
                                         EXT4_FEATURE_INCOMPAT_64BIT)
 #define EXT4_FEATURE_RO_COMPAT_SUPP    (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
                                         EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
+                                        EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \
+                                        EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \
                                         EXT4_FEATURE_RO_COMPAT_BTREE_DIR)
 
 /*
@@ -862,6 +955,7 @@ extern int ext4_change_inode_journal_flag(struct inode *, int);
 extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *);
 extern void ext4_truncate (struct inode *);
 extern void ext4_set_inode_flags(struct inode *);
+extern void ext4_get_inode_flags(struct ext4_inode_info *);
 extern void ext4_set_aops(struct inode *inode);
 extern int ext4_writepage_trans_blocks(struct inode *);
 extern int ext4_block_truncate_page(handle_t *handle, struct page *page,
@@ -983,6 +1077,8 @@ extern int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
 extern void ext4_ext_truncate(struct inode *, struct page *);
 extern void ext4_ext_init(struct super_block *);
 extern void ext4_ext_release(struct super_block *);
+extern long ext4_fallocate(struct inode *inode, int mode, loff_t offset,
+                         loff_t len);
 static inline int
 ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
                        unsigned long max_blocks, struct buffer_head *bh,
index acfe59740b032d1a5adcfebaa69ca491c048cafa..81406f3655d4bd162c0ed0aade00c19de8666371 100644 (file)
@@ -141,7 +141,25 @@ typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *,
 
 #define EXT_MAX_BLOCK  0xffffffff
 
-#define EXT_MAX_LEN    ((1UL << 15) - 1)
+/*
+ * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an
+ * initialized extent. This is 2^15 and not (2^16 - 1), since we use the
+ * MSB of ee_len field in the extent datastructure to signify if this
+ * particular extent is an initialized extent or an uninitialized (i.e.
+ * preallocated).
+ * EXT_UNINIT_MAX_LEN is the maximum number of blocks we can have in an
+ * uninitialized extent.
+ * If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an
+ * uninitialized one. In other words, if MSB of ee_len is set, it is an
+ * uninitialized extent with only one special scenario when ee_len = 0x8000.
+ * In this case we can not have an uninitialized extent of zero length and
+ * thus we make it as a special case of initialized extent with 0x8000 length.
+ * This way we get better extent-to-group alignment for initialized extents.
+ * Hence, the maximum number of blocks we can have in an *initialized*
+ * extent is 2^15 (32768) and in an *uninitialized* extent is 2^15-1 (32767).
+ */
+#define EXT_INIT_MAX_LEN       (1UL << 15)
+#define EXT_UNINIT_MAX_LEN     (EXT_INIT_MAX_LEN - 1)
 
 
 #define EXT_FIRST_EXTENT(__hdr__) \
@@ -188,8 +206,31 @@ ext4_ext_invalidate_cache(struct inode *inode)
        EXT4_I(inode)->i_cached_extent.ec_type = EXT4_EXT_CACHE_NO;
 }
 
+static inline void ext4_ext_mark_uninitialized(struct ext4_extent *ext)
+{
+       /* We can not have an uninitialized extent of zero length! */
+       BUG_ON((le16_to_cpu(ext->ee_len) & ~EXT_INIT_MAX_LEN) == 0);
+       ext->ee_len |= cpu_to_le16(EXT_INIT_MAX_LEN);
+}
+
+static inline int ext4_ext_is_uninitialized(struct ext4_extent *ext)
+{
+       /* Extent with ee_len of 0x8000 is treated as an initialized extent */
+       return (le16_to_cpu(ext->ee_len) > EXT_INIT_MAX_LEN);
+}
+
+static inline int ext4_ext_get_actual_len(struct ext4_extent *ext)
+{
+       return (le16_to_cpu(ext->ee_len) <= EXT_INIT_MAX_LEN ?
+               le16_to_cpu(ext->ee_len) :
+               (le16_to_cpu(ext->ee_len) - EXT_INIT_MAX_LEN));
+}
+
 extern int ext4_extent_tree_init(handle_t *, struct inode *);
 extern int ext4_ext_calc_credits_for_insert(struct inode *, struct ext4_ext_path *);
+extern int ext4_ext_try_to_merge(struct inode *inode,
+                                struct ext4_ext_path *path,
+                                struct ext4_extent *);
 extern unsigned int ext4_ext_check_overlap(struct inode *, struct ext4_extent *, struct ext4_ext_path *);
 extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *);
 extern int ext4_ext_walk_space(struct inode *, unsigned long, unsigned long, ext_prepare_callback, void *);
index 9de4944069955a46e0183fbfe0a00adf04163270..1a511e9905aa2ae7d5c38a23da98644632eb6977 100644 (file)
@@ -153,6 +153,11 @@ struct ext4_inode_info {
 
        unsigned long i_ext_generation;
        struct ext4_ext_cache i_cached_extent;
+       /*
+        * File creation time. Its function is same as that of
+        * struct timespec i_{a,c,m}time in the generic inode.
+        */
+       struct timespec i_crtime;
 };
 
 #endif /* _LINUX_EXT4_FS_I */
index 2347557a327ae7b29dec75f153432cfda2c3137c..1b2ffee12be910095b846d0ca18a856c5ef75e82 100644 (file)
@@ -73,7 +73,7 @@ struct ext4_sb_info {
        struct list_head s_orphan;
        unsigned long s_commit_interval;
        struct block_device *journal_bdev;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
        struct timer_list turn_ro_timer;        /* For turning read-only (crash simulation) */
        wait_queue_head_t ro_wait_queue;        /* For people waiting for the fs to go read-only */
 #endif
@@ -81,6 +81,7 @@ struct ext4_sb_info {
        char *s_qf_names[MAXQUOTAS];            /* Names of quota files with journalled quota */
        int s_jquota_fmt;                       /* Format of quota to use */
 #endif
+       unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */
 
 #ifdef EXTENTS_STATS
        /* ext4 extents stats */
diff --git a/include/linux/falloc.h b/include/linux/falloc.h
new file mode 100644 (file)
index 0000000..8e912ab
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _FALLOC_H_
+#define _FALLOC_H_
+
+#define FALLOC_FL_KEEP_SIZE    0x01 /* default is extend size */
+
+#endif /* _FALLOC_H_ */
index 58ce336d4a6b1c36fec8debf8f962cb10d1ccae9..0b806c5e32eb4e06f28244c78513a29021bcb65b 100644 (file)
@@ -284,6 +284,7 @@ extern int dir_notify_enable;
 #include <linux/pid.h>
 #include <linux/mutex.h>
 #include <linux/sysctl.h>
+#include <linux/capability.h>
 
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
@@ -990,6 +991,9 @@ enum {
 #define put_fs_excl() atomic_dec(&current->fs_excl)
 #define has_fs_excl() atomic_read(&current->fs_excl)
 
+#define is_owner_or_cap(inode) \
+       ((current->fsuid == (inode)->i_uid) || capable(CAP_FOWNER))
+
 /* not quite ready to be deprecated, but... */
 extern void lock_super(struct super_block *);
 extern void unlock_super(struct super_block *);
@@ -1143,6 +1147,8 @@ struct inode_operations {
        ssize_t (*listxattr) (struct dentry *, char *, size_t);
        int (*removexattr) (struct dentry *, const char *);
        void (*truncate_range)(struct inode *, loff_t, loff_t);
+       long (*fallocate)(struct inode *inode, int mode, loff_t offset,
+                         loff_t len);
 };
 
 struct seq_file;
index f7a93770e1be864cd6f1ddb152784597fdac0101..7da02c93002b4fd1f955230463ce0354aee3da95 100644 (file)
@@ -39,6 +39,9 @@ enum {
        CTRL_CMD_NEWOPS,
        CTRL_CMD_DELOPS,
        CTRL_CMD_GETOPS,
+       CTRL_CMD_NEWMCAST_GRP,
+       CTRL_CMD_DELMCAST_GRP,
+       CTRL_CMD_GETMCAST_GRP, /* unused */
        __CTRL_CMD_MAX,
 };
 
@@ -52,6 +55,7 @@ enum {
        CTRL_ATTR_HDRSIZE,
        CTRL_ATTR_MAXATTR,
        CTRL_ATTR_OPS,
+       CTRL_ATTR_MCAST_GROUPS,
        __CTRL_ATTR_MAX,
 };
 
@@ -66,4 +70,13 @@ enum {
 
 #define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1)
 
+enum {
+       CTRL_ATTR_MCAST_GRP_UNSPEC,
+       CTRL_ATTR_MCAST_GRP_NAME,
+       CTRL_ATTR_MCAST_GRP_ID,
+       __CTRL_ATTR_MCAST_GRP_MAX,
+};
+
+#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1)
+
 #endif /* __LINUX_GENERIC_NETLINK_H */
index 0e0fedd2039a3866a51fe093fb6792ef527c1804..260d6d76c5f3b898cfafad1cbc67ca7e8015bba1 100644 (file)
  */
 #define JBD_DEFAULT_MAX_COMMIT_AGE 5
 
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
 /*
  * Define JBD_EXPENSIVE_CHECKING to enable more expensive internal
  * consistency checks.  By default we don't do this unless
- * CONFIG_JBD_DEBUG is on.
+ * CONFIG_JBD2_DEBUG is on.
  */
 #define JBD_EXPENSIVE_CHECKING
-extern int jbd2_journal_enable_debug;
+extern u8 jbd2_journal_enable_debug;
 
 #define jbd_debug(n, f, a...)                                          \
        do {                                                            \
index 10f505c8431dc320f46d77a88095df20cb475cb8..5dc13848891b4840cc68678d6cba2f9d232b1aa0 100644 (file)
@@ -36,13 +36,57 @@ static inline int request_module(const char * name, ...) { return -ENOSYS; }
 #define try_then_request_module(x, mod...) ((x) ?: (request_module(mod), (x)))
 
 struct key;
-extern int call_usermodehelper_keys(char *path, char *argv[], char *envp[],
-                                   struct key *session_keyring, int wait);
+struct file;
+struct subprocess_info;
+
+/* Allocate a subprocess_info structure */
+struct subprocess_info *call_usermodehelper_setup(char *path,
+                                                 char **argv, char **envp);
+
+/* Set various pieces of state into the subprocess_info structure */
+void call_usermodehelper_setkeys(struct subprocess_info *info,
+                                struct key *session_keyring);
+int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
+                                 struct file **filp);
+void call_usermodehelper_setcleanup(struct subprocess_info *info,
+                                   void (*cleanup)(char **argv, char **envp));
+
+enum umh_wait {
+       UMH_NO_WAIT = -1,       /* don't wait at all */
+       UMH_WAIT_EXEC = 0,      /* wait for the exec, but not the process */
+       UMH_WAIT_PROC = 1,      /* wait for the process to complete */
+};
+
+/* Actually execute the sub-process */
+int call_usermodehelper_exec(struct subprocess_info *info, enum umh_wait wait);
+
+/* Free the subprocess_info. This is only needed if you're not going
+   to call call_usermodehelper_exec */
+void call_usermodehelper_freeinfo(struct subprocess_info *info);
 
 static inline int
-call_usermodehelper(char *path, char **argv, char **envp, int wait)
+call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait)
 {
-       return call_usermodehelper_keys(path, argv, envp, NULL, wait);
+       struct subprocess_info *info;
+
+       info = call_usermodehelper_setup(path, argv, envp);
+       if (info == NULL)
+               return -ENOMEM;
+       return call_usermodehelper_exec(info, wait);
+}
+
+static inline int
+call_usermodehelper_keys(char *path, char **argv, char **envp,
+                        struct key *session_keyring, enum umh_wait wait)
+{
+       struct subprocess_info *info;
+
+       info = call_usermodehelper_setup(path, argv, envp);
+       if (info == NULL)
+               return -ENOMEM;
+
+       call_usermodehelper_setkeys(info, session_keyring);
+       return call_usermodehelper_exec(info, wait);
 }
 
 extern void usermodehelper_init(void);
index 9d713c03e3da681664b31fb55e0ecb82df5cc072..36cc20dfd1427398daaad3a7b2fc0faeaaa04e93 100644 (file)
@@ -13,7 +13,6 @@
 #define HPFS_SUPER_MAGIC       0xf995e849
 #define ISOFS_SUPER_MAGIC      0x9660
 #define JFFS2_SUPER_MAGIC      0x72b6
-#define KVMFS_SUPER_MAGIC      0x19700426
 #define ANON_INODE_FS_MAGIC    0x09041934
 
 #define MINIX_SUPER_MAGIC      0x137F          /* original minix fs */
index 7e7c9093919af3ab51461e7c14c849008ca582d6..0cb98053537af4874ef83cfc149c6af629758694 100644 (file)
 #define VXSPEC_MAJOR           200     /* VERITAS volume config driver */
 #define VXDMP_MAJOR            201     /* VERITAS volume multipath driver */
 
+#define XENVBD_MAJOR           202     /* Xen virtual block device */
+
 #define MSR_MAJOR              202
 #define CPUID_MAJOR            203
 
index da7a13c97eb8c2ae21048724be12ec60ca0bf927..9820ca1e45e251fde417743e4ee1ac98c65937d4 100644 (file)
@@ -1098,10 +1098,8 @@ extern int               dev_mc_delete(struct net_device *dev, void *addr, int alen, int all
 extern int             dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly);
 extern int             dev_mc_sync(struct net_device *to, struct net_device *from);
 extern void            dev_mc_unsync(struct net_device *to, struct net_device *from);
-extern void            dev_mc_discard(struct net_device *dev);
 extern int             __dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int all);
 extern int             __dev_addr_add(struct dev_addr_list **list, int *count, void *addr, int alen, int newonly);
-extern void            __dev_addr_discard(struct dev_addr_list **list);
 extern void            dev_set_promiscuity(struct net_device *dev, int inc);
 extern void            dev_set_allmulti(struct net_device *dev, int inc);
 extern void            netdev_state_change(struct net_device *dev);
index 34ab0fb736e2f75d057ea3c6e2bd1d9a65410eaf..a92fefc3c7ecbc222f76694101c600886f61b6da 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _IPT_IPRANGE_H
 #define _IPT_IPRANGE_H
 
+#include <linux/types.h>
+
 #define IPRANGE_SRC            0x01    /* Match source IP address */
 #define IPRANGE_DST            0x02    /* Match destination IP address */
 #define IPRANGE_SRC_INV                0x10    /* Negate the condition */
index 2e23353c28a54c5757269d16b3491076a344134f..83d8239f0cce60ae79b79b7adaab7670073839cc 100644 (file)
@@ -161,6 +161,8 @@ extern struct sock *netlink_kernel_create(int unit, unsigned int groups,
                                          void (*input)(struct sock *sk, int len),
                                          struct mutex *cb_mutex,
                                          struct module *module);
+extern int netlink_change_ngroups(struct sock *sk, unsigned int groups);
+extern void netlink_clear_multicast_users(struct sock *sk, unsigned int group);
 extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
 extern int netlink_has_listeners(struct sock *sk, unsigned int group);
 extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
index 9431101bf8769508db8dc6263927049d1cfdb9df..576f2bb34cc80dcc84271c874fc47e0bf16cc50e 100644 (file)
@@ -196,6 +196,8 @@ extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
 #define CPU_DEAD               0x0007 /* CPU (unsigned)v dead */
 #define CPU_LOCK_ACQUIRE       0x0008 /* Acquire all hotcpu locks */
 #define CPU_LOCK_RELEASE       0x0009 /* Release all hotcpu locks */
+#define CPU_DYING              0x000A /* CPU (unsigned)v not running any task,
+                                       * not handling interrupts, soon dead */
 
 /* Used for CPU hotplug events occuring while tasks are frozen due to a suspend
  * operation in progress
@@ -208,6 +210,7 @@ extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
 #define CPU_DOWN_PREPARE_FROZEN        (CPU_DOWN_PREPARE | CPU_TASKS_FROZEN)
 #define CPU_DOWN_FAILED_FROZEN (CPU_DOWN_FAILED | CPU_TASKS_FROZEN)
 #define CPU_DEAD_FROZEN                (CPU_DEAD | CPU_TASKS_FROZEN)
+#define CPU_DYING_FROZEN       (CPU_DYING | CPU_TASKS_FROZEN)
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_NOTIFIER_H */
index ae2d79f2107e35fc81c72bf435f223787f4e304f..731cd2ac32274d744ac250893cb46b933a6bfb17 100644 (file)
@@ -92,6 +92,7 @@
 
 /* PG_owner_priv_1 users should have descriptive aliases */
 #define PG_checked             PG_owner_priv_1 /* Used by some filesystems */
+#define PG_pinned              PG_owner_priv_1 /* Xen pinned pagetable */
 
 #if (BITS_PER_LONG > 32)
 /*
@@ -170,6 +171,10 @@ static inline void SetPageUptodate(struct page *page)
 #define SetPageChecked(page)   set_bit(PG_checked, &(page)->flags)
 #define ClearPageChecked(page) clear_bit(PG_checked, &(page)->flags)
 
+#define PagePinned(page)       test_bit(PG_pinned, &(page)->flags)
+#define SetPagePinned(page)    set_bit(PG_pinned, &(page)->flags)
+#define ClearPagePinned(page)  clear_bit(PG_pinned, &(page)->flags)
+
 #define PageReserved(page)     test_bit(PG_reserved, &(page)->flags)
 #define SetPageReserved(page)  set_bit(PG_reserved, &(page)->flags)
 #define ClearPageReserved(page)        clear_bit(PG_reserved, &(page)->flags)
index 1dd1c707311fa0f1e5683547540d1f3edac48e21..85ea63f462af39fe0b589ac236baae4ee2831b39 100644 (file)
@@ -67,6 +67,11 @@ extern void kernel_power_off(void);
 
 void ctrl_alt_del(void);
 
+#define POWEROFF_CMD_PATH_LEN  256
+extern char poweroff_cmd[POWEROFF_CMD_PATH_LEN];
+
+extern int orderly_poweroff(bool force);
+
 /*
  * Emergency restart, callable from an interrupt handler.
  */
index 706ee9a4c80ca50d956c358e07630f68cf6669ed..8518fa2a6f89038d36ceac34c436a3519d69e8ee 100644 (file)
@@ -60,6 +60,8 @@ void serial8250_unregister_port(int line);
 void serial8250_suspend_port(int line);
 void serial8250_resume_port(int line);
 
+extern int early_serial_setup(struct uart_port *port);
+
 extern int serial8250_find_port(struct uart_port *p);
 extern int serial8250_find_port_for_earlycon(void);
 extern int setup_early_serial8250_console(char *cmdline);
index 9c721cd2c9d67a3ba0684d55c0d342c3340f6f27..773d8d8828ad77bb7006e039232b4d6bf6900dca 100644 (file)
@@ -62,8 +62,9 @@
 /* NEC v850.  */
 #define PORT_V850E_UART        40
 
-/* DZ */
-#define PORT_DZ                47
+/* DEC */
+#define PORT_DZ                46
+#define PORT_ZS                47
 
 /* Parisc type numbers. */
 #define PORT_MUX       48
index a2daf2d418a9dbdc50674529671dee07c6fbc9c6..59a3fa476ab9f7afe3f407c72b616c23143324a7 100644 (file)
@@ -33,14 +33,4 @@ static inline void *__kmalloc(size_t size, gfp_t flags)
        return kmalloc(size, flags);
 }
 
-/**
- * kzalloc - allocate memory. The memory is set to zero.
- * @size: how many bytes of memory are required.
- * @flags: the type of memory to allocate (see kcalloc).
- */
-static inline void *kzalloc(size_t size, gfp_t flags)
-{
-       return __kzalloc(size, flags);
-}
-
 #endif /* __LINUX_SLOB_DEF_H */
index 96ac21f8dd735ae2db06d9f16048bec4c8e40a23..259a13c3bd98eda779379be1c5df5e37aae6c73e 100644 (file)
@@ -99,11 +99,14 @@ static inline int up_smp_call_function(void)
 static inline void smp_send_reschedule(int cpu) { }
 #define num_booting_cpus()                     1
 #define smp_prepare_boot_cpu()                 do {} while (0)
-static inline int smp_call_function_single(int cpuid, void (*func) (void *info),
-                                          void *info, int retry, int wait)
-{
-       return -EBUSY;
-}
+#define smp_call_function_single(cpuid, func, info, retry, wait) \
+({ \
+       WARN_ON(cpuid != 0);    \
+       local_irq_disable();    \
+       (func)(info);           \
+       local_irq_enable();     \
+       0;                      \
+})
 
 #endif /* !SMP */
 
index 7f2eb6a477f9d60f6f85c49903612aa124b34f6d..836062b7582a95d23878b994144f5cba85d4ce34 100644 (file)
@@ -105,8 +105,12 @@ extern void * memchr(const void *,int,__kernel_size_t);
 #endif
 
 extern char *kstrdup(const char *s, gfp_t gfp);
+extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
 extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
 
+extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
+extern void argv_free(char **argv);
+
 #ifdef __cplusplus
 }
 #endif
index 83d0ec11235e1ccc2b405fe37f99a00f15e894d7..7a8b1e3322e072baf4f55550a1d746f91644121e 100644 (file)
@@ -610,6 +610,7 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas
 asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
                            const struct itimerspec __user *utmr);
 asmlinkage long sys_eventfd(unsigned int count);
+asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len);
 
 int kernel_execve(const char *filename, char *const argv[], char *const envp[]);
 
index 132b260aef1e5afeee3529eed8d282a9342e6bbe..c2b10cae5da52d06bf9c62a36aae5d36e24df6d4 100644 (file)
@@ -70,6 +70,10 @@ extern int map_vm_area(struct vm_struct *area, pgprot_t prot,
                        struct page ***pages);
 extern void unmap_kernel_range(unsigned long addr, unsigned long size);
 
+/* Allocate/destroy a 'vmalloc' VM area. */
+extern struct vm_struct *alloc_vm_area(size_t size);
+extern void free_vm_area(struct vm_struct *area);
+
 /*
  *     Internals.  Dont't use..
  */
index d3f4f5a38214bd31cee806b424faa97065b76bab..67703249b2454b4adb54ed2731bfdd07a63e6462 100644 (file)
@@ -114,7 +114,7 @@ struct saa7146_dev
        struct mutex                    lock;
 
        unsigned char                   __iomem *mem;           /* pointer to mapped IO memory */
-       int                             revision;       /* chip revision; needed for bug-workarounds*/
+       u32                             revision;       /* chip revision; needed for bug-workarounds*/
 
        /* pci-device & irq stuff*/
        char                            name[32];
@@ -157,8 +157,8 @@ struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc);
 int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt);
 void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt);
 int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length );
-char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt);
-void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, char *mem, struct saa7146_pgtable *pt);
+void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt);
+void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt);
 void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data);
 int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop);
 
index 6dcf3c45707d637518aef5b74d700fe8b2d261d7..160381c72e4bcdf5c930d0fa9f3db60f3cde86af 100644 (file)
@@ -23,8 +23,6 @@
 #define _TUNER_H
 
 #include <linux/videodev2.h>
-#include <linux/i2c.h>
-#include <media/tuner-types.h>
 
 extern int tuner_debug;
 
@@ -124,6 +122,7 @@ extern int tuner_debug;
 #define TUNER_THOMSON_FE6600           72      /* DViCO FusionHDTV DVB-T Hybrid */
 #define TUNER_SAMSUNG_TCPG_6121P30A     73     /* Hauppauge PVR-500 PAL */
 #define TUNER_TDA9887                   74      /* This tuner should be used only internally */
+#define TUNER_TEA5761                  75      /* Only FM Radio Tuner */
 
 /* tv card specific */
 #define TDA9887_PRESENT                (1<<0)
@@ -182,74 +181,6 @@ struct tuner_setup {
        int (*tuner_callback) (void *dev, int command,int arg);
 };
 
-struct tuner {
-       /* device */
-       struct i2c_client i2c;
-
-       unsigned int type;      /* chip type */
-
-       unsigned int mode;
-       unsigned int mode_mask; /* Combination of allowable modes */
-
-       unsigned int tv_freq;   /* keep track of the current settings */
-       unsigned int radio_freq;
-       u16          last_div;
-       unsigned int audmode;
-       v4l2_std_id  std;
-
-       int          using_v4l2;
-
-       /* used by tda9887 */
-       unsigned int       tda9887_config;
-       unsigned char      tda9887_data[4];
-
-       /* used by MT2032 */
-       unsigned int xogc;
-       unsigned int radio_if2;
-
-       /* used by tda8290 */
-       unsigned char tda8290_easy_mode;
-       unsigned char tda827x_lpsel;
-       unsigned char tda827x_addr;
-       unsigned char tda827x_ver;
-       unsigned int sgIF;
-
-       unsigned int config;
-       int (*tuner_callback) (void *dev, int command,int arg);
-
-       /* function ptrs */
-       void (*set_tv_freq)(struct i2c_client *c, unsigned int freq);
-       void (*set_radio_freq)(struct i2c_client *c, unsigned int freq);
-       int  (*has_signal)(struct i2c_client *c);
-       int  (*is_stereo)(struct i2c_client *c);
-       int  (*get_afc)(struct i2c_client *c);
-       void (*tuner_status)(struct i2c_client *c);
-       void (*standby)(struct i2c_client *c);
-};
-
-extern unsigned const int tuner_count;
-
-extern int microtune_init(struct i2c_client *c);
-extern int xc3028_init(struct i2c_client *c);
-extern int tda8290_init(struct i2c_client *c);
-extern int tda8290_probe(struct i2c_client *c);
-extern int tea5767_tuner_init(struct i2c_client *c);
-extern int default_tuner_init(struct i2c_client *c);
-extern int tea5767_autodetection(struct i2c_client *c);
-extern int tda9887_tuner_init(struct i2c_client *c);
-
-#define tuner_warn(fmt, arg...) do {\
-       printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
-                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-#define tuner_info(fmt, arg...) do {\
-       printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
-                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-#define tuner_dbg(fmt, arg...) do {\
-       extern int tuner_debug; \
-       if (tuner_debug) \
-               printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
-                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-
 #endif /* __KERNEL__ */
 
 #endif /* _TUNER_H */
index fa479c71aa34bc6c0cf8738dcb2810b984b89294..74efa77634790f6ab0ad4c1395f543f13211c304 100644 (file)
@@ -74,42 +74,13 @@ enum {
        UBI_COMPAT_REJECT   = 5
 };
 
-/*
- * ubi16_t/ubi32_t/ubi64_t - 16, 32, and 64-bit integers used in UBI on-flash
- * data structures.
- */
-typedef struct {
-       uint16_t int16;
-} __attribute__ ((packed)) ubi16_t;
-
-typedef struct {
-       uint32_t int32;
-} __attribute__ ((packed)) ubi32_t;
-
-typedef struct {
-       uint64_t int64;
-} __attribute__ ((packed)) ubi64_t;
-
-/*
- * In this implementation of UBI uses the big-endian format for on-flash
- * integers. The below are the corresponding conversion macros.
- */
-#define cpu_to_ubi16(x) ((ubi16_t){__cpu_to_be16(x)})
-#define ubi16_to_cpu(x) ((uint16_t)__be16_to_cpu((x).int16))
-
-#define cpu_to_ubi32(x) ((ubi32_t){__cpu_to_be32(x)})
-#define ubi32_to_cpu(x) ((uint32_t)__be32_to_cpu((x).int32))
-
-#define cpu_to_ubi64(x) ((ubi64_t){__cpu_to_be64(x)})
-#define ubi64_to_cpu(x) ((uint64_t)__be64_to_cpu((x).int64))
-
 /* Sizes of UBI headers */
 #define UBI_EC_HDR_SIZE  sizeof(struct ubi_ec_hdr)
 #define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr)
 
 /* Sizes of UBI headers without the ending CRC */
-#define UBI_EC_HDR_SIZE_CRC  (UBI_EC_HDR_SIZE  - sizeof(ubi32_t))
-#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(ubi32_t))
+#define UBI_EC_HDR_SIZE_CRC  (UBI_EC_HDR_SIZE  - sizeof(__be32))
+#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32))
 
 /**
  * struct ubi_ec_hdr - UBI erase counter header.
@@ -137,14 +108,14 @@ typedef struct {
  * eraseblocks.
  */
 struct ubi_ec_hdr {
-       ubi32_t magic;
-       uint8_t version;
-       uint8_t padding1[3];
-       ubi64_t ec; /* Warning: the current limit is 31-bit anyway! */
-       ubi32_t vid_hdr_offset;
-       ubi32_t data_offset;
-       uint8_t padding2[36];
-       ubi32_t hdr_crc;
+       __be32  magic;
+       __u8    version;
+       __u8    padding1[3];
+       __be64  ec; /* Warning: the current limit is 31-bit anyway! */
+       __be32  vid_hdr_offset;
+       __be32  data_offset;
+       __u8    padding2[36];
+       __be32  hdr_crc;
 } __attribute__ ((packed));
 
 /**
@@ -262,22 +233,22 @@ struct ubi_ec_hdr {
  * software (say, cramfs) on top of the UBI volume.
  */
 struct ubi_vid_hdr {
-       ubi32_t magic;
-       uint8_t version;
-       uint8_t vol_type;
-       uint8_t copy_flag;
-       uint8_t compat;
-       ubi32_t vol_id;
-       ubi32_t lnum;
-       ubi32_t leb_ver; /* obsolete, to be removed, don't use */
-       ubi32_t data_size;
-       ubi32_t used_ebs;
-       ubi32_t data_pad;
-       ubi32_t data_crc;
-       uint8_t padding1[4];
-       ubi64_t sqnum;
-       uint8_t padding2[12];
-       ubi32_t hdr_crc;
+       __be32  magic;
+       __u8    version;
+       __u8    vol_type;
+       __u8    copy_flag;
+       __u8    compat;
+       __be32  vol_id;
+       __be32  lnum;
+       __be32  leb_ver; /* obsolete, to be removed, don't use */
+       __be32  data_size;
+       __be32  used_ebs;
+       __be32  data_pad;
+       __be32  data_crc;
+       __u8    padding1[4];
+       __be64  sqnum;
+       __u8    padding2[12];
+       __be32  hdr_crc;
 } __attribute__ ((packed));
 
 /* Internal UBI volumes count */
@@ -306,7 +277,7 @@ struct ubi_vid_hdr {
 #define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
 
 /* Size of the volume table record without the ending CRC */
-#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(ubi32_t))
+#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32))
 
 /**
  * struct ubi_vtbl_record - a record in the volume table.
@@ -346,15 +317,15 @@ struct ubi_vid_hdr {
  * Empty records contain all zeroes and the CRC checksum of those zeroes.
  */
 struct ubi_vtbl_record {
-       ubi32_t reserved_pebs;
-       ubi32_t alignment;
-       ubi32_t data_pad;
-       uint8_t vol_type;
-       uint8_t upd_marker;
-       ubi16_t name_len;
-       uint8_t name[UBI_VOL_NAME_MAX+1];
-       uint8_t padding2[24];
-       ubi32_t crc;
+       __be32  reserved_pebs;
+       __be32  alignment;
+       __be32  data_pad;
+       __u8    vol_type;
+       __u8    upd_marker;
+       __be16  name_len;
+       __u8    name[UBI_VOL_NAME_MAX+1];
+       __u8    padding2[24];
+       __be32  crc;
 } __attribute__ ((packed));
 
 #endif /* !__UBI_HEADER_H__ */
index b6eaca122db871ab4b269a99dcbabda0fe9bcf90..decdda54682970302164242f8982ceeee669773d 100644 (file)
@@ -4,6 +4,22 @@
 #include <linux/genetlink.h>
 #include <net/netlink.h>
 
+/**
+ * struct genl_multicast_group - generic netlink multicast group
+ * @name: name of the multicast group, names are per-family
+ * @id: multicast group ID, assigned by the core, to use with
+ *      genlmsg_multicast().
+ * @list: list entry for linking
+ * @family: pointer to family, need not be set before registering
+ */
+struct genl_multicast_group
+{
+       struct genl_family      *family;        /* private */
+       struct list_head        list;           /* private */
+       char                    name[GENL_NAMSIZ];
+       u32                     id;
+};
+
 /**
  * struct genl_family - generic netlink family
  * @id: protocol family idenfitier
@@ -14,6 +30,7 @@
  * @attrbuf: buffer to store parsed attributes
  * @ops_list: list of all assigned operations
  * @family_list: family list
+ * @mcast_groups: multicast groups list
  */
 struct genl_family
 {
@@ -25,6 +42,7 @@ struct genl_family
        struct nlattr **        attrbuf;        /* private */
        struct list_head        ops_list;       /* private */
        struct list_head        family_list;    /* private */
+       struct list_head        mcast_groups;   /* private */
 };
 
 /**
@@ -73,6 +91,10 @@ extern int genl_register_family(struct genl_family *family);
 extern int genl_unregister_family(struct genl_family *family);
 extern int genl_register_ops(struct genl_family *, struct genl_ops *ops);
 extern int genl_unregister_ops(struct genl_family *, struct genl_ops *ops);
+extern int genl_register_mc_group(struct genl_family *family,
+                                 struct genl_multicast_group *grp);
+extern void genl_unregister_mc_group(struct genl_family *family,
+                                    struct genl_multicast_group *grp);
 
 extern struct sock *genl_sock;
 
index a8af9ae0017719bb7071ef5b34faa2c3f751a7b3..8b404b1ef7c8ed7ba6025e8e7dab582105b0c1ae 100644 (file)
@@ -652,8 +652,7 @@ struct tcp_congestion_ops {
        /* lower bound for congestion window (optional) */
        u32 (*min_cwnd)(const struct sock *sk);
        /* do new cwnd calculation (required) */
-       void (*cong_avoid)(struct sock *sk, u32 ack,
-                          u32 rtt, u32 in_flight, int good_ack);
+       void (*cong_avoid)(struct sock *sk, u32 ack, u32 in_flight, int good_ack);
        /* call before changing ca_state (optional) */
        void (*set_state)(struct sock *sk, u8 new_state);
        /* call when cwnd event occurs (optional) */
@@ -684,8 +683,7 @@ extern void tcp_slow_start(struct tcp_sock *tp);
 
 extern struct tcp_congestion_ops tcp_init_congestion_ops;
 extern u32 tcp_reno_ssthresh(struct sock *sk);
-extern void tcp_reno_cong_avoid(struct sock *sk, u32 ack,
-                               u32 rtt, u32 in_flight, int flag);
+extern void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight, int flag);
 extern u32 tcp_reno_min_cwnd(const struct sock *sk);
 extern struct tcp_congestion_ops tcp_reno;
 
index ae959e9501747ba2398db26d9035234718a5fe7d..a5f80bfbaaa467757f1ee4d45fe610c38622e652 100644 (file)
@@ -585,7 +585,6 @@ static inline int xfrm_sec_ctx_match(struct xfrm_sec_ctx *s1, struct xfrm_sec_ct
 struct xfrm_dst
 {
        union {
-               struct xfrm_dst         *next;
                struct dst_entry        dst;
                struct rtable           rt;
                struct rt6_info         rt6;
diff --git a/include/xen/events.h b/include/xen/events.h
new file mode 100644 (file)
index 0000000..2bde54d
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef _XEN_EVENTS_H
+#define _XEN_EVENTS_H
+
+#include <linux/interrupt.h>
+
+#include <xen/interface/event_channel.h>
+#include <asm/xen/hypercall.h>
+
+enum ipi_vector {
+       XEN_RESCHEDULE_VECTOR,
+       XEN_CALL_FUNCTION_VECTOR,
+
+       XEN_NR_IPIS,
+};
+
+int bind_evtchn_to_irq(unsigned int evtchn);
+int bind_evtchn_to_irqhandler(unsigned int evtchn,
+                             irq_handler_t handler,
+                             unsigned long irqflags, const char *devname,
+                             void *dev_id);
+int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
+                           irq_handler_t handler,
+                           unsigned long irqflags, const char *devname,
+                           void *dev_id);
+int bind_ipi_to_irqhandler(enum ipi_vector ipi,
+                          unsigned int cpu,
+                          irq_handler_t handler,
+                          unsigned long irqflags,
+                          const char *devname,
+                          void *dev_id);
+
+/*
+ * Common unbind function for all event sources. Takes IRQ to unbind from.
+ * Automatically closes the underlying event channel (even for bindings
+ * made with bind_evtchn_to_irqhandler()).
+ */
+void unbind_from_irqhandler(unsigned int irq, void *dev_id);
+
+void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector);
+
+static inline void notify_remote_via_evtchn(int port)
+{
+       struct evtchn_send send = { .port = port };
+       (void)HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
+}
+
+extern void notify_remote_via_irq(int irq);
+#endif /* _XEN_EVENTS_H */
diff --git a/include/xen/features.h b/include/xen/features.h
new file mode 100644 (file)
index 0000000..27292d4
--- /dev/null
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * features.h
+ *
+ * Query the features reported by Xen.
+ *
+ * Copyright (c) 2006, Ian Campbell
+ */
+
+#ifndef __XEN_FEATURES_H__
+#define __XEN_FEATURES_H__
+
+#include <xen/interface/features.h>
+
+void xen_setup_features(void);
+
+extern u8 xen_features[XENFEAT_NR_SUBMAPS * 32];
+
+static inline int xen_feature(int flag)
+{
+       return xen_features[flag];
+}
+
+#endif /* __ASM_XEN_FEATURES_H__ */
diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h
new file mode 100644 (file)
index 0000000..761c834
--- /dev/null
@@ -0,0 +1,107 @@
+/******************************************************************************
+ * grant_table.h
+ *
+ * Two sets of functionality:
+ * 1. Granting foreign access to our memory reservation.
+ * 2. Accessing others' memory reservations via grant references.
+ * (i.e., mechanisms for both sender and recipient of grant references)
+ *
+ * Copyright (c) 2004-2005, K A Fraser
+ * Copyright (c) 2005, Christopher Clark
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __ASM_GNTTAB_H__
+#define __ASM_GNTTAB_H__
+
+#include <asm/xen/hypervisor.h>
+#include <xen/interface/grant_table.h>
+
+/* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */
+#define NR_GRANT_FRAMES 4
+
+struct gnttab_free_callback {
+       struct gnttab_free_callback *next;
+       void (*fn)(void *);
+       void *arg;
+       u16 count;
+};
+
+int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
+                               int readonly);
+
+/*
+ * End access through the given grant reference, iff the grant entry is no
+ * longer in use.  Return 1 if the grant entry was freed, 0 if it is still in
+ * use.
+ */
+int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly);
+
+/*
+ * Eventually end access through the given grant reference, and once that
+ * access has been ended, free the given page too.  Access will be ended
+ * immediately iff the grant entry is not in use, otherwise it will happen
+ * some time later.  page may be 0, in which case no freeing will occur.
+ */
+void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
+                              unsigned long page);
+
+int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn);
+
+unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref);
+unsigned long gnttab_end_foreign_transfer(grant_ref_t ref);
+
+int gnttab_query_foreign_access(grant_ref_t ref);
+
+/*
+ * operations on reserved batches of grant references
+ */
+int gnttab_alloc_grant_references(u16 count, grant_ref_t *pprivate_head);
+
+void gnttab_free_grant_reference(grant_ref_t ref);
+
+void gnttab_free_grant_references(grant_ref_t head);
+
+int gnttab_empty_grant_references(const grant_ref_t *pprivate_head);
+
+int gnttab_claim_grant_reference(grant_ref_t *pprivate_head);
+
+void gnttab_release_grant_reference(grant_ref_t *private_head,
+                                   grant_ref_t release);
+
+void gnttab_request_free_callback(struct gnttab_free_callback *callback,
+                                 void (*fn)(void *), void *arg, u16 count);
+void gnttab_cancel_free_callback(struct gnttab_free_callback *callback);
+
+void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
+                                    unsigned long frame, int readonly);
+
+void gnttab_grant_foreign_transfer_ref(grant_ref_t, domid_t domid,
+                                      unsigned long pfn);
+
+#define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr))
+
+#endif /* __ASM_GNTTAB_H__ */
diff --git a/include/xen/hvc-console.h b/include/xen/hvc-console.h
new file mode 100644 (file)
index 0000000..21c0ecf
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef XEN_HVC_CONSOLE_H
+#define XEN_HVC_CONSOLE_H
+
+extern struct console xenboot_console;
+
+#endif /* XEN_HVC_CONSOLE_H */
diff --git a/include/xen/interface/elfnote.h b/include/xen/interface/elfnote.h
new file mode 100644 (file)
index 0000000..a64d3df
--- /dev/null
@@ -0,0 +1,133 @@
+/******************************************************************************
+ * elfnote.h
+ *
+ * Definitions used for the Xen ELF notes.
+ *
+ * Copyright (c) 2006, Ian Campbell, XenSource Ltd.
+ */
+
+#ifndef __XEN_PUBLIC_ELFNOTE_H__
+#define __XEN_PUBLIC_ELFNOTE_H__
+
+/*
+ * The notes should live in a SHT_NOTE segment and have "Xen" in the
+ * name field.
+ *
+ * Numeric types are either 4 or 8 bytes depending on the content of
+ * the desc field.
+ *
+ * LEGACY indicated the fields in the legacy __xen_guest string which
+ * this a note type replaces.
+ */
+
+/*
+ * NAME=VALUE pair (string).
+ *
+ * LEGACY: FEATURES and PAE
+ */
+#define XEN_ELFNOTE_INFO           0
+
+/*
+ * The virtual address of the entry point (numeric).
+ *
+ * LEGACY: VIRT_ENTRY
+ */
+#define XEN_ELFNOTE_ENTRY          1
+
+/* The virtual address of the hypercall transfer page (numeric).
+ *
+ * LEGACY: HYPERCALL_PAGE. (n.b. legacy value is a physical page
+ * number not a virtual address)
+ */
+#define XEN_ELFNOTE_HYPERCALL_PAGE 2
+
+/* The virtual address where the kernel image should be mapped (numeric).
+ *
+ * Defaults to 0.
+ *
+ * LEGACY: VIRT_BASE
+ */
+#define XEN_ELFNOTE_VIRT_BASE      3
+
+/*
+ * The offset of the ELF paddr field from the acutal required
+ * psuedo-physical address (numeric).
+ *
+ * This is used to maintain backwards compatibility with older kernels
+ * which wrote __PAGE_OFFSET into that field. This field defaults to 0
+ * if not present.
+ *
+ * LEGACY: ELF_PADDR_OFFSET. (n.b. legacy default is VIRT_BASE)
+ */
+#define XEN_ELFNOTE_PADDR_OFFSET   4
+
+/*
+ * The version of Xen that we work with (string).
+ *
+ * LEGACY: XEN_VER
+ */
+#define XEN_ELFNOTE_XEN_VERSION    5
+
+/*
+ * The name of the guest operating system (string).
+ *
+ * LEGACY: GUEST_OS
+ */
+#define XEN_ELFNOTE_GUEST_OS       6
+
+/*
+ * The version of the guest operating system (string).
+ *
+ * LEGACY: GUEST_VER
+ */
+#define XEN_ELFNOTE_GUEST_VERSION  7
+
+/*
+ * The loader type (string).
+ *
+ * LEGACY: LOADER
+ */
+#define XEN_ELFNOTE_LOADER         8
+
+/*
+ * The kernel supports PAE (x86/32 only, string = "yes" or "no").
+ *
+ * LEGACY: PAE (n.b. The legacy interface included a provision to
+ * indicate 'extended-cr3' support allowing L3 page tables to be
+ * placed above 4G. It is assumed that any kernel new enough to use
+ * these ELF notes will include this and therefore "yes" here is
+ * equivalent to "yes[entended-cr3]" in the __xen_guest interface.
+ */
+#define XEN_ELFNOTE_PAE_MODE       9
+
+/*
+ * The features supported/required by this kernel (string).
+ *
+ * The string must consist of a list of feature names (as given in
+ * features.h, without the "XENFEAT_" prefix) separated by '|'
+ * characters. If a feature is required for the kernel to function
+ * then the feature name must be preceded by a '!' character.
+ *
+ * LEGACY: FEATURES
+ */
+#define XEN_ELFNOTE_FEATURES      10
+
+/*
+ * The kernel requires the symbol table to be loaded (string = "yes" or "no")
+ * LEGACY: BSD_SYMTAB (n.b. The legacy treated the presence or absence
+ * of this string as a boolean flag rather than requiring "yes" or
+ * "no".
+ */
+#define XEN_ELFNOTE_BSD_SYMTAB    11
+
+#endif /* __XEN_PUBLIC_ELFNOTE_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/include/xen/interface/event_channel.h b/include/xen/interface/event_channel.h
new file mode 100644 (file)
index 0000000..919b5bd
--- /dev/null
@@ -0,0 +1,195 @@
+/******************************************************************************
+ * event_channel.h
+ *
+ * Event channels between domains.
+ *
+ * Copyright (c) 2003-2004, K A Fraser.
+ */
+
+#ifndef __XEN_PUBLIC_EVENT_CHANNEL_H__
+#define __XEN_PUBLIC_EVENT_CHANNEL_H__
+
+typedef uint32_t evtchn_port_t;
+DEFINE_GUEST_HANDLE(evtchn_port_t);
+
+/*
+ * EVTCHNOP_alloc_unbound: Allocate a port in domain <dom> and mark as
+ * accepting interdomain bindings from domain <remote_dom>. A fresh port
+ * is allocated in <dom> and returned as <port>.
+ * NOTES:
+ *  1. If the caller is unprivileged then <dom> must be DOMID_SELF.
+ *  2. <rdom> may be DOMID_SELF, allowing loopback connections.
+ */
+#define EVTCHNOP_alloc_unbound   6
+struct evtchn_alloc_unbound {
+       /* IN parameters */
+       domid_t dom, remote_dom;
+       /* OUT parameters */
+       evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_bind_interdomain: Construct an interdomain event channel between
+ * the calling domain and <remote_dom>. <remote_dom,remote_port> must identify
+ * a port that is unbound and marked as accepting bindings from the calling
+ * domain. A fresh port is allocated in the calling domain and returned as
+ * <local_port>.
+ * NOTES:
+ *  2. <remote_dom> may be DOMID_SELF, allowing loopback connections.
+ */
+#define EVTCHNOP_bind_interdomain 0
+struct evtchn_bind_interdomain {
+       /* IN parameters. */
+       domid_t remote_dom;
+       evtchn_port_t remote_port;
+       /* OUT parameters. */
+       evtchn_port_t local_port;
+};
+
+/*
+ * EVTCHNOP_bind_virq: Bind a local event channel to VIRQ <irq> on specified
+ * vcpu.
+ * NOTES:
+ *  1. A virtual IRQ may be bound to at most one event channel per vcpu.
+ *  2. The allocated event channel is bound to the specified vcpu. The binding
+ *     may not be changed.
+ */
+#define EVTCHNOP_bind_virq       1
+struct evtchn_bind_virq {
+       /* IN parameters. */
+       uint32_t virq;
+       uint32_t vcpu;
+       /* OUT parameters. */
+       evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_bind_pirq: Bind a local event channel to PIRQ <irq>.
+ * NOTES:
+ *  1. A physical IRQ may be bound to at most one event channel per domain.
+ *  2. Only a sufficiently-privileged domain may bind to a physical IRQ.
+ */
+#define EVTCHNOP_bind_pirq       2
+struct evtchn_bind_pirq {
+       /* IN parameters. */
+       uint32_t pirq;
+#define BIND_PIRQ__WILL_SHARE 1
+       uint32_t flags; /* BIND_PIRQ__* */
+       /* OUT parameters. */
+       evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_bind_ipi: Bind a local event channel to receive events.
+ * NOTES:
+ *  1. The allocated event channel is bound to the specified vcpu. The binding
+ *     may not be changed.
+ */
+#define EVTCHNOP_bind_ipi        7
+struct evtchn_bind_ipi {
+       uint32_t vcpu;
+       /* OUT parameters. */
+       evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_close: Close a local event channel <port>. If the channel is
+ * interdomain then the remote end is placed in the unbound state
+ * (EVTCHNSTAT_unbound), awaiting a new connection.
+ */
+#define EVTCHNOP_close           3
+struct evtchn_close {
+       /* IN parameters. */
+       evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_send: Send an event to the remote end of the channel whose local
+ * endpoint is <port>.
+ */
+#define EVTCHNOP_send            4
+struct evtchn_send {
+       /* IN parameters. */
+       evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_status: Get the current status of the communication channel which
+ * has an endpoint at <dom, port>.
+ * NOTES:
+ *  1. <dom> may be specified as DOMID_SELF.
+ *  2. Only a sufficiently-privileged domain may obtain the status of an event
+ *     channel for which <dom> is not DOMID_SELF.
+ */
+#define EVTCHNOP_status                  5
+struct evtchn_status {
+       /* IN parameters */
+       domid_t  dom;
+       evtchn_port_t port;
+       /* OUT parameters */
+#define EVTCHNSTAT_closed      0  /* Channel is not in use.                 */
+#define EVTCHNSTAT_unbound     1  /* Channel is waiting interdom connection.*/
+#define EVTCHNSTAT_interdomain 2  /* Channel is connected to remote domain. */
+#define EVTCHNSTAT_pirq                3  /* Channel is bound to a phys IRQ line.   */
+#define EVTCHNSTAT_virq                4  /* Channel is bound to a virtual IRQ line */
+#define EVTCHNSTAT_ipi         5  /* Channel is bound to a virtual IPI line */
+       uint32_t status;
+       uint32_t vcpu;             /* VCPU to which this channel is bound.   */
+       union {
+               struct {
+                       domid_t dom;
+               } unbound; /* EVTCHNSTAT_unbound */
+               struct {
+                       domid_t dom;
+                       evtchn_port_t port;
+               } interdomain; /* EVTCHNSTAT_interdomain */
+               uint32_t pirq;      /* EVTCHNSTAT_pirq        */
+               uint32_t virq;      /* EVTCHNSTAT_virq        */
+       } u;
+};
+
+/*
+ * EVTCHNOP_bind_vcpu: Specify which vcpu a channel should notify when an
+ * event is pending.
+ * NOTES:
+ *  1. IPI- and VIRQ-bound channels always notify the vcpu that initialised
+ *     the binding. This binding cannot be changed.
+ *  2. All other channels notify vcpu0 by default. This default is set when
+ *     the channel is allocated (a port that is freed and subsequently reused
+ *     has its binding reset to vcpu0).
+ */
+#define EVTCHNOP_bind_vcpu       8
+struct evtchn_bind_vcpu {
+       /* IN parameters. */
+       evtchn_port_t port;
+       uint32_t vcpu;
+};
+
+/*
+ * EVTCHNOP_unmask: Unmask the specified local event-channel port and deliver
+ * a notification to the appropriate VCPU if an event is pending.
+ */
+#define EVTCHNOP_unmask                  9
+struct evtchn_unmask {
+       /* IN parameters. */
+       evtchn_port_t port;
+};
+
+struct evtchn_op {
+       uint32_t cmd; /* EVTCHNOP_* */
+       union {
+               struct evtchn_alloc_unbound    alloc_unbound;
+               struct evtchn_bind_interdomain bind_interdomain;
+               struct evtchn_bind_virq        bind_virq;
+               struct evtchn_bind_pirq        bind_pirq;
+               struct evtchn_bind_ipi         bind_ipi;
+               struct evtchn_close            close;
+               struct evtchn_send             send;
+               struct evtchn_status           status;
+               struct evtchn_bind_vcpu        bind_vcpu;
+               struct evtchn_unmask           unmask;
+       } u;
+};
+DEFINE_GUEST_HANDLE_STRUCT(evtchn_op);
+
+#endif /* __XEN_PUBLIC_EVENT_CHANNEL_H__ */
diff --git a/include/xen/interface/features.h b/include/xen/interface/features.h
new file mode 100644 (file)
index 0000000..d73228d
--- /dev/null
@@ -0,0 +1,43 @@
+/******************************************************************************
+ * features.h
+ *
+ * Feature flags, reported by XENVER_get_features.
+ *
+ * Copyright (c) 2006, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_FEATURES_H__
+#define __XEN_PUBLIC_FEATURES_H__
+
+/*
+ * If set, the guest does not need to write-protect its pagetables, and can
+ * update them via direct writes.
+ */
+#define XENFEAT_writable_page_tables       0
+
+/*
+ * If set, the guest does not need to write-protect its segment descriptor
+ * tables, and can update them via direct writes.
+ */
+#define XENFEAT_writable_descriptor_tables 1
+
+/*
+ * If set, translation between the guest's 'pseudo-physical' address space
+ * and the host's machine address space are handled by the hypervisor. In this
+ * mode the guest does not need to perform phys-to/from-machine translations
+ * when performing page table operations.
+ */
+#define XENFEAT_auto_translated_physmap    2
+
+/* If set, the guest is running in supervisor mode (e.g., x86 ring 0). */
+#define XENFEAT_supervisor_mode_kernel     3
+
+/*
+ * If set, the guest does not need to allocate x86 PAE page directories
+ * below 4GB. This flag is usually implied by auto_translated_physmap.
+ */
+#define XENFEAT_pae_pgdir_above_4gb        4
+
+#define XENFEAT_NR_SUBMAPS 1
+
+#endif /* __XEN_PUBLIC_FEATURES_H__ */
diff --git a/include/xen/interface/grant_table.h b/include/xen/interface/grant_table.h
new file mode 100644 (file)
index 0000000..2190498
--- /dev/null
@@ -0,0 +1,375 @@
+/******************************************************************************
+ * grant_table.h
+ *
+ * Interface for granting foreign access to page frames, and receiving
+ * page-ownership transfers.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __XEN_PUBLIC_GRANT_TABLE_H__
+#define __XEN_PUBLIC_GRANT_TABLE_H__
+
+
+/***********************************
+ * GRANT TABLE REPRESENTATION
+ */
+
+/* Some rough guidelines on accessing and updating grant-table entries
+ * in a concurrency-safe manner. For more information, Linux contains a
+ * reference implementation for guest OSes (arch/xen/kernel/grant_table.c).
+ *
+ * NB. WMB is a no-op on current-generation x86 processors. However, a
+ *     compiler barrier will still be required.
+ *
+ * Introducing a valid entry into the grant table:
+ *  1. Write ent->domid.
+ *  2. Write ent->frame:
+ *      GTF_permit_access:   Frame to which access is permitted.
+ *      GTF_accept_transfer: Pseudo-phys frame slot being filled by new
+ *                           frame, or zero if none.
+ *  3. Write memory barrier (WMB).
+ *  4. Write ent->flags, inc. valid type.
+ *
+ * Invalidating an unused GTF_permit_access entry:
+ *  1. flags = ent->flags.
+ *  2. Observe that !(flags & (GTF_reading|GTF_writing)).
+ *  3. Check result of SMP-safe CMPXCHG(&ent->flags, flags, 0).
+ *  NB. No need for WMB as reuse of entry is control-dependent on success of
+ *      step 3, and all architectures guarantee ordering of ctrl-dep writes.
+ *
+ * Invalidating an in-use GTF_permit_access entry:
+ *  This cannot be done directly. Request assistance from the domain controller
+ *  which can set a timeout on the use of a grant entry and take necessary
+ *  action. (NB. This is not yet implemented!).
+ *
+ * Invalidating an unused GTF_accept_transfer entry:
+ *  1. flags = ent->flags.
+ *  2. Observe that !(flags & GTF_transfer_committed). [*]
+ *  3. Check result of SMP-safe CMPXCHG(&ent->flags, flags, 0).
+ *  NB. No need for WMB as reuse of entry is control-dependent on success of
+ *      step 3, and all architectures guarantee ordering of ctrl-dep writes.
+ *  [*] If GTF_transfer_committed is set then the grant entry is 'committed'.
+ *      The guest must /not/ modify the grant entry until the address of the
+ *      transferred frame is written. It is safe for the guest to spin waiting
+ *      for this to occur (detect by observing GTF_transfer_completed in
+ *      ent->flags).
+ *
+ * Invalidating a committed GTF_accept_transfer entry:
+ *  1. Wait for (ent->flags & GTF_transfer_completed).
+ *
+ * Changing a GTF_permit_access from writable to read-only:
+ *  Use SMP-safe CMPXCHG to set GTF_readonly, while checking !GTF_writing.
+ *
+ * Changing a GTF_permit_access from read-only to writable:
+ *  Use SMP-safe bit-setting instruction.
+ */
+
+/*
+ * A grant table comprises a packed array of grant entries in one or more
+ * page frames shared between Xen and a guest.
+ * [XEN]: This field is written by Xen and read by the sharing guest.
+ * [GST]: This field is written by the guest and read by Xen.
+ */
+struct grant_entry {
+    /* GTF_xxx: various type and flag information.  [XEN,GST] */
+    uint16_t flags;
+    /* The domain being granted foreign privileges. [GST] */
+    domid_t  domid;
+    /*
+     * GTF_permit_access: Frame that @domid is allowed to map and access. [GST]
+     * GTF_accept_transfer: Frame whose ownership transferred by @domid. [XEN]
+     */
+    uint32_t frame;
+};
+
+/*
+ * Type of grant entry.
+ *  GTF_invalid: This grant entry grants no privileges.
+ *  GTF_permit_access: Allow @domid to map/access @frame.
+ *  GTF_accept_transfer: Allow @domid to transfer ownership of one page frame
+ *                       to this guest. Xen writes the page number to @frame.
+ */
+#define GTF_invalid         (0U<<0)
+#define GTF_permit_access   (1U<<0)
+#define GTF_accept_transfer (2U<<0)
+#define GTF_type_mask       (3U<<0)
+
+/*
+ * Subflags for GTF_permit_access.
+ *  GTF_readonly: Restrict @domid to read-only mappings and accesses. [GST]
+ *  GTF_reading: Grant entry is currently mapped for reading by @domid. [XEN]
+ *  GTF_writing: Grant entry is currently mapped for writing by @domid. [XEN]
+ */
+#define _GTF_readonly       (2)
+#define GTF_readonly        (1U<<_GTF_readonly)
+#define _GTF_reading        (3)
+#define GTF_reading         (1U<<_GTF_reading)
+#define _GTF_writing        (4)
+#define GTF_writing         (1U<<_GTF_writing)
+
+/*
+ * Subflags for GTF_accept_transfer:
+ *  GTF_transfer_committed: Xen sets this flag to indicate that it is committed
+ *      to transferring ownership of a page frame. When a guest sees this flag
+ *      it must /not/ modify the grant entry until GTF_transfer_completed is
+ *      set by Xen.
+ *  GTF_transfer_completed: It is safe for the guest to spin-wait on this flag
+ *      after reading GTF_transfer_committed. Xen will always write the frame
+ *      address, followed by ORing this flag, in a timely manner.
+ */
+#define _GTF_transfer_committed (2)
+#define GTF_transfer_committed  (1U<<_GTF_transfer_committed)
+#define _GTF_transfer_completed (3)
+#define GTF_transfer_completed  (1U<<_GTF_transfer_completed)
+
+
+/***********************************
+ * GRANT TABLE QUERIES AND USES
+ */
+
+/*
+ * Reference to a grant entry in a specified domain's grant table.
+ */
+typedef uint32_t grant_ref_t;
+
+/*
+ * Handle to track a mapping created via a grant reference.
+ */
+typedef uint32_t grant_handle_t;
+
+/*
+ * GNTTABOP_map_grant_ref: Map the grant entry (<dom>,<ref>) for access
+ * by devices and/or host CPUs. If successful, <handle> is a tracking number
+ * that must be presented later to destroy the mapping(s). On error, <handle>
+ * is a negative status code.
+ * NOTES:
+ *  1. If GNTMAP_device_map is specified then <dev_bus_addr> is the address
+ *     via which I/O devices may access the granted frame.
+ *  2. If GNTMAP_host_map is specified then a mapping will be added at
+ *     either a host virtual address in the current address space, or at
+ *     a PTE at the specified machine address.  The type of mapping to
+ *     perform is selected through the GNTMAP_contains_pte flag, and the
+ *     address is specified in <host_addr>.
+ *  3. Mappings should only be destroyed via GNTTABOP_unmap_grant_ref. If a
+ *     host mapping is destroyed by other means then it is *NOT* guaranteed
+ *     to be accounted to the correct grant reference!
+ */
+#define GNTTABOP_map_grant_ref        0
+struct gnttab_map_grant_ref {
+    /* IN parameters. */
+    uint64_t host_addr;
+    uint32_t flags;               /* GNTMAP_* */
+    grant_ref_t ref;
+    domid_t  dom;
+    /* OUT parameters. */
+    int16_t  status;              /* GNTST_* */
+    grant_handle_t handle;
+    uint64_t dev_bus_addr;
+};
+
+/*
+ * GNTTABOP_unmap_grant_ref: Destroy one or more grant-reference mappings
+ * tracked by <handle>. If <host_addr> or <dev_bus_addr> is zero, that
+ * field is ignored. If non-zero, they must refer to a device/host mapping
+ * that is tracked by <handle>
+ * NOTES:
+ *  1. The call may fail in an undefined manner if either mapping is not
+ *     tracked by <handle>.
+ *  3. After executing a batch of unmaps, it is guaranteed that no stale
+ *     mappings will remain in the device or host TLBs.
+ */
+#define GNTTABOP_unmap_grant_ref      1
+struct gnttab_unmap_grant_ref {
+    /* IN parameters. */
+    uint64_t host_addr;
+    uint64_t dev_bus_addr;
+    grant_handle_t handle;
+    /* OUT parameters. */
+    int16_t  status;              /* GNTST_* */
+};
+
+/*
+ * GNTTABOP_setup_table: Set up a grant table for <dom> comprising at least
+ * <nr_frames> pages. The frame addresses are written to the <frame_list>.
+ * Only <nr_frames> addresses are written, even if the table is larger.
+ * NOTES:
+ *  1. <dom> may be specified as DOMID_SELF.
+ *  2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
+ *  3. Xen may not support more than a single grant-table page per domain.
+ */
+#define GNTTABOP_setup_table          2
+struct gnttab_setup_table {
+    /* IN parameters. */
+    domid_t  dom;
+    uint32_t nr_frames;
+    /* OUT parameters. */
+    int16_t  status;              /* GNTST_* */
+    ulong *frame_list;
+};
+
+/*
+ * GNTTABOP_dump_table: Dump the contents of the grant table to the
+ * xen console. Debugging use only.
+ */
+#define GNTTABOP_dump_table           3
+struct gnttab_dump_table {
+    /* IN parameters. */
+    domid_t dom;
+    /* OUT parameters. */
+    int16_t status;               /* GNTST_* */
+};
+
+/*
+ * GNTTABOP_transfer_grant_ref: Transfer <frame> to a foreign domain. The
+ * foreign domain has previously registered its interest in the transfer via
+ * <domid, ref>.
+ *
+ * Note that, even if the transfer fails, the specified page no longer belongs
+ * to the calling domain *unless* the error is GNTST_bad_page.
+ */
+#define GNTTABOP_transfer                4
+struct gnttab_transfer {
+    /* IN parameters. */
+    unsigned long mfn;
+    domid_t       domid;
+    grant_ref_t   ref;
+    /* OUT parameters. */
+    int16_t       status;
+};
+
+
+/*
+ * GNTTABOP_copy: Hypervisor based copy
+ * source and destinations can be eithers MFNs or, for foreign domains,
+ * grant references. the foreign domain has to grant read/write access
+ * in its grant table.
+ *
+ * The flags specify what type source and destinations are (either MFN
+ * or grant reference).
+ *
+ * Note that this can also be used to copy data between two domains
+ * via a third party if the source and destination domains had previously
+ * grant appropriate access to their pages to the third party.
+ *
+ * source_offset specifies an offset in the source frame, dest_offset
+ * the offset in the target frame and  len specifies the number of
+ * bytes to be copied.
+ */
+
+#define _GNTCOPY_source_gref      (0)
+#define GNTCOPY_source_gref       (1<<_GNTCOPY_source_gref)
+#define _GNTCOPY_dest_gref        (1)
+#define GNTCOPY_dest_gref         (1<<_GNTCOPY_dest_gref)
+
+#define GNTTABOP_copy                 5
+struct gnttab_copy {
+       /* IN parameters. */
+       struct {
+               union {
+                       grant_ref_t ref;
+                       unsigned long   gmfn;
+               } u;
+               domid_t  domid;
+               uint16_t offset;
+       } source, dest;
+       uint16_t      len;
+       uint16_t      flags;          /* GNTCOPY_* */
+       /* OUT parameters. */
+       int16_t       status;
+};
+
+/*
+ * GNTTABOP_query_size: Query the current and maximum sizes of the shared
+ * grant table.
+ * NOTES:
+ *  1. <dom> may be specified as DOMID_SELF.
+ *  2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
+ */
+#define GNTTABOP_query_size           6
+struct gnttab_query_size {
+    /* IN parameters. */
+    domid_t  dom;
+    /* OUT parameters. */
+    uint32_t nr_frames;
+    uint32_t max_nr_frames;
+    int16_t  status;              /* GNTST_* */
+};
+
+
+/*
+ * Bitfield values for update_pin_status.flags.
+ */
+ /* Map the grant entry for access by I/O devices. */
+#define _GNTMAP_device_map      (0)
+#define GNTMAP_device_map       (1<<_GNTMAP_device_map)
+ /* Map the grant entry for access by host CPUs. */
+#define _GNTMAP_host_map        (1)
+#define GNTMAP_host_map         (1<<_GNTMAP_host_map)
+ /* Accesses to the granted frame will be restricted to read-only access. */
+#define _GNTMAP_readonly        (2)
+#define GNTMAP_readonly         (1<<_GNTMAP_readonly)
+ /*
+  * GNTMAP_host_map subflag:
+  *  0 => The host mapping is usable only by the guest OS.
+  *  1 => The host mapping is usable by guest OS + current application.
+  */
+#define _GNTMAP_application_map (3)
+#define GNTMAP_application_map  (1<<_GNTMAP_application_map)
+
+ /*
+  * GNTMAP_contains_pte subflag:
+  *  0 => This map request contains a host virtual address.
+  *  1 => This map request contains the machine addess of the PTE to update.
+  */
+#define _GNTMAP_contains_pte    (4)
+#define GNTMAP_contains_pte     (1<<_GNTMAP_contains_pte)
+
+/*
+ * Values for error status returns. All errors are -ve.
+ */
+#define GNTST_okay             (0)  /* Normal return.                        */
+#define GNTST_general_error    (-1) /* General undefined error.              */
+#define GNTST_bad_domain       (-2) /* Unrecognsed domain id.                */
+#define GNTST_bad_gntref       (-3) /* Unrecognised or inappropriate gntref. */
+#define GNTST_bad_handle       (-4) /* Unrecognised or inappropriate handle. */
+#define GNTST_bad_virt_addr    (-5) /* Inappropriate virtual address to map. */
+#define GNTST_bad_dev_addr     (-6) /* Inappropriate device address to unmap.*/
+#define GNTST_no_device_space  (-7) /* Out of space in I/O MMU.              */
+#define GNTST_permission_denied (-8) /* Not enough privilege for operation.  */
+#define GNTST_bad_page         (-9) /* Specified page was invalid for op.    */
+#define GNTST_bad_copy_arg    (-10) /* copy arguments cross page boundary */
+
+#define GNTTABOP_error_msgs {                   \
+    "okay",                                     \
+    "undefined error",                          \
+    "unrecognised domain id",                   \
+    "invalid grant reference",                  \
+    "invalid mapping handle",                   \
+    "invalid virtual address",                  \
+    "invalid device address",                   \
+    "no spare translation slot in the I/O MMU", \
+    "permission denied",                        \
+    "bad page",                                 \
+    "copy arguments cross page boundary"        \
+}
+
+#endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */
diff --git a/include/xen/interface/io/blkif.h b/include/xen/interface/io/blkif.h
new file mode 100644 (file)
index 0000000..c2d1fa4
--- /dev/null
@@ -0,0 +1,94 @@
+/******************************************************************************
+ * blkif.h
+ *
+ * Unified block-device I/O interface for Xen guest OSes.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser
+ */
+
+#ifndef __XEN_PUBLIC_IO_BLKIF_H__
+#define __XEN_PUBLIC_IO_BLKIF_H__
+
+#include "ring.h"
+#include "../grant_table.h"
+
+/*
+ * Front->back notifications: When enqueuing a new request, sending a
+ * notification can be made conditional on req_event (i.e., the generic
+ * hold-off mechanism provided by the ring macros). Backends must set
+ * req_event appropriately (e.g., using RING_FINAL_CHECK_FOR_REQUESTS()).
+ *
+ * Back->front notifications: When enqueuing a new response, sending a
+ * notification can be made conditional on rsp_event (i.e., the generic
+ * hold-off mechanism provided by the ring macros). Frontends must set
+ * rsp_event appropriately (e.g., using RING_FINAL_CHECK_FOR_RESPONSES()).
+ */
+
+typedef uint16_t blkif_vdev_t;
+typedef uint64_t blkif_sector_t;
+
+/*
+ * REQUEST CODES.
+ */
+#define BLKIF_OP_READ              0
+#define BLKIF_OP_WRITE             1
+/*
+ * Recognised only if "feature-barrier" is present in backend xenbus info.
+ * The "feature_barrier" node contains a boolean indicating whether barrier
+ * requests are likely to succeed or fail. Either way, a barrier request
+ * may fail at any time with BLKIF_RSP_EOPNOTSUPP if it is unsupported by
+ * the underlying block-device hardware. The boolean simply indicates whether
+ * or not it is worthwhile for the frontend to attempt barrier requests.
+ * If a backend does not recognise BLKIF_OP_WRITE_BARRIER, it should *not*
+ * create the "feature-barrier" node!
+ */
+#define BLKIF_OP_WRITE_BARRIER     2
+
+/*
+ * Maximum scatter/gather segments per request.
+ * This is carefully chosen so that sizeof(struct blkif_ring) <= PAGE_SIZE.
+ * NB. This could be 12 if the ring indexes weren't stored in the same page.
+ */
+#define BLKIF_MAX_SEGMENTS_PER_REQUEST 11
+
+struct blkif_request {
+       uint8_t        operation;    /* BLKIF_OP_???                         */
+       uint8_t        nr_segments;  /* number of segments                   */
+       blkif_vdev_t   handle;       /* only for read/write requests         */
+       uint64_t       id;           /* private guest value, echoed in resp  */
+       blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
+       struct blkif_request_segment {
+               grant_ref_t gref;        /* reference to I/O buffer frame        */
+               /* @first_sect: first sector in frame to transfer (inclusive).   */
+               /* @last_sect: last sector in frame to transfer (inclusive).     */
+               uint8_t     first_sect, last_sect;
+       } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+
+struct blkif_response {
+       uint64_t        id;              /* copied from request */
+       uint8_t         operation;       /* copied from request */
+       int16_t         status;          /* BLKIF_RSP_???       */
+};
+
+/*
+ * STATUS RETURN CODES.
+ */
+ /* Operation not supported (only happens on barrier writes). */
+#define BLKIF_RSP_EOPNOTSUPP  -2
+ /* Operation failed for some unspecified reason (-EIO). */
+#define BLKIF_RSP_ERROR       -1
+ /* Operation completed successfully. */
+#define BLKIF_RSP_OKAY         0
+
+/*
+ * Generate blkif ring structures and types.
+ */
+
+DEFINE_RING_TYPES(blkif, struct blkif_request, struct blkif_response);
+
+#define VDISK_CDROM        0x1
+#define VDISK_REMOVABLE    0x2
+#define VDISK_READONLY     0x4
+
+#endif /* __XEN_PUBLIC_IO_BLKIF_H__ */
diff --git a/include/xen/interface/io/console.h b/include/xen/interface/io/console.h
new file mode 100644 (file)
index 0000000..e563de7
--- /dev/null
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * console.h
+ *
+ * Console I/O interface for Xen guest OSes.
+ *
+ * Copyright (c) 2005, Keir Fraser
+ */
+
+#ifndef __XEN_PUBLIC_IO_CONSOLE_H__
+#define __XEN_PUBLIC_IO_CONSOLE_H__
+
+typedef uint32_t XENCONS_RING_IDX;
+
+#define MASK_XENCONS_IDX(idx, ring) ((idx) & (sizeof(ring)-1))
+
+struct xencons_interface {
+    char in[1024];
+    char out[2048];
+    XENCONS_RING_IDX in_cons, in_prod;
+    XENCONS_RING_IDX out_cons, out_prod;
+};
+
+#endif /* __XEN_PUBLIC_IO_CONSOLE_H__ */
diff --git a/include/xen/interface/io/netif.h b/include/xen/interface/io/netif.h
new file mode 100644 (file)
index 0000000..518481c
--- /dev/null
@@ -0,0 +1,158 @@
+/******************************************************************************
+ * netif.h
+ *
+ * Unified network-device I/O interface for Xen guest OSes.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser
+ */
+
+#ifndef __XEN_PUBLIC_IO_NETIF_H__
+#define __XEN_PUBLIC_IO_NETIF_H__
+
+#include "ring.h"
+#include "../grant_table.h"
+
+/*
+ * Notifications after enqueuing any type of message should be conditional on
+ * the appropriate req_event or rsp_event field in the shared ring.
+ * If the client sends notification for rx requests then it should specify
+ * feature 'feature-rx-notify' via xenbus. Otherwise the backend will assume
+ * that it cannot safely queue packets (as it may not be kicked to send them).
+ */
+
+/*
+ * This is the 'wire' format for packets:
+ *  Request 1: netif_tx_request -- NETTXF_* (any flags)
+ * [Request 2: netif_tx_extra]  (only if request 1 has NETTXF_extra_info)
+ * [Request 3: netif_tx_extra]  (only if request 2 has XEN_NETIF_EXTRA_MORE)
+ *  Request 4: netif_tx_request -- NETTXF_more_data
+ *  Request 5: netif_tx_request -- NETTXF_more_data
+ *  ...
+ *  Request N: netif_tx_request -- 0
+ */
+
+/* Protocol checksum field is blank in the packet (hardware offload)? */
+#define _NETTXF_csum_blank     (0)
+#define  NETTXF_csum_blank     (1U<<_NETTXF_csum_blank)
+
+/* Packet data has been validated against protocol checksum. */
+#define _NETTXF_data_validated (1)
+#define  NETTXF_data_validated (1U<<_NETTXF_data_validated)
+
+/* Packet continues in the next request descriptor. */
+#define _NETTXF_more_data      (2)
+#define  NETTXF_more_data      (1U<<_NETTXF_more_data)
+
+/* Packet to be followed by extra descriptor(s). */
+#define _NETTXF_extra_info     (3)
+#define  NETTXF_extra_info     (1U<<_NETTXF_extra_info)
+
+struct xen_netif_tx_request {
+    grant_ref_t gref;      /* Reference to buffer page */
+    uint16_t offset;       /* Offset within buffer page */
+    uint16_t flags;        /* NETTXF_* */
+    uint16_t id;           /* Echoed in response message. */
+    uint16_t size;         /* Packet size in bytes.       */
+};
+
+/* Types of netif_extra_info descriptors. */
+#define XEN_NETIF_EXTRA_TYPE_NONE  (0)  /* Never used - invalid */
+#define XEN_NETIF_EXTRA_TYPE_GSO   (1)  /* u.gso */
+#define XEN_NETIF_EXTRA_TYPE_MAX   (2)
+
+/* netif_extra_info flags. */
+#define _XEN_NETIF_EXTRA_FLAG_MORE (0)
+#define XEN_NETIF_EXTRA_FLAG_MORE  (1U<<_XEN_NETIF_EXTRA_FLAG_MORE)
+
+/* GSO types - only TCPv4 currently supported. */
+#define XEN_NETIF_GSO_TYPE_TCPV4        (1)
+
+/*
+ * This structure needs to fit within both netif_tx_request and
+ * netif_rx_response for compatibility.
+ */
+struct xen_netif_extra_info {
+       uint8_t type;  /* XEN_NETIF_EXTRA_TYPE_* */
+       uint8_t flags; /* XEN_NETIF_EXTRA_FLAG_* */
+
+       union {
+               struct {
+                       /*
+                        * Maximum payload size of each segment. For
+                        * example, for TCP this is just the path MSS.
+                        */
+                       uint16_t size;
+
+                       /*
+                        * GSO type. This determines the protocol of
+                        * the packet and any extra features required
+                        * to segment the packet properly.
+                        */
+                       uint8_t type; /* XEN_NETIF_GSO_TYPE_* */
+
+                       /* Future expansion. */
+                       uint8_t pad;
+
+                       /*
+                        * GSO features. This specifies any extra GSO
+                        * features required to process this packet,
+                        * such as ECN support for TCPv4.
+                        */
+                       uint16_t features; /* XEN_NETIF_GSO_FEAT_* */
+               } gso;
+
+               uint16_t pad[3];
+       } u;
+};
+
+struct xen_netif_tx_response {
+       uint16_t id;
+       int16_t  status;       /* NETIF_RSP_* */
+};
+
+struct xen_netif_rx_request {
+       uint16_t    id;        /* Echoed in response message.        */
+       grant_ref_t gref;      /* Reference to incoming granted frame */
+};
+
+/* Packet data has been validated against protocol checksum. */
+#define _NETRXF_data_validated (0)
+#define  NETRXF_data_validated (1U<<_NETRXF_data_validated)
+
+/* Protocol checksum field is blank in the packet (hardware offload)? */
+#define _NETRXF_csum_blank     (1)
+#define  NETRXF_csum_blank     (1U<<_NETRXF_csum_blank)
+
+/* Packet continues in the next request descriptor. */
+#define _NETRXF_more_data      (2)
+#define  NETRXF_more_data      (1U<<_NETRXF_more_data)
+
+/* Packet to be followed by extra descriptor(s). */
+#define _NETRXF_extra_info     (3)
+#define  NETRXF_extra_info     (1U<<_NETRXF_extra_info)
+
+struct xen_netif_rx_response {
+    uint16_t id;
+    uint16_t offset;       /* Offset in page of start of received packet  */
+    uint16_t flags;        /* NETRXF_* */
+    int16_t  status;       /* -ve: BLKIF_RSP_* ; +ve: Rx'ed pkt size. */
+};
+
+/*
+ * Generate netif ring structures and types.
+ */
+
+DEFINE_RING_TYPES(xen_netif_tx,
+                 struct xen_netif_tx_request,
+                 struct xen_netif_tx_response);
+DEFINE_RING_TYPES(xen_netif_rx,
+                 struct xen_netif_rx_request,
+                 struct xen_netif_rx_response);
+
+#define NETIF_RSP_DROPPED         -2
+#define NETIF_RSP_ERROR           -1
+#define NETIF_RSP_OKAY             0
+/* No response: used for auxiliary requests (e.g., netif_tx_extra). */
+#define NETIF_RSP_NULL             1
+
+#endif
diff --git a/include/xen/interface/io/ring.h b/include/xen/interface/io/ring.h
new file mode 100644 (file)
index 0000000..e8cbf43
--- /dev/null
@@ -0,0 +1,260 @@
+/******************************************************************************
+ * ring.h
+ *
+ * Shared producer-consumer ring macros.
+ *
+ * Tim Deegan and Andrew Warfield November 2004.
+ */
+
+#ifndef __XEN_PUBLIC_IO_RING_H__
+#define __XEN_PUBLIC_IO_RING_H__
+
+typedef unsigned int RING_IDX;
+
+/* Round a 32-bit unsigned constant down to the nearest power of two. */
+#define __RD2(_x)  (((_x) & 0x00000002) ? 0x2                 : ((_x) & 0x1))
+#define __RD4(_x)  (((_x) & 0x0000000c) ? __RD2((_x)>>2)<<2    : __RD2(_x))
+#define __RD8(_x)  (((_x) & 0x000000f0) ? __RD4((_x)>>4)<<4    : __RD4(_x))
+#define __RD16(_x) (((_x) & 0x0000ff00) ? __RD8((_x)>>8)<<8    : __RD8(_x))
+#define __RD32(_x) (((_x) & 0xffff0000) ? __RD16((_x)>>16)<<16 : __RD16(_x))
+
+/*
+ * Calculate size of a shared ring, given the total available space for the
+ * ring and indexes (_sz), and the name tag of the request/response structure.
+ * A ring contains as many entries as will fit, rounded down to the nearest
+ * power of two (so we can mask with (size-1) to loop around).
+ */
+#define __RING_SIZE(_s, _sz) \
+    (__RD32(((_sz) - (long)&(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0])))
+
+/*
+ * Macros to make the correct C datatypes for a new kind of ring.
+ *
+ * To make a new ring datatype, you need to have two message structures,
+ * let's say struct request, and struct response already defined.
+ *
+ * In a header where you want the ring datatype declared, you then do:
+ *
+ *     DEFINE_RING_TYPES(mytag, struct request, struct response);
+ *
+ * These expand out to give you a set of types, as you can see below.
+ * The most important of these are:
+ *
+ *     struct mytag_sring      - The shared ring.
+ *     struct mytag_front_ring - The 'front' half of the ring.
+ *     struct mytag_back_ring  - The 'back' half of the ring.
+ *
+ * To initialize a ring in your code you need to know the location and size
+ * of the shared memory area (PAGE_SIZE, for instance). To initialise
+ * the front half:
+ *
+ *     struct mytag_front_ring front_ring;
+ *     SHARED_RING_INIT((struct mytag_sring *)shared_page);
+ *     FRONT_RING_INIT(&front_ring, (struct mytag_sring *)shared_page,
+ *                    PAGE_SIZE);
+ *
+ * Initializing the back follows similarly (note that only the front
+ * initializes the shared ring):
+ *
+ *     struct mytag_back_ring back_ring;
+ *     BACK_RING_INIT(&back_ring, (struct mytag_sring *)shared_page,
+ *                   PAGE_SIZE);
+ */
+
+#define DEFINE_RING_TYPES(__name, __req_t, __rsp_t)                    \
+                                                                       \
+/* Shared ring entry */                                                        \
+union __name##_sring_entry {                                           \
+    __req_t req;                                                       \
+    __rsp_t rsp;                                                       \
+};                                                                     \
+                                                                       \
+/* Shared ring page */                                                 \
+struct __name##_sring {                                                        \
+    RING_IDX req_prod, req_event;                                      \
+    RING_IDX rsp_prod, rsp_event;                                      \
+    uint8_t  pad[48];                                                  \
+    union __name##_sring_entry ring[1]; /* variable-length */          \
+};                                                                     \
+                                                                       \
+/* "Front" end's private variables */                                  \
+struct __name##_front_ring {                                           \
+    RING_IDX req_prod_pvt;                                             \
+    RING_IDX rsp_cons;                                                 \
+    unsigned int nr_ents;                                              \
+    struct __name##_sring *sring;                                      \
+};                                                                     \
+                                                                       \
+/* "Back" end's private variables */                                   \
+struct __name##_back_ring {                                            \
+    RING_IDX rsp_prod_pvt;                                             \
+    RING_IDX req_cons;                                                 \
+    unsigned int nr_ents;                                              \
+    struct __name##_sring *sring;                                      \
+};
+
+/*
+ * Macros for manipulating rings.
+ *
+ * FRONT_RING_whatever works on the "front end" of a ring: here
+ * requests are pushed on to the ring and responses taken off it.
+ *
+ * BACK_RING_whatever works on the "back end" of a ring: here
+ * requests are taken off the ring and responses put on.
+ *
+ * N.B. these macros do NO INTERLOCKS OR FLOW CONTROL.
+ * This is OK in 1-for-1 request-response situations where the
+ * requestor (front end) never has more than RING_SIZE()-1
+ * outstanding requests.
+ */
+
+/* Initialising empty rings */
+#define SHARED_RING_INIT(_s) do {                                      \
+    (_s)->req_prod  = (_s)->rsp_prod  = 0;                             \
+    (_s)->req_event = (_s)->rsp_event = 1;                             \
+    memset((_s)->pad, 0, sizeof((_s)->pad));                           \
+} while(0)
+
+#define FRONT_RING_INIT(_r, _s, __size) do {                           \
+    (_r)->req_prod_pvt = 0;                                            \
+    (_r)->rsp_cons = 0;                                                        \
+    (_r)->nr_ents = __RING_SIZE(_s, __size);                           \
+    (_r)->sring = (_s);                                                        \
+} while (0)
+
+#define BACK_RING_INIT(_r, _s, __size) do {                            \
+    (_r)->rsp_prod_pvt = 0;                                            \
+    (_r)->req_cons = 0;                                                        \
+    (_r)->nr_ents = __RING_SIZE(_s, __size);                           \
+    (_r)->sring = (_s);                                                        \
+} while (0)
+
+/* Initialize to existing shared indexes -- for recovery */
+#define FRONT_RING_ATTACH(_r, _s, __size) do {                         \
+    (_r)->sring = (_s);                                                        \
+    (_r)->req_prod_pvt = (_s)->req_prod;                               \
+    (_r)->rsp_cons = (_s)->rsp_prod;                                   \
+    (_r)->nr_ents = __RING_SIZE(_s, __size);                           \
+} while (0)
+
+#define BACK_RING_ATTACH(_r, _s, __size) do {                          \
+    (_r)->sring = (_s);                                                        \
+    (_r)->rsp_prod_pvt = (_s)->rsp_prod;                               \
+    (_r)->req_cons = (_s)->req_prod;                                   \
+    (_r)->nr_ents = __RING_SIZE(_s, __size);                           \
+} while (0)
+
+/* How big is this ring? */
+#define RING_SIZE(_r)                                                  \
+    ((_r)->nr_ents)
+
+/* Number of free requests (for use on front side only). */
+#define RING_FREE_REQUESTS(_r)                                         \
+    (RING_SIZE(_r) - ((_r)->req_prod_pvt - (_r)->rsp_cons))
+
+/* Test if there is an empty slot available on the front ring.
+ * (This is only meaningful from the front. )
+ */
+#define RING_FULL(_r)                                                  \
+    (RING_FREE_REQUESTS(_r) == 0)
+
+/* Test if there are outstanding messages to be processed on a ring. */
+#define RING_HAS_UNCONSUMED_RESPONSES(_r)                              \
+    ((_r)->sring->rsp_prod - (_r)->rsp_cons)
+
+#define RING_HAS_UNCONSUMED_REQUESTS(_r)                               \
+    ({                                                                 \
+       unsigned int req = (_r)->sring->req_prod - (_r)->req_cons;      \
+       unsigned int rsp = RING_SIZE(_r) -                              \
+                          ((_r)->req_cons - (_r)->rsp_prod_pvt);       \
+       req < rsp ? req : rsp;                                          \
+    })
+
+/* Direct access to individual ring elements, by index. */
+#define RING_GET_REQUEST(_r, _idx)                                     \
+    (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req))
+
+#define RING_GET_RESPONSE(_r, _idx)                                    \
+    (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp))
+
+/* Loop termination condition: Would the specified index overflow the ring? */
+#define RING_REQUEST_CONS_OVERFLOW(_r, _cons)                          \
+    (((_cons) - (_r)->rsp_prod_pvt) >= RING_SIZE(_r))
+
+#define RING_PUSH_REQUESTS(_r) do {                                    \
+    wmb(); /* back sees requests /before/ updated producer index */    \
+    (_r)->sring->req_prod = (_r)->req_prod_pvt;                                \
+} while (0)
+
+#define RING_PUSH_RESPONSES(_r) do {                                   \
+    wmb(); /* front sees responses /before/ updated producer index */  \
+    (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt;                                \
+} while (0)
+
+/*
+ * Notification hold-off (req_event and rsp_event):
+ *
+ * When queueing requests or responses on a shared ring, it may not always be
+ * necessary to notify the remote end. For example, if requests are in flight
+ * in a backend, the front may be able to queue further requests without
+ * notifying the back (if the back checks for new requests when it queues
+ * responses).
+ *
+ * When enqueuing requests or responses:
+ *
+ *  Use RING_PUSH_{REQUESTS,RESPONSES}_AND_CHECK_NOTIFY(). The second argument
+ *  is a boolean return value. True indicates that the receiver requires an
+ *  asynchronous notification.
+ *
+ * After dequeuing requests or responses (before sleeping the connection):
+ *
+ *  Use RING_FINAL_CHECK_FOR_REQUESTS() or RING_FINAL_CHECK_FOR_RESPONSES().
+ *  The second argument is a boolean return value. True indicates that there
+ *  are pending messages on the ring (i.e., the connection should not be put
+ *  to sleep).
+ *
+ *  These macros will set the req_event/rsp_event field to trigger a
+ *  notification on the very next message that is enqueued. If you want to
+ *  create batches of work (i.e., only receive a notification after several
+ *  messages have been enqueued) then you will need to create a customised
+ *  version of the FINAL_CHECK macro in your own code, which sets the event
+ *  field appropriately.
+ */
+
+#define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do {          \
+    RING_IDX __old = (_r)->sring->req_prod;                            \
+    RING_IDX __new = (_r)->req_prod_pvt;                               \
+    wmb(); /* back sees requests /before/ updated producer index */    \
+    (_r)->sring->req_prod = __new;                                     \
+    mb(); /* back sees new requests /before/ we check req_event */     \
+    (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) <          \
+                (RING_IDX)(__new - __old));                            \
+} while (0)
+
+#define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do {         \
+    RING_IDX __old = (_r)->sring->rsp_prod;                            \
+    RING_IDX __new = (_r)->rsp_prod_pvt;                               \
+    wmb(); /* front sees responses /before/ updated producer index */  \
+    (_r)->sring->rsp_prod = __new;                                     \
+    mb(); /* front sees new responses /before/ we check rsp_event */   \
+    (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) <          \
+                (RING_IDX)(__new - __old));                            \
+} while (0)
+
+#define RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) do {            \
+    (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r);                  \
+    if (_work_to_do) break;                                            \
+    (_r)->sring->req_event = (_r)->req_cons + 1;                       \
+    mb();                                                              \
+    (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r);                  \
+} while (0)
+
+#define RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) do {           \
+    (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r);                 \
+    if (_work_to_do) break;                                            \
+    (_r)->sring->rsp_event = (_r)->rsp_cons + 1;                       \
+    mb();                                                              \
+    (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r);                 \
+} while (0)
+
+#endif /* __XEN_PUBLIC_IO_RING_H__ */
diff --git a/include/xen/interface/io/xenbus.h b/include/xen/interface/io/xenbus.h
new file mode 100644 (file)
index 0000000..46508c7
--- /dev/null
@@ -0,0 +1,44 @@
+/*****************************************************************************
+ * xenbus.h
+ *
+ * Xenbus protocol details.
+ *
+ * Copyright (C) 2005 XenSource Ltd.
+ */
+
+#ifndef _XEN_PUBLIC_IO_XENBUS_H
+#define _XEN_PUBLIC_IO_XENBUS_H
+
+/* The state of either end of the Xenbus, i.e. the current communication
+   status of initialisation across the bus.  States here imply nothing about
+   the state of the connection between the driver and the kernel's device
+   layers.  */
+enum xenbus_state
+{
+       XenbusStateUnknown      = 0,
+       XenbusStateInitialising = 1,
+       XenbusStateInitWait     = 2,  /* Finished early
+                                        initialisation, but waiting
+                                        for information from the peer
+                                        or hotplug scripts. */
+       XenbusStateInitialised  = 3,  /* Initialised and waiting for a
+                                        connection from the peer. */
+       XenbusStateConnected    = 4,
+       XenbusStateClosing      = 5,  /* The device is being closed
+                                        due to an error or an unplug
+                                        event. */
+       XenbusStateClosed       = 6
+
+};
+
+#endif /* _XEN_PUBLIC_IO_XENBUS_H */
+
+/*
+ * Local variables:
+ *  c-file-style: "linux"
+ *  indent-tabs-mode: t
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/include/xen/interface/io/xs_wire.h b/include/xen/interface/io/xs_wire.h
new file mode 100644 (file)
index 0000000..99fcffb
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Details of the "wire" protocol between Xen Store Daemon and client
+ * library or guest kernel.
+ * Copyright (C) 2005 Rusty Russell IBM Corporation
+ */
+
+#ifndef _XS_WIRE_H
+#define _XS_WIRE_H
+
+enum xsd_sockmsg_type
+{
+    XS_DEBUG,
+    XS_DIRECTORY,
+    XS_READ,
+    XS_GET_PERMS,
+    XS_WATCH,
+    XS_UNWATCH,
+    XS_TRANSACTION_START,
+    XS_TRANSACTION_END,
+    XS_INTRODUCE,
+    XS_RELEASE,
+    XS_GET_DOMAIN_PATH,
+    XS_WRITE,
+    XS_MKDIR,
+    XS_RM,
+    XS_SET_PERMS,
+    XS_WATCH_EVENT,
+    XS_ERROR,
+    XS_IS_DOMAIN_INTRODUCED
+};
+
+#define XS_WRITE_NONE "NONE"
+#define XS_WRITE_CREATE "CREATE"
+#define XS_WRITE_CREATE_EXCL "CREATE|EXCL"
+
+/* We hand errors as strings, for portability. */
+struct xsd_errors
+{
+    int errnum;
+    const char *errstring;
+};
+#define XSD_ERROR(x) { x, #x }
+static struct xsd_errors xsd_errors[] __attribute__((unused)) = {
+    XSD_ERROR(EINVAL),
+    XSD_ERROR(EACCES),
+    XSD_ERROR(EEXIST),
+    XSD_ERROR(EISDIR),
+    XSD_ERROR(ENOENT),
+    XSD_ERROR(ENOMEM),
+    XSD_ERROR(ENOSPC),
+    XSD_ERROR(EIO),
+    XSD_ERROR(ENOTEMPTY),
+    XSD_ERROR(ENOSYS),
+    XSD_ERROR(EROFS),
+    XSD_ERROR(EBUSY),
+    XSD_ERROR(EAGAIN),
+    XSD_ERROR(EISCONN)
+};
+
+struct xsd_sockmsg
+{
+    uint32_t type;  /* XS_??? */
+    uint32_t req_id;/* Request identifier, echoed in daemon's response.  */
+    uint32_t tx_id; /* Transaction id (0 if not related to a transaction). */
+    uint32_t len;   /* Length of data following this. */
+
+    /* Generally followed by nul-terminated string(s). */
+};
+
+enum xs_watch_type
+{
+    XS_WATCH_PATH = 0,
+    XS_WATCH_TOKEN
+};
+
+/* Inter-domain shared memory communications. */
+#define XENSTORE_RING_SIZE 1024
+typedef uint32_t XENSTORE_RING_IDX;
+#define MASK_XENSTORE_IDX(idx) ((idx) & (XENSTORE_RING_SIZE-1))
+struct xenstore_domain_interface {
+    char req[XENSTORE_RING_SIZE]; /* Requests to xenstore daemon. */
+    char rsp[XENSTORE_RING_SIZE]; /* Replies and async watch events. */
+    XENSTORE_RING_IDX req_cons, req_prod;
+    XENSTORE_RING_IDX rsp_cons, rsp_prod;
+};
+
+#endif /* _XS_WIRE_H */
diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h
new file mode 100644 (file)
index 0000000..af36ead
--- /dev/null
@@ -0,0 +1,145 @@
+/******************************************************************************
+ * memory.h
+ *
+ * Memory reservation and information.
+ *
+ * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_MEMORY_H__
+#define __XEN_PUBLIC_MEMORY_H__
+
+/*
+ * Increase or decrease the specified domain's memory reservation. Returns a
+ * -ve errcode on failure, or the # extents successfully allocated or freed.
+ * arg == addr of struct xen_memory_reservation.
+ */
+#define XENMEM_increase_reservation 0
+#define XENMEM_decrease_reservation 1
+#define XENMEM_populate_physmap     6
+struct xen_memory_reservation {
+
+    /*
+     * XENMEM_increase_reservation:
+     *   OUT: MFN (*not* GMFN) bases of extents that were allocated
+     * XENMEM_decrease_reservation:
+     *   IN:  GMFN bases of extents to free
+     * XENMEM_populate_physmap:
+     *   IN:  GPFN bases of extents to populate with memory
+     *   OUT: GMFN bases of extents that were allocated
+     *   (NB. This command also updates the mach_to_phys translation table)
+     */
+    GUEST_HANDLE(ulong) extent_start;
+
+    /* Number of extents, and size/alignment of each (2^extent_order pages). */
+    unsigned long  nr_extents;
+    unsigned int   extent_order;
+
+    /*
+     * Maximum # bits addressable by the user of the allocated region (e.g.,
+     * I/O devices often have a 32-bit limitation even in 64-bit systems). If
+     * zero then the user has no addressing restriction.
+     * This field is not used by XENMEM_decrease_reservation.
+     */
+    unsigned int   address_bits;
+
+    /*
+     * Domain whose reservation is being changed.
+     * Unprivileged domains can specify only DOMID_SELF.
+     */
+    domid_t        domid;
+
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_memory_reservation);
+
+/*
+ * Returns the maximum machine frame number of mapped RAM in this system.
+ * This command always succeeds (it never returns an error code).
+ * arg == NULL.
+ */
+#define XENMEM_maximum_ram_page     2
+
+/*
+ * Returns the current or maximum memory reservation, in pages, of the
+ * specified domain (may be DOMID_SELF). Returns -ve errcode on failure.
+ * arg == addr of domid_t.
+ */
+#define XENMEM_current_reservation  3
+#define XENMEM_maximum_reservation  4
+
+/*
+ * Returns a list of MFN bases of 2MB extents comprising the machine_to_phys
+ * mapping table. Architectures which do not have a m2p table do not implement
+ * this command.
+ * arg == addr of xen_machphys_mfn_list_t.
+ */
+#define XENMEM_machphys_mfn_list    5
+struct xen_machphys_mfn_list {
+    /*
+     * Size of the 'extent_start' array. Fewer entries will be filled if the
+     * machphys table is smaller than max_extents * 2MB.
+     */
+    unsigned int max_extents;
+
+    /*
+     * Pointer to buffer to fill with list of extent starts. If there are
+     * any large discontiguities in the machine address space, 2MB gaps in
+     * the machphys table will be represented by an MFN base of zero.
+     */
+    GUEST_HANDLE(ulong) extent_start;
+
+    /*
+     * Number of extents written to the above array. This will be smaller
+     * than 'max_extents' if the machphys table is smaller than max_e * 2MB.
+     */
+    unsigned int nr_extents;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list);
+
+/*
+ * Sets the GPFN at which a particular page appears in the specified guest's
+ * pseudophysical address space.
+ * arg == addr of xen_add_to_physmap_t.
+ */
+#define XENMEM_add_to_physmap      7
+struct xen_add_to_physmap {
+    /* Which domain to change the mapping for. */
+    domid_t domid;
+
+    /* Source mapping space. */
+#define XENMAPSPACE_shared_info 0 /* shared info page */
+#define XENMAPSPACE_grant_table 1 /* grant table page */
+    unsigned int space;
+
+    /* Index into source mapping space. */
+    unsigned long idx;
+
+    /* GPFN where the source mapping page should appear. */
+    unsigned long gpfn;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_add_to_physmap);
+
+/*
+ * Translates a list of domain-specific GPFNs into MFNs. Returns a -ve error
+ * code on failure. This call only works for auto-translated guests.
+ */
+#define XENMEM_translate_gpfn_list  8
+struct xen_translate_gpfn_list {
+    /* Which domain to translate for? */
+    domid_t domid;
+
+    /* Length of list. */
+    unsigned long nr_gpfns;
+
+    /* List of GPFNs to translate. */
+    GUEST_HANDLE(ulong) gpfn_list;
+
+    /*
+     * Output list to contain MFN translations. May be the same as the input
+     * list (in which case each input GPFN is overwritten with the output MFN).
+     */
+    GUEST_HANDLE(ulong) mfn_list;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_translate_gpfn_list);
+
+#endif /* __XEN_PUBLIC_MEMORY_H__ */
diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h
new file mode 100644 (file)
index 0000000..cd69391
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __XEN_PUBLIC_PHYSDEV_H__
+#define __XEN_PUBLIC_PHYSDEV_H__
+
+/*
+ * Prototype for this hypercall is:
+ *  int physdev_op(int cmd, void *args)
+ * @cmd         == PHYSDEVOP_??? (physdev operation).
+ * @args == Operation-specific extra arguments (NULL if none).
+ */
+
+/*
+ * Notify end-of-interrupt (EOI) for the specified IRQ.
+ * @arg == pointer to physdev_eoi structure.
+ */
+#define PHYSDEVOP_eoi                  12
+struct physdev_eoi {
+       /* IN */
+       uint32_t irq;
+};
+
+/*
+ * Query the status of an IRQ line.
+ * @arg == pointer to physdev_irq_status_query structure.
+ */
+#define PHYSDEVOP_irq_status_query      5
+struct physdev_irq_status_query {
+       /* IN */
+       uint32_t irq;
+       /* OUT */
+       uint32_t flags; /* XENIRQSTAT_* */
+};
+
+/* Need to call PHYSDEVOP_eoi when the IRQ has been serviced? */
+#define _XENIRQSTAT_needs_eoi  (0)
+#define         XENIRQSTAT_needs_eoi   (1U<<_XENIRQSTAT_needs_eoi)
+
+/* IRQ shared by multiple guests? */
+#define _XENIRQSTAT_shared     (1)
+#define         XENIRQSTAT_shared      (1U<<_XENIRQSTAT_shared)
+
+/*
+ * Set the current VCPU's I/O privilege level.
+ * @arg == pointer to physdev_set_iopl structure.
+ */
+#define PHYSDEVOP_set_iopl              6
+struct physdev_set_iopl {
+       /* IN */
+       uint32_t iopl;
+};
+
+/*
+ * Set the current VCPU's I/O-port permissions bitmap.
+ * @arg == pointer to physdev_set_iobitmap structure.
+ */
+#define PHYSDEVOP_set_iobitmap          7
+struct physdev_set_iobitmap {
+       /* IN */
+       uint8_t * bitmap;
+       uint32_t nr_ports;
+};
+
+/*
+ * Read or write an IO-APIC register.
+ * @arg == pointer to physdev_apic structure.
+ */
+#define PHYSDEVOP_apic_read             8
+#define PHYSDEVOP_apic_write            9
+struct physdev_apic {
+       /* IN */
+       unsigned long apic_physbase;
+       uint32_t reg;
+       /* IN or OUT */
+       uint32_t value;
+};
+
+/*
+ * Allocate or free a physical upcall vector for the specified IRQ line.
+ * @arg == pointer to physdev_irq structure.
+ */
+#define PHYSDEVOP_alloc_irq_vector     10
+#define PHYSDEVOP_free_irq_vector      11
+struct physdev_irq {
+       /* IN */
+       uint32_t irq;
+       /* IN or OUT */
+       uint32_t vector;
+};
+
+/*
+ * Argument to physdev_op_compat() hypercall. Superceded by new physdev_op()
+ * hypercall since 0x00030202.
+ */
+struct physdev_op {
+       uint32_t cmd;
+       union {
+               struct physdev_irq_status_query      irq_status_query;
+               struct physdev_set_iopl              set_iopl;
+               struct physdev_set_iobitmap          set_iobitmap;
+               struct physdev_apic                  apic_op;
+               struct physdev_irq                   irq_op;
+       } u;
+};
+
+/*
+ * Notify that some PIRQ-bound event channels have been unmasked.
+ * ** This command is obsolete since interface version 0x00030202 and is **
+ * ** unsupported by newer versions of Xen.                             **
+ */
+#define PHYSDEVOP_IRQ_UNMASK_NOTIFY     4
+
+/*
+ * These all-capitals physdev operation names are superceded by the new names
+ * (defined above) since interface version 0x00030202.
+ */
+#define PHYSDEVOP_IRQ_STATUS_QUERY      PHYSDEVOP_irq_status_query
+#define PHYSDEVOP_SET_IOPL              PHYSDEVOP_set_iopl
+#define PHYSDEVOP_SET_IOBITMAP          PHYSDEVOP_set_iobitmap
+#define PHYSDEVOP_APIC_READ             PHYSDEVOP_apic_read
+#define PHYSDEVOP_APIC_WRITE            PHYSDEVOP_apic_write
+#define PHYSDEVOP_ASSIGN_VECTOR                 PHYSDEVOP_alloc_irq_vector
+#define PHYSDEVOP_FREE_VECTOR           PHYSDEVOP_free_irq_vector
+#define PHYSDEVOP_IRQ_NEEDS_UNMASK_NOTIFY XENIRQSTAT_needs_eoi
+#define PHYSDEVOP_IRQ_SHARED            XENIRQSTAT_shared
+
+#endif /* __XEN_PUBLIC_PHYSDEV_H__ */
diff --git a/include/xen/interface/sched.h b/include/xen/interface/sched.h
new file mode 100644 (file)
index 0000000..5fec575
--- /dev/null
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * sched.h
+ *
+ * Scheduler state interactions
+ *
+ * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_SCHED_H__
+#define __XEN_PUBLIC_SCHED_H__
+
+#include "event_channel.h"
+
+/*
+ * The prototype for this hypercall is:
+ *  long sched_op_new(int cmd, void *arg)
+ * @cmd == SCHEDOP_??? (scheduler operation).
+ * @arg == Operation-specific extra argument(s), as described below.
+ *
+ * **NOTE**:
+ * Versions of Xen prior to 3.0.2 provide only the following legacy version
+ * of this hypercall, supporting only the commands yield, block and shutdown:
+ *  long sched_op(int cmd, unsigned long arg)
+ * @cmd == SCHEDOP_??? (scheduler operation).
+ * @arg == 0               (SCHEDOP_yield and SCHEDOP_block)
+ *      == SHUTDOWN_* code (SCHEDOP_shutdown)
+ */
+
+/*
+ * Voluntarily yield the CPU.
+ * @arg == NULL.
+ */
+#define SCHEDOP_yield       0
+
+/*
+ * Block execution of this VCPU until an event is received for processing.
+ * If called with event upcalls masked, this operation will atomically
+ * reenable event delivery and check for pending events before blocking the
+ * VCPU. This avoids a "wakeup waiting" race.
+ * @arg == NULL.
+ */
+#define SCHEDOP_block       1
+
+/*
+ * Halt execution of this domain (all VCPUs) and notify the system controller.
+ * @arg == pointer to sched_shutdown structure.
+ */
+#define SCHEDOP_shutdown    2
+struct sched_shutdown {
+    unsigned int reason; /* SHUTDOWN_* */
+};
+DEFINE_GUEST_HANDLE_STRUCT(sched_shutdown);
+
+/*
+ * Poll a set of event-channel ports. Return when one or more are pending. An
+ * optional timeout may be specified.
+ * @arg == pointer to sched_poll structure.
+ */
+#define SCHEDOP_poll        3
+struct sched_poll {
+    GUEST_HANDLE(evtchn_port_t) ports;
+    unsigned int nr_ports;
+    uint64_t timeout;
+};
+DEFINE_GUEST_HANDLE_STRUCT(sched_poll);
+
+/*
+ * Reason codes for SCHEDOP_shutdown. These may be interpreted by control
+ * software to determine the appropriate action. For the most part, Xen does
+ * not care about the shutdown code.
+ */
+#define SHUTDOWN_poweroff   0  /* Domain exited normally. Clean up and kill. */
+#define SHUTDOWN_reboot     1  /* Clean up, kill, and then restart.          */
+#define SHUTDOWN_suspend    2  /* Clean up, save suspend info, kill.         */
+#define SHUTDOWN_crash      3  /* Tell controller we've crashed.             */
+
+#endif /* __XEN_PUBLIC_SCHED_H__ */
diff --git a/include/xen/interface/vcpu.h b/include/xen/interface/vcpu.h
new file mode 100644 (file)
index 0000000..ff61ea3
--- /dev/null
@@ -0,0 +1,167 @@
+/******************************************************************************
+ * vcpu.h
+ *
+ * VCPU initialisation, query, and hotplug.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_VCPU_H__
+#define __XEN_PUBLIC_VCPU_H__
+
+/*
+ * Prototype for this hypercall is:
+ *     int vcpu_op(int cmd, int vcpuid, void *extra_args)
+ * @cmd                   == VCPUOP_??? (VCPU operation).
+ * @vcpuid        == VCPU to operate on.
+ * @extra_args == Operation-specific extra arguments (NULL if none).
+ */
+
+/*
+ * Initialise a VCPU. Each VCPU can be initialised only once. A
+ * newly-initialised VCPU will not run until it is brought up by VCPUOP_up.
+ *
+ * @extra_arg == pointer to vcpu_guest_context structure containing initial
+ *                              state for the VCPU.
+ */
+#define VCPUOP_initialise                       0
+
+/*
+ * Bring up a VCPU. This makes the VCPU runnable. This operation will fail
+ * if the VCPU has not been initialised (VCPUOP_initialise).
+ */
+#define VCPUOP_up                                       1
+
+/*
+ * Bring down a VCPU (i.e., make it non-runnable).
+ * There are a few caveats that callers should observe:
+ *     1. This operation may return, and VCPU_is_up may return false, before the
+ *        VCPU stops running (i.e., the command is asynchronous). It is a good
+ *        idea to ensure that the VCPU has entered a non-critical loop before
+ *        bringing it down. Alternatively, this operation is guaranteed
+ *        synchronous if invoked by the VCPU itself.
+ *     2. After a VCPU is initialised, there is currently no way to drop all its
+ *        references to domain memory. Even a VCPU that is down still holds
+ *        memory references via its pagetable base pointer and GDT. It is good
+ *        practise to move a VCPU onto an 'idle' or default page table, LDT and
+ *        GDT before bringing it down.
+ */
+#define VCPUOP_down                                     2
+
+/* Returns 1 if the given VCPU is up. */
+#define VCPUOP_is_up                            3
+
+/*
+ * Return information about the state and running time of a VCPU.
+ * @extra_arg == pointer to vcpu_runstate_info structure.
+ */
+#define VCPUOP_get_runstate_info        4
+struct vcpu_runstate_info {
+               /* VCPU's current state (RUNSTATE_*). */
+               int              state;
+               /* When was current state entered (system time, ns)? */
+               uint64_t state_entry_time;
+               /*
+                * Time spent in each RUNSTATE_* (ns). The sum of these times is
+                * guaranteed not to drift from system time.
+                */
+               uint64_t time[4];
+};
+
+/* VCPU is currently running on a physical CPU. */
+#define RUNSTATE_running  0
+
+/* VCPU is runnable, but not currently scheduled on any physical CPU. */
+#define RUNSTATE_runnable 1
+
+/* VCPU is blocked (a.k.a. idle). It is therefore not runnable. */
+#define RUNSTATE_blocked  2
+
+/*
+ * VCPU is not runnable, but it is not blocked.
+ * This is a 'catch all' state for things like hotplug and pauses by the
+ * system administrator (or for critical sections in the hypervisor).
+ * RUNSTATE_blocked dominates this state (it is the preferred state).
+ */
+#define RUNSTATE_offline  3
+
+/*
+ * Register a shared memory area from which the guest may obtain its own
+ * runstate information without needing to execute a hypercall.
+ * Notes:
+ *     1. The registered address may be virtual or physical, depending on the
+ *        platform. The virtual address should be registered on x86 systems.
+ *     2. Only one shared area may be registered per VCPU. The shared area is
+ *        updated by the hypervisor each time the VCPU is scheduled. Thus
+ *        runstate.state will always be RUNSTATE_running and
+ *        runstate.state_entry_time will indicate the system time at which the
+ *        VCPU was last scheduled to run.
+ * @extra_arg == pointer to vcpu_register_runstate_memory_area structure.
+ */
+#define VCPUOP_register_runstate_memory_area 5
+struct vcpu_register_runstate_memory_area {
+               union {
+                               struct vcpu_runstate_info *v;
+                               uint64_t p;
+               } addr;
+};
+
+/*
+ * Set or stop a VCPU's periodic timer. Every VCPU has one periodic timer
+ * which can be set via these commands. Periods smaller than one millisecond
+ * may not be supported.
+ */
+#define VCPUOP_set_periodic_timer       6 /* arg == vcpu_set_periodic_timer_t */
+#define VCPUOP_stop_periodic_timer      7 /* arg == NULL */
+struct vcpu_set_periodic_timer {
+               uint64_t period_ns;
+};
+
+/*
+ * Set or stop a VCPU's single-shot timer. Every VCPU has one single-shot
+ * timer which can be set via these commands.
+ */
+#define VCPUOP_set_singleshot_timer     8 /* arg == vcpu_set_singleshot_timer_t */
+#define VCPUOP_stop_singleshot_timer 9 /* arg == NULL */
+struct vcpu_set_singleshot_timer {
+               uint64_t timeout_abs_ns;
+               uint32_t flags;                    /* VCPU_SSHOTTMR_??? */
+};
+
+/* Flags to VCPUOP_set_singleshot_timer. */
+ /* Require the timeout to be in the future (return -ETIME if it's passed). */
+#define _VCPU_SSHOTTMR_future (0)
+#define VCPU_SSHOTTMR_future  (1U << _VCPU_SSHOTTMR_future)
+
+/*
+ * Register a memory location in the guest address space for the
+ * vcpu_info structure.  This allows the guest to place the vcpu_info
+ * structure in a convenient place, such as in a per-cpu data area.
+ * The pointer need not be page aligned, but the structure must not
+ * cross a page boundary.
+ */
+#define VCPUOP_register_vcpu_info   10  /* arg == struct vcpu_info */
+struct vcpu_register_vcpu_info {
+    uint32_t mfn;               /* mfn of page to place vcpu_info */
+    uint32_t offset;            /* offset within page */
+};
+
+#endif /* __XEN_PUBLIC_VCPU_H__ */
diff --git a/include/xen/interface/version.h b/include/xen/interface/version.h
new file mode 100644 (file)
index 0000000..453235e
--- /dev/null
@@ -0,0 +1,60 @@
+/******************************************************************************
+ * version.h
+ *
+ * Xen version, type, and compile information.
+ *
+ * Copyright (c) 2005, Nguyen Anh Quynh <aquynh@gmail.com>
+ * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_VERSION_H__
+#define __XEN_PUBLIC_VERSION_H__
+
+/* NB. All ops return zero on success, except XENVER_version. */
+
+/* arg == NULL; returns major:minor (16:16). */
+#define XENVER_version      0
+
+/* arg == xen_extraversion_t. */
+#define XENVER_extraversion 1
+struct xen_extraversion {
+    char extraversion[16];
+};
+#define XEN_EXTRAVERSION_LEN (sizeof(struct xen_extraversion))
+
+/* arg == xen_compile_info_t. */
+#define XENVER_compile_info 2
+struct xen_compile_info {
+    char compiler[64];
+    char compile_by[16];
+    char compile_domain[32];
+    char compile_date[32];
+};
+
+#define XENVER_capabilities 3
+struct xen_capabilities_info {
+    char info[1024];
+};
+#define XEN_CAPABILITIES_INFO_LEN (sizeof(struct xen_capabilities_info))
+
+#define XENVER_changeset 4
+struct xen_changeset_info {
+    char info[64];
+};
+#define XEN_CHANGESET_INFO_LEN (sizeof(struct xen_changeset_info))
+
+#define XENVER_platform_parameters 5
+struct xen_platform_parameters {
+    unsigned long virt_start;
+};
+
+#define XENVER_get_features 6
+struct xen_feature_info {
+    unsigned int submap_idx;    /* IN: which 32-bit submap to return */
+    uint32_t     submap;        /* OUT: 32-bit submap */
+};
+
+/* Declares the features reported by XENVER_get_features. */
+#include "features.h"
+
+#endif /* __XEN_PUBLIC_VERSION_H__ */
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
new file mode 100644 (file)
index 0000000..518a5bf
--- /dev/null
@@ -0,0 +1,447 @@
+/******************************************************************************
+ * xen.h
+ *
+ * Guest OS interface to Xen.
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __XEN_PUBLIC_XEN_H__
+#define __XEN_PUBLIC_XEN_H__
+
+#include <asm/xen/interface.h>
+
+/*
+ * XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS).
+ */
+
+/*
+ * x86_32: EAX = vector; EBX, ECX, EDX, ESI, EDI = args 1, 2, 3, 4, 5.
+ *         EAX = return value
+ *         (argument registers may be clobbered on return)
+ * x86_64: RAX = vector; RDI, RSI, RDX, R10, R8, R9 = args 1, 2, 3, 4, 5, 6.
+ *         RAX = return value
+ *         (argument registers not clobbered on return; RCX, R11 are)
+ */
+#define __HYPERVISOR_set_trap_table        0
+#define __HYPERVISOR_mmu_update            1
+#define __HYPERVISOR_set_gdt               2
+#define __HYPERVISOR_stack_switch          3
+#define __HYPERVISOR_set_callbacks         4
+#define __HYPERVISOR_fpu_taskswitch        5
+#define __HYPERVISOR_sched_op              6
+#define __HYPERVISOR_dom0_op               7
+#define __HYPERVISOR_set_debugreg          8
+#define __HYPERVISOR_get_debugreg          9
+#define __HYPERVISOR_update_descriptor    10
+#define __HYPERVISOR_memory_op            12
+#define __HYPERVISOR_multicall            13
+#define __HYPERVISOR_update_va_mapping    14
+#define __HYPERVISOR_set_timer_op         15
+#define __HYPERVISOR_event_channel_op_compat 16
+#define __HYPERVISOR_xen_version          17
+#define __HYPERVISOR_console_io           18
+#define __HYPERVISOR_physdev_op_compat    19
+#define __HYPERVISOR_grant_table_op       20
+#define __HYPERVISOR_vm_assist            21
+#define __HYPERVISOR_update_va_mapping_otherdomain 22
+#define __HYPERVISOR_iret                 23 /* x86 only */
+#define __HYPERVISOR_vcpu_op              24
+#define __HYPERVISOR_set_segment_base     25 /* x86/64 only */
+#define __HYPERVISOR_mmuext_op            26
+#define __HYPERVISOR_acm_op               27
+#define __HYPERVISOR_nmi_op               28
+#define __HYPERVISOR_sched_op_new         29
+#define __HYPERVISOR_callback_op          30
+#define __HYPERVISOR_xenoprof_op          31
+#define __HYPERVISOR_event_channel_op     32
+#define __HYPERVISOR_physdev_op           33
+#define __HYPERVISOR_hvm_op               34
+
+/*
+ * VIRTUAL INTERRUPTS
+ *
+ * Virtual interrupts that a guest OS may receive from Xen.
+ */
+#define VIRQ_TIMER      0  /* Timebase update, and/or requested timeout.  */
+#define VIRQ_DEBUG      1  /* Request guest to dump debug info.           */
+#define VIRQ_CONSOLE    2  /* (DOM0) Bytes received on emergency console. */
+#define VIRQ_DOM_EXC    3  /* (DOM0) Exceptional event for some domain.   */
+#define VIRQ_DEBUGGER   6  /* (DOM0) A domain has paused for debugging.   */
+#define NR_VIRQS        8
+
+/*
+ * MMU-UPDATE REQUESTS
+ *
+ * HYPERVISOR_mmu_update() accepts a list of (ptr, val) pairs.
+ * A foreigndom (FD) can be specified (or DOMID_SELF for none).
+ * Where the FD has some effect, it is described below.
+ * ptr[1:0] specifies the appropriate MMU_* command.
+ *
+ * ptr[1:0] == MMU_NORMAL_PT_UPDATE:
+ * Updates an entry in a page table. If updating an L1 table, and the new
+ * table entry is valid/present, the mapped frame must belong to the FD, if
+ * an FD has been specified. If attempting to map an I/O page then the
+ * caller assumes the privilege of the FD.
+ * FD == DOMID_IO: Permit /only/ I/O mappings, at the priv level of the caller.
+ * FD == DOMID_XEN: Map restricted areas of Xen's heap space.
+ * ptr[:2]  -- Machine address of the page-table entry to modify.
+ * val      -- Value to write.
+ *
+ * ptr[1:0] == MMU_MACHPHYS_UPDATE:
+ * Updates an entry in the machine->pseudo-physical mapping table.
+ * ptr[:2]  -- Machine address within the frame whose mapping to modify.
+ *             The frame must belong to the FD, if one is specified.
+ * val      -- Value to write into the mapping entry.
+ */
+#define MMU_NORMAL_PT_UPDATE     0 /* checked '*ptr = val'. ptr is MA.       */
+#define MMU_MACHPHYS_UPDATE      1 /* ptr = MA of frame to modify entry for  */
+
+/*
+ * MMU EXTENDED OPERATIONS
+ *
+ * HYPERVISOR_mmuext_op() accepts a list of mmuext_op structures.
+ * A foreigndom (FD) can be specified (or DOMID_SELF for none).
+ * Where the FD has some effect, it is described below.
+ *
+ * cmd: MMUEXT_(UN)PIN_*_TABLE
+ * mfn: Machine frame number to be (un)pinned as a p.t. page.
+ *      The frame must belong to the FD, if one is specified.
+ *
+ * cmd: MMUEXT_NEW_BASEPTR
+ * mfn: Machine frame number of new page-table base to install in MMU.
+ *
+ * cmd: MMUEXT_NEW_USER_BASEPTR [x86/64 only]
+ * mfn: Machine frame number of new page-table base to install in MMU
+ *      when in user space.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_LOCAL
+ * No additional arguments. Flushes local TLB.
+ *
+ * cmd: MMUEXT_INVLPG_LOCAL
+ * linear_addr: Linear address to be flushed from the local TLB.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_MULTI
+ * vcpumask: Pointer to bitmap of VCPUs to be flushed.
+ *
+ * cmd: MMUEXT_INVLPG_MULTI
+ * linear_addr: Linear address to be flushed.
+ * vcpumask: Pointer to bitmap of VCPUs to be flushed.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_ALL
+ * No additional arguments. Flushes all VCPUs' TLBs.
+ *
+ * cmd: MMUEXT_INVLPG_ALL
+ * linear_addr: Linear address to be flushed from all VCPUs' TLBs.
+ *
+ * cmd: MMUEXT_FLUSH_CACHE
+ * No additional arguments. Writes back and flushes cache contents.
+ *
+ * cmd: MMUEXT_SET_LDT
+ * linear_addr: Linear address of LDT base (NB. must be page-aligned).
+ * nr_ents: Number of entries in LDT.
+ */
+#define MMUEXT_PIN_L1_TABLE      0
+#define MMUEXT_PIN_L2_TABLE      1
+#define MMUEXT_PIN_L3_TABLE      2
+#define MMUEXT_PIN_L4_TABLE      3
+#define MMUEXT_UNPIN_TABLE       4
+#define MMUEXT_NEW_BASEPTR       5
+#define MMUEXT_TLB_FLUSH_LOCAL   6
+#define MMUEXT_INVLPG_LOCAL      7
+#define MMUEXT_TLB_FLUSH_MULTI   8
+#define MMUEXT_INVLPG_MULTI      9
+#define MMUEXT_TLB_FLUSH_ALL    10
+#define MMUEXT_INVLPG_ALL       11
+#define MMUEXT_FLUSH_CACHE      12
+#define MMUEXT_SET_LDT          13
+#define MMUEXT_NEW_USER_BASEPTR 15
+
+#ifndef __ASSEMBLY__
+struct mmuext_op {
+       unsigned int cmd;
+       union {
+               /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR */
+               unsigned long mfn;
+               /* INVLPG_LOCAL, INVLPG_ALL, SET_LDT */
+               unsigned long linear_addr;
+       } arg1;
+       union {
+               /* SET_LDT */
+               unsigned int nr_ents;
+               /* TLB_FLUSH_MULTI, INVLPG_MULTI */
+               void *vcpumask;
+       } arg2;
+};
+DEFINE_GUEST_HANDLE_STRUCT(mmuext_op);
+#endif
+
+/* These are passed as 'flags' to update_va_mapping. They can be ORed. */
+/* When specifying UVMF_MULTI, also OR in a pointer to a CPU bitmap.   */
+/* UVMF_LOCAL is merely UVMF_MULTI with a NULL bitmap pointer.         */
+#define UVMF_NONE               (0UL<<0) /* No flushing at all.   */
+#define UVMF_TLB_FLUSH          (1UL<<0) /* Flush entire TLB(s).  */
+#define UVMF_INVLPG             (2UL<<0) /* Flush only one entry. */
+#define UVMF_FLUSHTYPE_MASK     (3UL<<0)
+#define UVMF_MULTI              (0UL<<2) /* Flush subset of TLBs. */
+#define UVMF_LOCAL              (0UL<<2) /* Flush local TLB.      */
+#define UVMF_ALL                (1UL<<2) /* Flush all TLBs.       */
+
+/*
+ * Commands to HYPERVISOR_console_io().
+ */
+#define CONSOLEIO_write         0
+#define CONSOLEIO_read          1
+
+/*
+ * Commands to HYPERVISOR_vm_assist().
+ */
+#define VMASST_CMD_enable                0
+#define VMASST_CMD_disable               1
+#define VMASST_TYPE_4gb_segments         0
+#define VMASST_TYPE_4gb_segments_notify  1
+#define VMASST_TYPE_writable_pagetables  2
+#define VMASST_TYPE_pae_extended_cr3     3
+#define MAX_VMASST_TYPE 3
+
+#ifndef __ASSEMBLY__
+
+typedef uint16_t domid_t;
+
+/* Domain ids >= DOMID_FIRST_RESERVED cannot be used for ordinary domains. */
+#define DOMID_FIRST_RESERVED (0x7FF0U)
+
+/* DOMID_SELF is used in certain contexts to refer to oneself. */
+#define DOMID_SELF (0x7FF0U)
+
+/*
+ * DOMID_IO is used to restrict page-table updates to mapping I/O memory.
+ * Although no Foreign Domain need be specified to map I/O pages, DOMID_IO
+ * is useful to ensure that no mappings to the OS's own heap are accidentally
+ * installed. (e.g., in Linux this could cause havoc as reference counts
+ * aren't adjusted on the I/O-mapping code path).
+ * This only makes sense in MMUEXT_SET_FOREIGNDOM, but in that context can
+ * be specified by any calling domain.
+ */
+#define DOMID_IO   (0x7FF1U)
+
+/*
+ * DOMID_XEN is used to allow privileged domains to map restricted parts of
+ * Xen's heap space (e.g., the machine_to_phys table).
+ * This only makes sense in MMUEXT_SET_FOREIGNDOM, and is only permitted if
+ * the caller is privileged.
+ */
+#define DOMID_XEN  (0x7FF2U)
+
+/*
+ * Send an array of these to HYPERVISOR_mmu_update().
+ * NB. The fields are natural pointer/address size for this architecture.
+ */
+struct mmu_update {
+    uint64_t ptr;       /* Machine address of PTE. */
+    uint64_t val;       /* New contents of PTE.    */
+};
+DEFINE_GUEST_HANDLE_STRUCT(mmu_update);
+
+/*
+ * Send an array of these to HYPERVISOR_multicall().
+ * NB. The fields are natural register size for this architecture.
+ */
+struct multicall_entry {
+    unsigned long op;
+    long result;
+    unsigned long args[6];
+};
+DEFINE_GUEST_HANDLE_STRUCT(multicall_entry);
+
+/*
+ * Event channel endpoints per domain:
+ *  1024 if a long is 32 bits; 4096 if a long is 64 bits.
+ */
+#define NR_EVENT_CHANNELS (sizeof(unsigned long) * sizeof(unsigned long) * 64)
+
+struct vcpu_time_info {
+       /*
+        * Updates to the following values are preceded and followed
+        * by an increment of 'version'. The guest can therefore
+        * detect updates by looking for changes to 'version'. If the
+        * least-significant bit of the version number is set then an
+        * update is in progress and the guest must wait to read a
+        * consistent set of values.  The correct way to interact with
+        * the version number is similar to Linux's seqlock: see the
+        * implementations of read_seqbegin/read_seqretry.
+        */
+       uint32_t version;
+       uint32_t pad0;
+       uint64_t tsc_timestamp;   /* TSC at last update of time vals.  */
+       uint64_t system_time;     /* Time, in nanosecs, since boot.    */
+       /*
+        * Current system time:
+        *   system_time + ((tsc - tsc_timestamp) << tsc_shift) * tsc_to_system_mul
+        * CPU frequency (Hz):
+        *   ((10^9 << 32) / tsc_to_system_mul) >> tsc_shift
+        */
+       uint32_t tsc_to_system_mul;
+       int8_t   tsc_shift;
+       int8_t   pad1[3];
+}; /* 32 bytes */
+
+struct vcpu_info {
+       /*
+        * 'evtchn_upcall_pending' is written non-zero by Xen to indicate
+        * a pending notification for a particular VCPU. It is then cleared
+        * by the guest OS /before/ checking for pending work, thus avoiding
+        * a set-and-check race. Note that the mask is only accessed by Xen
+        * on the CPU that is currently hosting the VCPU. This means that the
+        * pending and mask flags can be updated by the guest without special
+        * synchronisation (i.e., no need for the x86 LOCK prefix).
+        * This may seem suboptimal because if the pending flag is set by
+        * a different CPU then an IPI may be scheduled even when the mask
+        * is set. However, note:
+        *  1. The task of 'interrupt holdoff' is covered by the per-event-
+        *     channel mask bits. A 'noisy' event that is continually being
+        *     triggered can be masked at source at this very precise
+        *     granularity.
+        *  2. The main purpose of the per-VCPU mask is therefore to restrict
+        *     reentrant execution: whether for concurrency control, or to
+        *     prevent unbounded stack usage. Whatever the purpose, we expect
+        *     that the mask will be asserted only for short periods at a time,
+        *     and so the likelihood of a 'spurious' IPI is suitably small.
+        * The mask is read before making an event upcall to the guest: a
+        * non-zero mask therefore guarantees that the VCPU will not receive
+        * an upcall activation. The mask is cleared when the VCPU requests
+        * to block: this avoids wakeup-waiting races.
+        */
+       uint8_t evtchn_upcall_pending;
+       uint8_t evtchn_upcall_mask;
+       unsigned long evtchn_pending_sel;
+       struct arch_vcpu_info arch;
+       struct vcpu_time_info time;
+}; /* 64 bytes (x86) */
+
+/*
+ * Xen/kernel shared data -- pointer provided in start_info.
+ * NB. We expect that this struct is smaller than a page.
+ */
+struct shared_info {
+       struct vcpu_info vcpu_info[MAX_VIRT_CPUS];
+
+       /*
+        * A domain can create "event channels" on which it can send and receive
+        * asynchronous event notifications. There are three classes of event that
+        * are delivered by this mechanism:
+        *  1. Bi-directional inter- and intra-domain connections. Domains must
+        *     arrange out-of-band to set up a connection (usually by allocating
+        *     an unbound 'listener' port and avertising that via a storage service
+        *     such as xenstore).
+        *  2. Physical interrupts. A domain with suitable hardware-access
+        *     privileges can bind an event-channel port to a physical interrupt
+        *     source.
+        *  3. Virtual interrupts ('events'). A domain can bind an event-channel
+        *     port to a virtual interrupt source, such as the virtual-timer
+        *     device or the emergency console.
+        *
+        * Event channels are addressed by a "port index". Each channel is
+        * associated with two bits of information:
+        *  1. PENDING -- notifies the domain that there is a pending notification
+        *     to be processed. This bit is cleared by the guest.
+        *  2. MASK -- if this bit is clear then a 0->1 transition of PENDING
+        *     will cause an asynchronous upcall to be scheduled. This bit is only
+        *     updated by the guest. It is read-only within Xen. If a channel
+        *     becomes pending while the channel is masked then the 'edge' is lost
+        *     (i.e., when the channel is unmasked, the guest must manually handle
+        *     pending notifications as no upcall will be scheduled by Xen).
+        *
+        * To expedite scanning of pending notifications, any 0->1 pending
+        * transition on an unmasked channel causes a corresponding bit in a
+        * per-vcpu selector word to be set. Each bit in the selector covers a
+        * 'C long' in the PENDING bitfield array.
+        */
+       unsigned long evtchn_pending[sizeof(unsigned long) * 8];
+       unsigned long evtchn_mask[sizeof(unsigned long) * 8];
+
+       /*
+        * Wallclock time: updated only by control software. Guests should base
+        * their gettimeofday() syscall on this wallclock-base value.
+        */
+       uint32_t wc_version;      /* Version counter: see vcpu_time_info_t. */
+       uint32_t wc_sec;          /* Secs  00:00:00 UTC, Jan 1, 1970.  */
+       uint32_t wc_nsec;         /* Nsecs 00:00:00 UTC, Jan 1, 1970.  */
+
+       struct arch_shared_info arch;
+
+};
+
+/*
+ * Start-of-day memory layout for the initial domain (DOM0):
+ *  1. The domain is started within contiguous virtual-memory region.
+ *  2. The contiguous region begins and ends on an aligned 4MB boundary.
+ *  3. The region start corresponds to the load address of the OS image.
+ *     If the load address is not 4MB aligned then the address is rounded down.
+ *  4. This the order of bootstrap elements in the initial virtual region:
+ *      a. relocated kernel image
+ *      b. initial ram disk              [mod_start, mod_len]
+ *      c. list of allocated page frames [mfn_list, nr_pages]
+ *      d. start_info_t structure        [register ESI (x86)]
+ *      e. bootstrap page tables         [pt_base, CR3 (x86)]
+ *      f. bootstrap stack               [register ESP (x86)]
+ *  5. Bootstrap elements are packed together, but each is 4kB-aligned.
+ *  6. The initial ram disk may be omitted.
+ *  7. The list of page frames forms a contiguous 'pseudo-physical' memory
+ *     layout for the domain. In particular, the bootstrap virtual-memory
+ *     region is a 1:1 mapping to the first section of the pseudo-physical map.
+ *  8. All bootstrap elements are mapped read-writable for the guest OS. The
+ *     only exception is the bootstrap page table, which is mapped read-only.
+ *  9. There is guaranteed to be at least 512kB padding after the final
+ *     bootstrap element. If necessary, the bootstrap virtual region is
+ *     extended by an extra 4MB to ensure this.
+ */
+
+#define MAX_GUEST_CMDLINE 1024
+struct start_info {
+       /* THE FOLLOWING ARE FILLED IN BOTH ON INITIAL BOOT AND ON RESUME.    */
+       char magic[32];             /* "xen-<version>-<platform>".            */
+       unsigned long nr_pages;     /* Total pages allocated to this domain.  */
+       unsigned long shared_info;  /* MACHINE address of shared info struct. */
+       uint32_t flags;             /* SIF_xxx flags.                         */
+       unsigned long store_mfn;    /* MACHINE page number of shared page.    */
+       uint32_t store_evtchn;      /* Event channel for store communication. */
+       union {
+               struct {
+                       unsigned long mfn;  /* MACHINE page number of console page.   */
+                       uint32_t  evtchn;   /* Event channel for console page.        */
+               } domU;
+               struct {
+                       uint32_t info_off;  /* Offset of console_info struct.         */
+                       uint32_t info_size; /* Size of console_info struct from start.*/
+               } dom0;
+       } console;
+       /* THE FOLLOWING ARE ONLY FILLED IN ON INITIAL BOOT (NOT RESUME).     */
+       unsigned long pt_base;      /* VIRTUAL address of page directory.     */
+       unsigned long nr_pt_frames; /* Number of bootstrap p.t. frames.       */
+       unsigned long mfn_list;     /* VIRTUAL address of page-frame list.    */
+       unsigned long mod_start;    /* VIRTUAL address of pre-loaded module.  */
+       unsigned long mod_len;      /* Size (bytes) of pre-loaded module.     */
+       int8_t cmd_line[MAX_GUEST_CMDLINE];
+};
+
+/* These flags are passed in the 'flags' field of start_info_t. */
+#define SIF_PRIVILEGED    (1<<0)  /* Is the domain privileged? */
+#define SIF_INITDOMAIN    (1<<1)  /* Is this the initial control domain? */
+
+typedef uint64_t cpumap_t;
+
+typedef uint8_t xen_domain_handle_t[16];
+
+/* Turn a plain number into a C unsigned long constant. */
+#define __mk_unsigned_long(x) x ## UL
+#define mk_unsigned_long(x) __mk_unsigned_long(x)
+
+#else /* __ASSEMBLY__ */
+
+/* In assembly code we cannot use C numeric constant suffixes. */
+#define mk_unsigned_long(x) x
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __XEN_PUBLIC_XEN_H__ */
diff --git a/include/xen/page.h b/include/xen/page.h
new file mode 100644 (file)
index 0000000..1df6c19
--- /dev/null
@@ -0,0 +1,179 @@
+#ifndef __XEN_PAGE_H
+#define __XEN_PAGE_H
+
+#include <linux/pfn.h>
+
+#include <asm/uaccess.h>
+
+#include <xen/features.h>
+
+#ifdef CONFIG_X86_PAE
+/* Xen machine address */
+typedef struct xmaddr {
+       unsigned long long maddr;
+} xmaddr_t;
+
+/* Xen pseudo-physical address */
+typedef struct xpaddr {
+       unsigned long long paddr;
+} xpaddr_t;
+#else
+/* Xen machine address */
+typedef struct xmaddr {
+       unsigned long maddr;
+} xmaddr_t;
+
+/* Xen pseudo-physical address */
+typedef struct xpaddr {
+       unsigned long paddr;
+} xpaddr_t;
+#endif
+
+#define XMADDR(x)      ((xmaddr_t) { .maddr = (x) })
+#define XPADDR(x)      ((xpaddr_t) { .paddr = (x) })
+
+/**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/
+#define INVALID_P2M_ENTRY      (~0UL)
+#define FOREIGN_FRAME_BIT      (1UL<<31)
+#define FOREIGN_FRAME(m)       ((m) | FOREIGN_FRAME_BIT)
+
+extern unsigned long *phys_to_machine_mapping;
+
+static inline unsigned long pfn_to_mfn(unsigned long pfn)
+{
+       if (xen_feature(XENFEAT_auto_translated_physmap))
+               return pfn;
+
+       return phys_to_machine_mapping[(unsigned int)(pfn)] &
+               ~FOREIGN_FRAME_BIT;
+}
+
+static inline int phys_to_machine_mapping_valid(unsigned long pfn)
+{
+       if (xen_feature(XENFEAT_auto_translated_physmap))
+               return 1;
+
+       return (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY);
+}
+
+static inline unsigned long mfn_to_pfn(unsigned long mfn)
+{
+       unsigned long pfn;
+
+       if (xen_feature(XENFEAT_auto_translated_physmap))
+               return mfn;
+
+#if 0
+       if (unlikely((mfn >> machine_to_phys_order) != 0))
+               return max_mapnr;
+#endif
+
+       pfn = 0;
+       /*
+        * The array access can fail (e.g., device space beyond end of RAM).
+        * In such cases it doesn't matter what we return (we return garbage),
+        * but we must handle the fault without crashing!
+        */
+       __get_user(pfn, &machine_to_phys_mapping[mfn]);
+
+       return pfn;
+}
+
+static inline xmaddr_t phys_to_machine(xpaddr_t phys)
+{
+       unsigned offset = phys.paddr & ~PAGE_MASK;
+       return XMADDR(PFN_PHYS((u64)pfn_to_mfn(PFN_DOWN(phys.paddr))) | offset);
+}
+
+static inline xpaddr_t machine_to_phys(xmaddr_t machine)
+{
+       unsigned offset = machine.maddr & ~PAGE_MASK;
+       return XPADDR(PFN_PHYS((u64)mfn_to_pfn(PFN_DOWN(machine.maddr))) | offset);
+}
+
+/*
+ * We detect special mappings in one of two ways:
+ *  1. If the MFN is an I/O page then Xen will set the m2p entry
+ *     to be outside our maximum possible pseudophys range.
+ *  2. If the MFN belongs to a different domain then we will certainly
+ *     not have MFN in our p2m table. Conversely, if the page is ours,
+ *     then we'll have p2m(m2p(MFN))==MFN.
+ * If we detect a special mapping then it doesn't have a 'struct page'.
+ * We force !pfn_valid() by returning an out-of-range pointer.
+ *
+ * NB. These checks require that, for any MFN that is not in our reservation,
+ * there is no PFN such that p2m(PFN) == MFN. Otherwise we can get confused if
+ * we are foreign-mapping the MFN, and the other domain as m2p(MFN) == PFN.
+ * Yikes! Various places must poke in INVALID_P2M_ENTRY for safety.
+ *
+ * NB2. When deliberately mapping foreign pages into the p2m table, you *must*
+ *      use FOREIGN_FRAME(). This will cause pte_pfn() to choke on it, as we
+ *      require. In all the cases we care about, the FOREIGN_FRAME bit is
+ *      masked (e.g., pfn_to_mfn()) so behaviour there is correct.
+ */
+static inline unsigned long mfn_to_local_pfn(unsigned long mfn)
+{
+       extern unsigned long max_mapnr;
+       unsigned long pfn = mfn_to_pfn(mfn);
+       if ((pfn < max_mapnr)
+           && !xen_feature(XENFEAT_auto_translated_physmap)
+           && (phys_to_machine_mapping[pfn] != mfn))
+               return max_mapnr; /* force !pfn_valid() */
+       return pfn;
+}
+
+static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
+{
+       if (xen_feature(XENFEAT_auto_translated_physmap)) {
+               BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
+               return;
+       }
+       phys_to_machine_mapping[pfn] = mfn;
+}
+
+/* VIRT <-> MACHINE conversion */
+#define virt_to_machine(v)     (phys_to_machine(XPADDR(__pa(v))))
+#define virt_to_mfn(v)         (pfn_to_mfn(PFN_DOWN(__pa(v))))
+#define mfn_to_virt(m)         (__va(mfn_to_pfn(m) << PAGE_SHIFT))
+
+#ifdef CONFIG_X86_PAE
+#define pte_mfn(_pte) (((_pte).pte_low >> PAGE_SHIFT) |                        \
+                      (((_pte).pte_high & 0xfff) << (32-PAGE_SHIFT)))
+
+static inline pte_t mfn_pte(unsigned long page_nr, pgprot_t pgprot)
+{
+       pte_t pte;
+
+       pte.pte_high = (page_nr >> (32 - PAGE_SHIFT)) |
+               (pgprot_val(pgprot) >> 32);
+       pte.pte_high &= (__supported_pte_mask >> 32);
+       pte.pte_low = ((page_nr << PAGE_SHIFT) | pgprot_val(pgprot));
+       pte.pte_low &= __supported_pte_mask;
+
+       return pte;
+}
+
+static inline unsigned long long pte_val_ma(pte_t x)
+{
+       return ((unsigned long long)x.pte_high << 32) | x.pte_low;
+}
+#define pmd_val_ma(v) ((v).pmd)
+#define pud_val_ma(v) ((v).pgd.pgd)
+#define __pte_ma(x)    ((pte_t) { .pte_low = (x), .pte_high = (x)>>32 } )
+#define __pmd_ma(x)    ((pmd_t) { (x) } )
+#else  /* !X86_PAE */
+#define pte_mfn(_pte) ((_pte).pte_low >> PAGE_SHIFT)
+#define mfn_pte(pfn, prot)     __pte_ma(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define pte_val_ma(x)  ((x).pte_low)
+#define pmd_val_ma(v)  ((v).pud.pgd.pgd)
+#define __pte_ma(x)    ((pte_t) { (x) } )
+#endif /* CONFIG_X86_PAE */
+
+#define pgd_val_ma(x)  ((x).pgd)
+
+
+xmaddr_t arbitrary_virt_to_machine(unsigned long address);
+void make_lowmem_page_readonly(void *vaddr);
+void make_lowmem_page_readwrite(void *vaddr);
+
+#endif /* __XEN_PAGE_H */
diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h
new file mode 100644 (file)
index 0000000..6f7c290
--- /dev/null
@@ -0,0 +1,234 @@
+/******************************************************************************
+ * xenbus.h
+ *
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 XenSource Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _XEN_XENBUS_H
+#define _XEN_XENBUS_H
+
+#include <linux/device.h>
+#include <linux/notifier.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/init.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/xenbus.h>
+#include <xen/interface/io/xs_wire.h>
+
+/* Register callback to watch this node. */
+struct xenbus_watch
+{
+       struct list_head list;
+
+       /* Path being watched. */
+       const char *node;
+
+       /* Callback (executed in a process context with no locks held). */
+       void (*callback)(struct xenbus_watch *,
+                        const char **vec, unsigned int len);
+};
+
+
+/* A xenbus device. */
+struct xenbus_device {
+       const char *devicetype;
+       const char *nodename;
+       const char *otherend;
+       int otherend_id;
+       struct xenbus_watch otherend_watch;
+       struct device dev;
+       enum xenbus_state state;
+       struct completion down;
+};
+
+static inline struct xenbus_device *to_xenbus_device(struct device *dev)
+{
+       return container_of(dev, struct xenbus_device, dev);
+}
+
+struct xenbus_device_id
+{
+       /* .../device/<device_type>/<identifier> */
+       char devicetype[32];    /* General class of device. */
+};
+
+/* A xenbus driver. */
+struct xenbus_driver {
+       char *name;
+       struct module *owner;
+       const struct xenbus_device_id *ids;
+       int (*probe)(struct xenbus_device *dev,
+                    const struct xenbus_device_id *id);
+       void (*otherend_changed)(struct xenbus_device *dev,
+                                enum xenbus_state backend_state);
+       int (*remove)(struct xenbus_device *dev);
+       int (*suspend)(struct xenbus_device *dev);
+       int (*suspend_cancel)(struct xenbus_device *dev);
+       int (*resume)(struct xenbus_device *dev);
+       int (*uevent)(struct xenbus_device *, char **, int, char *, int);
+       struct device_driver driver;
+       int (*read_otherend_details)(struct xenbus_device *dev);
+};
+
+static inline struct xenbus_driver *to_xenbus_driver(struct device_driver *drv)
+{
+       return container_of(drv, struct xenbus_driver, driver);
+}
+
+int __must_check __xenbus_register_frontend(struct xenbus_driver *drv,
+                                           struct module *owner,
+                                           const char *mod_name);
+
+static inline int __must_check
+xenbus_register_frontend(struct xenbus_driver *drv)
+{
+       WARN_ON(drv->owner != THIS_MODULE);
+       return __xenbus_register_frontend(drv, THIS_MODULE, KBUILD_MODNAME);
+}
+
+int __must_check __xenbus_register_backend(struct xenbus_driver *drv,
+                                          struct module *owner,
+                                          const char *mod_name);
+static inline int __must_check
+xenbus_register_backend(struct xenbus_driver *drv)
+{
+       WARN_ON(drv->owner != THIS_MODULE);
+       return __xenbus_register_backend(drv, THIS_MODULE, KBUILD_MODNAME);
+}
+
+void xenbus_unregister_driver(struct xenbus_driver *drv);
+
+struct xenbus_transaction
+{
+       u32 id;
+};
+
+/* Nil transaction ID. */
+#define XBT_NIL ((struct xenbus_transaction) { 0 })
+
+int __init xenbus_dev_init(void);
+
+char **xenbus_directory(struct xenbus_transaction t,
+                       const char *dir, const char *node, unsigned int *num);
+void *xenbus_read(struct xenbus_transaction t,
+                 const char *dir, const char *node, unsigned int *len);
+int xenbus_write(struct xenbus_transaction t,
+                const char *dir, const char *node, const char *string);
+int xenbus_mkdir(struct xenbus_transaction t,
+                const char *dir, const char *node);
+int xenbus_exists(struct xenbus_transaction t,
+                 const char *dir, const char *node);
+int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node);
+int xenbus_transaction_start(struct xenbus_transaction *t);
+int xenbus_transaction_end(struct xenbus_transaction t, int abort);
+
+/* Single read and scanf: returns -errno or num scanned if > 0. */
+int xenbus_scanf(struct xenbus_transaction t,
+                const char *dir, const char *node, const char *fmt, ...)
+       __attribute__((format(scanf, 4, 5)));
+
+/* Single printf and write: returns -errno or 0. */
+int xenbus_printf(struct xenbus_transaction t,
+                 const char *dir, const char *node, const char *fmt, ...)
+       __attribute__((format(printf, 4, 5)));
+
+/* Generic read function: NULL-terminated triples of name,
+ * sprintf-style type string, and pointer. Returns 0 or errno.*/
+int xenbus_gather(struct xenbus_transaction t, const char *dir, ...);
+
+/* notifer routines for when the xenstore comes up */
+extern int xenstored_ready;
+int register_xenstore_notifier(struct notifier_block *nb);
+void unregister_xenstore_notifier(struct notifier_block *nb);
+
+int register_xenbus_watch(struct xenbus_watch *watch);
+void unregister_xenbus_watch(struct xenbus_watch *watch);
+void xs_suspend(void);
+void xs_resume(void);
+void xs_suspend_cancel(void);
+
+/* Used by xenbus_dev to borrow kernel's store connection. */
+void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg);
+
+struct work_struct;
+
+/* Prepare for domain suspend: then resume or cancel the suspend. */
+void xenbus_suspend(void);
+void xenbus_resume(void);
+void xenbus_probe(struct work_struct *);
+void xenbus_suspend_cancel(void);
+
+#define XENBUS_IS_ERR_READ(str) ({                     \
+       if (!IS_ERR(str) && strlen(str) == 0) {         \
+               kfree(str);                             \
+               str = ERR_PTR(-ERANGE);                 \
+       }                                               \
+       IS_ERR(str);                                    \
+})
+
+#define XENBUS_EXIST_ERR(err) ((err) == -ENOENT || (err) == -ERANGE)
+
+int xenbus_watch_path(struct xenbus_device *dev, const char *path,
+                     struct xenbus_watch *watch,
+                     void (*callback)(struct xenbus_watch *,
+                                      const char **, unsigned int));
+int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch,
+                        void (*callback)(struct xenbus_watch *,
+                                         const char **, unsigned int),
+                        const char *pathfmt, ...)
+       __attribute__ ((format (printf, 4, 5)));
+
+int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state);
+int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn);
+int xenbus_map_ring_valloc(struct xenbus_device *dev,
+                          int gnt_ref, void **vaddr);
+int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref,
+                          grant_handle_t *handle, void *vaddr);
+
+int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr);
+int xenbus_unmap_ring(struct xenbus_device *dev,
+                     grant_handle_t handle, void *vaddr);
+
+int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port);
+int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port);
+int xenbus_free_evtchn(struct xenbus_device *dev, int port);
+
+enum xenbus_state xenbus_read_driver_state(const char *path);
+
+void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...);
+void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...);
+
+const char *xenbus_strstate(enum xenbus_state state);
+int xenbus_dev_is_online(struct xenbus_device *dev);
+int xenbus_frontend_closed(struct xenbus_device *dev);
+
+#endif /* _XEN_XENBUS_H */
index cbd27e519943b140a2f291cecbf3e0e89820172a..a03fcb522fff827df275ab75a7e2c76610e229b7 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -385,7 +385,7 @@ copy_msqid_from_user(struct msq_setbuf *out, void __user *buf, int version)
 asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
 {
        struct kern_ipc_perm *ipcp;
-       struct msq_setbuf setbuf;
+       struct msq_setbuf uninitialized_var(setbuf);
        struct msg_queue *msq;
        int err, version;
        struct ipc_namespace *ns;
@@ -509,7 +509,7 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
        err = audit_ipc_obj(ipcp);
        if (err)
                goto out_unlock_up;
-       if (cmd==IPC_SET) {
+       if (cmd == IPC_SET) {
                err = audit_ipc_set_perm(setbuf.qbytes, setbuf.uid, setbuf.gid,
                                         setbuf.mode);
                if (err)
index 89bfdffb38d8f590818b28ae6844d0b40fb1095f..b676fef6d208b563dfe52929f6ef8a491860a928 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -856,7 +856,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid, int semnum,
 {
        struct sem_array *sma;
        int err;
-       struct sem_setbuf setbuf;
+       struct sem_setbuf uninitialized_var(setbuf);
        struct kern_ipc_perm *ipcp;
 
        if(cmd == IPC_SET) {
index ce61f423542c18b1a691d73f4f5d7cc4ca94ec75..1bf093dcffe03e9f97dc4a8e91b4a99bd6f11b32 100644 (file)
@@ -1210,8 +1210,8 @@ static inline int audit_add_rule(struct audit_entry *entry,
        struct audit_entry *e;
        struct audit_field *inode_f = entry->rule.inode_f;
        struct audit_watch *watch = entry->rule.watch;
-       struct nameidata *ndp, *ndw;
-       int h, err, putnd_needed = 0;
+       struct nameidata *ndp = NULL, *ndw = NULL;
+       int h, err;
 #ifdef CONFIG_AUDITSYSCALL
        int dont_count = 0;
 
@@ -1239,7 +1239,6 @@ static inline int audit_add_rule(struct audit_entry *entry,
                err = audit_get_nd(watch->path, &ndp, &ndw);
                if (err)
                        goto error;
-               putnd_needed = 1;
        }
 
        mutex_lock(&audit_filter_mutex);
@@ -1269,14 +1268,11 @@ static inline int audit_add_rule(struct audit_entry *entry,
 #endif
        mutex_unlock(&audit_filter_mutex);
 
-       if (putnd_needed)
-               audit_put_nd(ndp, ndw);
-
+       audit_put_nd(ndp, ndw);         /* NULL args OK */
        return 0;
 
 error:
-       if (putnd_needed)
-               audit_put_nd(ndp, ndw);
+       audit_put_nd(ndp, ndw);         /* NULL args OK */
        if (watch)
                audit_put_watch(watch); /* tmp watch, matches initial get */
        return err;
index 208cf3497c10230552e12de042a72a1da61fe955..181ae7086029e0b0eebb60cbc264b01b49f9297d 100644 (file)
@@ -103,11 +103,19 @@ static inline void check_for_tasks(int cpu)
        write_unlock_irq(&tasklist_lock);
 }
 
+struct take_cpu_down_param {
+       unsigned long mod;
+       void *hcpu;
+};
+
 /* Take this CPU down. */
-static int take_cpu_down(void *unused)
+static int take_cpu_down(void *_param)
 {
+       struct take_cpu_down_param *param = _param;
        int err;
 
+       raw_notifier_call_chain(&cpu_chain, CPU_DYING | param->mod,
+                               param->hcpu);
        /* Ensure this CPU doesn't handle any more interrupts. */
        err = __cpu_disable();
        if (err < 0)
@@ -127,6 +135,10 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen)
        cpumask_t old_allowed, tmp;
        void *hcpu = (void *)(long)cpu;
        unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
+       struct take_cpu_down_param tcd_param = {
+               .mod = mod,
+               .hcpu = hcpu,
+       };
 
        if (num_online_cpus() == 1)
                return -EBUSY;
@@ -153,7 +165,7 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen)
        set_cpus_allowed(current, tmp);
 
        mutex_lock(&cpu_bitmask_lock);
-       p = __stop_machine_run(take_cpu_down, NULL, cpu);
+       p = __stop_machine_run(take_cpu_down, &tcd_param, cpu);
        mutex_unlock(&cpu_bitmask_lock);
 
        if (IS_ERR(p) || cpu_online(cpu)) {
index 824b1c01f4107667abb7d0e4e8923678a15966c4..57e6448b171e9ff277a85bdf02d061ea8cac7623 100644 (file)
@@ -516,7 +516,7 @@ static void cpuset_release_agent(const char *pathbuf)
        envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
        envp[i] = NULL;
 
-       call_usermodehelper(argv[0], argv, envp, 0);
+       call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
        kfree(pathbuf);
 }
 
@@ -2138,6 +2138,9 @@ static void common_cpu_mem_hotplug_unplug(void)
 static int cpuset_handle_cpuhp(struct notifier_block *nb,
                                unsigned long phase, void *cpu)
 {
+       if (phase == CPU_DYING || phase == CPU_DYING_FROZEN)
+               return NOTIFY_DONE;
+
        common_cpu_mem_hotplug_unplug();
        return 0;
 }
index 4d32eb077179a2babd3f49b9f31631d4c6e27bb7..78d365c524ed6ffac44da5c2d1e8fb672008b4a8 100644 (file)
@@ -119,9 +119,10 @@ struct subprocess_info {
        char **argv;
        char **envp;
        struct key *ring;
-       int wait;
+       enum umh_wait wait;
        int retval;
        struct file *stdin;
+       void (*cleanup)(char **argv, char **envp);
 };
 
 /*
@@ -180,6 +181,14 @@ static int ____call_usermodehelper(void *data)
        do_exit(0);
 }
 
+void call_usermodehelper_freeinfo(struct subprocess_info *info)
+{
+       if (info->cleanup)
+               (*info->cleanup)(info->argv, info->envp);
+       kfree(info);
+}
+EXPORT_SYMBOL(call_usermodehelper_freeinfo);
+
 /* Keventd can't block, but this (a child) can. */
 static int wait_for_helper(void *data)
 {
@@ -216,8 +225,8 @@ static int wait_for_helper(void *data)
                        sub_info->retval = ret;
        }
 
-       if (sub_info->wait < 0)
-               kfree(sub_info);
+       if (sub_info->wait == UMH_NO_WAIT)
+               call_usermodehelper_freeinfo(sub_info);
        else
                complete(sub_info->complete);
        return 0;
@@ -229,34 +238,122 @@ static void __call_usermodehelper(struct work_struct *work)
        struct subprocess_info *sub_info =
                container_of(work, struct subprocess_info, work);
        pid_t pid;
-       int wait = sub_info->wait;
+       enum umh_wait wait = sub_info->wait;
 
        /* CLONE_VFORK: wait until the usermode helper has execve'd
         * successfully We need the data structures to stay around
         * until that is done.  */
-       if (wait)
+       if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT)
                pid = kernel_thread(wait_for_helper, sub_info,
                                    CLONE_FS | CLONE_FILES | SIGCHLD);
        else
                pid = kernel_thread(____call_usermodehelper, sub_info,
                                    CLONE_VFORK | SIGCHLD);
 
-       if (wait < 0)
-               return;
+       switch (wait) {
+       case UMH_NO_WAIT:
+               break;
 
-       if (pid < 0) {
+       case UMH_WAIT_PROC:
+               if (pid > 0)
+                       break;
                sub_info->retval = pid;
+               /* FALLTHROUGH */
+
+       case UMH_WAIT_EXEC:
                complete(sub_info->complete);
-       } else if (!wait)
-               complete(sub_info->complete);
+       }
+}
+
+/**
+ * call_usermodehelper_setup - prepare to call a usermode helper
+ * @path - path to usermode executable
+ * @argv - arg vector for process
+ * @envp - environment for process
+ *
+ * Returns either NULL on allocation failure, or a subprocess_info
+ * structure.  This should be passed to call_usermodehelper_exec to
+ * exec the process and free the structure.
+ */
+struct subprocess_info *call_usermodehelper_setup(char *path,
+                                                 char **argv, char **envp)
+{
+       struct subprocess_info *sub_info;
+       sub_info = kzalloc(sizeof(struct subprocess_info),  GFP_ATOMIC);
+       if (!sub_info)
+               goto out;
+
+       INIT_WORK(&sub_info->work, __call_usermodehelper);
+       sub_info->path = path;
+       sub_info->argv = argv;
+       sub_info->envp = envp;
+
+  out:
+       return sub_info;
 }
+EXPORT_SYMBOL(call_usermodehelper_setup);
 
 /**
- * call_usermodehelper_keys - start a usermode application
- * @path: pathname for the application
- * @argv: null-terminated argument list
- * @envp: null-terminated environment list
- * @session_keyring: session keyring for process (NULL for an empty keyring)
+ * call_usermodehelper_setkeys - set the session keys for usermode helper
+ * @info: a subprocess_info returned by call_usermodehelper_setup
+ * @session_keyring: the session keyring for the process
+ */
+void call_usermodehelper_setkeys(struct subprocess_info *info,
+                                struct key *session_keyring)
+{
+       info->ring = session_keyring;
+}
+EXPORT_SYMBOL(call_usermodehelper_setkeys);
+
+/**
+ * call_usermodehelper_setcleanup - set a cleanup function
+ * @info: a subprocess_info returned by call_usermodehelper_setup
+ * @cleanup: a cleanup function
+ *
+ * The cleanup function is just befor ethe subprocess_info is about to
+ * be freed.  This can be used for freeing the argv and envp.  The
+ * Function must be runnable in either a process context or the
+ * context in which call_usermodehelper_exec is called.
+ */
+void call_usermodehelper_setcleanup(struct subprocess_info *info,
+                                   void (*cleanup)(char **argv, char **envp))
+{
+       info->cleanup = cleanup;
+}
+EXPORT_SYMBOL(call_usermodehelper_setcleanup);
+
+/**
+ * call_usermodehelper_stdinpipe - set up a pipe to be used for stdin
+ * @sub_info: a subprocess_info returned by call_usermodehelper_setup
+ * @filp: set to the write-end of a pipe
+ *
+ * This constructs a pipe, and sets the read end to be the stdin of the
+ * subprocess, and returns the write-end in *@filp.
+ */
+int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
+                                 struct file **filp)
+{
+       struct file *f;
+
+       f = create_write_pipe();
+       if (IS_ERR(f))
+               return PTR_ERR(f);
+       *filp = f;
+
+       f = create_read_pipe(f);
+       if (IS_ERR(f)) {
+               free_write_pipe(*filp);
+               return PTR_ERR(f);
+       }
+       sub_info->stdin = f;
+
+       return 0;
+}
+EXPORT_SYMBOL(call_usermodehelper_stdinpipe);
+
+/**
+ * call_usermodehelper_exec - start a usermode application
+ * @sub_info: information about the subprocessa
  * @wait: wait for the application to finish and return status.
  *        when -1 don't wait at all, but you get no useful error back when
  *        the program couldn't be exec'ed. This makes it safe to call
@@ -265,81 +362,68 @@ static void __call_usermodehelper(struct work_struct *work)
  * Runs a user-space application.  The application is started
  * asynchronously if wait is not set, and runs as a child of keventd.
  * (ie. it runs with full root capabilities).
- *
- * Must be called from process context.  Returns a negative error code
- * if program was not execed successfully, or 0.
  */
-int call_usermodehelper_keys(char *path, char **argv, char **envp,
-                            struct key *session_keyring, int wait)
+int call_usermodehelper_exec(struct subprocess_info *sub_info,
+                            enum umh_wait wait)
 {
        DECLARE_COMPLETION_ONSTACK(done);
-       struct subprocess_info *sub_info;
        int retval;
 
-       if (!khelper_wq)
-               return -EBUSY;
-
-       if (path[0] == '\0')
-               return 0;
+       if (sub_info->path[0] == '\0') {
+               retval = 0;
+               goto out;
+       }
 
-       sub_info = kzalloc(sizeof(struct subprocess_info),  GFP_ATOMIC);
-       if (!sub_info)
-               return -ENOMEM;
+       if (!khelper_wq) {
+               retval = -EBUSY;
+               goto out;
+       }
 
-       INIT_WORK(&sub_info->work, __call_usermodehelper);
        sub_info->complete = &done;
-       sub_info->path = path;
-       sub_info->argv = argv;
-       sub_info->envp = envp;
-       sub_info->ring = session_keyring;
        sub_info->wait = wait;
 
        queue_work(khelper_wq, &sub_info->work);
-       if (wait < 0) /* task has freed sub_info */
+       if (wait == UMH_NO_WAIT) /* task has freed sub_info */
                return 0;
        wait_for_completion(&done);
        retval = sub_info->retval;
-       kfree(sub_info);
+
+  out:
+       call_usermodehelper_freeinfo(sub_info);
        return retval;
 }
-EXPORT_SYMBOL(call_usermodehelper_keys);
+EXPORT_SYMBOL(call_usermodehelper_exec);
 
+/**
+ * call_usermodehelper_pipe - call a usermode helper process with a pipe stdin
+ * @path: path to usermode executable
+ * @argv: arg vector for process
+ * @envp: environment for process
+ * @filp: set to the write-end of a pipe
+ *
+ * This is a simple wrapper which executes a usermode-helper function
+ * with a pipe as stdin.  It is implemented entirely in terms of
+ * lower-level call_usermodehelper_* functions.
+ */
 int call_usermodehelper_pipe(char *path, char **argv, char **envp,
                             struct file **filp)
 {
-       DECLARE_COMPLETION(done);
-       struct subprocess_info sub_info = {
-               .work           = __WORK_INITIALIZER(sub_info.work,
-                                                    __call_usermodehelper),
-               .complete       = &done,
-               .path           = path,
-               .argv           = argv,
-               .envp           = envp,
-               .retval         = 0,
-       };
-       struct file *f;
+       struct subprocess_info *sub_info;
+       int ret;
 
-       if (!khelper_wq)
-               return -EBUSY;
+       sub_info = call_usermodehelper_setup(path, argv, envp);
+       if (sub_info == NULL)
+               return -ENOMEM;
 
-       if (path[0] == '\0')
-               return 0;
+       ret = call_usermodehelper_stdinpipe(sub_info, filp);
+       if (ret < 0)
+               goto out;
 
-       f = create_write_pipe();
-       if (IS_ERR(f))
-               return PTR_ERR(f);
-       *filp = f;
-
-       f = create_read_pipe(f);
-       if (IS_ERR(f)) {
-               free_write_pipe(*filp);
-               return PTR_ERR(f);
-       }
-       sub_info.stdin = f;
+       return call_usermodehelper_exec(sub_info, 1);
 
-       queue_work(khelper_wq, &sub_info.work);
-       wait_for_completion(&done);
-       return sub_info.retval;
+  out:
+       call_usermodehelper_freeinfo(sub_info);
+       return ret;
 }
 EXPORT_SYMBOL(call_usermodehelper_pipe);
 
index 4d141ae3e8029d13deaaee39d3245e5c42766157..18987c7f6addae96d1049eb9d2dd2a93315975e0 100644 (file)
@@ -2286,3 +2286,61 @@ asmlinkage long sys_getcpu(unsigned __user *cpup, unsigned __user *nodep,
        }
        return err ? -EFAULT : 0;
 }
+
+char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
+
+static void argv_cleanup(char **argv, char **envp)
+{
+       argv_free(argv);
+}
+
+/**
+ * orderly_poweroff - Trigger an orderly system poweroff
+ * @force: force poweroff if command execution fails
+ *
+ * This may be called from any context to trigger a system shutdown.
+ * If the orderly shutdown fails, it will force an immediate shutdown.
+ */
+int orderly_poweroff(bool force)
+{
+       int argc;
+       char **argv = argv_split(GFP_ATOMIC, poweroff_cmd, &argc);
+       static char *envp[] = {
+               "HOME=/",
+               "PATH=/sbin:/bin:/usr/sbin:/usr/bin",
+               NULL
+       };
+       int ret = -ENOMEM;
+       struct subprocess_info *info;
+
+       if (argv == NULL) {
+               printk(KERN_WARNING "%s failed to allocate memory for \"%s\"\n",
+                      __func__, poweroff_cmd);
+               goto out;
+       }
+
+       info = call_usermodehelper_setup(argv[0], argv, envp);
+       if (info == NULL) {
+               argv_free(argv);
+               goto out;
+       }
+
+       call_usermodehelper_setcleanup(info, argv_cleanup);
+
+       ret = call_usermodehelper_exec(info, UMH_NO_WAIT);
+
+  out:
+       if (ret && force) {
+               printk(KERN_WARNING "Failed to start orderly shutdown: "
+                      "forcing the issue\n");
+
+               /* I guess this should try to kick off some daemon to
+                  sync and poweroff asap.  Or not even bother syncing
+                  if we're doing an emergency shutdown? */
+               emergency_sync();
+               kernel_power_off();
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(orderly_poweroff);
index 7063ebc6db05ec89cf4c095f0c6af271f3c49c75..44a1d699aad79048636bebe9c60ef77f27928791 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/syscalls.h>
 #include <linux/nfs_fs.h>
 #include <linux/acpi.h>
+#include <linux/reboot.h>
 
 #include <asm/uaccess.h>
 #include <asm/processor.h>
@@ -705,6 +706,15 @@ static ctl_table kern_table[] = {
                .proc_handler   = &proc_dointvec,
        },
 #endif
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "poweroff_cmd",
+               .data           = &poweroff_cmd,
+               .maxlen         = POWEROFF_CMD_PATH_LEN,
+               .mode           = 0644,
+               .proc_handler   = &proc_dostring,
+               .strategy       = &sysctl_string,
+       },
 
        { .ctl_name = 0 }
 };
index da68b2ca06062718405eeba72085a7d666f497dc..614966387402e57b26e7b9fe4fd51daa7f34f282 100644 (file)
@@ -5,7 +5,7 @@
 lib-y := ctype.o string.o vsprintf.o cmdline.o \
         rbtree.o radix-tree.o dump_stack.o \
         idr.o int_sqrt.o bitmap.o extable.o prio_tree.o \
-        sha1.o irq_regs.o reciprocal_div.o
+        sha1.o irq_regs.o reciprocal_div.o argv_split.o
 
 lib-$(CONFIG_MMU) += ioremap.o
 lib-$(CONFIG_SMP) += cpumask.o
diff --git a/lib/argv_split.c b/lib/argv_split.c
new file mode 100644 (file)
index 0000000..4096ed4
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Helper function for splitting a string into an argv-like array.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/bug.h>
+
+static const char *skip_sep(const char *cp)
+{
+       while (*cp && isspace(*cp))
+               cp++;
+
+       return cp;
+}
+
+static const char *skip_arg(const char *cp)
+{
+       while (*cp && !isspace(*cp))
+               cp++;
+
+       return cp;
+}
+
+static int count_argc(const char *str)
+{
+       int count = 0;
+
+       while (*str) {
+               str = skip_sep(str);
+               if (*str) {
+                       count++;
+                       str = skip_arg(str);
+               }
+       }
+
+       return count;
+}
+
+/**
+ * argv_free - free an argv
+ * @argv - the argument vector to be freed
+ *
+ * Frees an argv and the strings it points to.
+ */
+void argv_free(char **argv)
+{
+       char **p;
+       for (p = argv; *p; p++)
+               kfree(*p);
+
+       kfree(argv);
+}
+EXPORT_SYMBOL(argv_free);
+
+/**
+ * argv_split - split a string at whitespace, returning an argv
+ * @gfp: the GFP mask used to allocate memory
+ * @str: the string to be split
+ * @argcp: returned argument count
+ *
+ * Returns an array of pointers to strings which are split out from
+ * @str.  This is performed by strictly splitting on white-space; no
+ * quote processing is performed.  Multiple whitespace characters are
+ * considered to be a single argument separator.  The returned array
+ * is always NULL-terminated.  Returns NULL on memory allocation
+ * failure.
+ */
+char **argv_split(gfp_t gfp, const char *str, int *argcp)
+{
+       int argc = count_argc(str);
+       char **argv = kzalloc(sizeof(*argv) * (argc+1), gfp);
+       char **argvp;
+
+       if (argv == NULL)
+               goto out;
+
+       *argcp = argc;
+       argvp = argv;
+
+       while (*str) {
+               str = skip_sep(str);
+
+               if (*str) {
+                       const char *p = str;
+                       char *t;
+
+                       str = skip_arg(str);
+
+                       t = kstrndup(p, str-p, gfp);
+                       if (t == NULL)
+                               goto fail;
+                       *argvp++ = t;
+               }
+       }
+       *argvp = NULL;
+
+  out:
+       return argv;
+
+  fail:
+       argv_free(argv);
+       return NULL;
+}
+EXPORT_SYMBOL(argv_split);
index 12e311dc664cc8d58aa29264050e2f4a8f234e2c..bd5ecbbafab1cff8926f8ef14af983051209af23 100644 (file)
@@ -208,7 +208,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
                argv [0] = uevent_helper;
                argv [1] = (char *)subsystem;
                argv [2] = NULL;
-               call_usermodehelper (argv[0], argv, envp, 0);
+               call_usermodehelper (argv[0], argv, envp, UMH_WAIT_EXEC);
        }
 
 exit:
index 78f3783bdcc810d2c70e77071f4f2d27665da1fe..bf340d80686884bf765dc696a73f7fd840842e8f 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -6,7 +6,6 @@
 
 /**
  * kstrdup - allocate space for and copy an existing string
- *
  * @s: the string to duplicate
  * @gfp: the GFP mask used in the kmalloc() call when allocating memory
  */
@@ -26,6 +25,30 @@ char *kstrdup(const char *s, gfp_t gfp)
 }
 EXPORT_SYMBOL(kstrdup);
 
+/**
+ * kstrndup - allocate space for and copy an existing string
+ * @s: the string to duplicate
+ * @max: read at most @max chars from @s
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ */
+char *kstrndup(const char *s, size_t max, gfp_t gfp)
+{
+       size_t len;
+       char *buf;
+
+       if (!s)
+               return NULL;
+
+       len = strnlen(s, max);
+       buf = kmalloc_track_caller(len+1, gfp);
+       if (buf) {
+               memcpy(buf, s, len);
+               buf[len] = '\0';
+       }
+       return buf;
+}
+EXPORT_SYMBOL(kstrndup);
+
 /**
  * kmemdup - duplicate region of memory
  *
@@ -80,7 +103,6 @@ EXPORT_SYMBOL(krealloc);
 
 /*
  * strndup_user - duplicate an existing string from user space
- *
  * @s: The string to duplicate
  * @n: Maximum number of bytes to copy, including the trailing NUL.
  */
index 8e05a11155c9208e6daf17644168929105e433da..3130c343088fd823f211f9079f666ac67d1671e9 100644 (file)
@@ -767,3 +767,56 @@ EXPORT_SYMBOL(remap_vmalloc_range);
 void  __attribute__((weak)) vmalloc_sync_all(void)
 {
 }
+
+
+static int f(pte_t *pte, struct page *pmd_page, unsigned long addr, void *data)
+{
+       /* apply_to_page_range() does all the hard work. */
+       return 0;
+}
+
+/**
+ *     alloc_vm_area - allocate a range of kernel address space
+ *     @size:          size of the area
+ *     @returns:       NULL on failure, vm_struct on success
+ *
+ *     This function reserves a range of kernel address space, and
+ *     allocates pagetables to map that range.  No actual mappings
+ *     are created.  If the kernel address space is not shared
+ *     between processes, it syncs the pagetable across all
+ *     processes.
+ */
+struct vm_struct *alloc_vm_area(size_t size)
+{
+       struct vm_struct *area;
+
+       area = get_vm_area(size, VM_IOREMAP);
+       if (area == NULL)
+               return NULL;
+
+       /*
+        * This ensures that page tables are constructed for this region
+        * of kernel virtual address space and mapped into init_mm.
+        */
+       if (apply_to_page_range(&init_mm, (unsigned long)area->addr,
+                               area->size, f, NULL)) {
+               free_vm_area(area);
+               return NULL;
+       }
+
+       /* Make sure the pagetables are constructed in process kernel
+          mappings */
+       vmalloc_sync_all();
+
+       return area;
+}
+EXPORT_SYMBOL_GPL(alloc_vm_area);
+
+void free_vm_area(struct vm_struct *area)
+{
+       struct vm_struct *ret;
+       ret = remove_vm_area(area->addr);
+       BUG_ON(ret != area);
+       kfree(area);
+}
+EXPORT_SYMBOL_GPL(free_vm_area);
index faa6aaf67563ff298121518ffc192655a85be2ab..c0f6861eefe35061061d7ae39d4ecde87d8777da 100644 (file)
@@ -460,11 +460,7 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
        skb_pull(skb, plen);
        skb_set_mac_header(skb, -ETH_HLEN);
        skb->pkt_type = PACKET_HOST;
-#ifdef CONFIG_BR2684_FAST_TRANS
-       skb->protocol = ((u16 *) skb->data)[-1];
-#else                          /* some protocols might require this: */
        skb->protocol = br_type_trans(skb, net_dev);
-#endif /* CONFIG_BR2684_FAST_TRANS */
 #else
        skb_pull(skb, plen - ETH_HLEN);
        skb->protocol = eth_type_trans(skb, net_dev);
index a786e786320096a786a19b578f39a42d944c16db..1ea2f86f7683b1b6ec101158db133bc37af7896f 100644 (file)
@@ -125,7 +125,7 @@ static void br_stp_start(struct net_bridge *br)
        char *argv[] = { BR_STP_PROG, br->dev->name, "start", NULL };
        char *envp[] = { NULL };
 
-       r = call_usermodehelper(BR_STP_PROG, argv, envp, 1);
+       r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC);
        if (r == 0) {
                br->stp_enabled = BR_USER_STP;
                printk(KERN_INFO "%s: userspace STP started\n", br->dev->name);
index 13a0d9f6da54c02cbed38292ddef7eaa1d9241a0..6357f54c8ff761f52750ee3b8f852c651a04a522 100644 (file)
@@ -2715,20 +2715,6 @@ int __dev_addr_add(struct dev_addr_list **list, int *count,
        return 0;
 }
 
-void __dev_addr_discard(struct dev_addr_list **list)
-{
-       struct dev_addr_list *tmp;
-
-       while (*list != NULL) {
-               tmp = *list;
-               *list = tmp->next;
-               if (tmp->da_users > tmp->da_gusers)
-                       printk("__dev_addr_discard: address leakage! "
-                              "da_users=%d\n", tmp->da_users);
-               kfree(tmp);
-       }
-}
-
 /**
  *     dev_unicast_delete      - Release secondary unicast address.
  *     @dev: device
@@ -2777,11 +2763,30 @@ int dev_unicast_add(struct net_device *dev, void *addr, int alen)
 }
 EXPORT_SYMBOL(dev_unicast_add);
 
-static void dev_unicast_discard(struct net_device *dev)
+static void __dev_addr_discard(struct dev_addr_list **list)
+{
+       struct dev_addr_list *tmp;
+
+       while (*list != NULL) {
+               tmp = *list;
+               *list = tmp->next;
+               if (tmp->da_users > tmp->da_gusers)
+                       printk("__dev_addr_discard: address leakage! "
+                              "da_users=%d\n", tmp->da_users);
+               kfree(tmp);
+       }
+}
+
+static void dev_addr_discard(struct net_device *dev)
 {
        netif_tx_lock_bh(dev);
+
        __dev_addr_discard(&dev->uc_list);
        dev->uc_count = 0;
+
+       __dev_addr_discard(&dev->mc_list);
+       dev->mc_count = 0;
+
        netif_tx_unlock_bh(dev);
 }
 
@@ -3739,8 +3744,7 @@ void unregister_netdevice(struct net_device *dev)
        /*
         *      Flush the unicast and multicast chains
         */
-       dev_unicast_discard(dev);
-       dev_mc_discard(dev);
+       dev_addr_discard(dev);
 
        if (dev->uninit)
                dev->uninit(dev);
index 235a2a8a0d05b0b2163c180001f918274720a785..99aece1aeccff9aa950c3b8bb08385b8dd2b2b25 100644 (file)
@@ -177,18 +177,6 @@ void dev_mc_unsync(struct net_device *to, struct net_device *from)
 }
 EXPORT_SYMBOL(dev_mc_unsync);
 
-/*
- *     Discard multicast list when a device is downed
- */
-
-void dev_mc_discard(struct net_device *dev)
-{
-       netif_tx_lock_bh(dev);
-       __dev_addr_discard(&dev->mc_list);
-       dev->mc_count = 0;
-       netif_tx_unlock_bh(dev);
-}
-
 #ifdef CONFIG_PROC_FS
 static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos)
 {
index cc84d8d8a3c7d6c6c6e06a18080cfb99c50d86fa..590a767b029c15e82886bfcb49574dcfdbc7ba1e 100644 (file)
 
 struct gen_estimator
 {
-       struct gen_estimator    *next;
+       struct list_head        list;
        struct gnet_stats_basic *bstats;
        struct gnet_stats_rate_est      *rate_est;
        spinlock_t              *stats_lock;
-       unsigned                interval;
        int                     ewma_log;
        u64                     last_bytes;
        u32                     last_packets;
        u32                     avpps;
        u32                     avbps;
+       struct rcu_head         e_rcu;
 };
 
 struct gen_estimator_head
 {
        struct timer_list       timer;
-       struct gen_estimator    *list;
+       struct list_head        list;
 };
 
 static struct gen_estimator_head elist[EST_MAX_INTERVAL+1];
 
-/* Estimator array lock */
+/* Protects against NULL dereference */
 static DEFINE_RWLOCK(est_lock);
 
 static void est_timer(unsigned long arg)
@@ -107,13 +107,17 @@ static void est_timer(unsigned long arg)
        int idx = (int)arg;
        struct gen_estimator *e;
 
-       read_lock(&est_lock);
-       for (e = elist[idx].list; e; e = e->next) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(e, &elist[idx].list, list) {
                u64 nbytes;
                u32 npackets;
                u32 rate;
 
                spin_lock(e->stats_lock);
+               read_lock(&est_lock);
+               if (e->bstats == NULL)
+                       goto skip;
+
                nbytes = e->bstats->bytes;
                npackets = e->bstats->packets;
                rate = (nbytes - e->last_bytes)<<(7 - idx);
@@ -125,12 +129,14 @@ static void est_timer(unsigned long arg)
                e->last_packets = npackets;
                e->avpps += ((long)rate - (long)e->avpps) >> e->ewma_log;
                e->rate_est->pps = (e->avpps+0x1FF)>>10;
+skip:
+               read_unlock(&est_lock);
                spin_unlock(e->stats_lock);
        }
 
-       if (elist[idx].list != NULL)
+       if (!list_empty(&elist[idx].list))
                mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
-       read_unlock(&est_lock);
+       rcu_read_unlock();
 }
 
 /**
@@ -147,12 +153,17 @@ static void est_timer(unsigned long arg)
  * &rate_est with the statistics lock grabed during this period.
  *
  * Returns 0 on success or a negative error code.
+ *
+ * NOTE: Called under rtnl_mutex
  */
 int gen_new_estimator(struct gnet_stats_basic *bstats,
-       struct gnet_stats_rate_est *rate_est, spinlock_t *stats_lock, struct rtattr *opt)
+                     struct gnet_stats_rate_est *rate_est,
+                     spinlock_t *stats_lock,
+                     struct rtattr *opt)
 {
        struct gen_estimator *est;
        struct gnet_estimator *parm = RTA_DATA(opt);
+       int idx;
 
        if (RTA_PAYLOAD(opt) < sizeof(*parm))
                return -EINVAL;
@@ -164,7 +175,7 @@ int gen_new_estimator(struct gnet_stats_basic *bstats,
        if (est == NULL)
                return -ENOBUFS;
 
-       est->interval = parm->interval + 2;
+       idx = parm->interval + 2;
        est->bstats = bstats;
        est->rate_est = rate_est;
        est->stats_lock = stats_lock;
@@ -174,20 +185,25 @@ int gen_new_estimator(struct gnet_stats_basic *bstats,
        est->last_packets = bstats->packets;
        est->avpps = rate_est->pps<<10;
 
-       est->next = elist[est->interval].list;
-       if (est->next == NULL) {
-               init_timer(&elist[est->interval].timer);
-               elist[est->interval].timer.data = est->interval;
-               elist[est->interval].timer.expires = jiffies + ((HZ<<est->interval)/4);
-               elist[est->interval].timer.function = est_timer;
-               add_timer(&elist[est->interval].timer);
+       if (!elist[idx].timer.function) {
+               INIT_LIST_HEAD(&elist[idx].list);
+               setup_timer(&elist[idx].timer, est_timer, idx);
        }
-       write_lock_bh(&est_lock);
-       elist[est->interval].list = est;
-       write_unlock_bh(&est_lock);
+
+       if (list_empty(&elist[idx].list))
+               mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
+
+       list_add_rcu(&est->list, &elist[idx].list);
        return 0;
 }
 
+static void __gen_kill_estimator(struct rcu_head *head)
+{
+       struct gen_estimator *e = container_of(head,
+                                       struct gen_estimator, e_rcu);
+       kfree(e);
+}
+
 /**
  * gen_kill_estimator - remove a rate estimator
  * @bstats: basic statistics
@@ -195,31 +211,32 @@ int gen_new_estimator(struct gnet_stats_basic *bstats,
  *
  * Removes the rate estimator specified by &bstats and &rate_est
  * and deletes the timer.
+ *
+ * NOTE: Called under rtnl_mutex
  */
 void gen_kill_estimator(struct gnet_stats_basic *bstats,
        struct gnet_stats_rate_est *rate_est)
 {
        int idx;
-       struct gen_estimator *est, **pest;
+       struct gen_estimator *e, *n;
 
        for (idx=0; idx <= EST_MAX_INTERVAL; idx++) {
-               int killed = 0;
-               pest = &elist[idx].list;
-               while ((est=*pest) != NULL) {
-                       if (est->rate_est != rate_est || est->bstats != bstats) {
-                               pest = &est->next;
+
+               /* Skip non initialized indexes */
+               if (!elist[idx].timer.function)
+                       continue;
+
+               list_for_each_entry_safe(e, n, &elist[idx].list, list) {
+                       if (e->rate_est != rate_est || e->bstats != bstats)
                                continue;
-                       }
 
                        write_lock_bh(&est_lock);
-                       *pest = est->next;
+                       e->bstats = NULL;
                        write_unlock_bh(&est_lock);
 
-                       kfree(est);
-                       killed++;
+                       list_del_rcu(&e->list);
+                       call_rcu(&e->e_rcu, __gen_kill_estimator);
                }
-               if (killed && elist[idx].list == NULL)
-                       del_timer(&elist[idx].timer);
        }
 }
 
index dd9ef65ad3ff9e26fbeee30676edb4c99df4e7ad..519de091a94d01641f8ae5837abcc8943455fd25 100644 (file)
@@ -137,7 +137,7 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
 }
 
 static void bictcp_cong_avoid(struct sock *sk, u32 ack,
-                             u32 seq_rtt, u32 in_flight, int data_acked)
+                             u32 in_flight, int data_acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct bictcp *ca = inet_csk_ca(sk);
index 1260e52ad77286cc4d3022fb8afe1bbdf422cccb..55fca1820c344d7bb900e0ab486ff627c951f924 100644 (file)
@@ -324,8 +324,7 @@ EXPORT_SYMBOL_GPL(tcp_slow_start);
 /* This is Jacobson's slow start and congestion avoidance.
  * SIGCOMM '88, p. 328.
  */
-void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 rtt, u32 in_flight,
-                        int flag)
+void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight, int flag)
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
index ebfaac2f9f462854ce98c5e96a707ae5649e8287..d17da30d82d675545526b55c30228fb03334db26 100644 (file)
@@ -270,7 +270,7 @@ static inline void measure_delay(struct sock *sk)
 }
 
 static void bictcp_cong_avoid(struct sock *sk, u32 ack,
-                             u32 seq_rtt, u32 in_flight, int data_acked)
+                             u32 in_flight, int data_acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct bictcp *ca = inet_csk_ca(sk);
index 43d624e5043c34eba40fe07fd02e0839543eedee..14a073d8b60f41bf5ecf84bd07d21dcbd89664ff 100644 (file)
@@ -109,7 +109,7 @@ static void hstcp_init(struct sock *sk)
        tp->snd_cwnd_clamp = min_t(u32, tp->snd_cwnd_clamp, 0xffffffff/128);
 }
 
-static void hstcp_cong_avoid(struct sock *sk, u32 adk, u32 rtt,
+static void hstcp_cong_avoid(struct sock *sk, u32 adk,
                             u32 in_flight, int data_acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
index 4ba4a7ae0a85128837d017909fc883f592efb324..632c05a75883da2c6c15f25b20d0a908a49c1980 100644 (file)
@@ -225,7 +225,7 @@ static u32 htcp_recalc_ssthresh(struct sock *sk)
        return max((tp->snd_cwnd * ca->beta) >> 7, 2U);
 }
 
-static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void htcp_cong_avoid(struct sock *sk, u32 ack, s32 rtt,
                            u32 in_flight, int data_acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
index e5be35117223f19af191e9f4e24d2bdd318e17ce..b3e55cf56171b7fb90078d221df609777c6d84f2 100644 (file)
@@ -85,7 +85,7 @@ static inline u32 hybla_fraction(u32 odds)
  *     o Give cwnd a new value based on the model proposed
  *     o remember increments <1
  */
-static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void hybla_cong_avoid(struct sock *sk, u32 ack,
                            u32 in_flight, int flag)
 {
        struct tcp_sock *tp = tcp_sk(sk);
@@ -103,7 +103,7 @@ static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
                return;
 
        if (!ca->hybla_en)
-               return tcp_reno_cong_avoid(sk, ack, rtt, in_flight, flag);
+               return tcp_reno_cong_avoid(sk, ack, in_flight, flag);
 
        if (ca->rho == 0)
                hybla_recalc_param(sk);
index b2b2256d3b8450c944bc8d3a8869a76aaf2ceb69..cc5de6f69d46f0e2f4fd81e8c4815780ba609bb4 100644 (file)
@@ -258,7 +258,7 @@ static void tcp_illinois_state(struct sock *sk, u8 new_state)
 /*
  * Increase window in response to successful acknowledgment.
  */
-static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack,
                                    u32 in_flight, int flag)
 {
        struct tcp_sock *tp = tcp_sk(sk);
index 4e5884ac8f299672614fc497e3f3dff6e1153de9..fec8a7a4dbaffa3781685fe9203b4c998482dc8d 100644 (file)
@@ -2323,11 +2323,11 @@ static inline void tcp_ack_update_rtt(struct sock *sk, const int flag,
                tcp_ack_no_tstamp(sk, seq_rtt, flag);
 }
 
-static void tcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void tcp_cong_avoid(struct sock *sk, u32 ack,
                           u32 in_flight, int good)
 {
        const struct inet_connection_sock *icsk = inet_csk(sk);
-       icsk->icsk_ca_ops->cong_avoid(sk, ack, rtt, in_flight, good);
+       icsk->icsk_ca_ops->cong_avoid(sk, ack, in_flight, good);
        tcp_sk(sk)->snd_cwnd_stamp = tcp_time_stamp;
 }
 
@@ -2826,11 +2826,11 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
                /* Advance CWND, if state allows this. */
                if ((flag & FLAG_DATA_ACKED) && !frto_cwnd &&
                    tcp_may_raise_cwnd(sk, flag))
-                       tcp_cong_avoid(sk, ack,  seq_rtt, prior_in_flight, 0);
+                       tcp_cong_avoid(sk, ack, prior_in_flight, 0);
                tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag);
        } else {
                if ((flag & FLAG_DATA_ACKED) && !frto_cwnd)
-                       tcp_cong_avoid(sk, ack, seq_rtt, prior_in_flight, 1);
+                       tcp_cong_avoid(sk, ack, prior_in_flight, 1);
        }
 
        if ((flag & FLAG_FORWARD_PROGRESS) || !(flag&FLAG_NOT_DUP))
index e49836ce012e768a4586432f7b62be9a0b6e5140..80e140e3ec2d6db57529fc73494dc47600a48501 100644 (file)
@@ -115,13 +115,12 @@ static void tcp_lp_init(struct sock *sk)
  * Will only call newReno CA when away from inference.
  * From TCP-LP's paper, this will be handled in additive increasement.
  */
-static void tcp_lp_cong_avoid(struct sock *sk, u32 ack, u32 rtt, u32 in_flight,
-                             int flag)
+static void tcp_lp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight, int flag)
 {
        struct lp *lp = inet_csk_ca(sk);
 
        if (!(lp->flag & LP_WITHIN_INF))
-               tcp_reno_cong_avoid(sk, ack, rtt, in_flight, flag);
+               tcp_reno_cong_avoid(sk, ack, in_flight, flag);
 }
 
 /**
index 4624501e9680d14dc0ec462797cd9648b77541ea..be27a33a1c68dcad4235b7fb4ee4ac4286166dd6 100644 (file)
@@ -15,7 +15,7 @@
 #define TCP_SCALABLE_AI_CNT    50U
 #define TCP_SCALABLE_MD_SCALE  3
 
-static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack,
                                    u32 in_flight, int flag)
 {
        struct tcp_sock *tp = tcp_sk(sk);
index e218a51ceced186b9c37acab906009dfbfe94233..914e0307f7af2e89c58e7a29179dee64ebf29f3f 100644 (file)
@@ -163,13 +163,13 @@ void tcp_vegas_cwnd_event(struct sock *sk, enum tcp_ca_event event)
 EXPORT_SYMBOL_GPL(tcp_vegas_cwnd_event);
 
 static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack,
-                                u32 seq_rtt, u32 in_flight, int flag)
+                                u32 in_flight, int flag)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct vegas *vegas = inet_csk_ca(sk);
 
        if (!vegas->doing_vegas_now)
-               return tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
+               return tcp_reno_cong_avoid(sk, ack, in_flight, flag);
 
        /* The key players are v_beg_snd_una and v_beg_snd_nxt.
         *
@@ -228,7 +228,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack,
                        /* We don't have enough RTT samples to do the Vegas
                         * calculation, so we'll behave like Reno.
                         */
-                       tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
+                       tcp_reno_cong_avoid(sk, ack, in_flight, flag);
                } else {
                        u32 rtt, target_cwnd, diff;
 
index ec854cc5fad50fd90899818086310cd51b61cbdc..7a55ddf86032bdeab7bd0c48eca7358542c8f037 100644 (file)
@@ -115,13 +115,13 @@ static void tcp_veno_cwnd_event(struct sock *sk, enum tcp_ca_event event)
 }
 
 static void tcp_veno_cong_avoid(struct sock *sk, u32 ack,
-                               u32 seq_rtt, u32 in_flight, int flag)
+                               u32 in_flight, int flag)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct veno *veno = inet_csk_ca(sk);
 
        if (!veno->doing_veno_now)
-               return tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
+               return tcp_reno_cong_avoid(sk, ack, in_flight, flag);
 
        /* limited by applications */
        if (!tcp_is_cwnd_limited(sk, in_flight))
@@ -132,7 +132,7 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack,
                /* We don't have enough rtt samples to do the Veno
                 * calculation, so we'll behave like Reno.
                 */
-               tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
+               tcp_reno_cong_avoid(sk, ack, in_flight, flag);
        } else {
                u32 rtt, target_cwnd;
 
index 545ed237ab5381033e258b85250c1d02e3d77e6d..c04b7c6ec7027ceb35e11d4ae23d5a4ce68a1479 100644 (file)
@@ -70,7 +70,7 @@ static void tcp_yeah_pkts_acked(struct sock *sk, u32 pkts_acked, ktime_t last)
 }
 
 static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack,
-                               u32 seq_rtt, u32 in_flight, int flag)
+                               u32 in_flight, int flag)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct yeah *yeah = inet_csk_ca(sk);
index dcd7e325b283cc66885aef639b92424df473769d..4c670cf6aefaeb3c06438aa14e435ba7c11fabe3 100644 (file)
@@ -2567,7 +2567,7 @@ int __init irsock_init(void)
  *    Remove IrDA protocol
  *
  */
-void __exit irsock_cleanup(void)
+void irsock_cleanup(void)
 {
        sock_unregister(PF_IRDA);
        proto_unregister(&irda_proto);
index 7b5def1ea63326c2bc9a7d8d49eac274953f2940..435b563d29a6904223236f881f317705ba8f888c 100644 (file)
@@ -95,14 +95,14 @@ int __init irda_device_init( void)
        return 0;
 }
 
-static void __exit leftover_dongle(void *arg)
+static void leftover_dongle(void *arg)
 {
        struct dongle_reg *reg = arg;
        IRDA_WARNING("IrDA: Dongle type %x not unregistered\n",
                     reg->type);
 }
 
-void __exit irda_device_cleanup(void)
+void irda_device_cleanup(void)
 {
        IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
index 774eb707940c5929010254cd092fedb87e519548..ee3889fa49abf2d89721b99d9e0a0c25ff407a35 100644 (file)
@@ -153,7 +153,7 @@ int __init iriap_init(void)
  *    Initializes the IrIAP layer, called by the module cleanup code in
  *    irmod.c
  */
-void __exit iriap_cleanup(void)
+void iriap_cleanup(void)
 {
        irlmp_unregister_service(service_handle);
 
index 4adaae242b9e44b422b46f1fe3b4fd8422db1b0d..cf302457097bdefd1e6af972194ef04e97be465e 100644 (file)
@@ -36,39 +36,6 @@ hashbin_t *irias_objects;
  */
 struct ias_value irias_missing = { IAS_MISSING, 0, 0, 0, {0}};
 
-/*
- * Function strndup (str, max)
- *
- *    My own kernel version of strndup!
- *
- * Faster, check boundary... Jean II
- */
-static char *strndup(char *str, size_t max)
-{
-       char *new_str;
-       int len;
-
-       /* Check string */
-       if (str == NULL)
-               return NULL;
-       /* Check length, truncate */
-       len = strlen(str);
-       if(len > max)
-               len = max;
-
-       /* Allocate new string */
-       new_str = kmalloc(len + 1, GFP_ATOMIC);
-       if (new_str == NULL) {
-               IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
-               return NULL;
-       }
-
-       /* Copy and truncate */
-       memcpy(new_str, str, len);
-       new_str[len] = '\0';
-
-       return new_str;
-}
 
 /*
  * Function ias_new_object (name, id)
@@ -90,7 +57,7 @@ struct ias_object *irias_new_object( char *name, int id)
        }
 
        obj->magic = IAS_OBJECT_MAGIC;
-       obj->name = strndup(name, IAS_MAX_CLASSNAME);
+       obj->name = kstrndup(name, IAS_MAX_CLASSNAME, GFP_ATOMIC);
        if (!obj->name) {
                IRDA_WARNING("%s(), Unable to allocate name!\n",
                             __FUNCTION__);
@@ -360,7 +327,7 @@ void irias_add_integer_attrib(struct ias_object *obj, char *name, int value,
        }
 
        attrib->magic = IAS_ATTRIB_MAGIC;
-       attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
+       attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);
 
        /* Insert value */
        attrib->value = irias_new_integer_value(value);
@@ -404,7 +371,7 @@ void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets,
        }
 
        attrib->magic = IAS_ATTRIB_MAGIC;
-       attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
+       attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);
 
        attrib->value = irias_new_octseq_value( octets, len);
        if (!attrib->name || !attrib->value) {
@@ -446,7 +413,7 @@ void irias_add_string_attrib(struct ias_object *obj, char *name, char *value,
        }
 
        attrib->magic = IAS_ATTRIB_MAGIC;
-       attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
+       attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);
 
        attrib->value = irias_new_string_value(value);
        if (!attrib->name || !attrib->value) {
@@ -506,7 +473,7 @@ struct ias_value *irias_new_string_value(char *string)
 
        value->type = IAS_STRING;
        value->charset = CS_ASCII;
-       value->t.string = strndup(string, IAS_MAX_STRING);
+       value->t.string = kstrndup(string, IAS_MAX_STRING, GFP_ATOMIC);
        if (!value->t.string) {
                IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
                kfree(value);
index 2fc9f518f89db45771d3514bc9bee1bbef27f96b..3d76aafdb2e5c7bb25555dcfac05b619a92ba79a 100644 (file)
@@ -95,7 +95,7 @@ int __init irlap_init(void)
        return 0;
 }
 
-void __exit irlap_cleanup(void)
+void irlap_cleanup(void)
 {
        IRDA_ASSERT(irlap != NULL, return;);
 
index 24a5e3f237782b5017330b14ea58d2b401e3a1a7..7efa930ed68418ad6a2b0ebcfcc09e92b14bd047 100644 (file)
@@ -116,7 +116,7 @@ int __init irlmp_init(void)
  *    Remove IrLMP layer
  *
  */
-void __exit irlmp_cleanup(void)
+void irlmp_cleanup(void)
 {
        /* Check for main structure */
        IRDA_ASSERT(irlmp != NULL, return;);
index d6f9aba5b9dc1de454e058d4bb037ef0e56445cf..181cb51b48a8b5b50e64820a71581e702aa2f307 100644 (file)
@@ -84,7 +84,7 @@ void __init irda_proc_register(void)
  *    Unregister irda entry in /proc file system
  *
  */
-void __exit irda_proc_unregister(void)
+void irda_proc_unregister(void)
 {
        int i;
 
index 2e968e7d8feaddb68a99ea775f5a90a91efe7973..957e04feb0f71dbb1492121d93998dde4fb62d83 100644 (file)
@@ -287,7 +287,7 @@ int __init irda_sysctl_register(void)
  *    Unregister our sysctl interface
  *
  */
-void __exit irda_sysctl_unregister(void)
+void irda_sysctl_unregister(void)
 {
        unregister_sysctl_table(irda_table_header);
 }
index 7f50832a2cd5a2349e8f76dc0dd3a2141d3a9df7..3d7ab03fb131e1b9000eef3ef3b47b8ac0d4f3b1 100644 (file)
@@ -109,7 +109,7 @@ int __init irttp_init(void)
  *    Called by module destruction/cleanup code
  *
  */
-void __exit irttp_cleanup(void)
+void irttp_cleanup(void)
 {
        /* Check for main structure */
        IRDA_ASSERT(irttp->magic == TTP_MAGIC, return;);
index 3ac39f1ec775b95e6b3ecea49599090f069aa244..3599770a24730f0782a899205c7a99806955391f 100644 (file)
@@ -436,6 +436,7 @@ config NETFILTER_XT_MATCH_CONNBYTES
 config NETFILTER_XT_MATCH_CONNLIMIT
        tristate '"connlimit" match support"'
        depends on NETFILTER_XTABLES
+       depends on NF_CONNTRACK
        ---help---
          This match allows you to match against the number of parallel
          connections to a server per client IP address (or address block).
index a3c8e692f493902b0b7eb916dbfd4c781fe6d3d5..5681ce3aebca05f5fbfd4e5ba194f8cdd14fc3ba 100644 (file)
@@ -62,6 +62,7 @@
 #include <net/netlink.h>
 
 #define NLGRPSZ(x)     (ALIGN(x, sizeof(unsigned long) * 8) / 8)
+#define NLGRPLONGS(x)  (NLGRPSZ(x)/sizeof(unsigned long))
 
 struct netlink_sock {
        /* struct sock has to be the first member of netlink_sock */
@@ -314,10 +315,12 @@ netlink_update_listeners(struct sock *sk)
        unsigned long mask;
        unsigned int i;
 
-       for (i = 0; i < NLGRPSZ(tbl->groups)/sizeof(unsigned long); i++) {
+       for (i = 0; i < NLGRPLONGS(tbl->groups); i++) {
                mask = 0;
-               sk_for_each_bound(sk, node, &tbl->mc_list)
-                       mask |= nlk_sk(sk)->groups[i];
+               sk_for_each_bound(sk, node, &tbl->mc_list) {
+                       if (i < NLGRPLONGS(nlk_sk(sk)->ngroups))
+                               mask |= nlk_sk(sk)->groups[i];
+               }
                tbl->listeners[i] = mask;
        }
        /* this function is only called with the netlink table "grabbed", which
@@ -555,26 +558,37 @@ netlink_update_subscriptions(struct sock *sk, unsigned int subscriptions)
        nlk->subscriptions = subscriptions;
 }
 
-static int netlink_alloc_groups(struct sock *sk)
+static int netlink_realloc_groups(struct sock *sk)
 {
        struct netlink_sock *nlk = nlk_sk(sk);
        unsigned int groups;
+       unsigned long *new_groups;
        int err = 0;
 
-       netlink_lock_table();
+       netlink_table_grab();
+
        groups = nl_table[sk->sk_protocol].groups;
-       if (!nl_table[sk->sk_protocol].registered)
+       if (!nl_table[sk->sk_protocol].registered) {
                err = -ENOENT;
-       netlink_unlock_table();
+               goto out_unlock;
+       }
 
-       if (err)
-               return err;
+       if (nlk->ngroups >= groups)
+               goto out_unlock;
 
-       nlk->groups = kzalloc(NLGRPSZ(groups), GFP_KERNEL);
-       if (nlk->groups == NULL)
-               return -ENOMEM;
+       new_groups = krealloc(nlk->groups, NLGRPSZ(groups), GFP_ATOMIC);
+       if (new_groups == NULL) {
+               err = -ENOMEM;
+               goto out_unlock;
+       }
+       memset((char*)new_groups + NLGRPSZ(nlk->ngroups), 0,
+              NLGRPSZ(groups) - NLGRPSZ(nlk->ngroups));
+
+       nlk->groups = new_groups;
        nlk->ngroups = groups;
-       return 0;
+ out_unlock:
+       netlink_table_ungrab();
+       return err;
 }
 
 static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
@@ -591,11 +605,9 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len
        if (nladdr->nl_groups) {
                if (!netlink_capable(sock, NL_NONROOT_RECV))
                        return -EPERM;
-               if (nlk->groups == NULL) {
-                       err = netlink_alloc_groups(sk);
-                       if (err)
-                               return err;
-               }
+               err = netlink_realloc_groups(sk);
+               if (err)
+                       return err;
        }
 
        if (nlk->pid) {
@@ -839,10 +851,18 @@ retry:
 int netlink_has_listeners(struct sock *sk, unsigned int group)
 {
        int res = 0;
+       unsigned long *listeners;
 
        BUG_ON(!(nlk_sk(sk)->flags & NETLINK_KERNEL_SOCKET));
+
+       rcu_read_lock();
+       listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners);
+
        if (group - 1 < nl_table[sk->sk_protocol].groups)
-               res = test_bit(group - 1, nl_table[sk->sk_protocol].listeners);
+               res = test_bit(group - 1, listeners);
+
+       rcu_read_unlock();
+
        return res;
 }
 EXPORT_SYMBOL_GPL(netlink_has_listeners);
@@ -1007,18 +1027,36 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)
        read_unlock(&nl_table_lock);
 }
 
+/* must be called with netlink table grabbed */
+static void netlink_update_socket_mc(struct netlink_sock *nlk,
+                                    unsigned int group,
+                                    int is_new)
+{
+       int old, new = !!is_new, subscriptions;
+
+       old = test_bit(group - 1, nlk->groups);
+       subscriptions = nlk->subscriptions - old + new;
+       if (new)
+               __set_bit(group - 1, nlk->groups);
+       else
+               __clear_bit(group - 1, nlk->groups);
+       netlink_update_subscriptions(&nlk->sk, subscriptions);
+       netlink_update_listeners(&nlk->sk);
+}
+
 static int netlink_setsockopt(struct socket *sock, int level, int optname,
                              char __user *optval, int optlen)
 {
        struct sock *sk = sock->sk;
        struct netlink_sock *nlk = nlk_sk(sk);
-       int val = 0, err;
+       unsigned int val = 0;
+       int err;
 
        if (level != SOL_NETLINK)
                return -ENOPROTOOPT;
 
        if (optlen >= sizeof(int) &&
-           get_user(val, (int __user *)optval))
+           get_user(val, (unsigned int __user *)optval))
                return -EFAULT;
 
        switch (optname) {
@@ -1031,27 +1069,16 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
                break;
        case NETLINK_ADD_MEMBERSHIP:
        case NETLINK_DROP_MEMBERSHIP: {
-               unsigned int subscriptions;
-               int old, new = optname == NETLINK_ADD_MEMBERSHIP ? 1 : 0;
-
                if (!netlink_capable(sock, NL_NONROOT_RECV))
                        return -EPERM;
-               if (nlk->groups == NULL) {
-                       err = netlink_alloc_groups(sk);
-                       if (err)
-                               return err;
-               }
+               err = netlink_realloc_groups(sk);
+               if (err)
+                       return err;
                if (!val || val - 1 >= nlk->ngroups)
                        return -EINVAL;
                netlink_table_grab();
-               old = test_bit(val - 1, nlk->groups);
-               subscriptions = nlk->subscriptions - old + new;
-               if (new)
-                       __set_bit(val - 1, nlk->groups);
-               else
-                       __clear_bit(val - 1, nlk->groups);
-               netlink_update_subscriptions(sk, subscriptions);
-               netlink_update_listeners(sk);
+               netlink_update_socket_mc(nlk, val,
+                                        optname == NETLINK_ADD_MEMBERSHIP);
                netlink_table_ungrab();
                err = 0;
                break;
@@ -1327,6 +1354,71 @@ out_sock_release:
        return NULL;
 }
 
+/**
+ * netlink_change_ngroups - change number of multicast groups
+ *
+ * This changes the number of multicast groups that are available
+ * on a certain netlink family. Note that it is not possible to
+ * change the number of groups to below 32. Also note that it does
+ * not implicitly call netlink_clear_multicast_users() when the
+ * number of groups is reduced.
+ *
+ * @sk: The kernel netlink socket, as returned by netlink_kernel_create().
+ * @groups: The new number of groups.
+ */
+int netlink_change_ngroups(struct sock *sk, unsigned int groups)
+{
+       unsigned long *listeners, *old = NULL;
+       struct netlink_table *tbl = &nl_table[sk->sk_protocol];
+       int err = 0;
+
+       if (groups < 32)
+               groups = 32;
+
+       netlink_table_grab();
+       if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) {
+               listeners = kzalloc(NLGRPSZ(groups), GFP_ATOMIC);
+               if (!listeners) {
+                       err = -ENOMEM;
+                       goto out_ungrab;
+               }
+               old = tbl->listeners;
+               memcpy(listeners, old, NLGRPSZ(tbl->groups));
+               rcu_assign_pointer(tbl->listeners, listeners);
+       }
+       tbl->groups = groups;
+
+ out_ungrab:
+       netlink_table_ungrab();
+       synchronize_rcu();
+       kfree(old);
+       return err;
+}
+EXPORT_SYMBOL(netlink_change_ngroups);
+
+/**
+ * netlink_clear_multicast_users - kick off multicast listeners
+ *
+ * This function removes all listeners from the given group.
+ * @ksk: The kernel netlink socket, as returned by
+ *     netlink_kernel_create().
+ * @group: The multicast group to clear.
+ */
+void netlink_clear_multicast_users(struct sock *ksk, unsigned int group)
+{
+       struct sock *sk;
+       struct hlist_node *node;
+       struct netlink_table *tbl = &nl_table[ksk->sk_protocol];
+
+       netlink_table_grab();
+
+       sk_for_each_bound(sk, node, &tbl->mc_list)
+               netlink_update_socket_mc(nlk_sk(sk), group, 0);
+
+       netlink_table_ungrab();
+}
+EXPORT_SYMBOL(netlink_clear_multicast_users);
+
 void netlink_set_nonroot(int protocol, unsigned int flags)
 {
        if ((unsigned int)protocol < MAX_LINKS)
index b9ab62f938d07111f2b7489ad9f5ca9d31dbb746..e146531faf1d349434c89306eafc7968f506baa1 100644 (file)
@@ -3,6 +3,7 @@
  *
  *             Authors:        Jamal Hadi Salim
  *                             Thomas Graf <tgraf@suug.ch>
+ *                             Johannes Berg <johannes@sipsolutions.net>
  */
 
 #include <linux/module.h>
@@ -13,6 +14,7 @@
 #include <linux/string.h>
 #include <linux/skbuff.h>
 #include <linux/mutex.h>
+#include <linux/bitmap.h>
 #include <net/sock.h>
 #include <net/genetlink.h>
 
@@ -42,6 +44,16 @@ static void genl_unlock(void)
 #define GENL_FAM_TAB_MASK      (GENL_FAM_TAB_SIZE - 1)
 
 static struct list_head family_ht[GENL_FAM_TAB_SIZE];
+/*
+ * Bitmap of multicast groups that are currently in use.
+ *
+ * To avoid an allocation at boot of just one unsigned long,
+ * declare it global instead.
+ * Bit 0 is marked as already used since group 0 is invalid.
+ */
+static unsigned long mc_group_start = 0x1;
+static unsigned long *mc_groups = &mc_group_start;
+static unsigned long mc_groups_longs = 1;
 
 static int genl_ctrl_event(int event, void *data);
 
@@ -116,6 +128,114 @@ static inline u16 genl_generate_id(void)
        return id_gen_idx;
 }
 
+static struct genl_multicast_group notify_grp;
+
+/**
+ * genl_register_mc_group - register a multicast group
+ *
+ * Registers the specified multicast group and notifies userspace
+ * about the new group.
+ *
+ * Returns 0 on success or a negative error code.
+ *
+ * @family: The generic netlink family the group shall be registered for.
+ * @grp: The group to register, must have a name.
+ */
+int genl_register_mc_group(struct genl_family *family,
+                          struct genl_multicast_group *grp)
+{
+       int id;
+       unsigned long *new_groups;
+       int err;
+
+       BUG_ON(grp->name[0] == '\0');
+
+       genl_lock();
+
+       /* special-case our own group */
+       if (grp == &notify_grp)
+               id = GENL_ID_CTRL;
+       else
+               id = find_first_zero_bit(mc_groups,
+                                        mc_groups_longs * BITS_PER_LONG);
+
+
+       if (id >= mc_groups_longs * BITS_PER_LONG) {
+               size_t nlen = (mc_groups_longs + 1) * sizeof(unsigned long);
+
+               if (mc_groups == &mc_group_start) {
+                       new_groups = kzalloc(nlen, GFP_KERNEL);
+                       if (!new_groups) {
+                               err = -ENOMEM;
+                               goto out;
+                       }
+                       mc_groups = new_groups;
+                       *mc_groups = mc_group_start;
+               } else {
+                       new_groups = krealloc(mc_groups, nlen, GFP_KERNEL);
+                       if (!new_groups) {
+                               err = -ENOMEM;
+                               goto out;
+                       }
+                       mc_groups = new_groups;
+                       mc_groups[mc_groups_longs] = 0;
+               }
+               mc_groups_longs++;
+       }
+
+       err = netlink_change_ngroups(genl_sock,
+                                    sizeof(unsigned long) * NETLINK_GENERIC);
+       if (err)
+               goto out;
+
+       grp->id = id;
+       set_bit(id, mc_groups);
+       list_add_tail(&grp->list, &family->mcast_groups);
+       grp->family = family;
+
+       genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, grp);
+ out:
+       genl_unlock();
+       return 0;
+}
+EXPORT_SYMBOL(genl_register_mc_group);
+
+/**
+ * genl_unregister_mc_group - unregister a multicast group
+ *
+ * Unregisters the specified multicast group and notifies userspace
+ * about it. All current listeners on the group are removed.
+ *
+ * Note: It is not necessary to unregister all multicast groups before
+ *       unregistering the family, unregistering the family will cause
+ *       all assigned multicast groups to be unregistered automatically.
+ *
+ * @family: Generic netlink family the group belongs to.
+ * @grp: The group to unregister, must have been registered successfully
+ *      previously.
+ */
+void genl_unregister_mc_group(struct genl_family *family,
+                             struct genl_multicast_group *grp)
+{
+       BUG_ON(grp->family != family);
+       genl_lock();
+       netlink_clear_multicast_users(genl_sock, grp->id);
+       clear_bit(grp->id, mc_groups);
+       list_del(&grp->list);
+       genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp);
+       grp->id = 0;
+       grp->family = NULL;
+       genl_unlock();
+}
+
+static void genl_unregister_mc_groups(struct genl_family *family)
+{
+       struct genl_multicast_group *grp, *tmp;
+
+       list_for_each_entry_safe(grp, tmp, &family->mcast_groups, list)
+               genl_unregister_mc_group(family, grp);
+}
+
 /**
  * genl_register_ops - register generic netlink operations
  * @family: generic netlink family
@@ -216,6 +336,7 @@ int genl_register_family(struct genl_family *family)
                goto errout;
 
        INIT_LIST_HEAD(&family->ops_list);
+       INIT_LIST_HEAD(&family->mcast_groups);
 
        genl_lock();
 
@@ -275,6 +396,8 @@ int genl_unregister_family(struct genl_family *family)
 {
        struct genl_family *rc;
 
+       genl_unregister_mc_groups(family);
+
        genl_lock();
 
        list_for_each_entry(rc, genl_family_chain(family->id), family_list) {
@@ -410,6 +533,67 @@ static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
                nla_nest_end(skb, nla_ops);
        }
 
+       if (!list_empty(&family->mcast_groups)) {
+               struct genl_multicast_group *grp;
+               struct nlattr *nla_grps;
+               int idx = 1;
+
+               nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS);
+               if (nla_grps == NULL)
+                       goto nla_put_failure;
+
+               list_for_each_entry(grp, &family->mcast_groups, list) {
+                       struct nlattr *nest;
+
+                       nest = nla_nest_start(skb, idx++);
+                       if (nest == NULL)
+                               goto nla_put_failure;
+
+                       NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id);
+                       NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME,
+                                      grp->name);
+
+                       nla_nest_end(skb, nest);
+               }
+               nla_nest_end(skb, nla_grps);
+       }
+
+       return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+       return genlmsg_cancel(skb, hdr);
+}
+
+static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 pid,
+                               u32 seq, u32 flags, struct sk_buff *skb,
+                               u8 cmd)
+{
+       void *hdr;
+       struct nlattr *nla_grps;
+       struct nlattr *nest;
+
+       hdr = genlmsg_put(skb, pid, seq, &genl_ctrl, flags, cmd);
+       if (hdr == NULL)
+               return -1;
+
+       NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, grp->family->name);
+       NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, grp->family->id);
+
+       nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS);
+       if (nla_grps == NULL)
+               goto nla_put_failure;
+
+       nest = nla_nest_start(skb, 1);
+       if (nest == NULL)
+               goto nla_put_failure;
+
+       NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id);
+       NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME,
+                      grp->name);
+
+       nla_nest_end(skb, nest);
+       nla_nest_end(skb, nla_grps);
+
        return genlmsg_end(skb, hdr);
 
 nla_put_failure:
@@ -453,8 +637,8 @@ errout:
        return skb->len;
 }
 
-static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid,
-                                     int seq, u8 cmd)
+static struct sk_buff *ctrl_build_family_msg(struct genl_family *family,
+                                            u32 pid, int seq, u8 cmd)
 {
        struct sk_buff *skb;
        int err;
@@ -472,6 +656,25 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid,
        return skb;
 }
 
+static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_multicast_group *grp,
+                                           u32 pid, int seq, u8 cmd)
+{
+       struct sk_buff *skb;
+       int err;
+
+       skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (skb == NULL)
+               return ERR_PTR(-ENOBUFS);
+
+       err = ctrl_fill_mcgrp_info(grp, pid, seq, 0, skb, cmd);
+       if (err < 0) {
+               nlmsg_free(skb);
+               return ERR_PTR(err);
+       }
+
+       return skb;
+}
+
 static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
        [CTRL_ATTR_FAMILY_ID]   = { .type = NLA_U16 },
        [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING,
@@ -501,8 +704,8 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
                goto errout;
        }
 
-       msg = ctrl_build_msg(res, info->snd_pid, info->snd_seq,
-                            CTRL_CMD_NEWFAMILY);
+       msg = ctrl_build_family_msg(res, info->snd_pid, info->snd_seq,
+                                   CTRL_CMD_NEWFAMILY);
        if (IS_ERR(msg)) {
                err = PTR_ERR(msg);
                goto errout;
@@ -523,7 +726,15 @@ static int genl_ctrl_event(int event, void *data)
        switch (event) {
        case CTRL_CMD_NEWFAMILY:
        case CTRL_CMD_DELFAMILY:
-               msg = ctrl_build_msg(data, 0, 0, event);
+               msg = ctrl_build_family_msg(data, 0, 0, event);
+               if (IS_ERR(msg))
+                       return PTR_ERR(msg);
+
+               genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
+               break;
+       case CTRL_CMD_NEWMCAST_GRP:
+       case CTRL_CMD_DELMCAST_GRP:
+               msg = ctrl_build_mcgrp_msg(data, 0, 0, event);
                if (IS_ERR(msg))
                        return PTR_ERR(msg);
 
@@ -541,6 +752,10 @@ static struct genl_ops genl_ctrl_ops = {
        .policy         = ctrl_policy,
 };
 
+static struct genl_multicast_group notify_grp = {
+       .name           = "notify",
+};
+
 static int __init genl_init(void)
 {
        int i, err;
@@ -557,11 +772,17 @@ static int __init genl_init(void)
                goto errout_register;
 
        netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV);
-       genl_sock = netlink_kernel_create(NETLINK_GENERIC, GENL_MAX_ID,
-                                         genl_rcv, NULL, THIS_MODULE);
+
+       /* we'll bump the group number right afterwards */
+       genl_sock = netlink_kernel_create(NETLINK_GENERIC, 0, genl_rcv,
+                                         NULL, THIS_MODULE);
        if (genl_sock == NULL)
                panic("GENL: Cannot initialize generic netlink\n");
 
+       err = genl_register_mc_group(&genl_ctrl, &notify_grp);
+       if (err < 0)
+               goto errout_register;
+
        return 0;
 
 errout_register:
index f3986d498b4088622084a121fa0bcc73b07f228e..db3395bfbcfa304e5702dcd91c9d503fba01da84 100644 (file)
@@ -187,7 +187,7 @@ static ssize_t rfkill_claim_store(struct device *dev,
 static struct device_attribute rfkill_dev_attrs[] = {
        __ATTR(name, S_IRUGO, rfkill_name_show, NULL),
        __ATTR(type, S_IRUGO, rfkill_type_show, NULL),
-       __ATTR(state, S_IRUGO, rfkill_state_show, rfkill_state_store),
+       __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store),
        __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store),
        __ATTR_NULL
 };
index d3f7c3f9407a8f6751304a6f99f84c3d8c4d7b3b..8a74cac0be8c01382979f8fd93144ea4065753e5 100644 (file)
@@ -97,7 +97,7 @@ config NET_SCH_ATM
          select classes of this queuing discipline.  Each class maps
          the flow(s) it is handling to a given virtual circuit.
 
-         See the top of <file:net/sched/sch_atm.c>) for more details.
+         See the top of <file:net/sched/sch_atm.c> for more details.
 
          To compile this code as a module, choose M here: the
          module will be called sch_atm.
@@ -137,7 +137,7 @@ config NET_SCH_SFQ
        tristate "Stochastic Fairness Queueing (SFQ)"
        ---help---
          Say Y here if you want to use the Stochastic Fairness Queueing (SFQ)
-         packet scheduling algorithm .
+         packet scheduling algorithm.
 
          See the top of <file:net/sched/sch_sfq.c> for more details.
 
@@ -306,7 +306,7 @@ config NET_CLS_RSVP6
          is important for real time data such as streaming sound or video.
 
          Say Y here if you want to be able to classify outgoing packets based
-         on their RSVP requests and you are using the IPv6.
+         on their RSVP requests and you are using the IPv6 protocol.
 
          To compile this code as a module, choose M here: the
          module will be called cls_rsvp6.
index 417ec8fb7f1a6373f7184cabf2a4c50b0ab85ce4..ddc4f2c54379791de9d60bd9829c68dad52c5e54 100644 (file)
@@ -292,13 +292,12 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
                }
        }
        DPRINTK("atm_tc_change: new id %x\n", classid);
-       flow = kmalloc(sizeof(struct atm_flow_data) + hdr_len, GFP_KERNEL);
+       flow = kzalloc(sizeof(struct atm_flow_data) + hdr_len, GFP_KERNEL);
        DPRINTK("atm_tc_change: flow %p\n", flow);
        if (!flow) {
                error = -ENOBUFS;
                goto err_out;
        }
-       memset(flow, 0, sizeof(*flow));
        flow->filter_list = NULL;
        if (!(flow->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid)))
                flow->q = &noop_qdisc;
index 157bfbd250ba62f2c451805106b25a1f13b581bf..b48f06fc9fd9e25440fc26f392a231156bb28f35 100644 (file)
@@ -2141,7 +2141,7 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,
                if (last == first)
                        break;
 
-               last = last->u.next;
+               last = (struct xfrm_dst *)last->u.dst.next;
                last->child_mtu_cached = mtu;
        }
 
index f573ac189a0a6595b2184b43a9d54c3b01e0d5a0..557500110a13ccd319515a8f96a6d44bc9e13667 100644 (file)
@@ -108,7 +108,8 @@ static int call_sbin_request_key(struct key *key,
        argv[i] = NULL;
 
        /* do it */
-       ret = call_usermodehelper_keys(argv[0], argv, envp, keyring, 1);
+       ret = call_usermodehelper_keys(argv[0], argv, envp, keyring,
+                                      UMH_WAIT_PROC);
 
 error_link:
        key_put(keyring);
index 78c3f98fcdcfa94b2bf72a2bbcc7158b11756eba..520b9998123efa9a65f41f665105aaaada6d47d7 100644 (file)
@@ -2318,7 +2318,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value
        if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
                return -EOPNOTSUPP;
 
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                return -EPERM;
 
        AVC_AUDIT_DATA_INIT(&ad,FS);
index 1d9232d2db342c0569f468f1df036e9b2e5e2da7..170781a72292c1bef14fd861b0099cb24048897f 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/firmware.h>
+#include <linux/vmalloc.h>
 #include <asm/io.h>
 #include <sound/core.h>
 #include "mixart.h"