Merge branch 'for-linus' of git://linux-nfs.org/~bfields/linux
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Thu, 19 Jul 2007 01:27:00 +0000 (18:27 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Thu, 19 Jul 2007 01:27:00 +0000 (18:27 -0700)
* 'for-linus' of git://linux-nfs.org/~bfields/linux:
  locks: fix vfs_test_lock() comment
  locks: make posix_test_lock() interface more consistent
  nfs: disable leases over NFS
  gfs2: stop giving out non-cluster-coherent leases
  locks: export setlease to filesystems
  locks: provide a file lease method enabling cluster-coherent leases
  locks: rename lease functions to reflect locks.c conventions
  locks: share more common lease code
  locks: clean up lease_alloc()
  locks: convert an -EINVAL return to a BUG
  leases: minor break_lease() comment clarification

476 files changed:
Documentation/dvb/bt8xx.txt
Documentation/dvb/get_dvb_firmware
Documentation/dvb/opera-firmware.txt [new file with mode: 0644]
Documentation/feature-removal-schedule.txt
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/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/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/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/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/powerpc/kernel/pci-common.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/sys_ppc32.c
arch/sparc/Kconfig
arch/sparc64/Kconfig
arch/sparc64/kernel/ds.c
arch/sparc64/kernel/mdesc.c
arch/sparc64/kernel/vio.c
arch/sparc64/kernel/viohs.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
drivers/Makefile
drivers/acpi/thermal.c
drivers/atm/Kconfig
drivers/atm/eni.c
drivers/atm/firestream.c
drivers/atm/idt77252.c
drivers/atm/lanai.c
drivers/atm/nicstarmac.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/hvc_xen.c [new file with mode: 0644]
drivers/firewire/fw-ohci.c
drivers/firewire/fw-sbp2.c
drivers/firewire/fw-transaction.c
drivers/firewire/fw-transaction.h
drivers/infiniband/core/cm.c
drivers/infiniband/core/cma.c
drivers/infiniband/hw/cxgb3/iwch_cm.c
drivers/infiniband/hw/ehca/ehca_av.c
drivers/infiniband/hw/ehca/ehca_classes.h
drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
drivers/infiniband/hw/ehca/ehca_cq.c
drivers/infiniband/hw/ehca/ehca_eq.c
drivers/infiniband/hw/ehca/ehca_hca.c
drivers/infiniband/hw/ehca/ehca_irq.c
drivers/infiniband/hw/ehca/ehca_iverbs.h
drivers/infiniband/hw/ehca/ehca_main.c
drivers/infiniband/hw/ehca/ehca_mrmw.c
drivers/infiniband/hw/ehca/ehca_mrmw.h
drivers/infiniband/hw/ehca/ehca_qes.h
drivers/infiniband/hw/ehca/ehca_qp.c
drivers/infiniband/hw/ehca/ehca_reqs.c
drivers/infiniband/hw/ehca/ehca_tools.h
drivers/infiniband/hw/ehca/ehca_uverbs.c
drivers/infiniband/hw/ehca/hcp_if.c
drivers/infiniband/hw/ehca/hcp_phyp.c
drivers/infiniband/hw/ehca/hipz_fns_core.h
drivers/infiniband/hw/ehca/hipz_hw.h
drivers/infiniband/hw/ehca/ipz_pt_fn.c
drivers/infiniband/hw/ehca/ipz_pt_fn.h
drivers/infiniband/hw/ipath/ipath_driver.c
drivers/infiniband/hw/ipath/ipath_eeprom.c
drivers/infiniband/hw/ipath/ipath_intr.c
drivers/infiniband/hw/ipath/ipath_kernel.h
drivers/infiniband/hw/ipath/ipath_ruc.c
drivers/infiniband/hw/ipath/ipath_user_pages.c
drivers/infiniband/hw/ipath/ipath_verbs.c
drivers/infiniband/hw/ipath/ipath_verbs.h
drivers/infiniband/hw/mlx4/qp.c
drivers/infiniband/hw/mthca/mthca_main.c
drivers/infiniband/hw/mthca/mthca_qp.c
drivers/infiniband/hw/mthca/mthca_srq.c
drivers/infiniband/hw/mthca/mthca_wqe.h
drivers/infiniband/ulp/iser/iscsi_iser.h
drivers/infiniband/ulp/iser/iser_memory.c
drivers/infiniband/ulp/iser/iser_verbs.c
drivers/macintosh/therm_pm72.c
drivers/macintosh/windfarm_core.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/bnx2.c
drivers/net/bnx2.h
drivers/net/hamradio/baycom_epp.c
drivers/net/mlx4/catas.c
drivers/net/mlx4/eq.c
drivers/net/mlx4/intf.c
drivers/net/mlx4/main.c
drivers/net/mlx4/mlx4.h
drivers/net/pppol2tp.c
drivers/net/sunvnet.c
drivers/net/sunvnet.h
drivers/net/xen-netfront.c [new file with mode: 0644]
drivers/pnp/pnpbios/core.c
drivers/sbus/char/bbc_envctrl.c
drivers/sbus/char/envctrl.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/Kconfig
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/jbd2/journal.c
fs/jbd2/recovery.c
fs/ocfs2/heartbeat.c
fs/open.c
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-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-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/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/jbd2.h
include/linux/kmod.h
include/linux/major.h
include/linux/netdevice.h
include/linux/netfilter_ipv4/ipt_iprange.h
include/linux/page-flags.h
include/linux/reboot.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/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]
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/sched/Kconfig
net/sched/sch_atm.c
net/xfrm/xfrm_policy.c
security/keys/request_key.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 d05e6243b4df2b0bc0db3d58e1105644a91ba48d..d245c639c2221cae626475d2e418e8dd1afff4dc 100644 (file)
@@ -310,3 +310,13 @@ Why:  The arch/powerpc tree is the merged architecture for ppc32 and ppc64
 Who:  linuxppc-dev@ozlabs.org
 
 ---------------------------
+
+What:  mthca driver's MSI support
+When:  January 2008
+Files: drivers/infiniband/hw/mthca/*.[ch]
+Why:   All mthca hardware also supports MSI-X, which provides
+       strictly more functionality than MSI.  So there is no point in
+       having both MSI-X and MSI support in the driver.
+Who:   Roland Dreier <rolandd@cisco.com>
+
+---------------------------
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 a9615a567da661aad5620efae3fa1e6e62c6dd94..e78f62f13bacc60340e2fecbd2dd03691d290bc2 100644 (file)
@@ -1740,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
@@ -2393,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
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 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 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 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 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 73df7115325bc4cd813f4a753d5a8991a1223869..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"
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 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 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 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 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 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 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 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 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 97bd71bc3aea791645dc7fcb9ba7f6ef6cb16bbe..9e8f21410d2d06a3f499c5d22397a45fb5ff0472 100644 (file)
@@ -604,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
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 41476abc069310ce0989f546de49130d566ea736..db703758db98c3ec0a7f26067e6d410f3fe770c7 100644 (file)
@@ -224,6 +224,7 @@ ohci_update_phy_reg(struct fw_card *card, int addr,
        u32 val, old;
 
        reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr));
+       flush_writes(ohci);
        msleep(2);
        val = reg_read(ohci, OHCI1394_PhyControl);
        if ((val & OHCI1394_PhyControl_ReadDone) == 0) {
@@ -586,7 +587,7 @@ static void context_stop(struct context *ctx)
                        break;
 
                fw_notify("context_stop: still active (0x%08x)\n", reg);
-               msleep(1);
+               mdelay(1);
        }
 }
 
index 7c53be0387fbb675b8c26453982d14a6ddf9da0d..fc984474162c3c493cc78c06f9fe43a3071e634e 100644 (file)
@@ -840,7 +840,6 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
                container_of(base_orb, struct sbp2_command_orb, base);
        struct fw_unit *unit = orb->unit;
        struct fw_device *device = fw_device(unit->device.parent);
-       struct scatterlist *sg;
        int result;
 
        if (status != NULL) {
@@ -876,11 +875,10 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
        dma_unmap_single(device->card->device, orb->base.request_bus,
                         sizeof(orb->request), DMA_TO_DEVICE);
 
-       if (orb->cmd->use_sg > 0) {
-               sg = (struct scatterlist *)orb->cmd->request_buffer;
-               dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg,
+       if (scsi_sg_count(orb->cmd) > 0)
+               dma_unmap_sg(device->card->device, scsi_sglist(orb->cmd),
+                            scsi_sg_count(orb->cmd),
                             orb->cmd->sc_data_direction);
-       }
 
        if (orb->page_table_bus != 0)
                dma_unmap_single(device->card->device, orb->page_table_bus,
@@ -901,8 +899,8 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
        int sg_len, l, i, j, count;
        dma_addr_t sg_addr;
 
-       sg = (struct scatterlist *)orb->cmd->request_buffer;
-       count = dma_map_sg(device->card->device, sg, orb->cmd->use_sg,
+       sg = scsi_sglist(orb->cmd);
+       count = dma_map_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
                           orb->cmd->sc_data_direction);
        if (count == 0)
                goto fail;
@@ -971,7 +969,7 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
        return 0;
 
  fail_page_table:
-       dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg,
+       dma_unmap_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
                     orb->cmd->sc_data_direction);
  fail:
        return -ENOMEM;
@@ -1031,7 +1029,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
                orb->request.misc |=
                        COMMAND_ORB_DIRECTION(SBP2_DIRECTION_TO_MEDIA);
 
-       if (cmd->use_sg && sbp2_command_orb_map_scatterlist(orb) < 0)
+       if (scsi_sg_count(cmd) && sbp2_command_orb_map_scatterlist(orb) < 0)
                goto fail_mapping;
 
        fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request));
index 80d0121463d0d7fee8b0a49b6e56a3aab53b20f3..3ce8e2fbe15fc3d84fb6be6cf8b73cdcc195ac2c 100644 (file)
@@ -605,8 +605,10 @@ fw_send_response(struct fw_card *card, struct fw_request *request, int rcode)
         * check is sufficient to ensure we don't send response to
         * broadcast packets or posted writes.
         */
-       if (request->ack != ACK_PENDING)
+       if (request->ack != ACK_PENDING) {
+               kfree(request);
                return;
+       }
 
        if (rcode == RCODE_COMPLETE)
                fw_fill_response(&request->response, request->request_header,
@@ -628,11 +630,6 @@ fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
        unsigned long flags;
        int tcode, destination, source;
 
-       if (p->payload_length > 2048) {
-               /* FIXME: send error response. */
-               return;
-       }
-
        if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)
                return;
 
index 5abed193f4a65deb8c6ab3f27355a03a9d3092e8..5ceaccd10564cbfd7623757ba351e8490d542fe7 100644 (file)
@@ -123,6 +123,10 @@ typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode,
                                          size_t length,
                                          void *callback_data);
 
+/*
+ * Important note:  The callback must guarantee that either fw_send_response()
+ * or kfree() is called on the @request.
+ */
 typedef void (*fw_address_callback_t)(struct fw_card *card,
                                      struct fw_request *request,
                                      int tcode, int destination, int source,
index 9820c67ba47dd2566eaaac76cce25e5a0ebdc834..4df269f5d9ac96ca8895ee04ceecd7ab75e12569 100644 (file)
@@ -3374,7 +3374,7 @@ int ib_cm_init_qp_attr(struct ib_cm_id *cm_id,
 }
 EXPORT_SYMBOL(ib_cm_init_qp_attr);
 
-void cm_get_ack_delay(struct cm_device *cm_dev)
+static void cm_get_ack_delay(struct cm_device *cm_dev)
 {
        struct ib_device_attr attr;
 
index 23af7a032a035fbb1c082ca69fdc69053d026515..9ffb9987450a8ef2ddf294ab32dd300b9621c2cf 100644 (file)
@@ -573,7 +573,7 @@ int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr,
                break;
        case RDMA_TRANSPORT_IWARP:
                if (!id_priv->cm_id.iw) {
-                       qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE;
+                       qp_attr->qp_access_flags = 0;
                        *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS;
                } else
                        ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr,
index 3b41dc0c39dd9c2da189273862ae5c1cf3362be3..5dc68cd5621b4e574d49d37da181287f9fb5da74 100644 (file)
@@ -1914,6 +1914,7 @@ int iwch_create_listen(struct iw_cm_id *cm_id, int backlog)
 fail3:
        cxgb3_free_stid(ep->com.tdev, ep->stid);
 fail2:
+       cm_id->rem_ref(cm_id);
        put_ep(&ep->com);
 fail1:
 out:
index 3cd6bf3402d10c8a0d9d097b72d8fdf9b1bb5a11..e53a97af126034c95f386193b2ca5909f16257c5 100644 (file)
@@ -79,7 +79,7 @@ struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
                        av->av.ipd = (ah_mult > 0) ?
                                ((ehca_mult - 1) / ah_mult) : 0;
        } else
-               av->av.ipd = ehca_static_rate;
+               av->av.ipd = ehca_static_rate;
 
        av->av.lnh = ah_attr->ah_flags;
        av->av.grh.word_0 = EHCA_BMASK_SET(GRH_IPVERSION_MASK, 6);
index daf823ea1acedb242caa59e22b35de602570d1b5..043e4fb23fb093bb92f800518d38e8bd1f6dbc4b 100644 (file)
@@ -204,11 +204,11 @@ struct ehca_mr {
        spinlock_t mrlock;
 
        enum ehca_mr_flag flags;
-       u32 num_pages;          /* number of MR pages */
-       u32 num_4k;             /* number of 4k "page" portions to form MR */
+       u32 num_kpages;         /* number of kernel pages */
+       u32 num_hwpages;        /* number of hw pages to form MR */
        int acl;                /* ACL (stored here for usage in reregister) */
        u64 *start;             /* virtual start address (stored here for */
-                               /* usage in reregister) */
+                               /* usage in reregister) */
        u64 size;               /* size (stored here for usage in reregister) */
        u32 fmr_page_size;      /* page size for FMR */
        u32 fmr_max_pages;      /* max pages for FMR */
@@ -217,9 +217,6 @@ struct ehca_mr {
        /* fw specific data */
        struct ipz_mrmw_handle ipz_mr_handle;   /* MR handle for h-calls */
        struct h_galpas galpas;
-       /* data for userspace bridge */
-       u32 nr_of_pages;
-       void *pagearray;
 };
 
 struct ehca_mw {
@@ -241,26 +238,29 @@ enum ehca_mr_pgi_type {
 
 struct ehca_mr_pginfo {
        enum ehca_mr_pgi_type type;
-       u64 num_pages;
-       u64 page_cnt;
-       u64 num_4k;       /* number of 4k "page" portions */
-       u64 page_4k_cnt;  /* counter for 4k "page" portions */
-       u64 next_4k;      /* next 4k "page" portion in buffer/chunk/listelem */
-
-       /* type EHCA_MR_PGI_PHYS section */
-       int num_phys_buf;
-       struct ib_phys_buf *phys_buf_array;
-       u64 next_buf;
-
-       /* type EHCA_MR_PGI_USER section */
-       struct ib_umem *region;
-       struct ib_umem_chunk *next_chunk;
-       u64 next_nmap;
-
-       /* type EHCA_MR_PGI_FMR section */
-       u64 *page_list;
-       u64 next_listelem;
-       /* next_4k also used within EHCA_MR_PGI_FMR */
+       u64 num_kpages;
+       u64 kpage_cnt;
+       u64 num_hwpages;     /* number of hw pages */
+       u64 hwpage_cnt;      /* counter for hw pages */
+       u64 next_hwpage;     /* next hw page in buffer/chunk/listelem */
+
+       union {
+               struct { /* type EHCA_MR_PGI_PHYS section */
+                       int num_phys_buf;
+                       struct ib_phys_buf *phys_buf_array;
+                       u64 next_buf;
+               } phy;
+               struct { /* type EHCA_MR_PGI_USER section */
+                       struct ib_umem *region;
+                       struct ib_umem_chunk *next_chunk;
+                       u64 next_nmap;
+               } usr;
+               struct { /* type EHCA_MR_PGI_FMR section */
+                       u64 fmr_pgsize;
+                       u64 *page_list;
+                       u64 next_listelem;
+               } fmr;
+       } u;
 };
 
 /* output parameters for MR/FMR hipz calls */
@@ -391,6 +391,6 @@ struct ehca_alloc_qp_parms {
 
 int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp);
 int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int qp_num);
-struct ehca_qpehca_cq_get_qp(struct ehca_cq *cq, int qp_num);
+struct ehca_qp *ehca_cq_get_qp(struct ehca_cq *cq, int qp_num);
 
 #endif
index fb3df5c271e7e144d5ffb344296ba9a9a775adab..1798e6466bd07b87f6069182a00dc878b95c6858 100644 (file)
@@ -154,83 +154,83 @@ struct hcp_modify_qp_control_block {
        u32 reserved_70_127[58];       /* 70 */
 };
 
-#define MQPCB_MASK_QKEY                         EHCA_BMASK_IBM(0,0)
-#define MQPCB_MASK_SEND_PSN                     EHCA_BMASK_IBM(2,2)
-#define MQPCB_MASK_RECEIVE_PSN                  EHCA_BMASK_IBM(3,3)
-#define MQPCB_MASK_PRIM_PHYS_PORT               EHCA_BMASK_IBM(4,4)
-#define MQPCB_PRIM_PHYS_PORT                    EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_ALT_PHYS_PORT                EHCA_BMASK_IBM(5,5)
-#define MQPCB_MASK_PRIM_P_KEY_IDX               EHCA_BMASK_IBM(6,6)
-#define MQPCB_PRIM_P_KEY_IDX                    EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_ALT_P_KEY_IDX                EHCA_BMASK_IBM(7,7)
-#define MQPCB_MASK_RDMA_ATOMIC_CTRL             EHCA_BMASK_IBM(8,8)
-#define MQPCB_MASK_QP_STATE                     EHCA_BMASK_IBM(9,9)
-#define MQPCB_QP_STATE                          EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES      EHCA_BMASK_IBM(11,11)
-#define MQPCB_MASK_PATH_MIGRATION_STATE         EHCA_BMASK_IBM(12,12)
-#define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP    EHCA_BMASK_IBM(13,13)
-#define MQPCB_MASK_DEST_QP_NR                   EHCA_BMASK_IBM(14,14)
-#define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD      EHCA_BMASK_IBM(15,15)
-#define MQPCB_MASK_SERVICE_LEVEL                EHCA_BMASK_IBM(16,16)
-#define MQPCB_MASK_SEND_GRH_FLAG                EHCA_BMASK_IBM(17,17)
-#define MQPCB_MASK_RETRY_COUNT                  EHCA_BMASK_IBM(18,18)
-#define MQPCB_MASK_TIMEOUT                      EHCA_BMASK_IBM(19,19)
-#define MQPCB_MASK_PATH_MTU                     EHCA_BMASK_IBM(20,20)
-#define MQPCB_PATH_MTU                          EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_MAX_STATIC_RATE              EHCA_BMASK_IBM(21,21)
-#define MQPCB_MAX_STATIC_RATE                   EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_DLID                         EHCA_BMASK_IBM(22,22)
-#define MQPCB_DLID                              EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_RNR_RETRY_COUNT              EHCA_BMASK_IBM(23,23)
-#define MQPCB_RNR_RETRY_COUNT                   EHCA_BMASK_IBM(29,31)
-#define MQPCB_MASK_SOURCE_PATH_BITS             EHCA_BMASK_IBM(24,24)
-#define MQPCB_SOURCE_PATH_BITS                  EHCA_BMASK_IBM(25,31)
-#define MQPCB_MASK_TRAFFIC_CLASS                EHCA_BMASK_IBM(25,25)
-#define MQPCB_TRAFFIC_CLASS                     EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_HOP_LIMIT                    EHCA_BMASK_IBM(26,26)
-#define MQPCB_HOP_LIMIT                         EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_SOURCE_GID_IDX               EHCA_BMASK_IBM(27,27)
-#define MQPCB_SOURCE_GID_IDX                    EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_FLOW_LABEL                   EHCA_BMASK_IBM(28,28)
-#define MQPCB_FLOW_LABEL                        EHCA_BMASK_IBM(12,31)
-#define MQPCB_MASK_DEST_GID                     EHCA_BMASK_IBM(30,30)
-#define MQPCB_MASK_SERVICE_LEVEL_AL             EHCA_BMASK_IBM(31,31)
-#define MQPCB_SERVICE_LEVEL_AL                  EHCA_BMASK_IBM(28,31)
-#define MQPCB_MASK_SEND_GRH_FLAG_AL             EHCA_BMASK_IBM(32,32)
-#define MQPCB_SEND_GRH_FLAG_AL                  EHCA_BMASK_IBM(31,31)
-#define MQPCB_MASK_RETRY_COUNT_AL               EHCA_BMASK_IBM(33,33)
-#define MQPCB_RETRY_COUNT_AL                    EHCA_BMASK_IBM(29,31)
-#define MQPCB_MASK_TIMEOUT_AL                   EHCA_BMASK_IBM(34,34)
-#define MQPCB_TIMEOUT_AL                        EHCA_BMASK_IBM(27,31)
-#define MQPCB_MASK_MAX_STATIC_RATE_AL           EHCA_BMASK_IBM(35,35)
-#define MQPCB_MAX_STATIC_RATE_AL                EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_DLID_AL                      EHCA_BMASK_IBM(36,36)
-#define MQPCB_DLID_AL                           EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_RNR_RETRY_COUNT_AL           EHCA_BMASK_IBM(37,37)
-#define MQPCB_RNR_RETRY_COUNT_AL                EHCA_BMASK_IBM(29,31)
-#define MQPCB_MASK_SOURCE_PATH_BITS_AL          EHCA_BMASK_IBM(38,38)
-#define MQPCB_SOURCE_PATH_BITS_AL               EHCA_BMASK_IBM(25,31)
-#define MQPCB_MASK_TRAFFIC_CLASS_AL             EHCA_BMASK_IBM(39,39)
-#define MQPCB_TRAFFIC_CLASS_AL                  EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_HOP_LIMIT_AL                 EHCA_BMASK_IBM(40,40)
-#define MQPCB_HOP_LIMIT_AL                      EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_SOURCE_GID_IDX_AL            EHCA_BMASK_IBM(41,41)
-#define MQPCB_SOURCE_GID_IDX_AL                 EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_FLOW_LABEL_AL                EHCA_BMASK_IBM(42,42)
-#define MQPCB_FLOW_LABEL_AL                     EHCA_BMASK_IBM(12,31)
-#define MQPCB_MASK_DEST_GID_AL                  EHCA_BMASK_IBM(44,44)
-#define MQPCB_MASK_MAX_NR_OUTST_SEND_WR         EHCA_BMASK_IBM(45,45)
-#define MQPCB_MAX_NR_OUTST_SEND_WR              EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_MAX_NR_OUTST_RECV_WR         EHCA_BMASK_IBM(46,46)
-#define MQPCB_MAX_NR_OUTST_RECV_WR              EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK     EHCA_BMASK_IBM(47,47)
-#define MQPCB_DISABLE_ETE_CREDIT_CHECK          EHCA_BMASK_IBM(31,31)
-#define MQPCB_QP_NUMBER                         EHCA_BMASK_IBM(8,31)
-#define MQPCB_MASK_QP_ENABLE                    EHCA_BMASK_IBM(48,48)
-#define MQPCB_QP_ENABLE                         EHCA_BMASK_IBM(31,31)
-#define MQPCB_MASK_CURR_SRQ_LIMIT               EHCA_BMASK_IBM(49,49)
-#define MQPCB_CURR_SRQ_LIMIT                    EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG       EHCA_BMASK_IBM(50,50)
-#define MQPCB_MASK_SHARED_RQ_HNDL               EHCA_BMASK_IBM(51,51)
+#define MQPCB_MASK_QKEY                         EHCA_BMASK_IBM( 0,  0)
+#define MQPCB_MASK_SEND_PSN                     EHCA_BMASK_IBM( 2,  2)
+#define MQPCB_MASK_RECEIVE_PSN                  EHCA_BMASK_IBM( 3,  3)
+#define MQPCB_MASK_PRIM_PHYS_PORT               EHCA_BMASK_IBM( 4,  4)
+#define MQPCB_PRIM_PHYS_PORT                    EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_ALT_PHYS_PORT                EHCA_BMASK_IBM( 5,  5)
+#define MQPCB_MASK_PRIM_P_KEY_IDX               EHCA_BMASK_IBM( 6,  6)
+#define MQPCB_PRIM_P_KEY_IDX                    EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_ALT_P_KEY_IDX                EHCA_BMASK_IBM( 7,  7)
+#define MQPCB_MASK_RDMA_ATOMIC_CTRL             EHCA_BMASK_IBM( 8,  8)
+#define MQPCB_MASK_QP_STATE                     EHCA_BMASK_IBM( 9,  9)
+#define MQPCB_QP_STATE                          EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES      EHCA_BMASK_IBM(11, 11)
+#define MQPCB_MASK_PATH_MIGRATION_STATE         EHCA_BMASK_IBM(12, 12)
+#define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP    EHCA_BMASK_IBM(13, 13)
+#define MQPCB_MASK_DEST_QP_NR                   EHCA_BMASK_IBM(14, 14)
+#define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD      EHCA_BMASK_IBM(15, 15)
+#define MQPCB_MASK_SERVICE_LEVEL                EHCA_BMASK_IBM(16, 16)
+#define MQPCB_MASK_SEND_GRH_FLAG                EHCA_BMASK_IBM(17, 17)
+#define MQPCB_MASK_RETRY_COUNT                  EHCA_BMASK_IBM(18, 18)
+#define MQPCB_MASK_TIMEOUT                      EHCA_BMASK_IBM(19, 19)
+#define MQPCB_MASK_PATH_MTU                     EHCA_BMASK_IBM(20, 20)
+#define MQPCB_PATH_MTU                          EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_MAX_STATIC_RATE              EHCA_BMASK_IBM(21, 21)
+#define MQPCB_MAX_STATIC_RATE                   EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_DLID                         EHCA_BMASK_IBM(22, 22)
+#define MQPCB_DLID                              EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_RNR_RETRY_COUNT              EHCA_BMASK_IBM(23, 23)
+#define MQPCB_RNR_RETRY_COUNT                   EHCA_BMASK_IBM(29, 31)
+#define MQPCB_MASK_SOURCE_PATH_BITS             EHCA_BMASK_IBM(24, 24)
+#define MQPCB_SOURCE_PATH_BITS                  EHCA_BMASK_IBM(25, 31)
+#define MQPCB_MASK_TRAFFIC_CLASS                EHCA_BMASK_IBM(25, 25)
+#define MQPCB_TRAFFIC_CLASS                     EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_HOP_LIMIT                    EHCA_BMASK_IBM(26, 26)
+#define MQPCB_HOP_LIMIT                         EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_SOURCE_GID_IDX               EHCA_BMASK_IBM(27, 27)
+#define MQPCB_SOURCE_GID_IDX                    EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_FLOW_LABEL                   EHCA_BMASK_IBM(28, 28)
+#define MQPCB_FLOW_LABEL                        EHCA_BMASK_IBM(12, 31)
+#define MQPCB_MASK_DEST_GID                     EHCA_BMASK_IBM(30, 30)
+#define MQPCB_MASK_SERVICE_LEVEL_AL             EHCA_BMASK_IBM(31, 31)
+#define MQPCB_SERVICE_LEVEL_AL                  EHCA_BMASK_IBM(28, 31)
+#define MQPCB_MASK_SEND_GRH_FLAG_AL             EHCA_BMASK_IBM(32, 32)
+#define MQPCB_SEND_GRH_FLAG_AL                  EHCA_BMASK_IBM(31, 31)
+#define MQPCB_MASK_RETRY_COUNT_AL               EHCA_BMASK_IBM(33, 33)
+#define MQPCB_RETRY_COUNT_AL                    EHCA_BMASK_IBM(29, 31)
+#define MQPCB_MASK_TIMEOUT_AL                   EHCA_BMASK_IBM(34, 34)
+#define MQPCB_TIMEOUT_AL                        EHCA_BMASK_IBM(27, 31)
+#define MQPCB_MASK_MAX_STATIC_RATE_AL           EHCA_BMASK_IBM(35, 35)
+#define MQPCB_MAX_STATIC_RATE_AL                EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_DLID_AL                      EHCA_BMASK_IBM(36, 36)
+#define MQPCB_DLID_AL                           EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_RNR_RETRY_COUNT_AL           EHCA_BMASK_IBM(37, 37)
+#define MQPCB_RNR_RETRY_COUNT_AL                EHCA_BMASK_IBM(29, 31)
+#define MQPCB_MASK_SOURCE_PATH_BITS_AL          EHCA_BMASK_IBM(38, 38)
+#define MQPCB_SOURCE_PATH_BITS_AL               EHCA_BMASK_IBM(25, 31)
+#define MQPCB_MASK_TRAFFIC_CLASS_AL             EHCA_BMASK_IBM(39, 39)
+#define MQPCB_TRAFFIC_CLASS_AL                  EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_HOP_LIMIT_AL                 EHCA_BMASK_IBM(40, 40)
+#define MQPCB_HOP_LIMIT_AL                      EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_SOURCE_GID_IDX_AL            EHCA_BMASK_IBM(41, 41)
+#define MQPCB_SOURCE_GID_IDX_AL                 EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_FLOW_LABEL_AL                EHCA_BMASK_IBM(42, 42)
+#define MQPCB_FLOW_LABEL_AL                     EHCA_BMASK_IBM(12, 31)
+#define MQPCB_MASK_DEST_GID_AL                  EHCA_BMASK_IBM(44, 44)
+#define MQPCB_MASK_MAX_NR_OUTST_SEND_WR         EHCA_BMASK_IBM(45, 45)
+#define MQPCB_MAX_NR_OUTST_SEND_WR              EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_MAX_NR_OUTST_RECV_WR         EHCA_BMASK_IBM(46, 46)
+#define MQPCB_MAX_NR_OUTST_RECV_WR              EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK     EHCA_BMASK_IBM(47, 47)
+#define MQPCB_DISABLE_ETE_CREDIT_CHECK          EHCA_BMASK_IBM(31, 31)
+#define MQPCB_QP_NUMBER                         EHCA_BMASK_IBM( 8, 31)
+#define MQPCB_MASK_QP_ENABLE                    EHCA_BMASK_IBM(48, 48)
+#define MQPCB_QP_ENABLE                         EHCA_BMASK_IBM(31, 31)
+#define MQPCB_MASK_CURR_SRQ_LIMIT               EHCA_BMASK_IBM(49, 49)
+#define MQPCB_CURR_SRQ_LIMIT                    EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG       EHCA_BMASK_IBM(50, 50)
+#define MQPCB_MASK_SHARED_RQ_HNDL               EHCA_BMASK_IBM(51, 51)
 
 #endif /* __EHCA_CLASSES_PSERIES_H__ */
index 01d4a148bd719c4cd955c0628034b97cc14543d8..9e87883b561a1f409e69f1d634d1424cf0137230 100644 (file)
@@ -97,7 +97,7 @@ int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int real_qp_num)
        return ret;
 }
 
-struct ehca_qpehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num)
+struct ehca_qp *ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num)
 {
        struct ehca_qp *ret = NULL;
        unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1);
index 4961eb88827cd85bb6438a5777c1458297f349e0..4825975f88cf5752482f4aa2db58e2b6243b66a8 100644 (file)
@@ -96,7 +96,8 @@ int ehca_create_eq(struct ehca_shca *shca,
        for (i = 0; i < nr_pages; i++) {
                u64 rpage;
 
-               if (!(vpage = ipz_qpageit_get_inc(&eq->ipz_queue))) {
+               vpage = ipz_qpageit_get_inc(&eq->ipz_queue);
+               if (!vpage) {
                        ret = H_RESOURCE;
                        goto create_eq_exit2;
                }
index bbd3c6a5822f1d0b65cc97f536e1a3ee7d33719e..fc19ef9fd963ca2c5fa4b2b6fbf5e58ded297f93 100644 (file)
@@ -127,6 +127,7 @@ int ehca_query_port(struct ib_device *ibdev,
                    u8 port, struct ib_port_attr *props)
 {
        int ret = 0;
+       u64 h_ret;
        struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
                                              ib_device);
        struct hipz_query_port *rblock;
@@ -137,7 +138,8 @@ int ehca_query_port(struct ib_device *ibdev,
                return -ENOMEM;
        }
 
-       if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+       h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+       if (h_ret != H_SUCCESS) {
                ehca_err(&shca->ib_device, "Can't query port properties");
                ret = -EINVAL;
                goto query_port1;
@@ -197,6 +199,7 @@ int ehca_query_sma_attr(struct ehca_shca *shca,
                        u8 port, struct ehca_sma_attr *attr)
 {
        int ret = 0;
+       u64 h_ret;
        struct hipz_query_port *rblock;
 
        rblock = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
@@ -205,7 +208,8 @@ int ehca_query_sma_attr(struct ehca_shca *shca,
                return -ENOMEM;
        }
 
-       if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+       h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+       if (h_ret != H_SUCCESS) {
                ehca_err(&shca->ib_device, "Can't query port properties");
                ret = -EINVAL;
                goto query_sma_attr1;
@@ -230,9 +234,11 @@ query_sma_attr1:
 int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
 {
        int ret = 0;
-       struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device);
+       u64 h_ret;
+       struct ehca_shca *shca;
        struct hipz_query_port *rblock;
 
+       shca = container_of(ibdev, struct ehca_shca, ib_device);
        if (index > 16) {
                ehca_err(&shca->ib_device, "Invalid index: %x.", index);
                return -EINVAL;
@@ -244,7 +250,8 @@ int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
                return -ENOMEM;
        }
 
-       if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+       h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+       if (h_ret != H_SUCCESS) {
                ehca_err(&shca->ib_device, "Can't query port properties");
                ret = -EINVAL;
                goto query_pkey1;
@@ -262,6 +269,7 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port,
                   int index, union ib_gid *gid)
 {
        int ret = 0;
+       u64 h_ret;
        struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
                                              ib_device);
        struct hipz_query_port *rblock;
@@ -277,7 +285,8 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port,
                return -ENOMEM;
        }
 
-       if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+       h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+       if (h_ret != H_SUCCESS) {
                ehca_err(&shca->ib_device, "Can't query port properties");
                ret = -EINVAL;
                goto query_gid1;
@@ -302,11 +311,12 @@ int ehca_modify_port(struct ib_device *ibdev,
                     struct ib_port_modify *props)
 {
        int ret = 0;
-       struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device);
+       struct ehca_shca *shca;
        struct hipz_query_port *rblock;
        u32 cap;
        u64 hret;
 
+       shca = container_of(ibdev, struct ehca_shca, ib_device);
        if ((props->set_port_cap_mask | props->clr_port_cap_mask)
            & ~allowed_port_caps) {
                ehca_err(&shca->ib_device, "Non-changeable bits set in masks  "
@@ -325,7 +335,8 @@ int ehca_modify_port(struct ib_device *ibdev,
                goto modify_port1;
        }
 
-       if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+       hret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+       if (hret != H_SUCCESS) {
                ehca_err(&shca->ib_device, "Can't query port properties");
                ret = -EINVAL;
                goto modify_port2;
@@ -337,7 +348,8 @@ int ehca_modify_port(struct ib_device *ibdev,
        hret = hipz_h_modify_port(shca->ipz_hca_handle, port,
                                  cap, props->init_type, port_modify_mask);
        if (hret != H_SUCCESS) {
-               ehca_err(&shca->ib_device, "Modify port failed  hret=%lx", hret);
+               ehca_err(&shca->ib_device, "Modify port failed  hret=%lx",
+                        hret);
                ret = -EINVAL;
        }
 
index 96eba383075437e4dfea5deb10e307b693282ed4..4fb01fcb63aec20acb2e013bdfac9242f98f190e 100644 (file)
 #include "hipz_fns.h"
 #include "ipz_pt_fn.h"
 
-#define EQE_COMPLETION_EVENT   EHCA_BMASK_IBM(1,1)
-#define EQE_CQ_QP_NUMBER       EHCA_BMASK_IBM(8,31)
-#define EQE_EE_IDENTIFIER      EHCA_BMASK_IBM(2,7)
-#define EQE_CQ_NUMBER          EHCA_BMASK_IBM(8,31)
-#define EQE_QP_NUMBER          EHCA_BMASK_IBM(8,31)
-#define EQE_QP_TOKEN           EHCA_BMASK_IBM(32,63)
-#define EQE_CQ_TOKEN           EHCA_BMASK_IBM(32,63)
-
-#define NEQE_COMPLETION_EVENT  EHCA_BMASK_IBM(1,1)
-#define NEQE_EVENT_CODE        EHCA_BMASK_IBM(2,7)
-#define NEQE_PORT_NUMBER       EHCA_BMASK_IBM(8,15)
-#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16,16)
-#define NEQE_DISRUPTIVE        EHCA_BMASK_IBM(16,16)
-
-#define ERROR_DATA_LENGTH      EHCA_BMASK_IBM(52,63)
-#define ERROR_DATA_TYPE        EHCA_BMASK_IBM(0,7)
+#define EQE_COMPLETION_EVENT   EHCA_BMASK_IBM( 1,  1)
+#define EQE_CQ_QP_NUMBER       EHCA_BMASK_IBM( 8, 31)
+#define EQE_EE_IDENTIFIER      EHCA_BMASK_IBM( 2,  7)
+#define EQE_CQ_NUMBER          EHCA_BMASK_IBM( 8, 31)
+#define EQE_QP_NUMBER          EHCA_BMASK_IBM( 8, 31)
+#define EQE_QP_TOKEN           EHCA_BMASK_IBM(32, 63)
+#define EQE_CQ_TOKEN           EHCA_BMASK_IBM(32, 63)
+
+#define NEQE_COMPLETION_EVENT  EHCA_BMASK_IBM( 1,  1)
+#define NEQE_EVENT_CODE        EHCA_BMASK_IBM( 2,  7)
+#define NEQE_PORT_NUMBER       EHCA_BMASK_IBM( 8, 15)
+#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16, 16)
+#define NEQE_DISRUPTIVE        EHCA_BMASK_IBM(16, 16)
+
+#define ERROR_DATA_LENGTH      EHCA_BMASK_IBM(52, 63)
+#define ERROR_DATA_TYPE        EHCA_BMASK_IBM( 0,  7)
 
 static void queue_comp_task(struct ehca_cq *__cq);
 
-static struct ehca_comp_poolpool;
+static struct ehca_comp_pool *pool;
 #ifdef CONFIG_HOTPLUG_CPU
 static struct notifier_block comp_pool_callback_nb;
 #endif
@@ -85,8 +85,8 @@ static inline void comp_event_callback(struct ehca_cq *cq)
        return;
 }
 
-static void print_error_data(struct ehca_shca * shca, void* data,
-                            u64rblock, int length)
+static void print_error_data(struct ehca_shca *shca, void *data,
+                            u64 *rblock, int length)
 {
        u64 type = EHCA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]);
        u64 resource = rblock[1];
@@ -94,7 +94,7 @@ static void print_error_data(struct ehca_shca * shca, void* data,
        switch (type) {
        case 0x1: /* Queue Pair */
        {
-               struct ehca_qp *qp = (struct ehca_qp*)data;
+               struct ehca_qp *qp = (struct ehca_qp *)data;
 
                /* only print error data if AER is set */
                if (rblock[6] == 0)
@@ -107,7 +107,7 @@ static void print_error_data(struct ehca_shca * shca, void* data,
        }
        case 0x4: /* Completion Queue */
        {
-               struct ehca_cq *cq = (struct ehca_cq*)data;
+               struct ehca_cq *cq = (struct ehca_cq *)data;
 
                ehca_err(&shca->ib_device,
                         "CQ 0x%x (resource=%lx) has errors.",
@@ -572,7 +572,7 @@ void ehca_tasklet_eq(unsigned long data)
        ehca_process_eq((struct ehca_shca*)data, 1);
 }
 
-static inline int find_next_online_cpu(struct ehca_comp_poolpool)
+static inline int find_next_online_cpu(struct ehca_comp_pool *pool)
 {
        int cpu;
        unsigned long flags;
@@ -636,7 +636,7 @@ static void queue_comp_task(struct ehca_cq *__cq)
        __queue_comp_task(__cq, cct);
 }
 
-static void run_comp_task(struct ehca_cpu_comp_taskcct)
+static void run_comp_task(struct ehca_cpu_comp_task *cct)
 {
        struct ehca_cq *cq;
        unsigned long flags;
@@ -666,12 +666,12 @@ static void run_comp_task(struct ehca_cpu_comp_task* cct)
 
 static int comp_task(void *__cct)
 {
-       struct ehca_cpu_comp_taskcct = __cct;
+       struct ehca_cpu_comp_task *cct = __cct;
        int cql_empty;
        DECLARE_WAITQUEUE(wait, current);
 
        set_current_state(TASK_INTERRUPTIBLE);
-       while(!kthread_should_stop()) {
+       while (!kthread_should_stop()) {
                add_wait_queue(&cct->wait_queue, &wait);
 
                spin_lock_irq(&cct->task_lock);
@@ -745,7 +745,7 @@ static void take_over_work(struct ehca_comp_pool *pool,
 
        list_splice_init(&cct->cq_list, &list);
 
-       while(!list_empty(&list)) {
+       while (!list_empty(&list)) {
                cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
 
                list_del(&cq->entry);
@@ -768,7 +768,7 @@ static int comp_pool_callback(struct notifier_block *nfb,
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
                ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu);
-               if(!create_comp_task(pool, cpu)) {
+               if (!create_comp_task(pool, cpu)) {
                        ehca_gen_err("Can't create comp_task for cpu: %x", cpu);
                        return NOTIFY_BAD;
                }
@@ -838,7 +838,7 @@ int ehca_create_comp_pool(void)
 
 #ifdef CONFIG_HOTPLUG_CPU
        comp_pool_callback_nb.notifier_call = comp_pool_callback;
-       comp_pool_callback_nb.priority =0;
+       comp_pool_callback_nb.priority = 0;
        register_cpu_notifier(&comp_pool_callback_nb);
 #endif
 
index 77aeca6a2c2f3e2428dd989b8eabc4afa496fd5d..dce503bb7d6b471315ed6d3a55190cfda2273193 100644 (file)
@@ -81,8 +81,9 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
                               int num_phys_buf,
                               int mr_access_flags, u64 *iova_start);
 
-struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt,
-                              int mr_access_flags, struct ib_udata *udata);
+struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+                              u64 virt, int mr_access_flags,
+                              struct ib_udata *udata);
 
 int ehca_rereg_phys_mr(struct ib_mr *mr,
                       int mr_rereg_mask,
@@ -192,7 +193,7 @@ void ehca_poll_eqs(unsigned long data);
 void *ehca_alloc_fw_ctrlblock(gfp_t flags);
 void ehca_free_fw_ctrlblock(void *ptr);
 #else
-#define ehca_alloc_fw_ctrlblock(flags) ((void *) get_zeroed_page(flags))
+#define ehca_alloc_fw_ctrlblock(flags) ((void *)get_zeroed_page(flags))
 #define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr))
 #endif
 
index 28ba2dd242165f626ead5afc46f43a978de18d9b..36377c6db3d4a22ab6794cb9e954950dfd4a4668 100644 (file)
@@ -107,7 +107,7 @@ static DEFINE_SPINLOCK(shca_list_lock);
 static struct timer_list poll_eqs_timer;
 
 #ifdef CONFIG_PPC_64K_PAGES
-static struct kmem_cache *ctblk_cache = NULL;
+static struct kmem_cache *ctblk_cache;
 
 void *ehca_alloc_fw_ctrlblock(gfp_t flags)
 {
@@ -200,8 +200,8 @@ static void ehca_destroy_slab_caches(void)
 #endif
 }
 
-#define EHCA_HCAAVER  EHCA_BMASK_IBM(32,39)
-#define EHCA_REVID    EHCA_BMASK_IBM(40,63)
+#define EHCA_HCAAVER  EHCA_BMASK_IBM(32, 39)
+#define EHCA_REVID    EHCA_BMASK_IBM(40, 63)
 
 static struct cap_descr {
        u64 mask;
@@ -263,22 +263,27 @@ int ehca_sense_attributes(struct ehca_shca *shca)
 
                ehca_gen_dbg(" ... hardware version=%x:%x", hcaaver, revid);
 
-               if ((hcaaver == 1) && (revid == 0))
-                       shca->hw_level = 0x11;
-               else if ((hcaaver == 1) && (revid == 1))
-                       shca->hw_level = 0x12;
-               else if ((hcaaver == 1) && (revid == 2))
-                       shca->hw_level = 0x13;
-               else if ((hcaaver == 2) && (revid == 0))
-                       shca->hw_level = 0x21;
-               else if ((hcaaver == 2) && (revid == 0x10))
-                       shca->hw_level = 0x22;
-               else {
+               if (hcaaver == 1) {
+                       if (revid <= 3)
+                               shca->hw_level = 0x10 | (revid + 1);
+                       else
+                               shca->hw_level = 0x14;
+               } else if (hcaaver == 2) {
+                       if (revid == 0)
+                               shca->hw_level = 0x21;
+                       else if (revid == 0x10)
+                               shca->hw_level = 0x22;
+                       else if (revid == 0x20 || revid == 0x21)
+                               shca->hw_level = 0x23;
+               }
+
+               if (!shca->hw_level) {
                        ehca_gen_warn("unknown hardware version"
                                      " - assuming default level");
                        shca->hw_level = 0x22;
                }
-       }
+       } else
+               shca->hw_level = ehca_hw_level;
        ehca_gen_dbg(" ... hardware level=%x", shca->hw_level);
 
        shca->sport[0].rate = IB_RATE_30_GBPS;
@@ -290,7 +295,7 @@ int ehca_sense_attributes(struct ehca_shca *shca)
                if (EHCA_BMASK_GET(hca_cap_descr[i].mask, shca->hca_cap))
                        ehca_gen_dbg("   %s", hca_cap_descr[i].descr);
 
-       port = (struct hipz_query_port *) rblock;
+       port = (struct hipz_query_port *)rblock;
        h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port);
        if (h_ret != H_SUCCESS) {
                ehca_gen_err("Cannot query port properties. h_ret=%lx",
@@ -439,7 +444,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
                return -EPERM;
        }
 
-       ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10, 0);
+       ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void *)(-1), 10, 0);
        if (IS_ERR(ibcq)) {
                ehca_err(&shca->ib_device, "Cannot create AQP1 CQ.");
                return PTR_ERR(ibcq);
@@ -666,7 +671,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
        }
 
        /* create internal protection domain */
-       ibpd = ehca_alloc_pd(&shca->ib_device, (void*)(-1), NULL);
+       ibpd = ehca_alloc_pd(&shca->ib_device, (void *)(-1), NULL);
        if (IS_ERR(ibpd)) {
                ehca_err(&shca->ib_device, "Cannot create internal PD.");
                ret = PTR_ERR(ibpd);
@@ -863,18 +868,21 @@ int __init ehca_module_init(void)
        printk(KERN_INFO "eHCA Infiniband Device Driver "
               "(Rel.: SVNEHCA_0023)\n");
 
-       if ((ret = ehca_create_comp_pool())) {
+       ret = ehca_create_comp_pool();
+       if (ret) {
                ehca_gen_err("Cannot create comp pool.");
                return ret;
        }
 
-       if ((ret = ehca_create_slab_caches())) {
+       ret = ehca_create_slab_caches();
+       if (ret) {
                ehca_gen_err("Cannot create SLAB caches");
                ret = -ENOMEM;
                goto module_init1;
        }
 
-       if ((ret = ibmebus_register_driver(&ehca_driver))) {
+       ret = ibmebus_register_driver(&ehca_driver);
+       if (ret) {
                ehca_gen_err("Cannot register eHCA device driver");
                ret = -EINVAL;
                goto module_init2;
index add79bd44e398b0ef82fa7f193f27470ccf92714..6262c5462d5054afa89d7497c4aea4159eed9f45 100644 (file)
 #include "hcp_if.h"
 #include "hipz_hw.h"
 
+#define NUM_CHUNKS(length, chunk_size) \
+       (((length) + (chunk_size - 1)) / (chunk_size))
+/* max number of rpages (per hcall register_rpages) */
+#define MAX_RPAGES 512
+
 static struct kmem_cache *mr_cache;
 static struct kmem_cache *mw_cache;
 
@@ -56,9 +61,9 @@ static struct ehca_mr *ehca_mr_new(void)
        struct ehca_mr *me;
 
        me = kmem_cache_zalloc(mr_cache, GFP_KERNEL);
-       if (me) {
+       if (me)
                spin_lock_init(&me->mrlock);
-       else
+       else
                ehca_gen_err("alloc failed");
 
        return me;
@@ -74,9 +79,9 @@ static struct ehca_mw *ehca_mw_new(void)
        struct ehca_mw *me;
 
        me = kmem_cache_zalloc(mw_cache, GFP_KERNEL);
-       if (me) {
+       if (me)
                spin_lock_init(&me->mwlock);
-       else
+       else
                ehca_gen_err("alloc failed");
 
        return me;
@@ -106,11 +111,12 @@ struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
                        goto get_dma_mr_exit0;
                }
 
-               ret = ehca_reg_maxmr(shca, e_maxmr, (u64*)KERNELBASE,
+               ret = ehca_reg_maxmr(shca, e_maxmr, (u64 *)KERNELBASE,
                                     mr_access_flags, e_pd,
                                     &e_maxmr->ib.ib_mr.lkey,
                                     &e_maxmr->ib.ib_mr.rkey);
                if (ret) {
+                       ehca_mr_delete(e_maxmr);
                        ib_mr = ERR_PTR(ret);
                        goto get_dma_mr_exit0;
                }
@@ -144,9 +150,6 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
        struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
 
        u64 size;
-       struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
-       u32 num_pages_mr;
-       u32 num_pages_4k; /* 4k portion "pages" */
 
        if ((num_phys_buf <= 0) || !phys_buf_array) {
                ehca_err(pd->device, "bad input values: num_phys_buf=%x "
@@ -190,12 +193,6 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
                goto reg_phys_mr_exit0;
        }
 
-       /* determine number of MR pages */
-       num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size +
-                        PAGE_SIZE - 1) / PAGE_SIZE);
-       num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size +
-                        EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
-
        /* register MR on HCA */
        if (ehca_mr_is_maxmr(size, iova_start)) {
                e_mr->flags |= EHCA_MR_FLAG_MAXMR;
@@ -207,13 +204,22 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
                        goto reg_phys_mr_exit1;
                }
        } else {
-               pginfo.type           = EHCA_MR_PGI_PHYS;
-               pginfo.num_pages      = num_pages_mr;
-               pginfo.num_4k         = num_pages_4k;
-               pginfo.num_phys_buf   = num_phys_buf;
-               pginfo.phys_buf_array = phys_buf_array;
-               pginfo.next_4k        = (((u64)iova_start & ~PAGE_MASK) /
-                                        EHCA_PAGESIZE);
+               struct ehca_mr_pginfo pginfo;
+               u32 num_kpages;
+               u32 num_hwpages;
+
+               num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size,
+                                       PAGE_SIZE);
+               num_hwpages = NUM_CHUNKS(((u64)iova_start % EHCA_PAGESIZE) +
+                                        size, EHCA_PAGESIZE);
+               memset(&pginfo, 0, sizeof(pginfo));
+               pginfo.type = EHCA_MR_PGI_PHYS;
+               pginfo.num_kpages = num_kpages;
+               pginfo.num_hwpages = num_hwpages;
+               pginfo.u.phy.num_phys_buf = num_phys_buf;
+               pginfo.u.phy.phys_buf_array = phys_buf_array;
+               pginfo.next_hwpage = (((u64)iova_start & ~PAGE_MASK) /
+                                     EHCA_PAGESIZE);
 
                ret = ehca_reg_mr(shca, e_mr, iova_start, size, mr_access_flags,
                                  e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
@@ -240,18 +246,19 @@ reg_phys_mr_exit0:
 
 /*----------------------------------------------------------------------*/
 
-struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt,
-                              int mr_access_flags, struct ib_udata *udata)
+struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+                              u64 virt, int mr_access_flags,
+                              struct ib_udata *udata)
 {
        struct ib_mr *ib_mr;
        struct ehca_mr *e_mr;
        struct ehca_shca *shca =
                container_of(pd->device, struct ehca_shca, ib_device);
        struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
-       struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+       struct ehca_mr_pginfo pginfo;
        int ret;
-       u32 num_pages_mr;
-       u32 num_pages_4k; /* 4k portion "pages" */
+       u32 num_kpages;
+       u32 num_hwpages;
 
        if (!pd) {
                ehca_gen_err("bad pd=%p", pd);
@@ -289,7 +296,7 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt
        e_mr->umem = ib_umem_get(pd->uobject->context, start, length,
                                 mr_access_flags);
        if (IS_ERR(e_mr->umem)) {
-               ib_mr = (void *) e_mr->umem;
+               ib_mr = (void *)e_mr->umem;
                goto reg_user_mr_exit1;
        }
 
@@ -301,23 +308,24 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt
        }
 
        /* determine number of MR pages */
-       num_pages_mr = (((virt % PAGE_SIZE) + length + PAGE_SIZE - 1) /
-                       PAGE_SIZE);
-       num_pages_4k = (((virt % EHCA_PAGESIZE) + length + EHCA_PAGESIZE - 1) /
-                       EHCA_PAGESIZE);
+       num_kpages = NUM_CHUNKS((virt % PAGE_SIZE) + length, PAGE_SIZE);
+       num_hwpages = NUM_CHUNKS((virt % EHCA_PAGESIZE) + length,
+                                EHCA_PAGESIZE);
 
        /* register MR on HCA */
-       pginfo.type       = EHCA_MR_PGI_USER;
-       pginfo.num_pages  = num_pages_mr;
-       pginfo.num_4k     = num_pages_4k;
-       pginfo.region     = e_mr->umem;
-       pginfo.next_4k    = e_mr->umem->offset / EHCA_PAGESIZE;
-       pginfo.next_chunk = list_prepare_entry(pginfo.next_chunk,
-                                              (&e_mr->umem->chunk_list),
-                                              list);
-
-       ret = ehca_reg_mr(shca, e_mr, (u64*) virt, length, mr_access_flags, e_pd,
-                         &pginfo, &e_mr->ib.ib_mr.lkey, &e_mr->ib.ib_mr.rkey);
+       memset(&pginfo, 0, sizeof(pginfo));
+       pginfo.type = EHCA_MR_PGI_USER;
+       pginfo.num_kpages = num_kpages;
+       pginfo.num_hwpages = num_hwpages;
+       pginfo.u.usr.region = e_mr->umem;
+       pginfo.next_hwpage = e_mr->umem->offset / EHCA_PAGESIZE;
+       pginfo.u.usr.next_chunk = list_prepare_entry(pginfo.u.usr.next_chunk,
+                                                    (&e_mr->umem->chunk_list),
+                                                    list);
+
+       ret = ehca_reg_mr(shca, e_mr, (u64 *)virt, length, mr_access_flags,
+                         e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
+                         &e_mr->ib.ib_mr.rkey);
        if (ret) {
                ib_mr = ERR_PTR(ret);
                goto reg_user_mr_exit2;
@@ -360,9 +368,9 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
        struct ehca_pd *new_pd;
        u32 tmp_lkey, tmp_rkey;
        unsigned long sl_flags;
-       u32 num_pages_mr = 0;
-       u32 num_pages_4k = 0; /* 4k portion "pages" */
-       struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+       u32 num_kpages = 0;
+       u32 num_hwpages = 0;
+       struct ehca_mr_pginfo pginfo;
        u32 cur_pid = current->tgid;
 
        if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
@@ -414,7 +422,7 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
                        goto rereg_phys_mr_exit0;
                }
                if (!phys_buf_array || num_phys_buf <= 0) {
-                       ehca_err(mr->device, "bad input values: mr_rereg_mask=%x"
+                       ehca_err(mr->device, "bad input values mr_rereg_mask=%x"
                                 " phys_buf_array=%p num_phys_buf=%x",
                                 mr_rereg_mask, phys_buf_array, num_phys_buf);
                        ret = -EINVAL;
@@ -438,10 +446,10 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
 
        /* set requested values dependent on rereg request */
        spin_lock_irqsave(&e_mr->mrlock, sl_flags);
-       new_start = e_mr->start;  /* new == old address */
-       new_size  = e_mr->size;   /* new == old length */
-       new_acl   = e_mr->acl;    /* new == old access control */
-       new_pd    = container_of(mr->pd,struct ehca_pd,ib_pd); /*new == old PD*/
+       new_start = e_mr->start;
+       new_size = e_mr->size;
+       new_acl = e_mr->acl;
+       new_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
 
        if (mr_rereg_mask & IB_MR_REREG_TRANS) {
                new_start = iova_start; /* change address */
@@ -458,17 +466,18 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
                        ret = -EINVAL;
                        goto rereg_phys_mr_exit1;
                }
-               num_pages_mr = ((((u64)new_start % PAGE_SIZE) + new_size +
-                                PAGE_SIZE - 1) / PAGE_SIZE);
-               num_pages_4k = ((((u64)new_start % EHCA_PAGESIZE) + new_size +
-                                EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
-               pginfo.type           = EHCA_MR_PGI_PHYS;
-               pginfo.num_pages      = num_pages_mr;
-               pginfo.num_4k         = num_pages_4k;
-               pginfo.num_phys_buf   = num_phys_buf;
-               pginfo.phys_buf_array = phys_buf_array;
-               pginfo.next_4k        = (((u64)iova_start & ~PAGE_MASK) /
-                                        EHCA_PAGESIZE);
+               num_kpages = NUM_CHUNKS(((u64)new_start % PAGE_SIZE) +
+                                       new_size, PAGE_SIZE);
+               num_hwpages = NUM_CHUNKS(((u64)new_start % EHCA_PAGESIZE) +
+                                        new_size, EHCA_PAGESIZE);
+               memset(&pginfo, 0, sizeof(pginfo));
+               pginfo.type = EHCA_MR_PGI_PHYS;
+               pginfo.num_kpages = num_kpages;
+               pginfo.num_hwpages = num_hwpages;
+               pginfo.u.phy.num_phys_buf = num_phys_buf;
+               pginfo.u.phy.phys_buf_array = phys_buf_array;
+               pginfo.next_hwpage = (((u64)iova_start & ~PAGE_MASK) /
+                                     EHCA_PAGESIZE);
        }
        if (mr_rereg_mask & IB_MR_REREG_ACCESS)
                new_acl = mr_access_flags;
@@ -510,7 +519,7 @@ int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
        struct ehca_pd *my_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
        u32 cur_pid = current->tgid;
        unsigned long sl_flags;
-       struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+       struct ehca_mr_hipzout_parms hipzout;
 
        if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
            (my_pd->ownpid != cur_pid)) {
@@ -536,14 +545,14 @@ int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
                         "hca_hndl=%lx mr_hndl=%lx lkey=%x",
                         h_ret, mr, shca->ipz_hca_handle.handle,
                         e_mr->ipz_mr_handle.handle, mr->lkey);
-               ret = ehca_mrmw_map_hrc_query_mr(h_ret);
+               ret = ehca2ib_return_code(h_ret);
                goto query_mr_exit1;
        }
-       mr_attr->pd               = mr->pd;
+       mr_attr->pd = mr->pd;
        mr_attr->device_virt_addr = hipzout.vaddr;
-       mr_attr->size             = hipzout.len;
-       mr_attr->lkey             = hipzout.lkey;
-       mr_attr->rkey             = hipzout.rkey;
+       mr_attr->size = hipzout.len;
+       mr_attr->lkey = hipzout.lkey;
+       mr_attr->rkey = hipzout.rkey;
        ehca_mrmw_reverse_map_acl(&hipzout.acl, &mr_attr->mr_access_flags);
 
 query_mr_exit1:
@@ -596,7 +605,7 @@ int ehca_dereg_mr(struct ib_mr *mr)
                         "e_mr=%p hca_hndl=%lx mr_hndl=%lx mr->lkey=%x",
                         h_ret, shca, e_mr, shca->ipz_hca_handle.handle,
                         e_mr->ipz_mr_handle.handle, mr->lkey);
-               ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+               ret = ehca2ib_return_code(h_ret);
                goto dereg_mr_exit0;
        }
 
@@ -622,7 +631,7 @@ struct ib_mw *ehca_alloc_mw(struct ib_pd *pd)
        struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
        struct ehca_shca *shca =
                container_of(pd->device, struct ehca_shca, ib_device);
-       struct ehca_mw_hipzout_parms hipzout = {{0},0};
+       struct ehca_mw_hipzout_parms hipzout;
 
        e_mw = ehca_mw_new();
        if (!e_mw) {
@@ -636,7 +645,7 @@ struct ib_mw *ehca_alloc_mw(struct ib_pd *pd)
                ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%lx "
                         "shca=%p hca_hndl=%lx mw=%p",
                         h_ret, shca, shca->ipz_hca_handle.handle, e_mw);
-               ib_mw = ERR_PTR(ehca_mrmw_map_hrc_alloc(h_ret));
+               ib_mw = ERR_PTR(ehca2ib_return_code(h_ret));
                goto alloc_mw_exit1;
        }
        /* successful MW allocation */
@@ -679,7 +688,7 @@ int ehca_dealloc_mw(struct ib_mw *mw)
                         "mw=%p rkey=%x hca_hndl=%lx mw_hndl=%lx",
                         h_ret, shca, mw, mw->rkey, shca->ipz_hca_handle.handle,
                         e_mw->ipz_mw_handle.handle);
-               return ehca_mrmw_map_hrc_free_mw(h_ret);
+               return ehca2ib_return_code(h_ret);
        }
        /* successful deallocation */
        ehca_mw_delete(e_mw);
@@ -699,7 +708,7 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
        struct ehca_mr *e_fmr;
        int ret;
        u32 tmp_lkey, tmp_rkey;
-       struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+       struct ehca_mr_pginfo pginfo;
 
        /* check other parameters */
        if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
@@ -745,6 +754,7 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
        e_fmr->flags |= EHCA_MR_FLAG_FMR;
 
        /* register MR on HCA */
+       memset(&pginfo, 0, sizeof(pginfo));
        ret = ehca_reg_mr(shca, e_fmr, NULL,
                          fmr_attr->max_pages * (1 << fmr_attr->page_shift),
                          mr_access_flags, e_pd, &pginfo,
@@ -783,7 +793,7 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr,
                container_of(fmr->device, struct ehca_shca, ib_device);
        struct ehca_mr *e_fmr = container_of(fmr, struct ehca_mr, ib.ib_fmr);
        struct ehca_pd *e_pd = container_of(fmr->pd, struct ehca_pd, ib_pd);
-       struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+       struct ehca_mr_pginfo pginfo;
        u32 tmp_lkey, tmp_rkey;
 
        if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) {
@@ -809,14 +819,16 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr,
                          fmr, e_fmr->fmr_map_cnt, e_fmr->fmr_max_maps);
        }
 
-       pginfo.type      = EHCA_MR_PGI_FMR;
-       pginfo.num_pages = list_len;
-       pginfo.num_4k    = list_len * (e_fmr->fmr_page_size / EHCA_PAGESIZE);
-       pginfo.page_list = page_list;
-       pginfo.next_4k   = ((iova & (e_fmr->fmr_page_size-1)) /
-                           EHCA_PAGESIZE);
+       memset(&pginfo, 0, sizeof(pginfo));
+       pginfo.type = EHCA_MR_PGI_FMR;
+       pginfo.num_kpages = list_len;
+       pginfo.num_hwpages = list_len * (e_fmr->fmr_page_size / EHCA_PAGESIZE);
+       pginfo.u.fmr.page_list = page_list;
+       pginfo.next_hwpage = ((iova & (e_fmr->fmr_page_size-1)) /
+                             EHCA_PAGESIZE);
+       pginfo.u.fmr.fmr_pgsize = e_fmr->fmr_page_size;
 
-       ret = ehca_rereg_mr(shca, e_fmr, (u64*)iova,
+       ret = ehca_rereg_mr(shca, e_fmr, (u64 *)iova,
                            list_len * e_fmr->fmr_page_size,
                            e_fmr->acl, e_pd, &pginfo, &tmp_lkey, &tmp_rkey);
        if (ret)
@@ -831,8 +843,7 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr,
 map_phys_fmr_exit0:
        if (ret)
                ehca_err(fmr->device, "ret=%x fmr=%p page_list=%p list_len=%x "
-                        "iova=%lx",
-                        ret, fmr, page_list, list_len, iova);
+                        "iova=%lx", ret, fmr, page_list, list_len, iova);
        return ret;
 } /* end ehca_map_phys_fmr() */
 
@@ -922,7 +933,7 @@ int ehca_dealloc_fmr(struct ib_fmr *fmr)
                         "hca_hndl=%lx fmr_hndl=%lx fmr->lkey=%x",
                         h_ret, e_fmr, shca->ipz_hca_handle.handle,
                         e_fmr->ipz_mr_handle.handle, fmr->lkey);
-               ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+               ret = ehca2ib_return_code(h_ret);
                goto free_fmr_exit0;
        }
        /* successful deregistration */
@@ -950,12 +961,12 @@ int ehca_reg_mr(struct ehca_shca *shca,
        int ret;
        u64 h_ret;
        u32 hipz_acl;
-       struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+       struct ehca_mr_hipzout_parms hipzout;
 
        ehca_mrmw_map_acl(acl, &hipz_acl);
        ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
        if (ehca_use_hp_mr == 1)
-               hipz_acl |= 0x00000001;
+               hipz_acl |= 0x00000001;
 
        h_ret = hipz_h_alloc_resource_mr(shca->ipz_hca_handle, e_mr,
                                         (u64)iova_start, size, hipz_acl,
@@ -963,7 +974,7 @@ int ehca_reg_mr(struct ehca_shca *shca,
        if (h_ret != H_SUCCESS) {
                ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%lx "
                         "hca_hndl=%lx", h_ret, shca->ipz_hca_handle.handle);
-               ret = ehca_mrmw_map_hrc_alloc(h_ret);
+               ret = ehca2ib_return_code(h_ret);
                goto ehca_reg_mr_exit0;
        }
 
@@ -974,11 +985,11 @@ int ehca_reg_mr(struct ehca_shca *shca,
                goto ehca_reg_mr_exit1;
 
        /* successful registration */
-       e_mr->num_pages = pginfo->num_pages;
-       e_mr->num_4k    = pginfo->num_4k;
-       e_mr->start     = iova_start;
-       e_mr->size      = size;
-       e_mr->acl       = acl;
+       e_mr->num_kpages = pginfo->num_kpages;
+       e_mr->num_hwpages = pginfo->num_hwpages;
+       e_mr->start = iova_start;
+       e_mr->size = size;
+       e_mr->acl = acl;
        *lkey = hipzout.lkey;
        *rkey = hipzout.rkey;
        return 0;
@@ -988,10 +999,10 @@ ehca_reg_mr_exit1:
        if (h_ret != H_SUCCESS) {
                ehca_err(&shca->ib_device, "h_ret=%lx shca=%p e_mr=%p "
                         "iova_start=%p size=%lx acl=%x e_pd=%p lkey=%x "
-                        "pginfo=%p num_pages=%lx num_4k=%lx ret=%x",
+                        "pginfo=%p num_kpages=%lx num_hwpages=%lx ret=%x",
                         h_ret, shca, e_mr, iova_start, size, acl, e_pd,
-                        hipzout.lkey, pginfo, pginfo->num_pages,
-                        pginfo->num_4k, ret);
+                        hipzout.lkey, pginfo, pginfo->num_kpages,
+                        pginfo->num_hwpages, ret);
                ehca_err(&shca->ib_device, "internal error in ehca_reg_mr, "
                         "not recoverable");
        }
@@ -999,9 +1010,9 @@ ehca_reg_mr_exit0:
        if (ret)
                ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p "
                         "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
-                        "num_pages=%lx num_4k=%lx",
+                        "num_kpages=%lx num_hwpages=%lx",
                         ret, shca, e_mr, iova_start, size, acl, e_pd, pginfo,
-                        pginfo->num_pages, pginfo->num_4k);
+                        pginfo->num_kpages, pginfo->num_hwpages);
        return ret;
 } /* end ehca_reg_mr() */
 
@@ -1026,24 +1037,24 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
        }
 
        /* max 512 pages per shot */
-       for (i = 0; i < ((pginfo->num_4k + 512 - 1) / 512); i++) {
+       for (i = 0; i < NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES); i++) {
 
-               if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) {
-                       rnum = pginfo->num_4k % 512; /* last shot */
+               if (i == NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES) - 1) {
+                       rnum = pginfo->num_hwpages % MAX_RPAGES; /* last shot */
                        if (rnum == 0)
-                               rnum = 512;      /* last shot is full */
+                               rnum = MAX_RPAGES;      /* last shot is full */
                } else
-                       rnum = 512;
+                       rnum = MAX_RPAGES;
 
-               if (rnum > 1) {
-                       ret = ehca_set_pagebuf(e_mr, pginfo, rnum, kpage);
-                       if (ret) {
-                               ehca_err(&shca->ib_device, "ehca_set_pagebuf "
+               ret = ehca_set_pagebuf(pginfo, rnum, kpage);
+               if (ret) {
+                       ehca_err(&shca->ib_device, "ehca_set_pagebuf "
                                         "bad rc, ret=%x rnum=%x kpage=%p",
                                         ret, rnum, kpage);
-                               ret = -EFAULT;
-                               goto ehca_reg_mr_rpages_exit1;
-                       }
+                       goto ehca_reg_mr_rpages_exit1;
+               }
+
+               if (rnum > 1) {
                        rpage = virt_to_abs(kpage);
                        if (!rpage) {
                                ehca_err(&shca->ib_device, "kpage=%p i=%x",
@@ -1051,21 +1062,14 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
                                ret = -EFAULT;
                                goto ehca_reg_mr_rpages_exit1;
                        }
-               } else {  /* rnum==1 */
-                       ret = ehca_set_pagebuf_1(e_mr, pginfo, &rpage);
-                       if (ret) {
-                               ehca_err(&shca->ib_device, "ehca_set_pagebuf_1 "
-                                        "bad rc, ret=%x i=%x", ret, i);
-                               ret = -EFAULT;
-                               goto ehca_reg_mr_rpages_exit1;
-                       }
-               }
+               } else
+                       rpage = *kpage;
 
                h_ret = hipz_h_register_rpage_mr(shca->ipz_hca_handle, e_mr,
                                                 0, /* pagesize 4k */
                                                 0, rpage, rnum);
 
-               if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) {
+               if (i == NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES) - 1) {
                        /*
                         * check for 'registration complete'==H_SUCCESS
                         * and for 'page registered'==H_PAGE_REGISTERED
@@ -1078,7 +1082,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
                                         shca->ipz_hca_handle.handle,
                                         e_mr->ipz_mr_handle.handle,
                                         e_mr->ib.ib_mr.lkey);
-                               ret = ehca_mrmw_map_hrc_rrpg_last(h_ret);
+                               ret = ehca2ib_return_code(h_ret);
                                break;
                        } else
                                ret = 0;
@@ -1089,7 +1093,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
                                 e_mr->ib.ib_mr.lkey,
                                 shca->ipz_hca_handle.handle,
                                 e_mr->ipz_mr_handle.handle);
-                       ret = ehca_mrmw_map_hrc_rrpg_notlast(h_ret);
+                       ret = ehca2ib_return_code(h_ret);
                        break;
                } else
                        ret = 0;
@@ -1101,8 +1105,8 @@ ehca_reg_mr_rpages_exit1:
 ehca_reg_mr_rpages_exit0:
        if (ret)
                ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p pginfo=%p "
-                        "num_pages=%lx num_4k=%lx", ret, shca, e_mr, pginfo,
-                        pginfo->num_pages, pginfo->num_4k);
+                        "num_kpages=%lx num_hwpages=%lx", ret, shca, e_mr,
+                        pginfo, pginfo->num_kpages, pginfo->num_hwpages);
        return ret;
 } /* end ehca_reg_mr_rpages() */
 
@@ -1124,7 +1128,7 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
        u64 *kpage;
        u64 rpage;
        struct ehca_mr_pginfo pginfo_save;
-       struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+       struct ehca_mr_hipzout_parms hipzout;
 
        ehca_mrmw_map_acl(acl, &hipz_acl);
        ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
@@ -1137,12 +1141,12 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
        }
 
        pginfo_save = *pginfo;
-       ret = ehca_set_pagebuf(e_mr, pginfo, pginfo->num_4k, kpage);
+       ret = ehca_set_pagebuf(pginfo, pginfo->num_hwpages, kpage);
        if (ret) {
                ehca_err(&shca->ib_device, "set pagebuf failed, e_mr=%p "
-                        "pginfo=%p type=%x num_pages=%lx num_4k=%lx kpage=%p",
-                        e_mr, pginfo, pginfo->type, pginfo->num_pages,
-                        pginfo->num_4k,kpage);
+                        "pginfo=%p type=%x num_kpages=%lx num_hwpages=%lx "
+                        "kpage=%p", e_mr, pginfo, pginfo->type,
+                        pginfo->num_kpages, pginfo->num_hwpages, kpage);
                goto ehca_rereg_mr_rereg1_exit1;
        }
        rpage = virt_to_abs(kpage);
@@ -1164,7 +1168,7 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
                          "(Rereg1), h_ret=%lx e_mr=%p", h_ret, e_mr);
                *pginfo = pginfo_save;
                ret = -EAGAIN;
-       } else if ((u64*)hipzout.vaddr != iova_start) {
+       } else if ((u64 *)hipzout.vaddr != iova_start) {
                ehca_err(&shca->ib_device, "PHYP changed iova_start in "
                         "rereg_pmr, iova_start=%p iova_start_out=%lx e_mr=%p "
                         "mr_handle=%lx lkey=%x lkey_out=%x", iova_start,
@@ -1176,11 +1180,11 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
                 * successful reregistration
                 * note: start and start_out are identical for eServer HCAs
                 */
-               e_mr->num_pages = pginfo->num_pages;
-               e_mr->num_4k    = pginfo->num_4k;
-               e_mr->start     = iova_start;
-               e_mr->size      = size;
-               e_mr->acl       = acl;
+               e_mr->num_kpages = pginfo->num_kpages;
+               e_mr->num_hwpages = pginfo->num_hwpages;
+               e_mr->start = iova_start;
+               e_mr->size = size;
+               e_mr->acl = acl;
                *lkey = hipzout.lkey;
                *rkey = hipzout.rkey;
        }
@@ -1190,9 +1194,9 @@ ehca_rereg_mr_rereg1_exit1:
 ehca_rereg_mr_rereg1_exit0:
        if ( ret && (ret != -EAGAIN) )
                ehca_err(&shca->ib_device, "ret=%x lkey=%x rkey=%x "
-                        "pginfo=%p num_pages=%lx num_4k=%lx",
-                        ret, *lkey, *rkey, pginfo, pginfo->num_pages,
-                        pginfo->num_4k);
+                        "pginfo=%p num_kpages=%lx num_hwpages=%lx",
+                        ret, *lkey, *rkey, pginfo, pginfo->num_kpages,
+                        pginfo->num_hwpages);
        return ret;
 } /* end ehca_rereg_mr_rereg1() */
 
@@ -1214,10 +1218,12 @@ int ehca_rereg_mr(struct ehca_shca *shca,
        int rereg_3_hcall = 0; /* 1: use 3 hipz calls for reregistration */
 
        /* first determine reregistration hCall(s) */
-       if ((pginfo->num_4k > 512) || (e_mr->num_4k > 512) ||
-           (pginfo->num_4k > e_mr->num_4k)) {
-               ehca_dbg(&shca->ib_device, "Rereg3 case, pginfo->num_4k=%lx "
-                        "e_mr->num_4k=%x", pginfo->num_4k, e_mr->num_4k);
+       if ((pginfo->num_hwpages > MAX_RPAGES) ||
+           (e_mr->num_hwpages > MAX_RPAGES) ||
+           (pginfo->num_hwpages > e_mr->num_hwpages)) {
+               ehca_dbg(&shca->ib_device, "Rereg3 case, "
+                        "pginfo->num_hwpages=%lx e_mr->num_hwpages=%x",
+                        pginfo->num_hwpages, e_mr->num_hwpages);
                rereg_1_hcall = 0;
                rereg_3_hcall = 1;
        }
@@ -1253,7 +1259,7 @@ int ehca_rereg_mr(struct ehca_shca *shca,
                                 h_ret, e_mr, shca->ipz_hca_handle.handle,
                                 e_mr->ipz_mr_handle.handle,
                                 e_mr->ib.ib_mr.lkey);
-                       ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+                       ret = ehca2ib_return_code(h_ret);
                        goto ehca_rereg_mr_exit0;
                }
                /* clean ehca_mr_t, without changing struct ib_mr and lock */
@@ -1281,9 +1287,9 @@ ehca_rereg_mr_exit0:
        if (ret)
                ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p "
                         "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
-                        "num_pages=%lx lkey=%x rkey=%x rereg_1_hcall=%x "
+                        "num_kpages=%lx lkey=%x rkey=%x rereg_1_hcall=%x "
                         "rereg_3_hcall=%x", ret, shca, e_mr, iova_start, size,
-                        acl, e_pd, pginfo, pginfo->num_pages, *lkey, *rkey,
+                        acl, e_pd, pginfo, pginfo->num_kpages, *lkey, *rkey,
                         rereg_1_hcall, rereg_3_hcall);
        return ret;
 } /* end ehca_rereg_mr() */
@@ -1295,97 +1301,86 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca,
 {
        int ret = 0;
        u64 h_ret;
-       int rereg_1_hcall = 1; /* 1: use hipz_mr_reregister directly */
-       int rereg_3_hcall = 0; /* 1: use 3 hipz calls for unmapping */
        struct ehca_pd *e_pd =
                container_of(e_fmr->ib.ib_fmr.pd, struct ehca_pd, ib_pd);
        struct ehca_mr save_fmr;
        u32 tmp_lkey, tmp_rkey;
-       struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
-       struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+       struct ehca_mr_pginfo pginfo;
+       struct ehca_mr_hipzout_parms hipzout;
+       struct ehca_mr save_mr;
 
-       /* first check if reregistration hCall can be used for unmap */
-       if (e_fmr->fmr_max_pages > 512) {
-               rereg_1_hcall = 0;
-               rereg_3_hcall = 1;
-       }
-
-       if (rereg_1_hcall) {
+       if (e_fmr->fmr_max_pages <= MAX_RPAGES) {
                /*
                 * note: after using rereg hcall with len=0,
                 * rereg hcall must be used again for registering pages
                 */
                h_ret = hipz_h_reregister_pmr(shca->ipz_hca_handle, e_fmr, 0,
                                              0, 0, e_pd->fw_pd, 0, &hipzout);
-               if (h_ret != H_SUCCESS) {
-                       /*
-                        * should not happen, because length checked above,
-                        * FMRs are not shared and no MW bound to FMRs
-                        */
-                       ehca_err(&shca->ib_device, "hipz_reregister_pmr failed "
-                                "(Rereg1), h_ret=%lx e_fmr=%p hca_hndl=%lx "
-                                "mr_hndl=%lx lkey=%x lkey_out=%x",
-                                h_ret, e_fmr, shca->ipz_hca_handle.handle,
-                                e_fmr->ipz_mr_handle.handle,
-                                e_fmr->ib.ib_fmr.lkey, hipzout.lkey);
-                       rereg_3_hcall = 1;
-               } else {
+               if (h_ret == H_SUCCESS) {
                        /* successful reregistration */
                        e_fmr->start = NULL;
                        e_fmr->size = 0;
                        tmp_lkey = hipzout.lkey;
                        tmp_rkey = hipzout.rkey;
+                       return 0;
                }
+               /*
+                * should not happen, because length checked above,
+                * FMRs are not shared and no MW bound to FMRs
+                */
+               ehca_err(&shca->ib_device, "hipz_reregister_pmr failed "
+                        "(Rereg1), h_ret=%lx e_fmr=%p hca_hndl=%lx "
+                        "mr_hndl=%lx lkey=%x lkey_out=%x",
+                        h_ret, e_fmr, shca->ipz_hca_handle.handle,
+                        e_fmr->ipz_mr_handle.handle,
+                        e_fmr->ib.ib_fmr.lkey, hipzout.lkey);
+               /* try free and rereg */
        }
 
-       if (rereg_3_hcall) {
-               struct ehca_mr save_mr;
-
-               /* first free old FMR */
-               h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
-               if (h_ret != H_SUCCESS) {
-                       ehca_err(&shca->ib_device, "hipz_free_mr failed, "
-                                "h_ret=%lx e_fmr=%p hca_hndl=%lx mr_hndl=%lx "
-                                "lkey=%x",
-                                h_ret, e_fmr, shca->ipz_hca_handle.handle,
-                                e_fmr->ipz_mr_handle.handle,
-                                e_fmr->ib.ib_fmr.lkey);
-                       ret = ehca_mrmw_map_hrc_free_mr(h_ret);
-                       goto ehca_unmap_one_fmr_exit0;
-               }
-               /* clean ehca_mr_t, without changing lock */
-               save_fmr = *e_fmr;
-               ehca_mr_deletenew(e_fmr);
-
-               /* set some MR values */
-               e_fmr->flags = save_fmr.flags;
-               e_fmr->fmr_page_size = save_fmr.fmr_page_size;
-               e_fmr->fmr_max_pages = save_fmr.fmr_max_pages;
-               e_fmr->fmr_max_maps = save_fmr.fmr_max_maps;
-               e_fmr->fmr_map_cnt = save_fmr.fmr_map_cnt;
-               e_fmr->acl = save_fmr.acl;
-
-               pginfo.type      = EHCA_MR_PGI_FMR;
-               pginfo.num_pages = 0;
-               pginfo.num_4k    = 0;
-               ret = ehca_reg_mr(shca, e_fmr, NULL,
-                                 (e_fmr->fmr_max_pages * e_fmr->fmr_page_size),
-                                 e_fmr->acl, e_pd, &pginfo, &tmp_lkey,
-                                 &tmp_rkey);
-               if (ret) {
-                       u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr;
-                       memcpy(&e_fmr->flags, &(save_mr.flags),
-                              sizeof(struct ehca_mr) - offset);
-                       goto ehca_unmap_one_fmr_exit0;
-               }
+       /* first free old FMR */
+       h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
+       if (h_ret != H_SUCCESS) {
+               ehca_err(&shca->ib_device, "hipz_free_mr failed, "
+                        "h_ret=%lx e_fmr=%p hca_hndl=%lx mr_hndl=%lx "
+                        "lkey=%x",
+                        h_ret, e_fmr, shca->ipz_hca_handle.handle,
+                        e_fmr->ipz_mr_handle.handle,
+                        e_fmr->ib.ib_fmr.lkey);
+               ret = ehca2ib_return_code(h_ret);
+               goto ehca_unmap_one_fmr_exit0;
+       }
+       /* clean ehca_mr_t, without changing lock */
+       save_fmr = *e_fmr;
+       ehca_mr_deletenew(e_fmr);
+
+       /* set some MR values */
+       e_fmr->flags = save_fmr.flags;
+       e_fmr->fmr_page_size = save_fmr.fmr_page_size;
+       e_fmr->fmr_max_pages = save_fmr.fmr_max_pages;
+       e_fmr->fmr_max_maps = save_fmr.fmr_max_maps;
+       e_fmr->fmr_map_cnt = save_fmr.fmr_map_cnt;
+       e_fmr->acl = save_fmr.acl;
+
+       memset(&pginfo, 0, sizeof(pginfo));
+       pginfo.type = EHCA_MR_PGI_FMR;
+       pginfo.num_kpages = 0;
+       pginfo.num_hwpages = 0;
+       ret = ehca_reg_mr(shca, e_fmr, NULL,
+                         (e_fmr->fmr_max_pages * e_fmr->fmr_page_size),
+                         e_fmr->acl, e_pd, &pginfo, &tmp_lkey,
+                         &tmp_rkey);
+       if (ret) {
+               u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr;
+               memcpy(&e_fmr->flags, &(save_mr.flags),
+                      sizeof(struct ehca_mr) - offset);
+               goto ehca_unmap_one_fmr_exit0;
        }
 
 ehca_unmap_one_fmr_exit0:
        if (ret)
                ehca_err(&shca->ib_device, "ret=%x tmp_lkey=%x tmp_rkey=%x "
-                        "fmr_max_pages=%x rereg_1_hcall=%x rereg_3_hcall=%x",
-                        ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages,
-                        rereg_1_hcall, rereg_3_hcall);
+                        "fmr_max_pages=%x",
+                        ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages);
        return ret;
 } /* end ehca_unmap_one_fmr() */
 
@@ -1403,7 +1398,7 @@ int ehca_reg_smr(struct ehca_shca *shca,
        int ret = 0;
        u64 h_ret;
        u32 hipz_acl;
-       struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+       struct ehca_mr_hipzout_parms hipzout;
 
        ehca_mrmw_map_acl(acl, &hipz_acl);
        ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
@@ -1419,15 +1414,15 @@ int ehca_reg_smr(struct ehca_shca *shca,
                         shca->ipz_hca_handle.handle,
                         e_origmr->ipz_mr_handle.handle,
                         e_origmr->ib.ib_mr.lkey);
-               ret = ehca_mrmw_map_hrc_reg_smr(h_ret);
+               ret = ehca2ib_return_code(h_ret);
                goto ehca_reg_smr_exit0;
        }
        /* successful registration */
-       e_newmr->num_pages     = e_origmr->num_pages;
-       e_newmr->num_4k        = e_origmr->num_4k;
-       e_newmr->start         = iova_start;
-       e_newmr->size          = e_origmr->size;
-       e_newmr->acl           = acl;
+       e_newmr->num_kpages = e_origmr->num_kpages;
+       e_newmr->num_hwpages = e_origmr->num_hwpages;
+       e_newmr->start = iova_start;
+       e_newmr->size = e_origmr->size;
+       e_newmr->acl = acl;
        e_newmr->ipz_mr_handle = hipzout.handle;
        *lkey = hipzout.lkey;
        *rkey = hipzout.rkey;
@@ -1453,10 +1448,10 @@ int ehca_reg_internal_maxmr(
        struct ehca_mr *e_mr;
        u64 *iova_start;
        u64 size_maxmr;
-       struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+       struct ehca_mr_pginfo pginfo;
        struct ib_phys_buf ib_pbuf;
-       u32 num_pages_mr;
-       u32 num_pages_4k; /* 4k portion "pages" */
+       u32 num_kpages;
+       u32 num_hwpages;
 
        e_mr = ehca_mr_new();
        if (!e_mr) {
@@ -1468,28 +1463,29 @@ int ehca_reg_internal_maxmr(
 
        /* register internal max-MR on HCA */
        size_maxmr = (u64)high_memory - PAGE_OFFSET;
-       iova_start = (u64*)KERNELBASE;
+       iova_start = (u64 *)KERNELBASE;
        ib_pbuf.addr = 0;
        ib_pbuf.size = size_maxmr;
-       num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size_maxmr +
-                        PAGE_SIZE - 1) / PAGE_SIZE);
-       num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size_maxmr +
-                        EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
-
-       pginfo.type           = EHCA_MR_PGI_PHYS;
-       pginfo.num_pages      = num_pages_mr;
-       pginfo.num_4k         = num_pages_4k;
-       pginfo.num_phys_buf   = 1;
-       pginfo.phys_buf_array = &ib_pbuf;
+       num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size_maxmr,
+                               PAGE_SIZE);
+       num_hwpages = NUM_CHUNKS(((u64)iova_start % EHCA_PAGESIZE) + size_maxmr,
+                                EHCA_PAGESIZE);
+
+       memset(&pginfo, 0, sizeof(pginfo));
+       pginfo.type = EHCA_MR_PGI_PHYS;
+       pginfo.num_kpages = num_kpages;
+       pginfo.num_hwpages = num_hwpages;
+       pginfo.u.phy.num_phys_buf = 1;
+       pginfo.u.phy.phys_buf_array = &ib_pbuf;
 
        ret = ehca_reg_mr(shca, e_mr, iova_start, size_maxmr, 0, e_pd,
                          &pginfo, &e_mr->ib.ib_mr.lkey,
                          &e_mr->ib.ib_mr.rkey);
        if (ret) {
                ehca_err(&shca->ib_device, "reg of internal max MR failed, "
-                        "e_mr=%p iova_start=%p size_maxmr=%lx num_pages_mr=%x "
-                        "num_pages_4k=%x", e_mr, iova_start, size_maxmr,
-                        num_pages_mr, num_pages_4k);
+                        "e_mr=%p iova_start=%p size_maxmr=%lx num_kpages=%x "
+                        "num_hwpages=%x", e_mr, iova_start, size_maxmr,
+                        num_kpages, num_hwpages);
                goto ehca_reg_internal_maxmr_exit1;
        }
 
@@ -1524,7 +1520,7 @@ int ehca_reg_maxmr(struct ehca_shca *shca,
        u64 h_ret;
        struct ehca_mr *e_origmr = shca->maxmr;
        u32 hipz_acl;
-       struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+       struct ehca_mr_hipzout_parms hipzout;
 
        ehca_mrmw_map_acl(acl, &hipz_acl);
        ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
@@ -1538,14 +1534,14 @@ int ehca_reg_maxmr(struct ehca_shca *shca,
                         h_ret, e_origmr, shca->ipz_hca_handle.handle,
                         e_origmr->ipz_mr_handle.handle,
                         e_origmr->ib.ib_mr.lkey);
-               return ehca_mrmw_map_hrc_reg_smr(h_ret);
+               return ehca2ib_return_code(h_ret);
        }
        /* successful registration */
-       e_newmr->num_pages     = e_origmr->num_pages;
-       e_newmr->num_4k        = e_origmr->num_4k;
-       e_newmr->start         = iova_start;
-       e_newmr->size          = e_origmr->size;
-       e_newmr->acl           = acl;
+       e_newmr->num_kpages = e_origmr->num_kpages;
+       e_newmr->num_hwpages = e_origmr->num_hwpages;
+       e_newmr->start = iova_start;
+       e_newmr->size = e_origmr->size;
+       e_newmr->acl = acl;
        e_newmr->ipz_mr_handle = hipzout.handle;
        *lkey = hipzout.lkey;
        *rkey = hipzout.rkey;
@@ -1677,299 +1673,187 @@ int ehca_fmr_check_page_list(struct ehca_mr *e_fmr,
 
 /*----------------------------------------------------------------------*/
 
-/* setup page buffer from page info */
-int ehca_set_pagebuf(struct ehca_mr *e_mr,
-                    struct ehca_mr_pginfo *pginfo,
-                    u32 number,
-                    u64 *kpage)
+/* PAGE_SIZE >= pginfo->hwpage_size */
+static int ehca_set_pagebuf_user1(struct ehca_mr_pginfo *pginfo,
+                                 u32 number,
+                                 u64 *kpage)
 {
        int ret = 0;
        struct ib_umem_chunk *prev_chunk;
        struct ib_umem_chunk *chunk;
-       struct ib_phys_buf *pbuf;
-       u64 *fmrlist;
-       u64 num4k, pgaddr, offs4k;
+       u64 pgaddr;
        u32 i = 0;
        u32 j = 0;
 
-       if (pginfo->type == EHCA_MR_PGI_PHYS) {
-               /* loop over desired phys_buf_array entries */
-               while (i < number) {
-                       pbuf   = pginfo->phys_buf_array + pginfo->next_buf;
-                       num4k  = ((pbuf->addr % EHCA_PAGESIZE) + pbuf->size +
-                                 EHCA_PAGESIZE - 1) / EHCA_PAGESIZE;
-                       offs4k = (pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
-                       while (pginfo->next_4k < offs4k + num4k) {
-                               /* sanity check */
-                               if ((pginfo->page_cnt >= pginfo->num_pages) ||
-                                   (pginfo->page_4k_cnt >= pginfo->num_4k)) {
-                                       ehca_gen_err("page_cnt >= num_pages, "
-                                                    "page_cnt=%lx "
-                                                    "num_pages=%lx "
-                                                    "page_4k_cnt=%lx "
-                                                    "num_4k=%lx i=%x",
-                                                    pginfo->page_cnt,
-                                                    pginfo->num_pages,
-                                                    pginfo->page_4k_cnt,
-                                                    pginfo->num_4k, i);
-                                       ret = -EFAULT;
-                                       goto ehca_set_pagebuf_exit0;
-                               }
-                               *kpage = phys_to_abs(
-                                       (pbuf->addr & EHCA_PAGEMASK)
-                                       + (pginfo->next_4k * EHCA_PAGESIZE));
-                               if ( !(*kpage) && pbuf->addr ) {
-                                       ehca_gen_err("pbuf->addr=%lx "
-                                                    "pbuf->size=%lx "
-                                                    "next_4k=%lx", pbuf->addr,
-                                                    pbuf->size,
-                                                    pginfo->next_4k);
-                                       ret = -EFAULT;
-                                       goto ehca_set_pagebuf_exit0;
-                               }
-                               (pginfo->page_4k_cnt)++;
-                               (pginfo->next_4k)++;
-                               if (pginfo->next_4k %
-                                   (PAGE_SIZE / EHCA_PAGESIZE) == 0)
-                                       (pginfo->page_cnt)++;
-                               kpage++;
-                               i++;
-                               if (i >= number) break;
-                       }
-                       if (pginfo->next_4k >= offs4k + num4k) {
-                               (pginfo->next_buf)++;
-                               pginfo->next_4k = 0;
-                       }
-               }
-       } else if (pginfo->type == EHCA_MR_PGI_USER) {
-               /* loop over desired chunk entries */
-               chunk      = pginfo->next_chunk;
-               prev_chunk = pginfo->next_chunk;
-               list_for_each_entry_continue(chunk,
-                                            (&(pginfo->region->chunk_list)),
-                                            list) {
-                       for (i = pginfo->next_nmap; i < chunk->nmap; ) {
-                               pgaddr = ( page_to_pfn(chunk->page_list[i].page)
-                                          << PAGE_SHIFT );
-                               *kpage = phys_to_abs(pgaddr +
-                                                    (pginfo->next_4k *
-                                                     EHCA_PAGESIZE));
-                               if ( !(*kpage) ) {
-                                       ehca_gen_err("pgaddr=%lx "
-                                                    "chunk->page_list[i]=%lx "
-                                                    "i=%x next_4k=%lx mr=%p",
-                                                    pgaddr,
-                                                    (u64)sg_dma_address(
-                                                            &chunk->
-                                                            page_list[i]),
-                                                    i, pginfo->next_4k, e_mr);
-                                       ret = -EFAULT;
-                                       goto ehca_set_pagebuf_exit0;
-                               }
-                               (pginfo->page_4k_cnt)++;
-                               (pginfo->next_4k)++;
-                               kpage++;
-                               if (pginfo->next_4k %
-                                   (PAGE_SIZE / EHCA_PAGESIZE) == 0) {
-                                       (pginfo->page_cnt)++;
-                                       (pginfo->next_nmap)++;
-                                       pginfo->next_4k = 0;
-                                       i++;
-                               }
-                               j++;
-                               if (j >= number) break;
-                       }
-                       if ((pginfo->next_nmap >= chunk->nmap) &&
-                           (j >= number)) {
-                               pginfo->next_nmap = 0;
-                               prev_chunk = chunk;
-                               break;
-                       } else if (pginfo->next_nmap >= chunk->nmap) {
-                               pginfo->next_nmap = 0;
-                               prev_chunk = chunk;
-                       } else if (j >= number)
-                               break;
-                       else
-                               prev_chunk = chunk;
-               }
-               pginfo->next_chunk =
-                       list_prepare_entry(prev_chunk,
-                                          (&(pginfo->region->chunk_list)),
-                                          list);
-       } else if (pginfo->type == EHCA_MR_PGI_FMR) {
-               /* loop over desired page_list entries */
-               fmrlist = pginfo->page_list + pginfo->next_listelem;
-               for (i = 0; i < number; i++) {
-                       *kpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) +
-                                            pginfo->next_4k * EHCA_PAGESIZE);
+       /* loop over desired chunk entries */
+       chunk      = pginfo->u.usr.next_chunk;
+       prev_chunk = pginfo->u.usr.next_chunk;
+       list_for_each_entry_continue(
+               chunk, (&(pginfo->u.usr.region->chunk_list)), list) {
+               for (i = pginfo->u.usr.next_nmap; i < chunk->nmap; ) {
+                       pgaddr = page_to_pfn(chunk->page_list[i].page)
+                               << PAGE_SHIFT ;
+                       *kpage = phys_to_abs(pgaddr +
+                                            (pginfo->next_hwpage *
+                                             EHCA_PAGESIZE));
                        if ( !(*kpage) ) {
-                               ehca_gen_err("*fmrlist=%lx fmrlist=%p "
-                                            "next_listelem=%lx next_4k=%lx",
-                                            *fmrlist, fmrlist,
-                                            pginfo->next_listelem,
-                                            pginfo->next_4k);
-                               ret = -EFAULT;
-                               goto ehca_set_pagebuf_exit0;
+                               ehca_gen_err("pgaddr=%lx "
+                                            "chunk->page_list[i]=%lx "
+                                            "i=%x next_hwpage=%lx",
+                                            pgaddr, (u64)sg_dma_address(
+                                                    &chunk->page_list[i]),
+                                            i, pginfo->next_hwpage);
+                               return -EFAULT;
                        }
-                       (pginfo->page_4k_cnt)++;
-                       (pginfo->next_4k)++;
+                       (pginfo->hwpage_cnt)++;
+                       (pginfo->next_hwpage)++;
                        kpage++;
-                       if (pginfo->next_4k %
-                           (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) {
-                               (pginfo->page_cnt)++;
-                               (pginfo->next_listelem)++;
-                               fmrlist++;
-                               pginfo->next_4k = 0;
+                       if (pginfo->next_hwpage %
+                           (PAGE_SIZE / EHCA_PAGESIZE) == 0) {
+                               (pginfo->kpage_cnt)++;
+                               (pginfo->u.usr.next_nmap)++;
+                               pginfo->next_hwpage = 0;
+                               i++;
                        }
+                       j++;
+                       if (j >= number) break;
                }
-       } else {
-               ehca_gen_err("bad pginfo->type=%x", pginfo->type);
-               ret = -EFAULT;
-               goto ehca_set_pagebuf_exit0;
+               if ((pginfo->u.usr.next_nmap >= chunk->nmap) &&
+                   (j >= number)) {
+                       pginfo->u.usr.next_nmap = 0;
+                       prev_chunk = chunk;
+                       break;
+               } else if (pginfo->u.usr.next_nmap >= chunk->nmap) {
+                       pginfo->u.usr.next_nmap = 0;
+                       prev_chunk = chunk;
+               } else if (j >= number)
+                       break;
+               else
+                       prev_chunk = chunk;
        }
-
-ehca_set_pagebuf_exit0:
-       if (ret)
-               ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
-                            "num_4k=%lx next_buf=%lx next_4k=%lx number=%x "
-                            "kpage=%p page_cnt=%lx page_4k_cnt=%lx i=%x "
-                            "next_listelem=%lx region=%p next_chunk=%p "
-                            "next_nmap=%lx", ret, e_mr, pginfo, pginfo->type,
-                            pginfo->num_pages, pginfo->num_4k,
-                            pginfo->next_buf, pginfo->next_4k, number, kpage,
-                            pginfo->page_cnt, pginfo->page_4k_cnt, i,
-                            pginfo->next_listelem, pginfo->region,
-                            pginfo->next_chunk, pginfo->next_nmap);
+       pginfo->u.usr.next_chunk =
+               list_prepare_entry(prev_chunk,
+                                  (&(pginfo->u.usr.region->chunk_list)),
+                                  list);
        return ret;
-} /* end ehca_set_pagebuf() */
-
-/*----------------------------------------------------------------------*/
+}
 
-/* setup 1 page from page info page buffer */
-int ehca_set_pagebuf_1(struct ehca_mr *e_mr,
-                      struct ehca_mr_pginfo *pginfo,
-                      u64 *rpage)
+int ehca_set_pagebuf_phys(struct ehca_mr_pginfo *pginfo,
+                         u32 number,
+                         u64 *kpage)
 {
        int ret = 0;
-       struct ib_phys_buf *tmp_pbuf;
-       u64 *fmrlist;
-       struct ib_umem_chunk *chunk;
-       struct ib_umem_chunk *prev_chunk;
-       u64 pgaddr, num4k, offs4k;
-
-       if (pginfo->type == EHCA_MR_PGI_PHYS) {
-               /* sanity check */
-               if ((pginfo->page_cnt >= pginfo->num_pages) ||
-                   (pginfo->page_4k_cnt >= pginfo->num_4k)) {
-                       ehca_gen_err("page_cnt >= num_pages, page_cnt=%lx "
-                                    "num_pages=%lx page_4k_cnt=%lx num_4k=%lx",
-                                    pginfo->page_cnt, pginfo->num_pages,
-                                    pginfo->page_4k_cnt, pginfo->num_4k);
-                       ret = -EFAULT;
-                       goto ehca_set_pagebuf_1_exit0;
-               }
-               tmp_pbuf = pginfo->phys_buf_array + pginfo->next_buf;
-               num4k  = ((tmp_pbuf->addr % EHCA_PAGESIZE) + tmp_pbuf->size +
-                         EHCA_PAGESIZE - 1) / EHCA_PAGESIZE;
-               offs4k = (tmp_pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
-               *rpage = phys_to_abs((tmp_pbuf->addr & EHCA_PAGEMASK) +
-                                    (pginfo->next_4k * EHCA_PAGESIZE));
-               if ( !(*rpage) && tmp_pbuf->addr ) {
-                       ehca_gen_err("tmp_pbuf->addr=%lx"
-                                    " tmp_pbuf->size=%lx next_4k=%lx",
-                                    tmp_pbuf->addr, tmp_pbuf->size,
-                                    pginfo->next_4k);
-                       ret = -EFAULT;
-                       goto ehca_set_pagebuf_1_exit0;
-               }
-               (pginfo->page_4k_cnt)++;
-               (pginfo->next_4k)++;
-               if (pginfo->next_4k % (PAGE_SIZE / EHCA_PAGESIZE) == 0)
-                       (pginfo->page_cnt)++;
-               if (pginfo->next_4k >= offs4k + num4k) {
-                       (pginfo->next_buf)++;
-                       pginfo->next_4k = 0;
-               }
-       } else if (pginfo->type == EHCA_MR_PGI_USER) {
-               chunk      = pginfo->next_chunk;
-               prev_chunk = pginfo->next_chunk;
-               list_for_each_entry_continue(chunk,
-                                            (&(pginfo->region->chunk_list)),
-                                            list) {
-                       pgaddr = ( page_to_pfn(chunk->page_list[
-                                                      pginfo->next_nmap].page)
-                                  << PAGE_SHIFT);
-                       *rpage = phys_to_abs(pgaddr +
-                                            (pginfo->next_4k * EHCA_PAGESIZE));
-                       if ( !(*rpage) ) {
-                               ehca_gen_err("pgaddr=%lx chunk->page_list[]=%lx"
-                                            " next_nmap=%lx next_4k=%lx mr=%p",
-                                            pgaddr, (u64)sg_dma_address(
-                                                    &chunk->page_list[
-                                                            pginfo->
-                                                            next_nmap]),
-                                            pginfo->next_nmap, pginfo->next_4k,
-                                            e_mr);
-                               ret = -EFAULT;
-                               goto ehca_set_pagebuf_1_exit0;
-                       }
-                       (pginfo->page_4k_cnt)++;
-                       (pginfo->next_4k)++;
-                       if (pginfo->next_4k %
-                           (PAGE_SIZE / EHCA_PAGESIZE) == 0) {
-                               (pginfo->page_cnt)++;
-                               (pginfo->next_nmap)++;
-                               pginfo->next_4k = 0;
+       struct ib_phys_buf *pbuf;
+       u64 num_hw, offs_hw;
+       u32 i = 0;
+
+       /* loop over desired phys_buf_array entries */
+       while (i < number) {
+               pbuf   = pginfo->u.phy.phys_buf_array + pginfo->u.phy.next_buf;
+               num_hw  = NUM_CHUNKS((pbuf->addr % EHCA_PAGESIZE) +
+                                    pbuf->size, EHCA_PAGESIZE);
+               offs_hw = (pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
+               while (pginfo->next_hwpage < offs_hw + num_hw) {
+                       /* sanity check */
+                       if ((pginfo->kpage_cnt >= pginfo->num_kpages) ||
+                           (pginfo->hwpage_cnt >= pginfo->num_hwpages)) {
+                               ehca_gen_err("kpage_cnt >= num_kpages, "
+                                            "kpage_cnt=%lx num_kpages=%lx "
+                                            "hwpage_cnt=%lx "
+                                            "num_hwpages=%lx i=%x",
+                                            pginfo->kpage_cnt,
+                                            pginfo->num_kpages,
+                                            pginfo->hwpage_cnt,
+                                            pginfo->num_hwpages, i);
+                               return -EFAULT;
                        }
-                       if (pginfo->next_nmap >= chunk->nmap) {
-                               pginfo->next_nmap = 0;
-                               prev_chunk = chunk;
+                       *kpage = phys_to_abs(
+                               (pbuf->addr & EHCA_PAGEMASK)
+                               + (pginfo->next_hwpage * EHCA_PAGESIZE));
+                       if ( !(*kpage) && pbuf->addr ) {
+                               ehca_gen_err("pbuf->addr=%lx "
+                                            "pbuf->size=%lx "
+                                            "next_hwpage=%lx", pbuf->addr,
+                                            pbuf->size,
+                                            pginfo->next_hwpage);
+                               return -EFAULT;
                        }
-                       break;
+                       (pginfo->hwpage_cnt)++;
+                       (pginfo->next_hwpage)++;
+                       if (pginfo->next_hwpage %
+                           (PAGE_SIZE / EHCA_PAGESIZE) == 0)
+                               (pginfo->kpage_cnt)++;
+                       kpage++;
+                       i++;
+                       if (i >= number) break;
+               }
+               if (pginfo->next_hwpage >= offs_hw + num_hw) {
+                       (pginfo->u.phy.next_buf)++;
+                       pginfo->next_hwpage = 0;
                }
-               pginfo->next_chunk =
-                       list_prepare_entry(prev_chunk,
-                                          (&(pginfo->region->chunk_list)),
-                                          list);
-       } else if (pginfo->type == EHCA_MR_PGI_FMR) {
-               fmrlist = pginfo->page_list + pginfo->next_listelem;
-               *rpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) +
-                                    pginfo->next_4k * EHCA_PAGESIZE);
-               if ( !(*rpage) ) {
+       }
+       return ret;
+}
+
+int ehca_set_pagebuf_fmr(struct ehca_mr_pginfo *pginfo,
+                        u32 number,
+                        u64 *kpage)
+{
+       int ret = 0;
+       u64 *fmrlist;
+       u32 i;
+
+       /* loop over desired page_list entries */
+       fmrlist = pginfo->u.fmr.page_list + pginfo->u.fmr.next_listelem;
+       for (i = 0; i < number; i++) {
+               *kpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) +
+                                    pginfo->next_hwpage * EHCA_PAGESIZE);
+               if ( !(*kpage) ) {
                        ehca_gen_err("*fmrlist=%lx fmrlist=%p "
-                                    "next_listelem=%lx next_4k=%lx",
-                                    *fmrlist, fmrlist, pginfo->next_listelem,
-                                    pginfo->next_4k);
-                       ret = -EFAULT;
-                       goto ehca_set_pagebuf_1_exit0;
+                                    "next_listelem=%lx next_hwpage=%lx",
+                                    *fmrlist, fmrlist,
+                                    pginfo->u.fmr.next_listelem,
+                                    pginfo->next_hwpage);
+                       return -EFAULT;
                }
-               (pginfo->page_4k_cnt)++;
-               (pginfo->next_4k)++;
-               if (pginfo->next_4k %
-                   (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) {
-                       (pginfo->page_cnt)++;
-                       (pginfo->next_listelem)++;
-                       pginfo->next_4k = 0;
+               (pginfo->hwpage_cnt)++;
+               (pginfo->next_hwpage)++;
+               kpage++;
+               if (pginfo->next_hwpage %
+                   (pginfo->u.fmr.fmr_pgsize / EHCA_PAGESIZE) == 0) {
+                       (pginfo->kpage_cnt)++;
+                       (pginfo->u.fmr.next_listelem)++;
+                       fmrlist++;
+                       pginfo->next_hwpage = 0;
                }
-       } else {
+       }
+       return ret;
+}
+
+/* setup page buffer from page info */
+int ehca_set_pagebuf(struct ehca_mr_pginfo *pginfo,
+                    u32 number,
+                    u64 *kpage)
+{
+       int ret;
+
+       switch (pginfo->type) {
+       case EHCA_MR_PGI_PHYS:
+               ret = ehca_set_pagebuf_phys(pginfo, number, kpage);
+               break;
+       case EHCA_MR_PGI_USER:
+               ret = ehca_set_pagebuf_user1(pginfo, number, kpage);
+               break;
+       case EHCA_MR_PGI_FMR:
+               ret = ehca_set_pagebuf_fmr(pginfo, number, kpage);
+               break;
+       default:
                ehca_gen_err("bad pginfo->type=%x", pginfo->type);
                ret = -EFAULT;
-               goto ehca_set_pagebuf_1_exit0;
+               break;
        }
-
-ehca_set_pagebuf_1_exit0:
-       if (ret)
-               ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
-                            "num_4k=%lx next_buf=%lx next_4k=%lx rpage=%p "
-                            "page_cnt=%lx page_4k_cnt=%lx next_listelem=%lx "
-                            "region=%p next_chunk=%p next_nmap=%lx", ret, e_mr,
-                            pginfo, pginfo->type, pginfo->num_pages,
-                            pginfo->num_4k, pginfo->next_buf, pginfo->next_4k,
-                            rpage, pginfo->page_cnt, pginfo->page_4k_cnt,
-                            pginfo->next_listelem, pginfo->region,
-                            pginfo->next_chunk, pginfo->next_nmap);
        return ret;
-} /* end ehca_set_pagebuf_1() */
+} /* end ehca_set_pagebuf() */
 
 /*----------------------------------------------------------------------*/
 
@@ -1982,7 +1866,7 @@ int ehca_mr_is_maxmr(u64 size,
 {
        /* a MR is treated as max-MR only if it fits following: */
        if ((size == ((u64)high_memory - PAGE_OFFSET)) &&
-           (iova_start == (void*)KERNELBASE)) {
+           (iova_start == (void *)KERNELBASE)) {
                ehca_gen_dbg("this is a max-MR");
                return 1;
        } else
@@ -2039,177 +1923,6 @@ void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
 } /* end ehca_mrmw_reverse_map_acl() */
 
 
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for MR/MW allocations
- * Used for hipz_mr_reg_alloc and hipz_mw_alloc.
- */
-int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc)
-{
-       switch (hipz_rc) {
-       case H_SUCCESS:              /* successful completion */
-               return 0;
-       case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
-       case H_CONSTRAINED:          /* resource constraint */
-       case H_NO_MEM:
-               return -ENOMEM;
-       case H_BUSY:                 /* long busy */
-               return -EBUSY;
-       default:
-               return -EINVAL;
-       }
-} /* end ehca_mrmw_map_hrc_alloc() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for MR register rpage
- * Used for hipz_h_register_rpage_mr at registering last page
- */
-int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc)
-{
-       switch (hipz_rc) {
-       case H_SUCCESS:         /* registration complete */
-               return 0;
-       case H_PAGE_REGISTERED: /* page registered */
-       case H_ADAPTER_PARM:    /* invalid adapter handle */
-       case H_RH_PARM:         /* invalid resource handle */
-/*     case H_QT_PARM:            invalid queue type */
-       case H_PARAMETER:       /*
-                                * invalid logical address,
-                                * or count zero or greater 512
-                                */
-       case H_TABLE_FULL:      /* page table full */
-       case H_HARDWARE:        /* HCA not operational */
-               return -EINVAL;
-       case H_BUSY:            /* long busy */
-               return -EBUSY;
-       default:
-               return -EINVAL;
-       }
-} /* end ehca_mrmw_map_hrc_rrpg_last() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for MR register rpage
- * Used for hipz_h_register_rpage_mr at registering one page, but not last page
- */
-int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc)
-{
-       switch (hipz_rc) {
-       case H_PAGE_REGISTERED: /* page registered */
-               return 0;
-       case H_SUCCESS:         /* registration complete */
-       case H_ADAPTER_PARM:    /* invalid adapter handle */
-       case H_RH_PARM:         /* invalid resource handle */
-/*     case H_QT_PARM:            invalid queue type */
-       case H_PARAMETER:       /*
-                                * invalid logical address,
-                                * or count zero or greater 512
-                                */
-       case H_TABLE_FULL:      /* page table full */
-       case H_HARDWARE:        /* HCA not operational */
-               return -EINVAL;
-       case H_BUSY:            /* long busy */
-               return -EBUSY;
-       default:
-               return -EINVAL;
-       }
-} /* end ehca_mrmw_map_hrc_rrpg_notlast() */
-
-/*----------------------------------------------------------------------*/
-
-/* map HIPZ rc to IB retcodes for MR query. Used for hipz_mr_query. */
-int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc)
-{
-       switch (hipz_rc) {
-       case H_SUCCESS:              /* successful completion */
-               return 0;
-       case H_ADAPTER_PARM:         /* invalid adapter handle */
-       case H_RH_PARM:              /* invalid resource handle */
-               return -EINVAL;
-       case H_BUSY:                 /* long busy */
-               return -EBUSY;
-       default:
-               return -EINVAL;
-       }
-} /* end ehca_mrmw_map_hrc_query_mr() */
-
-/*----------------------------------------------------------------------*/
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for freeing MR resource
- * Used for hipz_h_free_resource_mr
- */
-int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc)
-{
-       switch (hipz_rc) {
-       case H_SUCCESS:      /* resource freed */
-               return 0;
-       case H_ADAPTER_PARM: /* invalid adapter handle */
-       case H_RH_PARM:      /* invalid resource handle */
-       case H_R_STATE:      /* invalid resource state */
-       case H_HARDWARE:     /* HCA not operational */
-               return -EINVAL;
-       case H_RESOURCE:     /* Resource in use */
-       case H_BUSY:         /* long busy */
-               return -EBUSY;
-       default:
-               return -EINVAL;
-       }
-} /* end ehca_mrmw_map_hrc_free_mr() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for freeing MW resource
- * Used for hipz_h_free_resource_mw
- */
-int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc)
-{
-       switch (hipz_rc) {
-       case H_SUCCESS:      /* resource freed */
-               return 0;
-       case H_ADAPTER_PARM: /* invalid adapter handle */
-       case H_RH_PARM:      /* invalid resource handle */
-       case H_R_STATE:      /* invalid resource state */
-       case H_HARDWARE:     /* HCA not operational */
-               return -EINVAL;
-       case H_RESOURCE:     /* Resource in use */
-       case H_BUSY:         /* long busy */
-               return -EBUSY;
-       default:
-               return -EINVAL;
-       }
-} /* end ehca_mrmw_map_hrc_free_mw() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for SMR registrations
- * Used for hipz_h_register_smr.
- */
-int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc)
-{
-       switch (hipz_rc) {
-       case H_SUCCESS:              /* successful completion */
-               return 0;
-       case H_ADAPTER_PARM:         /* invalid adapter handle */
-       case H_RH_PARM:              /* invalid resource handle */
-       case H_MEM_PARM:             /* invalid MR virtual address */
-       case H_MEM_ACCESS_PARM:      /* invalid access controls */
-       case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
-               return -EINVAL;
-       case H_BUSY:                 /* long busy */
-               return -EBUSY;
-       default:
-               return -EINVAL;
-       }
-} /* end ehca_mrmw_map_hrc_reg_smr() */
-
 /*----------------------------------------------------------------------*/
 
 /*
@@ -2219,19 +1932,17 @@ int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc)
  */
 void ehca_mr_deletenew(struct ehca_mr *mr)
 {
-       mr->flags         = 0;
-       mr->num_pages     = 0;
-       mr->num_4k        = 0;
-       mr->acl           = 0;
-       mr->start         = NULL;
+       mr->flags = 0;
+       mr->num_kpages = 0;
+       mr->num_hwpages = 0;
+       mr->acl = 0;
+       mr->start = NULL;
        mr->fmr_page_size = 0;
        mr->fmr_max_pages = 0;
-       mr->fmr_max_maps  = 0;
-       mr->fmr_map_cnt   = 0;
+       mr->fmr_max_maps = 0;
+       mr->fmr_map_cnt = 0;
        memset(&mr->ipz_mr_handle, 0, sizeof(mr->ipz_mr_handle));
        memset(&mr->galpas, 0, sizeof(mr->galpas));
-       mr->nr_of_pages   = 0;
-       mr->pagearray     = NULL;
 } /* end ehca_mr_deletenew() */
 
 int ehca_init_mrmw_cache(void)
index d936e40a5748484f38cc1f77cc57ca101c8918fb..24f13fe3708bf4910f202b2ff93a47fc19222a17 100644 (file)
@@ -101,15 +101,10 @@ int ehca_fmr_check_page_list(struct ehca_mr *e_fmr,
                             u64 *page_list,
                             int list_len);
 
-int ehca_set_pagebuf(struct ehca_mr *e_mr,
-                    struct ehca_mr_pginfo *pginfo,
+int ehca_set_pagebuf(struct ehca_mr_pginfo *pginfo,
                     u32 number,
                     u64 *kpage);
 
-int ehca_set_pagebuf_1(struct ehca_mr *e_mr,
-                      struct ehca_mr_pginfo *pginfo,
-                      u64 *rpage);
-
 int ehca_mr_is_maxmr(u64 size,
                     u64 *iova_start);
 
@@ -121,20 +116,6 @@ void ehca_mrmw_set_pgsize_hipz_acl(u32 *hipz_acl);
 void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
                               int *ib_acl);
 
-int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc);
-
 void ehca_mr_deletenew(struct ehca_mr *mr);
 
 #endif  /*_EHCA_MRMW_H_*/
index 8707d297ce4c60a1747424068599e220d194b10d..818803057ebf0bc37b8ef9a45bb49c79aad01122 100644 (file)
@@ -53,13 +53,13 @@ struct ehca_vsgentry {
        u32 length;
 };
 
-#define GRH_FLAG_MASK        EHCA_BMASK_IBM(7,7)
-#define GRH_IPVERSION_MASK   EHCA_BMASK_IBM(0,3)
-#define GRH_TCLASS_MASK      EHCA_BMASK_IBM(4,12)
-#define GRH_FLOWLABEL_MASK   EHCA_BMASK_IBM(13,31)
-#define GRH_PAYLEN_MASK      EHCA_BMASK_IBM(32,47)
-#define GRH_NEXTHEADER_MASK  EHCA_BMASK_IBM(48,55)
-#define GRH_HOPLIMIT_MASK    EHCA_BMASK_IBM(56,63)
+#define GRH_FLAG_MASK        EHCA_BMASK_IBM( 7,  7)
+#define GRH_IPVERSION_MASK   EHCA_BMASK_IBM( 0,  3)
+#define GRH_TCLASS_MASK      EHCA_BMASK_IBM( 4, 12)
+#define GRH_FLOWLABEL_MASK   EHCA_BMASK_IBM(13, 31)
+#define GRH_PAYLEN_MASK      EHCA_BMASK_IBM(32, 47)
+#define GRH_NEXTHEADER_MASK  EHCA_BMASK_IBM(48, 55)
+#define GRH_HOPLIMIT_MASK    EHCA_BMASK_IBM(56, 63)
 
 /*
  * Unreliable Datagram Address Vector Format
@@ -206,10 +206,10 @@ struct ehca_wqe {
 
 };
 
-#define WC_SEND_RECEIVE EHCA_BMASK_IBM(0,0)
-#define WC_IMM_DATA     EHCA_BMASK_IBM(1,1)
-#define WC_GRH_PRESENT  EHCA_BMASK_IBM(2,2)
-#define WC_SE_BIT       EHCA_BMASK_IBM(3,3)
+#define WC_SEND_RECEIVE EHCA_BMASK_IBM(0, 0)
+#define WC_IMM_DATA     EHCA_BMASK_IBM(1, 1)
+#define WC_GRH_PRESENT  EHCA_BMASK_IBM(2, 2)
+#define WC_SE_BIT       EHCA_BMASK_IBM(3, 3)
 #define WC_STATUS_ERROR_BIT 0x80000000
 #define WC_STATUS_REMOTE_ERROR_FLAGS 0x0000F800
 #define WC_STATUS_PURGE_BIT 0x10
index 74671250303f00433247cae49679b89be401a6f8..48e9ceacd6fac10edfbfd396e9d5b52b8d784c2c 100644 (file)
@@ -602,10 +602,10 @@ struct ehca_qp *internal_create_qp(struct ib_pd *pd,
                        /* UD circumvention */
                        parms.act_nr_send_sges -= 2;
                        parms.act_nr_recv_sges -= 2;
-                       swqe_size = offsetof(struct ehca_wqe,
-                                            u.ud_av.sg_list[parms.act_nr_send_sges]);
-                       rwqe_size = offsetof(struct ehca_wqe,
-                                            u.ud_av.sg_list[parms.act_nr_recv_sges]);
+                       swqe_size = offsetof(struct ehca_wqe, u.ud_av.sg_list[
+                                                    parms.act_nr_send_sges]);
+                       rwqe_size = offsetof(struct ehca_wqe, u.ud_av.sg_list[
+                                                    parms.act_nr_recv_sges]);
                }
 
                if (IB_QPT_GSI == qp_type || IB_QPT_SMI == qp_type) {
@@ -690,8 +690,8 @@ struct ehca_qp *internal_create_qp(struct ib_pd *pd,
        if (my_qp->send_cq) {
                ret = ehca_cq_assign_qp(my_qp->send_cq, my_qp);
                if (ret) {
-                       ehca_err(pd->device, "Couldn't assign qp to send_cq ret=%x",
-                                ret);
+                       ehca_err(pd->device,
+                                "Couldn't assign qp to send_cq ret=%x", ret);
                        goto create_qp_exit4;
                }
        }
@@ -749,7 +749,7 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
        struct ehca_qp *ret;
 
        ret = internal_create_qp(pd, qp_init_attr, NULL, udata, 0);
-       return IS_ERR(ret) ? (struct ib_qp *) ret : &ret->ib_qp;
+       return IS_ERR(ret) ? (struct ib_qp *)ret : &ret->ib_qp;
 }
 
 int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
@@ -780,7 +780,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
 
        my_qp = internal_create_qp(pd, &qp_init_attr, srq_init_attr, udata, 1);
        if (IS_ERR(my_qp))
-               return (struct ib_srq *) my_qp;
+               return (struct ib_srq *)my_qp;
 
        /* copy back return values */
        srq_init_attr->attr.max_wr = qp_init_attr.cap.max_recv_wr;
@@ -875,7 +875,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
                         my_qp, qp_num, h_ret);
                return ehca2ib_return_code(h_ret);
        }
-       bad_send_wqe_p = (void*)((u64)bad_send_wqe_p & (~(1L<<63)));
+       bad_send_wqe_p = (void *)((u64)bad_send_wqe_p & (~(1L << 63)));
        ehca_dbg(&shca->ib_device, "qp_num=%x bad_send_wqe_p=%p",
                 qp_num, bad_send_wqe_p);
        /* convert wqe pointer to vadr */
@@ -890,7 +890,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
        }
 
        /* loop sets wqe's purge bit */
-       wqe = (struct ehca_wqe*)ipz_qeit_calc(squeue, q_ofs);
+       wqe = (struct ehca_wqe *)ipz_qeit_calc(squeue, q_ofs);
        *bad_wqe_cnt = 0;
        while (wqe->optype != 0xff && wqe->wqef != 0xff) {
                if (ehca_debug_level)
@@ -898,7 +898,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
                wqe->nr_of_data_seg = 0; /* suppress data access */
                wqe->wqef = WQEF_PURGE; /* WQE to be purged */
                q_ofs = ipz_queue_advance_offset(squeue, q_ofs);
-               wqe = (struct ehca_wqe*)ipz_qeit_calc(squeue, q_ofs);
+               wqe = (struct ehca_wqe *)ipz_qeit_calc(squeue, q_ofs);
                *bad_wqe_cnt = (*bad_wqe_cnt)+1;
        }
        /*
@@ -1003,7 +1003,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
                goto modify_qp_exit1;
        }
 
-       ehca_dbg(ibqp->device,"ehca_qp=%p qp_num=%x current qp_state=%x "
+       ehca_dbg(ibqp->device, "ehca_qp=%p qp_num=%x current qp_state=%x "
                 "new qp_state=%x attribute_mask=%x",
                 my_qp, ibqp->qp_num, qp_cur_state, attr->qp_state, attr_mask);
 
@@ -1019,7 +1019,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
                goto modify_qp_exit1;
        }
 
-       if ((mqpcb->qp_state = ib2ehca_qp_state(qp_new_state)))
+       mqpcb->qp_state = ib2ehca_qp_state(qp_new_state);
+       if (mqpcb->qp_state)
                update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_STATE, 1);
        else {
                ret = -EINVAL;
@@ -1077,7 +1078,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
                        spin_lock_irqsave(&my_qp->spinlock_s, flags);
                        squeue_locked = 1;
                        /* mark next free wqe */
-                       wqe = (struct ehca_wqe*)
+                       wqe = (struct ehca_wqe *)
                                ipz_qeit_get(&my_qp->ipz_squeue);
                        wqe->optype = wqe->wqef = 0xff;
                        ehca_dbg(ibqp->device, "qp_num=%x next_free_wqe=%p",
@@ -1312,7 +1313,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
        if (h_ret != H_SUCCESS) {
                ret = ehca2ib_return_code(h_ret);
                ehca_err(ibqp->device, "hipz_h_modify_qp() failed rc=%lx "
-                        "ehca_qp=%p qp_num=%x",h_ret, my_qp, ibqp->qp_num);
+                        "ehca_qp=%p qp_num=%x", h_ret, my_qp, ibqp->qp_num);
                goto modify_qp_exit2;
        }
 
@@ -1411,7 +1412,7 @@ int ehca_query_qp(struct ib_qp *qp,
        }
 
        if (qp_attr_mask & QP_ATTR_QUERY_NOT_SUPPORTED) {
-               ehca_err(qp->device,"Invalid attribute mask "
+               ehca_err(qp->device, "Invalid attribute mask "
                         "ehca_qp=%p qp_num=%x qp_attr_mask=%x ",
                         my_qp, qp->qp_num, qp_attr_mask);
                return -EINVAL;
@@ -1419,7 +1420,7 @@ int ehca_query_qp(struct ib_qp *qp,
 
        qpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
        if (!qpcb) {
-               ehca_err(qp->device,"Out of memory for qpcb "
+               ehca_err(qp->device, "Out of memory for qpcb "
                         "ehca_qp=%p qp_num=%x", my_qp, qp->qp_num);
                return -ENOMEM;
        }
@@ -1431,7 +1432,7 @@ int ehca_query_qp(struct ib_qp *qp,
 
        if (h_ret != H_SUCCESS) {
                ret = ehca2ib_return_code(h_ret);
-               ehca_err(qp->device,"hipz_h_query_qp() failed "
+               ehca_err(qp->device, "hipz_h_query_qp() failed "
                         "ehca_qp=%p qp_num=%x h_ret=%lx",
                         my_qp, qp->qp_num, h_ret);
                goto query_qp_exit1;
@@ -1442,7 +1443,7 @@ int ehca_query_qp(struct ib_qp *qp,
 
        if (qp_attr->cur_qp_state == -EINVAL) {
                ret = -EINVAL;
-               ehca_err(qp->device,"Got invalid ehca_qp_state=%x "
+               ehca_err(qp->device, "Got invalid ehca_qp_state=%x "
                         "ehca_qp=%p qp_num=%x",
                         qpcb->qp_state, my_qp, qp->qp_num);
                goto query_qp_exit1;
index 61da65e6e5e09957868d2097808d77ad809b5baf..94eed70fedf58366adbb02d7d2188cecfe0c83fc 100644 (file)
@@ -79,7 +79,8 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
        }
 
        if (ehca_debug_level) {
-               ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p", ipz_rqueue);
+               ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p",
+                            ipz_rqueue);
                ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
        }
 
@@ -99,7 +100,7 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
                struct ib_mad_hdr *mad_hdr = send_wr->wr.ud.mad_hdr;
                struct ib_sge *sge = send_wr->sg_list;
                ehca_gen_dbg("send_wr#%x wr_id=%lx num_sge=%x "
-                            "send_flags=%x opcode=%x",idx, send_wr->wr_id,
+                            "send_flags=%x opcode=%x", idx, send_wr->wr_id,
                             send_wr->num_sge, send_wr->send_flags,
                             send_wr->opcode);
                if (mad_hdr) {
@@ -116,7 +117,7 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
                                     mad_hdr->attr_mod);
                }
                for (j = 0; j < send_wr->num_sge; j++) {
-                       u8 *data = (u8 *) abs_to_virt(sge->addr);
+                       u8 *data = (u8 *)abs_to_virt(sge->addr);
                        ehca_gen_dbg("send_wr#%x sge#%x addr=%p length=%x "
                                     "lkey=%x",
                                     idx, j, data, sge->length, sge->lkey);
@@ -534,9 +535,11 @@ poll_cq_one_read_cqe:
 
        cqe_count++;
        if (unlikely(cqe->status & WC_STATUS_PURGE_BIT)) {
-               struct ehca_qp *qp=ehca_cq_get_qp(my_cq, cqe->local_qp_number);
+               struct ehca_qp *qp;
                int purgeflag;
                unsigned long flags;
+
+               qp = ehca_cq_get_qp(my_cq, cqe->local_qp_number);
                if (!qp) {
                        ehca_err(cq->device, "cq_num=%x qp_num=%x "
                                 "could not find qp -> ignore cqe",
@@ -551,8 +554,8 @@ poll_cq_one_read_cqe:
                spin_unlock_irqrestore(&qp->spinlock_s, flags);
 
                if (purgeflag) {
-                       ehca_dbg(cq->device, "Got CQE with purged bit qp_num=%x "
-                                "src_qp=%x",
+                       ehca_dbg(cq->device,
+                                "Got CQE with purged bit qp_num=%x src_qp=%x",
                                 cqe->local_qp_number, cqe->remote_qp_number);
                        if (ehca_debug_level)
                                ehca_dmp(cqe, 64, "qp_num=%x src_qp=%x",
index 03b185f873dafb8c8641358efef02f9f1633dd0f..678b813918619b52fa0842b0aff59503af0a7e6f 100644 (file)
@@ -93,14 +93,14 @@ extern int ehca_debug_level;
 #define ehca_gen_dbg(format, arg...) \
        do { \
                if (unlikely(ehca_debug_level)) \
-                       printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n",\
+                       printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n", \
                               get_paca()->paca_index, __FUNCTION__, ## arg); \
        } while (0)
 
 #define ehca_gen_warn(format, arg...) \
        do { \
                if (unlikely(ehca_debug_level)) \
-                       printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n",\
+                       printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n", \
                               get_paca()->paca_index, __FUNCTION__, ## arg); \
        } while (0)
 
@@ -114,12 +114,12 @@ extern int ehca_debug_level;
  * <format string> adr=X ofs=Y <8 bytes hex> <8 bytes hex>
  */
 #define ehca_dmp(adr, len, format, args...) \
-       do {                                   \
-               unsigned int x;                       \
+       do { \
+               unsigned int x; \
                unsigned int l = (unsigned int)(len); \
-               unsigned char *deb = (unsigned char*)(adr);     \
+               unsigned char *deb = (unsigned char *)(adr); \
                for (x = 0; x < l; x += 16) { \
-                       printk("EHCA_DMP:%s " format \
+                       printk(KERN_INFO "EHCA_DMP:%s " format \
                               " adr=%p ofs=%04x %016lx %016lx\n", \
                               __FUNCTION__, ##args, deb, x, \
                               *((u64 *)&deb[0]), *((u64 *)&deb[8])); \
@@ -128,16 +128,16 @@ extern int ehca_debug_level;
        } while (0)
 
 /* define a bitmask, little endian version */
-#define EHCA_BMASK(pos,length) (((pos)<<16)+(length))
+#define EHCA_BMASK(pos, length) (((pos) << 16) + (length))
 
 /* define a bitmask, the ibm way... */
-#define EHCA_BMASK_IBM(from,to) (((63-to)<<16)+((to)-(from)+1))
+#define EHCA_BMASK_IBM(from, to) (((63 - to) << 16) + ((to) - (from) + 1))
 
 /* internal function, don't use */
-#define EHCA_BMASK_SHIFTPOS(mask) (((mask)>>16)&0xffff)
+#define EHCA_BMASK_SHIFTPOS(mask) (((mask) >> 16) & 0xffff)
 
 /* internal function, don't use */
-#define EHCA_BMASK_MASK(mask) (0xffffffffffffffffULL >> ((64-(mask))&0xffff))
+#define EHCA_BMASK_MASK(mask) (~0ULL >> ((64 - (mask)) & 0xffff))
 
 /**
  * EHCA_BMASK_SET - return value shifted and masked by mask
@@ -145,14 +145,14 @@ extern int ehca_debug_level;
  * variable&=~EHCA_BMASK_SET(MY_MASK,-1) clears the bits from the mask
  * in variable
  */
-#define EHCA_BMASK_SET(mask,value) \
-       ((EHCA_BMASK_MASK(mask) & ((u64)(value)))<<EHCA_BMASK_SHIFTPOS(mask))
+#define EHCA_BMASK_SET(mask, value) \
+       ((EHCA_BMASK_MASK(mask) & ((u64)(value))) << EHCA_BMASK_SHIFTPOS(mask))
 
 /**
  * EHCA_BMASK_GET - extract a parameter from value by mask
  */
-#define EHCA_BMASK_GET(mask,value) \
-       (EHCA_BMASK_MASK(mask)& (((u64)(value))>>EHCA_BMASK_SHIFTPOS(mask)))
+#define EHCA_BMASK_GET(mask, value) \
+       (EHCA_BMASK_MASK(mask) & (((u64)(value)) >> EHCA_BMASK_SHIFTPOS(mask)))
 
 
 /* Converts ehca to ib return code */
@@ -161,8 +161,11 @@ static inline int ehca2ib_return_code(u64 ehca_rc)
        switch (ehca_rc) {
        case H_SUCCESS:
                return 0;
+       case H_RESOURCE:             /* Resource in use */
        case H_BUSY:
                return -EBUSY;
+       case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
+       case H_CONSTRAINED:          /* resource constraint */
        case H_NO_MEM:
                return -ENOMEM;
        default:
index 3031b3bb56f9bc6b7ad3eb24d58d2b6d21f138ac..05c415744e3bfabbed45fbdc2b3d7b66f75bd214 100644 (file)
@@ -70,7 +70,7 @@ int ehca_dealloc_ucontext(struct ib_ucontext *context)
 
 static void ehca_mm_open(struct vm_area_struct *vma)
 {
-       u32 *count = (u32*)vma->vm_private_data;
+       u32 *count = (u32 *)vma->vm_private_data;
        if (!count) {
                ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
                             vma->vm_start, vma->vm_end);
@@ -86,7 +86,7 @@ static void ehca_mm_open(struct vm_area_struct *vma)
 
 static void ehca_mm_close(struct vm_area_struct *vma)
 {
-       u32 *count = (u32*)vma->vm_private_data;
+       u32 *count = (u32 *)vma->vm_private_data;
        if (!count) {
                ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
                             vma->vm_start, vma->vm_end);
@@ -215,7 +215,8 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
        case 2: /* qp rqueue_addr */
                ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue",
                         qp->ib_qp.qp_num);
-               ret = ehca_mmap_queue(vma, &qp->ipz_rqueue, &qp->mm_count_rqueue);
+               ret = ehca_mmap_queue(vma, &qp->ipz_rqueue,
+                                     &qp->mm_count_rqueue);
                if (unlikely(ret)) {
                        ehca_err(qp->ib_qp.device,
                                 "ehca_mmap_queue(rq) failed rc=%x qp_num=%x",
@@ -227,7 +228,8 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
        case 3: /* qp squeue_addr */
                ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue",
                         qp->ib_qp.qp_num);
-               ret = ehca_mmap_queue(vma, &qp->ipz_squeue, &qp->mm_count_squeue);
+               ret = ehca_mmap_queue(vma, &qp->ipz_squeue,
+                                     &qp->mm_count_squeue);
                if (unlikely(ret)) {
                        ehca_err(qp->ib_qp.device,
                                 "ehca_mmap_queue(sq) failed rc=%x qp_num=%x",
index 4776a8b0feec4f02bbf6f90e8de04f79e0e9dbda..3394e05f4b4fcbc0d1a879ef705320ca9efe77a7 100644 (file)
@@ -501,8 +501,8 @@ u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle,
                return H_PARAMETER;
        }
 
-       return hipz_h_register_rpage(adapter_handle,pagesize,queue_type,
-                                    qp_handle.handle,logical_address_of_page,
+       return hipz_h_register_rpage(adapter_handle, pagesize, queue_type,
+                                    qp_handle.handle, logical_address_of_page,
                                     count);
 }
 
@@ -522,9 +522,9 @@ u64 hipz_h_disable_and_get_wqe(const struct ipz_adapter_handle adapter_handle,
                                qp_handle.handle,          /* r6 */
                                0, 0, 0, 0, 0, 0);
        if (log_addr_next_sq_wqe2processed)
-               *log_addr_next_sq_wqe2processed = (void*)outs[0];
+               *log_addr_next_sq_wqe2processed = (void *)outs[0];
        if (log_addr_next_rq_wqe2processed)
-               *log_addr_next_rq_wqe2processed = (void*)outs[1];
+               *log_addr_next_rq_wqe2processed = (void *)outs[1];
 
        return ret;
 }
index 0b1a4772c78a4392231d54d268ff6e2e5637ebc3..214821095cb15c2ff0793882877f9889a5052bd0 100644 (file)
@@ -50,7 +50,7 @@ int hcall_map_page(u64 physaddr, u64 *mapaddr)
 
 int hcall_unmap_page(u64 mapaddr)
 {
-       iounmap((volatile void __iomem*)mapaddr);
+       iounmap((volatile void __iomem *) mapaddr);
        return 0;
 }
 
index 20898a153446ad05fa9f12524b2d538ca720a71a..868735fd31876fd85930902980de278be75235fb 100644 (file)
 #define hipz_galpa_load_cq(gal, offset) \
        hipz_galpa_load(gal, CQTEMM_OFFSET(offset))
 
-#define hipz_galpa_store_qp(gal,offset, value) \
+#define hipz_galpa_store_qp(gal, offset, value) \
        hipz_galpa_store(gal, QPTEMM_OFFSET(offset), value)
 #define hipz_galpa_load_qp(gal, offset) \
-       hipz_galpa_load(gal,QPTEMM_OFFSET(offset))
+       hipz_galpa_load(gal, QPTEMM_OFFSET(offset))
 
 static inline void hipz_update_sqa(struct ehca_qp *qp, u16 nr_wqes)
 {
index dad6dea5636b55e1883eca6ac59e6f9248aafbd7..d9739e554515eb7796803f55b88e82bf80572925 100644 (file)
@@ -161,11 +161,11 @@ struct hipz_qptemm {
 /* 0x1000      */
 };
 
-#define QPX_SQADDER EHCA_BMASK_IBM(48,63)
-#define QPX_RQADDER EHCA_BMASK_IBM(48,63)
-#define QPX_AAELOG_RESET_SRQ_LIMIT EHCA_BMASK_IBM(3,3)
+#define QPX_SQADDER EHCA_BMASK_IBM(48, 63)
+#define QPX_RQADDER EHCA_BMASK_IBM(48, 63)
+#define QPX_AAELOG_RESET_SRQ_LIMIT EHCA_BMASK_IBM(3, 3)
 
-#define QPTEMM_OFFSET(x) offsetof(struct hipz_qptemm,x)
+#define QPTEMM_OFFSET(x) offsetof(struct hipz_qptemm, x)
 
 /* MRMWPT Entry Memory Map */
 struct hipz_mrmwmm {
@@ -187,7 +187,7 @@ struct hipz_mrmwmm {
 
 };
 
-#define MRMWMM_OFFSET(x) offsetof(struct hipz_mrmwmm,x)
+#define MRMWMM_OFFSET(x) offsetof(struct hipz_mrmwmm, x)
 
 struct hipz_qpedmm {
        /* 0x00 */
@@ -238,7 +238,7 @@ struct hipz_qpedmm {
        u64 qpedx_rrva3;
 };
 
-#define QPEDMM_OFFSET(x) offsetof(struct hipz_qpedmm,x)
+#define QPEDMM_OFFSET(x) offsetof(struct hipz_qpedmm, x)
 
 /* CQ Table Entry Memory Map */
 struct hipz_cqtemm {
@@ -263,12 +263,12 @@ struct hipz_cqtemm {
 /* 0x1000 */
 };
 
-#define CQX_FEC_CQE_CNT           EHCA_BMASK_IBM(32,63)
-#define CQX_FECADDER              EHCA_BMASK_IBM(32,63)
-#define CQX_N0_GENERATE_SOLICITED_COMP_EVENT EHCA_BMASK_IBM(0,0)
-#define CQX_N1_GENERATE_COMP_EVENT EHCA_BMASK_IBM(0,0)
+#define CQX_FEC_CQE_CNT           EHCA_BMASK_IBM(32, 63)
+#define CQX_FECADDER              EHCA_BMASK_IBM(32, 63)
+#define CQX_N0_GENERATE_SOLICITED_COMP_EVENT EHCA_BMASK_IBM(0, 0)
+#define CQX_N1_GENERATE_COMP_EVENT EHCA_BMASK_IBM(0, 0)
 
-#define CQTEMM_OFFSET(x) offsetof(struct hipz_cqtemm,x)
+#define CQTEMM_OFFSET(x) offsetof(struct hipz_cqtemm, x)
 
 /* EQ Table Entry Memory Map */
 struct hipz_eqtemm {
@@ -293,7 +293,7 @@ struct hipz_eqtemm {
 
 };
 
-#define EQTEMM_OFFSET(x) offsetof(struct hipz_eqtemm,x)
+#define EQTEMM_OFFSET(x) offsetof(struct hipz_eqtemm, x)
 
 /* access control defines for MR/MW */
 #define HIPZ_ACCESSCTRL_L_WRITE  0x00800000
index bf7a40088f61ad57f7830cc620306c1867286c11..9606f13ed0925c8d836b6a138e14459e0b4d9d43 100644 (file)
@@ -114,7 +114,7 @@ int ipz_queue_ctor(struct ipz_queue *queue,
         */
        f = 0;
        while (f < nr_of_pages) {
-               u8 *kpage = (u8*)get_zeroed_page(GFP_KERNEL);
+               u8 *kpage = (u8 *)get_zeroed_page(GFP_KERNEL);
                int k;
                if (!kpage)
                        goto ipz_queue_ctor_exit0; /*NOMEM*/
index 007f0882fd403a20805c988b2dd98e3ba0db1d07..39a4f64aff41b91b2c62e7ed9f0a0c54ef65c8cc 100644 (file)
@@ -240,7 +240,7 @@ void *ipz_qeit_eq_get_inc(struct ipz_queue *queue);
 static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
 {
        void *ret = ipz_qeit_get(queue);
-       u32 qe = *(u8 *) ret;
+       u32 qe = *(u8 *)ret;
        if ((qe >> 7) != (queue->toggle_state & 1))
                return NULL;
        ipz_qeit_eq_get_inc(queue); /* this is a good one */
@@ -250,7 +250,7 @@ static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
 static inline void *ipz_eqit_eq_peek_valid(struct ipz_queue *queue)
 {
        void *ret = ipz_qeit_get(queue);
-       u32 qe = *(u8 *) ret;
+       u32 qe = *(u8 *)ret;
        if ((qe >> 7) != (queue->toggle_state & 1))
                return NULL;
        return ret;
index 9361f5ab8bd637f32dc6171ef0f5281f20b8c060..09c5fd84b1e335cce7b82cd49a7b1b1d899fd010 100644 (file)
@@ -1889,7 +1889,7 @@ void ipath_write_kreg_port(const struct ipath_devdata *dd, ipath_kreg regno,
 /* Below is "non-zero" to force override, but both actual LEDs are off */
 #define LED_OVER_BOTH_OFF (8)
 
-void ipath_run_led_override(unsigned long opaque)
+static void ipath_run_led_override(unsigned long opaque)
 {
        struct ipath_devdata *dd = (struct ipath_devdata *)opaque;
        int timeoff;
index 6b9147964a4f734638e42ae648493326b953d4b8..b4503e9c1e954bb4a7ff346344894818c42c9a5a 100644 (file)
@@ -426,8 +426,8 @@ bail:
  * @buffer: data to write
  * @len: number of bytes to write
  */
-int ipath_eeprom_internal_write(struct ipath_devdata *dd, u8 eeprom_offset,
-                               const void *buffer, int len)
+static int ipath_eeprom_internal_write(struct ipath_devdata *dd, u8 eeprom_offset,
+                                      const void *buffer, int len)
 {
        u8 single_byte;
        int sub_len;
index 47aa43428fbf90b1284b6af4dee729debdc976bd..1fd91c59f2466f4c738f58f1caf74b560164d3ca 100644 (file)
@@ -70,7 +70,7 @@ static void ipath_clrpiobuf(struct ipath_devdata *dd, u32 pnum)
  * If rewrite is true, and bits are set in the sendbufferror registers,
  * we'll write to the buffer, for error recovery on parity errors.
  */
-void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
+static void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
 {
        u32 piobcnt;
        unsigned long sbuf[4];
index 3105005fc9d25d0dfd84a5afb93dae7dd6a8bf4a..ace63ef78e6fa3c23e6a908b1e92ae47cd6ecff1 100644 (file)
@@ -776,7 +776,6 @@ void ipath_get_eeprom_info(struct ipath_devdata *);
 int ipath_update_eeprom_log(struct ipath_devdata *dd);
 void ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr);
 u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg);
-void ipath_disarm_senderrbufs(struct ipath_devdata *, int);
 
 /*
  * Set LED override, only the two LSBs have "public" meaning, but
@@ -820,7 +819,6 @@ static inline u64 ipath_mdio_req(int cmd, int dev, int reg, int data)
 #define IPATH_MDIO_CTRL_8355_REG_10 0x1D
 
 int ipath_get_user_pages(unsigned long, size_t, struct page **);
-int ipath_get_user_pages_nocopy(unsigned long, struct page **);
 void ipath_release_user_pages(struct page **, size_t);
 void ipath_release_user_pages_on_close(struct page **, size_t);
 int ipath_eeprom_read(struct ipath_devdata *, u8, void *, int);
index 85256747d8a185223da6aaf4eab5dd8287d04908..c69c2523944339eec85a832edc6a0f596267f9ec 100644 (file)
@@ -507,7 +507,7 @@ static int want_buffer(struct ipath_devdata *dd)
  *
  * Called when we run out of PIO buffers.
  */
-void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev)
+static void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev)
 {
        unsigned long flags;
 
index 27034d38b3ddcadcdcfed50c066081533e8915ac..0190edc8044e664a0cba534db6c1737a974cb233 100644 (file)
@@ -171,32 +171,6 @@ int ipath_get_user_pages(unsigned long start_page, size_t num_pages,
        return ret;
 }
 
-/**
- * ipath_get_user_pages_nocopy - lock a single page for I/O and mark shared
- * @start_page: the page to lock
- * @p: the output page structure
- *
- * This is similar to ipath_get_user_pages, but it's always one page, and we
- * mark the page as locked for I/O, and shared.  This is used for the user
- * process page that contains the destination address for the rcvhdrq tail
- * update, so we need to have the vma. If we don't do this, the page can be
- * taken away from us on fork, even if the child never touches it, and then
- * the user process never sees the tail register updates.
- */
-int ipath_get_user_pages_nocopy(unsigned long page, struct page **p)
-{
-       struct vm_area_struct *vma;
-       int ret;
-
-       down_write(&current->mm->mmap_sem);
-
-       ret = __get_user_pages(page, 1, p, &vma);
-
-       up_write(&current->mm->mmap_sem);
-
-       return ret;
-}
-
 void ipath_release_user_pages(struct page **p, size_t num_pages)
 {
        down_write(&current->mm->mmap_sem);
index 65f7181e9cf81b7e2db757dc188fc6e7dfee0cb6..16aa61fd80856419957fdbe7ec6dcbb0054de026 100644 (file)
@@ -488,7 +488,7 @@ bail:;
  * This is called from ipath_do_rcv_timer() at interrupt level to check for
  * QPs which need retransmits and to collect performance numbers.
  */
-void ipath_ib_timer(struct ipath_ibdev *dev)
+static void ipath_ib_timer(struct ipath_ibdev *dev)
 {
        struct ipath_qp *resend = NULL;
        struct list_head *last;
index f3d1f2cee6f8f15ac5cd066e92f79dda3ebf9d3b..9bbe81967f14bc8d224f45108692da0be73d42aa 100644 (file)
@@ -782,8 +782,6 @@ void ipath_update_mmap_info(struct ipath_ibdev *dev,
 
 int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
 
-void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev);
-
 void ipath_insert_rnr_queue(struct ipath_qp *qp);
 
 int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only);
@@ -807,8 +805,6 @@ void ipath_ib_rcv(struct ipath_ibdev *, void *, void *, u32);
 
 int ipath_ib_piobufavail(struct ipath_ibdev *);
 
-void ipath_ib_timer(struct ipath_ibdev *);
-
 unsigned ipath_get_npkeys(struct ipath_devdata *);
 
 u32 ipath_get_cr_errpkey(struct ipath_devdata *);
index 40042184ad589b0b8b9d124b6622637f11251f02..b5a24fbef70d95768e3bd9a572dff993aa67e854 100644 (file)
@@ -1183,6 +1183,43 @@ static int mlx4_wq_overflow(struct mlx4_ib_wq *wq, int nreq, struct ib_cq *ib_cq
        return cur + nreq >= wq->max_post;
 }
 
+static __always_inline void set_raddr_seg(struct mlx4_wqe_raddr_seg *rseg,
+                                         u64 remote_addr, u32 rkey)
+{
+       rseg->raddr    = cpu_to_be64(remote_addr);
+       rseg->rkey     = cpu_to_be32(rkey);
+       rseg->reserved = 0;
+}
+
+static void set_atomic_seg(struct mlx4_wqe_atomic_seg *aseg, struct ib_send_wr *wr)
+{
+       if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+               aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap);
+               aseg->compare  = cpu_to_be64(wr->wr.atomic.compare_add);
+       } else {
+               aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
+               aseg->compare  = 0;
+       }
+
+}
+
+static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg,
+                            struct ib_send_wr *wr)
+{
+       memcpy(dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av));
+       dseg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
+       dseg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+
+}
+
+static void set_data_seg(struct mlx4_wqe_data_seg *dseg,
+                        struct ib_sge *sg)
+{
+       dseg->byte_count = cpu_to_be32(sg->length);
+       dseg->lkey       = cpu_to_be32(sg->lkey);
+       dseg->addr       = cpu_to_be64(sg->addr);
+}
+
 int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                      struct ib_send_wr **bad_wr)
 {
@@ -1238,26 +1275,13 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        switch (wr->opcode) {
                        case IB_WR_ATOMIC_CMP_AND_SWP:
                        case IB_WR_ATOMIC_FETCH_AND_ADD:
-                               ((struct mlx4_wqe_raddr_seg *) wqe)->raddr =
-                                       cpu_to_be64(wr->wr.atomic.remote_addr);
-                               ((struct mlx4_wqe_raddr_seg *) wqe)->rkey =
-                                       cpu_to_be32(wr->wr.atomic.rkey);
-                               ((struct mlx4_wqe_raddr_seg *) wqe)->reserved = 0;
-
+                               set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
+                                             wr->wr.atomic.rkey);
                                wqe  += sizeof (struct mlx4_wqe_raddr_seg);
 
-                               if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
-                                       ((struct mlx4_wqe_atomic_seg *) wqe)->swap_add =
-                                               cpu_to_be64(wr->wr.atomic.swap);
-                                       ((struct mlx4_wqe_atomic_seg *) wqe)->compare =
-                                               cpu_to_be64(wr->wr.atomic.compare_add);
-                               } else {
-                                       ((struct mlx4_wqe_atomic_seg *) wqe)->swap_add =
-                                               cpu_to_be64(wr->wr.atomic.compare_add);
-                                       ((struct mlx4_wqe_atomic_seg *) wqe)->compare = 0;
-                               }
-
+                               set_atomic_seg(wqe, wr);
                                wqe  += sizeof (struct mlx4_wqe_atomic_seg);
+
                                size += (sizeof (struct mlx4_wqe_raddr_seg) +
                                         sizeof (struct mlx4_wqe_atomic_seg)) / 16;
 
@@ -1266,15 +1290,10 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        case IB_WR_RDMA_READ:
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
-                               ((struct mlx4_wqe_raddr_seg *) wqe)->raddr =
-                                       cpu_to_be64(wr->wr.rdma.remote_addr);
-                               ((struct mlx4_wqe_raddr_seg *) wqe)->rkey =
-                                       cpu_to_be32(wr->wr.rdma.rkey);
-                               ((struct mlx4_wqe_raddr_seg *) wqe)->reserved = 0;
-
+                               set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+                                             wr->wr.rdma.rkey);
                                wqe  += sizeof (struct mlx4_wqe_raddr_seg);
                                size += sizeof (struct mlx4_wqe_raddr_seg) / 16;
-
                                break;
 
                        default:
@@ -1284,13 +1303,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        break;
 
                case IB_QPT_UD:
-                       memcpy(((struct mlx4_wqe_datagram_seg *) wqe)->av,
-                              &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av));
-                       ((struct mlx4_wqe_datagram_seg *) wqe)->dqpn =
-                               cpu_to_be32(wr->wr.ud.remote_qpn);
-                       ((struct mlx4_wqe_datagram_seg *) wqe)->qkey =
-                               cpu_to_be32(wr->wr.ud.remote_qkey);
-
+                       set_datagram_seg(wqe, wr);
                        wqe  += sizeof (struct mlx4_wqe_datagram_seg);
                        size += sizeof (struct mlx4_wqe_datagram_seg) / 16;
                        break;
@@ -1313,12 +1326,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                }
 
                for (i = 0; i < wr->num_sge; ++i) {
-                       ((struct mlx4_wqe_data_seg *) wqe)->byte_count =
-                               cpu_to_be32(wr->sg_list[i].length);
-                       ((struct mlx4_wqe_data_seg *) wqe)->lkey =
-                               cpu_to_be32(wr->sg_list[i].lkey);
-                       ((struct mlx4_wqe_data_seg *) wqe)->addr =
-                               cpu_to_be64(wr->sg_list[i].addr);
+                       set_data_seg(wqe, wr->sg_list + i);
 
                        wqe  += sizeof (struct mlx4_wqe_data_seg);
                        size += sizeof (struct mlx4_wqe_data_seg) / 16;
@@ -1498,7 +1506,7 @@ static int to_ib_qp_access_flags(int mlx4_flags)
 static void to_ib_ah_attr(struct mlx4_dev *dev, struct ib_ah_attr *ib_ah_attr,
                                struct mlx4_qp_path *path)
 {
-       memset(ib_ah_attr, 0, sizeof *path);
+       memset(ib_ah_attr, 0, sizeof *ib_ah_attr);
        ib_ah_attr->port_num      = path->sched_queue & 0x40 ? 2 : 1;
 
        if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->caps.num_ports)
@@ -1515,7 +1523,7 @@ static void to_ib_ah_attr(struct mlx4_dev *dev, struct ib_ah_attr *ib_ah_attr,
                ib_ah_attr->grh.traffic_class =
                        (be32_to_cpu(path->tclass_flowlabel) >> 20) & 0xff;
                ib_ah_attr->grh.flow_label =
-                       be32_to_cpu(path->tclass_flowlabel) & 0xffffff;
+                       be32_to_cpu(path->tclass_flowlabel) & 0xfffff;
                memcpy(ib_ah_attr->grh.dgid.raw,
                        path->rgid, sizeof ib_ah_attr->grh.dgid.raw);
        }
@@ -1560,7 +1568,10 @@ int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr
        }
 
        qp_attr->pkey_index = context.pri_path.pkey_index & 0x7f;
-       qp_attr->port_num   = context.pri_path.sched_queue & 0x40 ? 2 : 1;
+       if (qp_attr->qp_state == IB_QPS_INIT)
+               qp_attr->port_num = qp->port;
+       else
+               qp_attr->port_num = context.pri_path.sched_queue & 0x40 ? 2 : 1;
 
        /* qp_attr->en_sqd_async_notify is only applicable in modify qp */
        qp_attr->sq_draining = mlx4_state == MLX4_QP_STATE_SQ_DRAINING;
@@ -1578,17 +1589,25 @@ int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr
 
 done:
        qp_attr->cur_qp_state        = qp_attr->qp_state;
+       qp_attr->cap.max_recv_wr     = qp->rq.wqe_cnt;
+       qp_attr->cap.max_recv_sge    = qp->rq.max_gs;
+
        if (!ibqp->uobject) {
-               qp_attr->cap.max_send_wr     = qp->sq.wqe_cnt;
-               qp_attr->cap.max_recv_wr     = qp->rq.wqe_cnt;
-               qp_attr->cap.max_send_sge    = qp->sq.max_gs;
-               qp_attr->cap.max_recv_sge    = qp->rq.max_gs;
-               qp_attr->cap.max_inline_data = (1 << qp->sq.wqe_shift) -
-                       send_wqe_overhead(qp->ibqp.qp_type) -
-                       sizeof (struct mlx4_wqe_inline_seg);
-               qp_init_attr->cap            = qp_attr->cap;
+               qp_attr->cap.max_send_wr  = qp->sq.wqe_cnt;
+               qp_attr->cap.max_send_sge = qp->sq.max_gs;
+       } else {
+               qp_attr->cap.max_send_wr  = 0;
+               qp_attr->cap.max_send_sge = 0;
        }
 
+       /*
+        * We don't support inline sends for kernel QPs (yet), and we
+        * don't know what userspace's value should be.
+        */
+       qp_attr->cap.max_inline_data = 0;
+
+       qp_init_attr->cap            = qp_attr->cap;
+
        return 0;
 }
 
index aa563e61de65cb3fb02f0129290b448dfb529936..76fed7545c536334c6bb5567ae87aca4df1df6f9 100644 (file)
@@ -67,7 +67,7 @@ MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
 
 static int msi = 0;
 module_param(msi, int, 0444);
-MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero");
+MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero (deprecated, use MSI-X instead)");
 
 #else /* CONFIG_PCI_MSI */
 
@@ -1117,9 +1117,21 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
 
        if (msi_x && !mthca_enable_msi_x(mdev))
                mdev->mthca_flags |= MTHCA_FLAG_MSI_X;
-       if (msi && !(mdev->mthca_flags & MTHCA_FLAG_MSI_X) &&
-           !pci_enable_msi(pdev))
-               mdev->mthca_flags |= MTHCA_FLAG_MSI;
+       else if (msi) {
+               static int warned;
+
+               if (!warned) {
+                       printk(KERN_WARNING PFX "WARNING: MSI support will be "
+                              "removed from the ib_mthca driver in January 2008.\n");
+                       printk(KERN_WARNING "    If you are using MSI and cannot "
+                              "switch to MSI-X, please tell "
+                              "<general@lists.openfabrics.org>.\n");
+                       ++warned;
+               }
+
+               if (!pci_enable_msi(pdev))
+                       mdev->mthca_flags |= MTHCA_FLAG_MSI;
+       }
 
        if (mthca_cmd_init(mdev)) {
                mthca_err(mdev, "Failed to init command interface, aborting.\n");
@@ -1135,7 +1147,7 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
                goto err_cmd;
 
        if (mdev->fw_ver < mthca_hca_table[hca_type].latest_fw) {
-               mthca_warn(mdev, "HCA FW version %d.%d.%3d is old (%d.%d.%3d is current).\n",
+               mthca_warn(mdev, "HCA FW version %d.%d.%03d is old (%d.%d.%03d is current).\n",
                           (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,
                           (int) (mdev->fw_ver & 0xffff),
                           (int) (mthca_hca_table[hca_type].latest_fw >> 32),
index 11f1d99db40b5896698d98bf81a90a48e3c54879..df01b2026a644657b288e5304d17dbd22517c8bf 100644 (file)
@@ -1578,6 +1578,45 @@ static inline int mthca_wq_overflow(struct mthca_wq *wq, int nreq,
        return cur + nreq >= wq->max;
 }
 
+static __always_inline void set_raddr_seg(struct mthca_raddr_seg *rseg,
+                                         u64 remote_addr, u32 rkey)
+{
+       rseg->raddr    = cpu_to_be64(remote_addr);
+       rseg->rkey     = cpu_to_be32(rkey);
+       rseg->reserved = 0;
+}
+
+static __always_inline void set_atomic_seg(struct mthca_atomic_seg *aseg,
+                                          struct ib_send_wr *wr)
+{
+       if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+               aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap);
+               aseg->compare  = cpu_to_be64(wr->wr.atomic.compare_add);
+       } else {
+               aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
+               aseg->compare  = 0;
+       }
+
+}
+
+static void set_tavor_ud_seg(struct mthca_tavor_ud_seg *useg,
+                            struct ib_send_wr *wr)
+{
+       useg->lkey    = cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
+       useg->av_addr = cpu_to_be64(to_mah(wr->wr.ud.ah)->avdma);
+       useg->dqpn    = cpu_to_be32(wr->wr.ud.remote_qpn);
+       useg->qkey    = cpu_to_be32(wr->wr.ud.remote_qkey);
+
+}
+
+static void set_arbel_ud_seg(struct mthca_arbel_ud_seg *useg,
+                            struct ib_send_wr *wr)
+{
+       memcpy(useg->av, to_mah(wr->wr.ud.ah)->av, MTHCA_AV_SIZE);
+       useg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
+       useg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+}
+
 int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                          struct ib_send_wr **bad_wr)
 {
@@ -1590,8 +1629,15 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
        int nreq;
        int i;
        int size;
-       int size0 = 0;
-       u32 f0 = 0;
+       /*
+        * f0 and size0 are only used if nreq != 0, and they will
+        * always be initialized the first time through the main loop
+        * before nreq is incremented.  So nreq cannot become non-zero
+        * without initializing f0 and size0, and they are in fact
+        * never used uninitialized.
+        */
+       int uninitialized_var(size0);
+       u32 uninitialized_var(f0);
        int ind;
        u8 op0 = 0;
 
@@ -1636,25 +1682,11 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        switch (wr->opcode) {
                        case IB_WR_ATOMIC_CMP_AND_SWP:
                        case IB_WR_ATOMIC_FETCH_AND_ADD:
-                               ((struct mthca_raddr_seg *) wqe)->raddr =
-                                       cpu_to_be64(wr->wr.atomic.remote_addr);
-                               ((struct mthca_raddr_seg *) wqe)->rkey =
-                                       cpu_to_be32(wr->wr.atomic.rkey);
-                               ((struct mthca_raddr_seg *) wqe)->reserved = 0;
-
+                               set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
+                                             wr->wr.atomic.rkey);
                                wqe += sizeof (struct mthca_raddr_seg);
 
-                               if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
-                                       ((struct mthca_atomic_seg *) wqe)->swap_add =
-                                               cpu_to_be64(wr->wr.atomic.swap);
-                                       ((struct mthca_atomic_seg *) wqe)->compare =
-                                               cpu_to_be64(wr->wr.atomic.compare_add);
-                               } else {
-                                       ((struct mthca_atomic_seg *) wqe)->swap_add =
-                                               cpu_to_be64(wr->wr.atomic.compare_add);
-                                       ((struct mthca_atomic_seg *) wqe)->compare = 0;
-                               }
-
+                               set_atomic_seg(wqe, wr);
                                wqe += sizeof (struct mthca_atomic_seg);
                                size += (sizeof (struct mthca_raddr_seg) +
                                         sizeof (struct mthca_atomic_seg)) / 16;
@@ -1663,12 +1695,9 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
                        case IB_WR_RDMA_READ:
-                               ((struct mthca_raddr_seg *) wqe)->raddr =
-                                       cpu_to_be64(wr->wr.rdma.remote_addr);
-                               ((struct mthca_raddr_seg *) wqe)->rkey =
-                                       cpu_to_be32(wr->wr.rdma.rkey);
-                               ((struct mthca_raddr_seg *) wqe)->reserved = 0;
-                               wqe += sizeof (struct mthca_raddr_seg);
+                               set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+                                             wr->wr.rdma.rkey);
+                               wqe  += sizeof (struct mthca_raddr_seg);
                                size += sizeof (struct mthca_raddr_seg) / 16;
                                break;
 
@@ -1683,12 +1712,9 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        switch (wr->opcode) {
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
-                               ((struct mthca_raddr_seg *) wqe)->raddr =
-                                       cpu_to_be64(wr->wr.rdma.remote_addr);
-                               ((struct mthca_raddr_seg *) wqe)->rkey =
-                                       cpu_to_be32(wr->wr.rdma.rkey);
-                               ((struct mthca_raddr_seg *) wqe)->reserved = 0;
-                               wqe += sizeof (struct mthca_raddr_seg);
+                               set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+                                             wr->wr.rdma.rkey);
+                               wqe  += sizeof (struct mthca_raddr_seg);
                                size += sizeof (struct mthca_raddr_seg) / 16;
                                break;
 
@@ -1700,16 +1726,8 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        break;
 
                case UD:
-                       ((struct mthca_tavor_ud_seg *) wqe)->lkey =
-                               cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
-                       ((struct mthca_tavor_ud_seg *) wqe)->av_addr =
-                               cpu_to_be64(to_mah(wr->wr.ud.ah)->avdma);
-                       ((struct mthca_tavor_ud_seg *) wqe)->dqpn =
-                               cpu_to_be32(wr->wr.ud.remote_qpn);
-                       ((struct mthca_tavor_ud_seg *) wqe)->qkey =
-                               cpu_to_be32(wr->wr.ud.remote_qkey);
-
-                       wqe += sizeof (struct mthca_tavor_ud_seg);
+                       set_tavor_ud_seg(wqe, wr);
+                       wqe  += sizeof (struct mthca_tavor_ud_seg);
                        size += sizeof (struct mthca_tavor_ud_seg) / 16;
                        break;
 
@@ -1734,13 +1752,8 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                }
 
                for (i = 0; i < wr->num_sge; ++i) {
-                       ((struct mthca_data_seg *) wqe)->byte_count =
-                               cpu_to_be32(wr->sg_list[i].length);
-                       ((struct mthca_data_seg *) wqe)->lkey =
-                               cpu_to_be32(wr->sg_list[i].lkey);
-                       ((struct mthca_data_seg *) wqe)->addr =
-                               cpu_to_be64(wr->sg_list[i].addr);
-                       wqe += sizeof (struct mthca_data_seg);
+                       mthca_set_data_seg(wqe, wr->sg_list + i);
+                       wqe  += sizeof (struct mthca_data_seg);
                        size += sizeof (struct mthca_data_seg) / 16;
                }
 
@@ -1768,11 +1781,11 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                                    mthca_opcode[wr->opcode]);
                wmb();
                ((struct mthca_next_seg *) prev_wqe)->ee_nds =
-                       cpu_to_be32((size0 ? 0 : MTHCA_NEXT_DBD) | size |
+                       cpu_to_be32((nreq ? 0 : MTHCA_NEXT_DBD) | size |
                                    ((wr->send_flags & IB_SEND_FENCE) ?
                                    MTHCA_NEXT_FENCE : 0));
 
-               if (!size0) {
+               if (!nreq) {
                        size0 = size;
                        op0   = mthca_opcode[wr->opcode];
                        f0    = wr->send_flags & IB_SEND_FENCE ?
@@ -1822,7 +1835,14 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
        int nreq;
        int i;
        int size;
-       int size0 = 0;
+       /*
+        * size0 is only used if nreq != 0, and it will always be
+        * initialized the first time through the main loop before
+        * nreq is incremented.  So nreq cannot become non-zero
+        * without initializing size0, and it is in fact never used
+        * uninitialized.
+        */
+       int uninitialized_var(size0);
        int ind;
        void *wqe;
        void *prev_wqe;
@@ -1863,13 +1883,8 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
                }
 
                for (i = 0; i < wr->num_sge; ++i) {
-                       ((struct mthca_data_seg *) wqe)->byte_count =
-                               cpu_to_be32(wr->sg_list[i].length);
-                       ((struct mthca_data_seg *) wqe)->lkey =
-                               cpu_to_be32(wr->sg_list[i].lkey);
-                       ((struct mthca_data_seg *) wqe)->addr =
-                               cpu_to_be64(wr->sg_list[i].addr);
-                       wqe += sizeof (struct mthca_data_seg);
+                       mthca_set_data_seg(wqe, wr->sg_list + i);
+                       wqe  += sizeof (struct mthca_data_seg);
                        size += sizeof (struct mthca_data_seg) / 16;
                }
 
@@ -1881,7 +1896,7 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
                ((struct mthca_next_seg *) prev_wqe)->ee_nds =
                        cpu_to_be32(MTHCA_NEXT_DBD | size);
 
-               if (!size0)
+               if (!nreq)
                        size0 = size;
 
                ++ind;
@@ -1903,7 +1918,6 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
 
                        qp->rq.next_ind = ind;
                        qp->rq.head += MTHCA_TAVOR_MAX_WQES_PER_RECV_DB;
-                       size0 = 0;
                }
        }
 
@@ -1945,8 +1959,15 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
        int nreq;
        int i;
        int size;
-       int size0 = 0;
-       u32 f0 = 0;
+       /*
+        * f0 and size0 are only used if nreq != 0, and they will
+        * always be initialized the first time through the main loop
+        * before nreq is incremented.  So nreq cannot become non-zero
+        * without initializing f0 and size0, and they are in fact
+        * never used uninitialized.
+        */
+       int uninitialized_var(size0);
+       u32 uninitialized_var(f0);
        int ind;
        u8 op0 = 0;
 
@@ -1966,7 +1987,6 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        doorbell[1] = cpu_to_be32((qp->qpn << 8) | size0);
 
                        qp->sq.head += MTHCA_ARBEL_MAX_WQES_PER_SEND_DB;
-                       size0 = 0;
 
                        /*
                         * Make sure that descriptors are written before
@@ -2017,26 +2037,12 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        switch (wr->opcode) {
                        case IB_WR_ATOMIC_CMP_AND_SWP:
                        case IB_WR_ATOMIC_FETCH_AND_ADD:
-                               ((struct mthca_raddr_seg *) wqe)->raddr =
-                                       cpu_to_be64(wr->wr.atomic.remote_addr);
-                               ((struct mthca_raddr_seg *) wqe)->rkey =
-                                       cpu_to_be32(wr->wr.atomic.rkey);
-                               ((struct mthca_raddr_seg *) wqe)->reserved = 0;
-
+                               set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
+                                             wr->wr.atomic.rkey);
                                wqe += sizeof (struct mthca_raddr_seg);
 
-                               if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
-                                       ((struct mthca_atomic_seg *) wqe)->swap_add =
-                                               cpu_to_be64(wr->wr.atomic.swap);
-                                       ((struct mthca_atomic_seg *) wqe)->compare =
-                                               cpu_to_be64(wr->wr.atomic.compare_add);
-                               } else {
-                                       ((struct mthca_atomic_seg *) wqe)->swap_add =
-                                               cpu_to_be64(wr->wr.atomic.compare_add);
-                                       ((struct mthca_atomic_seg *) wqe)->compare = 0;
-                               }
-
-                               wqe += sizeof (struct mthca_atomic_seg);
+                               set_atomic_seg(wqe, wr);
+                               wqe  += sizeof (struct mthca_atomic_seg);
                                size += (sizeof (struct mthca_raddr_seg) +
                                         sizeof (struct mthca_atomic_seg)) / 16;
                                break;
@@ -2044,12 +2050,9 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        case IB_WR_RDMA_READ:
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
-                               ((struct mthca_raddr_seg *) wqe)->raddr =
-                                       cpu_to_be64(wr->wr.rdma.remote_addr);
-                               ((struct mthca_raddr_seg *) wqe)->rkey =
-                                       cpu_to_be32(wr->wr.rdma.rkey);
-                               ((struct mthca_raddr_seg *) wqe)->reserved = 0;
-                               wqe += sizeof (struct mthca_raddr_seg);
+                               set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+                                             wr->wr.rdma.rkey);
+                               wqe  += sizeof (struct mthca_raddr_seg);
                                size += sizeof (struct mthca_raddr_seg) / 16;
                                break;
 
@@ -2064,12 +2067,9 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        switch (wr->opcode) {
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
-                               ((struct mthca_raddr_seg *) wqe)->raddr =
-                                       cpu_to_be64(wr->wr.rdma.remote_addr);
-                               ((struct mthca_raddr_seg *) wqe)->rkey =
-                                       cpu_to_be32(wr->wr.rdma.rkey);
-                               ((struct mthca_raddr_seg *) wqe)->reserved = 0;
-                               wqe += sizeof (struct mthca_raddr_seg);
+                               set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+                                             wr->wr.rdma.rkey);
+                               wqe  += sizeof (struct mthca_raddr_seg);
                                size += sizeof (struct mthca_raddr_seg) / 16;
                                break;
 
@@ -2081,14 +2081,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        break;
 
                case UD:
-                       memcpy(((struct mthca_arbel_ud_seg *) wqe)->av,
-                              to_mah(wr->wr.ud.ah)->av, MTHCA_AV_SIZE);
-                       ((struct mthca_arbel_ud_seg *) wqe)->dqpn =
-                               cpu_to_be32(wr->wr.ud.remote_qpn);
-                       ((struct mthca_arbel_ud_seg *) wqe)->qkey =
-                               cpu_to_be32(wr->wr.ud.remote_qkey);
-
-                       wqe += sizeof (struct mthca_arbel_ud_seg);
+                       set_arbel_ud_seg(wqe, wr);
+                       wqe  += sizeof (struct mthca_arbel_ud_seg);
                        size += sizeof (struct mthca_arbel_ud_seg) / 16;
                        break;
 
@@ -2113,13 +2107,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                }
 
                for (i = 0; i < wr->num_sge; ++i) {
-                       ((struct mthca_data_seg *) wqe)->byte_count =
-                               cpu_to_be32(wr->sg_list[i].length);
-                       ((struct mthca_data_seg *) wqe)->lkey =
-                               cpu_to_be32(wr->sg_list[i].lkey);
-                       ((struct mthca_data_seg *) wqe)->addr =
-                               cpu_to_be64(wr->sg_list[i].addr);
-                       wqe += sizeof (struct mthca_data_seg);
+                       mthca_set_data_seg(wqe, wr->sg_list + i);
+                       wqe  += sizeof (struct mthca_data_seg);
                        size += sizeof (struct mthca_data_seg) / 16;
                }
 
@@ -2151,7 +2140,7 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                                    ((wr->send_flags & IB_SEND_FENCE) ?
                                     MTHCA_NEXT_FENCE : 0));
 
-               if (!size0) {
+               if (!nreq) {
                        size0 = size;
                        op0   = mthca_opcode[wr->opcode];
                        f0    = wr->send_flags & IB_SEND_FENCE ?
@@ -2241,20 +2230,12 @@ int mthca_arbel_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
                }
 
                for (i = 0; i < wr->num_sge; ++i) {
-                       ((struct mthca_data_seg *) wqe)->byte_count =
-                               cpu_to_be32(wr->sg_list[i].length);
-                       ((struct mthca_data_seg *) wqe)->lkey =
-                               cpu_to_be32(wr->sg_list[i].lkey);
-                       ((struct mthca_data_seg *) wqe)->addr =
-                               cpu_to_be64(wr->sg_list[i].addr);
+                       mthca_set_data_seg(wqe, wr->sg_list + i);
                        wqe += sizeof (struct mthca_data_seg);
                }
 
-               if (i < qp->rq.max_gs) {
-                       ((struct mthca_data_seg *) wqe)->byte_count = 0;
-                       ((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
-                       ((struct mthca_data_seg *) wqe)->addr = 0;
-               }
+               if (i < qp->rq.max_gs)
+                       mthca_set_data_seg_inval(wqe);
 
                qp->wrid[ind] = wr->wr_id;
 
index b8f05a52667376830b8dd450261341b49cb30fe8..88d219e730ad5a2d773a6206512fabae40bd07a2 100644 (file)
@@ -543,20 +543,12 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
                }
 
                for (i = 0; i < wr->num_sge; ++i) {
-                       ((struct mthca_data_seg *) wqe)->byte_count =
-                               cpu_to_be32(wr->sg_list[i].length);
-                       ((struct mthca_data_seg *) wqe)->lkey =
-                               cpu_to_be32(wr->sg_list[i].lkey);
-                       ((struct mthca_data_seg *) wqe)->addr =
-                               cpu_to_be64(wr->sg_list[i].addr);
+                       mthca_set_data_seg(wqe, wr->sg_list + i);
                        wqe += sizeof (struct mthca_data_seg);
                }
 
-               if (i < srq->max_gs) {
-                       ((struct mthca_data_seg *) wqe)->byte_count = 0;
-                       ((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
-                       ((struct mthca_data_seg *) wqe)->addr = 0;
-               }
+               if (i < srq->max_gs)
+                       mthca_set_data_seg_inval(wqe);
 
                ((struct mthca_next_seg *) prev_wqe)->nda_op =
                        cpu_to_be32((ind << srq->wqe_shift) | 1);
@@ -662,20 +654,12 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
                }
 
                for (i = 0; i < wr->num_sge; ++i) {
-                       ((struct mthca_data_seg *) wqe)->byte_count =
-                               cpu_to_be32(wr->sg_list[i].length);
-                       ((struct mthca_data_seg *) wqe)->lkey =
-                               cpu_to_be32(wr->sg_list[i].lkey);
-                       ((struct mthca_data_seg *) wqe)->addr =
-                               cpu_to_be64(wr->sg_list[i].addr);
+                       mthca_set_data_seg(wqe, wr->sg_list + i);
                        wqe += sizeof (struct mthca_data_seg);
                }
 
-               if (i < srq->max_gs) {
-                       ((struct mthca_data_seg *) wqe)->byte_count = 0;
-                       ((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
-                       ((struct mthca_data_seg *) wqe)->addr = 0;
-               }
+               if (i < srq->max_gs)
+                       mthca_set_data_seg_inval(wqe);
 
                srq->wrid[ind]  = wr->wr_id;
                srq->first_free = next_ind;
index e7d2c1e86199598a6762adcdc57d6a6858bcca77..f6a66fe78e486d38dfb6bd453c1d389de31263df 100644 (file)
@@ -113,4 +113,19 @@ struct mthca_mlx_seg {
        __be16 vcrc;
 };
 
+static __always_inline void mthca_set_data_seg(struct mthca_data_seg *dseg,
+                                              struct ib_sge *sg)
+{
+       dseg->byte_count = cpu_to_be32(sg->length);
+       dseg->lkey       = cpu_to_be32(sg->lkey);
+       dseg->addr       = cpu_to_be64(sg->addr);
+}
+
+static __always_inline void mthca_set_data_seg_inval(struct mthca_data_seg *dseg)
+{
+       dseg->byte_count = 0;
+       dseg->lkey       = cpu_to_be32(MTHCA_INVAL_LKEY);
+       dseg->addr       = 0;
+}
+
 #endif /* MTHCA_WQE_H */
index e2353701e8bbdcfc86bd488bb7090ded9367828c..1ee867b1b3411754c58a814331283944b45b9587 100644 (file)
@@ -310,8 +310,6 @@ int  iser_conn_init(struct iser_conn **ib_conn);
 
 void iser_conn_terminate(struct iser_conn *ib_conn);
 
-void iser_conn_release(struct iser_conn *ib_conn);
-
 void iser_rcv_completion(struct iser_desc *desc,
                         unsigned long    dto_xfer_len);
 
@@ -329,9 +327,6 @@ void iser_reg_single(struct iser_device      *device,
                     struct iser_regd_buf    *regd_buf,
                     enum dma_data_direction direction);
 
-int  iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task    *ctask,
-                                 enum iser_data_dir            cmd_dir);
-
 void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *ctask,
                                     enum iser_data_dir         cmd_dir);
 
index fc9f1fd0ae54ff3818c65f893047f48faeb81871..36cdf77ae92abd79d1bb34818052034c92e16648 100644 (file)
@@ -103,8 +103,8 @@ void iser_reg_single(struct iser_device *device,
 /**
  * iser_start_rdma_unaligned_sg
  */
-int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task  *iser_ctask,
-                                enum iser_data_dir cmd_dir)
+static int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
+                                       enum iser_data_dir cmd_dir)
 {
        int dma_nents;
        struct ib_device *dev;
index 2044de1164ac0e498d242f4908006b889b02f52b..d42ec0156eec7bb215317ea649a8140da451785a 100644 (file)
@@ -310,6 +310,29 @@ static int iser_conn_state_comp_exch(struct iser_conn *ib_conn,
        return ret;
 }
 
+/**
+ * Frees all conn objects and deallocs conn descriptor
+ */
+static void iser_conn_release(struct iser_conn *ib_conn)
+{
+       struct iser_device  *device = ib_conn->device;
+
+       BUG_ON(ib_conn->state != ISER_CONN_DOWN);
+
+       mutex_lock(&ig.connlist_mutex);
+       list_del(&ib_conn->conn_list);
+       mutex_unlock(&ig.connlist_mutex);
+
+       iser_free_ib_conn_res(ib_conn);
+       ib_conn->device = NULL;
+       /* on EVENT_ADDR_ERROR there's no device yet for this conn */
+       if (device != NULL)
+               iser_device_try_release(device);
+       if (ib_conn->iser_conn)
+               ib_conn->iser_conn->ib_conn = NULL;
+       kfree(ib_conn);
+}
+
 /**
  * triggers start of the disconnect procedures and wait for them to be done
  */
@@ -549,30 +572,6 @@ connect_failure:
        return err;
 }
 
-/**
- * Frees all conn objects and deallocs conn descriptor
- */
-void iser_conn_release(struct iser_conn *ib_conn)
-{
-       struct iser_device  *device = ib_conn->device;
-
-       BUG_ON(ib_conn->state != ISER_CONN_DOWN);
-
-       mutex_lock(&ig.connlist_mutex);
-       list_del(&ib_conn->conn_list);
-       mutex_unlock(&ig.connlist_mutex);
-
-       iser_free_ib_conn_res(ib_conn);
-       ib_conn->device = NULL;
-       /* on EVENT_ADDR_ERROR there's no device yet for this conn */
-       if (device != NULL)
-               iser_device_try_release(device);
-       if (ib_conn->iser_conn)
-               ib_conn->iser_conn->ib_conn = NULL;
-       kfree(ib_conn);
-}
-
-
 /**
  * iser_reg_page_vec - Register physical memory
  *
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 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 7c6b223b3f8a0a22b114a5b593f1ad605b85fcc5..8aff9385613f36601316ce0b9df2a4b410a2358a 100644 (file)
@@ -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);
        }
 
@@ -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 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 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 1bb088aeaf713e929f2c73d9b93173c8bcefff98..6b32ec94b3a8b8d63c3d3f87b13d7423f597b837 100644 (file)
  * SOFTWARE.
  */
 
+#include <linux/workqueue.h>
+
 #include "mlx4.h"
 
-void mlx4_handle_catas_err(struct mlx4_dev *dev)
+enum {
+       MLX4_CATAS_POLL_INTERVAL        = 5 * HZ,
+};
+
+static DEFINE_SPINLOCK(catas_lock);
+
+static LIST_HEAD(catas_list);
+static struct workqueue_struct *catas_wq;
+static struct work_struct catas_work;
+
+static int internal_err_reset = 1;
+module_param(internal_err_reset, int, 0644);
+MODULE_PARM_DESC(internal_err_reset,
+                "Reset device on internal errors if non-zero (default 1)");
+
+static void dump_err_buf(struct mlx4_dev *dev)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
 
        int i;
 
-       mlx4_err(dev, "Catastrophic error detected:\n");
+       mlx4_err(dev, "Internal error detected:\n");
        for (i = 0; i < priv->fw.catas_size; ++i)
                mlx4_err(dev, "  buf[%02x]: %08x\n",
                         i, swab32(readl(priv->catas_err.map + i)));
+}
 
-       mlx4_dispatch_event(dev, MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR, 0, 0);
+static void poll_catas(unsigned long dev_ptr)
+{
+       struct mlx4_dev *dev = (struct mlx4_dev *) dev_ptr;
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       if (readl(priv->catas_err.map)) {
+               dump_err_buf(dev);
+
+               mlx4_dispatch_event(dev, MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR, 0, 0);
+
+               if (internal_err_reset) {
+                       spin_lock(&catas_lock);
+                       list_add(&priv->catas_err.list, &catas_list);
+                       spin_unlock(&catas_lock);
+
+                       queue_work(catas_wq, &catas_work);
+               }
+       } else
+               mod_timer(&priv->catas_err.timer,
+                         round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL));
 }
 
-void mlx4_map_catas_buf(struct mlx4_dev *dev)
+static void catas_reset(struct work_struct *work)
+{
+       struct mlx4_priv *priv, *tmppriv;
+       struct mlx4_dev *dev;
+
+       LIST_HEAD(tlist);
+       int ret;
+
+       spin_lock_irq(&catas_lock);
+       list_splice_init(&catas_list, &tlist);
+       spin_unlock_irq(&catas_lock);
+
+       list_for_each_entry_safe(priv, tmppriv, &tlist, catas_err.list) {
+               ret = mlx4_restart_one(priv->dev.pdev);
+               dev = &priv->dev;
+               if (ret)
+                       mlx4_err(dev, "Reset failed (%d)\n", ret);
+               else
+                       mlx4_dbg(dev, "Reset succeeded\n");
+       }
+}
+
+void mlx4_start_catas_poll(struct mlx4_dev *dev)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
        unsigned long addr;
 
+       INIT_LIST_HEAD(&priv->catas_err.list);
+       init_timer(&priv->catas_err.timer);
+       priv->catas_err.map = NULL;
+
        addr = pci_resource_start(dev->pdev, priv->fw.catas_bar) +
                priv->fw.catas_offset;
 
        priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4);
-       if (!priv->catas_err.map)
-               mlx4_warn(dev, "Failed to map catastrophic error buffer at 0x%lx\n",
+       if (!priv->catas_err.map) {
+               mlx4_warn(dev, "Failed to map internal error buffer at 0x%lx\n",
                          addr);
+               return;
+       }
 
+       priv->catas_err.timer.data     = (unsigned long) dev;
+       priv->catas_err.timer.function = poll_catas;
+       priv->catas_err.timer.expires  =
+               round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL);
+       add_timer(&priv->catas_err.timer);
 }
 
-void mlx4_unmap_catas_buf(struct mlx4_dev *dev)
+void mlx4_stop_catas_poll(struct mlx4_dev *dev)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
 
+       del_timer_sync(&priv->catas_err.timer);
+
        if (priv->catas_err.map)
                iounmap(priv->catas_err.map);
+
+       spin_lock_irq(&catas_lock);
+       list_del(&priv->catas_err.list);
+       spin_unlock_irq(&catas_lock);
+}
+
+int __init mlx4_catas_init(void)
+{
+       INIT_WORK(&catas_work, catas_reset);
+
+       catas_wq = create_singlethread_workqueue("mlx4_err");
+       if (!catas_wq)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void mlx4_catas_cleanup(void)
+{
+       destroy_workqueue(catas_wq);
 }
index 27a82cecd6930bc5fe7b7baf41f8388bbf882d73..2095c843fa15067dd25e67a82119d89e53c15368 100644 (file)
@@ -89,14 +89,12 @@ struct mlx4_eq_context {
                               (1ull << MLX4_EVENT_TYPE_PATH_MIG_FAILED)    | \
                               (1ull << MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \
                               (1ull << MLX4_EVENT_TYPE_WQ_ACCESS_ERROR)    | \
-                              (1ull << MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR)  | \
                               (1ull << MLX4_EVENT_TYPE_PORT_CHANGE)        | \
                               (1ull << MLX4_EVENT_TYPE_ECC_DETECT)         | \
                               (1ull << MLX4_EVENT_TYPE_SRQ_CATAS_ERROR)    | \
                               (1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE)    | \
                               (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT)          | \
                               (1ull << MLX4_EVENT_TYPE_CMD))
-#define MLX4_CATAS_EVENT_MASK  (1ull << MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR)
 
 struct mlx4_eqe {
        u8                      reserved1;
@@ -264,7 +262,7 @@ static irqreturn_t mlx4_interrupt(int irq, void *dev_ptr)
 
        writel(priv->eq_table.clr_mask, priv->eq_table.clr_int);
 
-       for (i = 0; i < MLX4_EQ_CATAS; ++i)
+       for (i = 0; i < MLX4_NUM_EQ; ++i)
                work |= mlx4_eq_int(dev, &priv->eq_table.eq[i]);
 
        return IRQ_RETVAL(work);
@@ -281,14 +279,6 @@ static irqreturn_t mlx4_msi_x_interrupt(int irq, void *eq_ptr)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t mlx4_catas_interrupt(int irq, void *dev_ptr)
-{
-       mlx4_handle_catas_err(dev_ptr);
-
-       /* MSI-X vectors always belong to us */
-       return IRQ_HANDLED;
-}
-
 static int mlx4_MAP_EQ(struct mlx4_dev *dev, u64 event_mask, int unmap,
                        int eq_num)
 {
@@ -490,11 +480,9 @@ static void mlx4_free_irqs(struct mlx4_dev *dev)
 
        if (eq_table->have_irq)
                free_irq(dev->pdev->irq, dev);
-       for (i = 0; i < MLX4_EQ_CATAS; ++i)
+       for (i = 0; i < MLX4_NUM_EQ; ++i)
                if (eq_table->eq[i].have_irq)
                        free_irq(eq_table->eq[i].irq, eq_table->eq + i);
-       if (eq_table->eq[MLX4_EQ_CATAS].have_irq)
-               free_irq(eq_table->eq[MLX4_EQ_CATAS].irq, dev);
 }
 
 static int __devinit mlx4_map_clr_int(struct mlx4_dev *dev)
@@ -598,32 +586,19 @@ int __devinit mlx4_init_eq_table(struct mlx4_dev *dev)
        if (dev->flags & MLX4_FLAG_MSI_X) {
                static const char *eq_name[] = {
                        [MLX4_EQ_COMP]  = DRV_NAME " (comp)",
-                       [MLX4_EQ_ASYNC] = DRV_NAME " (async)",
-                       [MLX4_EQ_CATAS] = DRV_NAME " (catas)"
+                       [MLX4_EQ_ASYNC] = DRV_NAME " (async)"
                };
 
-               err = mlx4_create_eq(dev, 1, MLX4_EQ_CATAS,
-                                    &priv->eq_table.eq[MLX4_EQ_CATAS]);
-               if (err)
-                       goto err_out_async;
-
-               for (i = 0; i < MLX4_EQ_CATAS; ++i) {
+               for (i = 0; i < MLX4_NUM_EQ; ++i) {
                        err = request_irq(priv->eq_table.eq[i].irq,
                                          mlx4_msi_x_interrupt,
                                          0, eq_name[i], priv->eq_table.eq + i);
                        if (err)
-                               goto err_out_catas;
+                               goto err_out_async;
 
                        priv->eq_table.eq[i].have_irq = 1;
                }
 
-               err = request_irq(priv->eq_table.eq[MLX4_EQ_CATAS].irq,
-                                 mlx4_catas_interrupt, 0,
-                                 eq_name[MLX4_EQ_CATAS], dev);
-               if (err)
-                       goto err_out_catas;
-
-               priv->eq_table.eq[MLX4_EQ_CATAS].have_irq = 1;
        } else {
                err = request_irq(dev->pdev->irq, mlx4_interrupt,
                                  IRQF_SHARED, DRV_NAME, dev);
@@ -639,22 +614,11 @@ int __devinit mlx4_init_eq_table(struct mlx4_dev *dev)
                mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n",
                           priv->eq_table.eq[MLX4_EQ_ASYNC].eqn, err);
 
-       for (i = 0; i < MLX4_EQ_CATAS; ++i)
+       for (i = 0; i < MLX4_NUM_EQ; ++i)
                eq_set_ci(&priv->eq_table.eq[i], 1);
 
-       if (dev->flags & MLX4_FLAG_MSI_X) {
-               err = mlx4_MAP_EQ(dev, MLX4_CATAS_EVENT_MASK, 0,
-                                 priv->eq_table.eq[MLX4_EQ_CATAS].eqn);
-               if (err)
-                       mlx4_warn(dev, "MAP_EQ for catas EQ %d failed (%d)\n",
-                                 priv->eq_table.eq[MLX4_EQ_CATAS].eqn, err);
-       }
-
        return 0;
 
-err_out_catas:
-       mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_CATAS]);
-
 err_out_async:
        mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_ASYNC]);
 
@@ -675,19 +639,13 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
        struct mlx4_priv *priv = mlx4_priv(dev);
        int i;
 
-       if (dev->flags & MLX4_FLAG_MSI_X)
-               mlx4_MAP_EQ(dev, MLX4_CATAS_EVENT_MASK, 1,
-                           priv->eq_table.eq[MLX4_EQ_CATAS].eqn);
-
        mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1,
                    priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
 
        mlx4_free_irqs(dev);
 
-       for (i = 0; i < MLX4_EQ_CATAS; ++i)
+       for (i = 0; i < MLX4_NUM_EQ; ++i)
                mlx4_free_eq(dev, &priv->eq_table.eq[i]);
-       if (dev->flags & MLX4_FLAG_MSI_X)
-               mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_CATAS]);
 
        mlx4_unmap_clr_int(dev);
 
index 9ae951bf6aa681116bc914db52699d62e6857d19..be5d9e90ccf2bd8a58766c2991abe004f326f119 100644 (file)
@@ -142,6 +142,7 @@ int mlx4_register_device(struct mlx4_dev *dev)
                mlx4_add_device(intf, priv);
 
        mutex_unlock(&intf_mutex);
+       mlx4_start_catas_poll(dev);
 
        return 0;
 }
@@ -151,6 +152,7 @@ void mlx4_unregister_device(struct mlx4_dev *dev)
        struct mlx4_priv *priv = mlx4_priv(dev);
        struct mlx4_interface *intf;
 
+       mlx4_stop_catas_poll(dev);
        mutex_lock(&intf_mutex);
 
        list_for_each_entry(intf, &intf_list, list)
index a4f2e0475a719e249358a54f5cd2c892ad5c12e0..4dc9dc19b7167a22bc69e8750aaccec6ccb0417e 100644 (file)
@@ -78,7 +78,7 @@ static const char mlx4_version[] __devinitdata =
 static struct mlx4_profile default_profile = {
        .num_qp         = 1 << 16,
        .num_srq        = 1 << 16,
-       .rdmarc_per_qp  = 4,
+       .rdmarc_per_qp  = 1 << 4,
        .num_cq         = 1 << 16,
        .num_mcg        = 1 << 13,
        .num_mpt        = 1 << 17,
@@ -583,13 +583,11 @@ static int __devinit mlx4_setup_hca(struct mlx4_dev *dev)
                goto err_pd_table_free;
        }
 
-       mlx4_map_catas_buf(dev);
-
        err = mlx4_init_eq_table(dev);
        if (err) {
                mlx4_err(dev, "Failed to initialize "
                         "event queue table, aborting.\n");
-               goto err_catas_buf;
+               goto err_mr_table_free;
        }
 
        err = mlx4_cmd_use_events(dev);
@@ -659,8 +657,7 @@ err_cmd_poll:
 err_eq_table_free:
        mlx4_cleanup_eq_table(dev);
 
-err_catas_buf:
-       mlx4_unmap_catas_buf(dev);
+err_mr_table_free:
        mlx4_cleanup_mr_table(dev);
 
 err_pd_table_free:
@@ -836,9 +833,6 @@ err_cleanup:
        mlx4_cleanup_cq_table(dev);
        mlx4_cmd_use_polling(dev);
        mlx4_cleanup_eq_table(dev);
-
-       mlx4_unmap_catas_buf(dev);
-
        mlx4_cleanup_mr_table(dev);
        mlx4_cleanup_pd_table(dev);
        mlx4_cleanup_uar_table(dev);
@@ -885,9 +879,6 @@ static void __devexit mlx4_remove_one(struct pci_dev *pdev)
                mlx4_cleanup_cq_table(dev);
                mlx4_cmd_use_polling(dev);
                mlx4_cleanup_eq_table(dev);
-
-               mlx4_unmap_catas_buf(dev);
-
                mlx4_cleanup_mr_table(dev);
                mlx4_cleanup_pd_table(dev);
 
@@ -908,6 +899,12 @@ static void __devexit mlx4_remove_one(struct pci_dev *pdev)
        }
 }
 
+int mlx4_restart_one(struct pci_dev *pdev)
+{
+       mlx4_remove_one(pdev);
+       return mlx4_init_one(pdev, NULL);
+}
+
 static struct pci_device_id mlx4_pci_table[] = {
        { PCI_VDEVICE(MELLANOX, 0x6340) }, /* MT25408 "Hermon" SDR */
        { PCI_VDEVICE(MELLANOX, 0x634a) }, /* MT25408 "Hermon" DDR */
@@ -930,6 +927,10 @@ static int __init mlx4_init(void)
 {
        int ret;
 
+       ret = mlx4_catas_init();
+       if (ret)
+               return ret;
+
        ret = pci_register_driver(&mlx4_driver);
        return ret < 0 ? ret : 0;
 }
@@ -937,6 +938,7 @@ static int __init mlx4_init(void)
 static void __exit mlx4_cleanup(void)
 {
        pci_unregister_driver(&mlx4_driver);
+       mlx4_catas_cleanup();
 }
 
 module_init(mlx4_init);
index d9c91a71fc873b71ba85bd8b242df9e830eb3972..be304a7c2c9163bee2178c24463bdd57b955045c 100644 (file)
@@ -39,6 +39,7 @@
 
 #include <linux/mutex.h>
 #include <linux/radix-tree.h>
+#include <linux/timer.h>
 
 #include <linux/mlx4/device.h>
 #include <linux/mlx4/doorbell.h>
@@ -67,7 +68,6 @@ enum {
 enum {
        MLX4_EQ_ASYNC,
        MLX4_EQ_COMP,
-       MLX4_EQ_CATAS,
        MLX4_NUM_EQ
 };
 
@@ -248,7 +248,8 @@ struct mlx4_mcg_table {
 
 struct mlx4_catas_err {
        u32 __iomem            *map;
-       int                     size;
+       struct timer_list       timer;
+       struct list_head        list;
 };
 
 struct mlx4_priv {
@@ -311,9 +312,11 @@ void mlx4_cleanup_qp_table(struct mlx4_dev *dev);
 void mlx4_cleanup_srq_table(struct mlx4_dev *dev);
 void mlx4_cleanup_mcg_table(struct mlx4_dev *dev);
 
-void mlx4_map_catas_buf(struct mlx4_dev *dev);
-void mlx4_unmap_catas_buf(struct mlx4_dev *dev);
-
+void mlx4_start_catas_poll(struct mlx4_dev *dev);
+void mlx4_stop_catas_poll(struct mlx4_dev *dev);
+int mlx4_catas_init(void);
+void mlx4_catas_cleanup(void);
+int mlx4_restart_one(struct pci_dev *pdev);
 int mlx4_register_device(struct mlx4_dev *dev);
 void mlx4_unregister_device(struct mlx4_dev *dev);
 void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_event type,
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 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 */
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 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 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 */
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 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 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 7b4aa4543c833b6f9b1e0f5eb3db5acafbaa8bdc..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: {
@@ -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:
@@ -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,
@@ -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 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 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 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 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 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 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 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 80deaaf1b7469aa4de8c9409521fc9eb355d0a77..9562a59b3703132302a01d8bd6e481345c001f21 100644 (file)
@@ -1149,6 +1149,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 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 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 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 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 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 b4796d8501403a9bf848704ff0a868da211c3352..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);
 }
 
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..641cfbc278d8534acbc7514bc4a5d3d31c255fec 100644 (file)
@@ -1012,13 +1012,14 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
 {
        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) {
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);
This page took 1.337764 seconds and 5 git commands to generate.