summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Luck <tony.luck@intel.com>2005-07-08 08:52:42 -0700
committerTony Luck <tony.luck@intel.com>2005-07-08 08:52:42 -0700
commit88c3cdfdde3cf87e1831265ea4246430bef34fc9 (patch)
treecaea510ffb2f81a5ea13b00ecb8a4146ad462048
parent2b2c3750330325ae5071582b5c4dbdf1c8bc1e51 (diff)
parenta92b7b80579fe68fe229892815c750f6652eb6a9 (diff)
Auto merge with /home/aegl/GIT/linus
-rw-r--r--Documentation/dvb/README.dvb-usb132
-rw-r--r--Documentation/dvb/bt8xx.txt79
-rw-r--r--Documentation/feature-removal-schedule.txt16
-rw-r--r--Documentation/infiniband/user_verbs.txt69
-rw-r--r--Documentation/power/video.txt1
-rw-r--r--MAINTAINERS7
-rw-r--r--Makefile6
-rw-r--r--arch/frv/defconfig627
-rw-r--r--arch/i386/kernel/cpu/common.c5
-rw-r--r--arch/i386/kernel/cpu/intel.c2
-rw-r--r--arch/i386/kernel/cpu/mtrr/generic.c22
-rw-r--r--arch/i386/kernel/cpu/mtrr/main.c76
-rw-r--r--arch/i386/kernel/cpu/mtrr/mtrr.h1
-rw-r--r--arch/i386/kernel/smpboot.c18
-rw-r--r--arch/i386/kernel/time.c2
-rw-r--r--arch/i386/kernel/timers/timer_hpet.c4
-rw-r--r--arch/i386/kernel/vmlinux.lds.S3
-rw-r--r--arch/i386/mm/ioremap.c6
-rw-r--r--arch/i386/power/cpu.c1
-rw-r--r--arch/m32r/kernel/setup_m32700ut.c55
-rw-r--r--arch/m32r/kernel/setup_mappi.c51
-rw-r--r--arch/m32r/kernel/setup_mappi2.c4
-rw-r--r--arch/m32r/kernel/setup_mappi3.c52
-rw-r--r--arch/m32r/kernel/setup_oaks32r.c5
-rw-r--r--arch/m32r/kernel/setup_opsput.c53
-rw-r--r--arch/ppc/platforms/pmac_cpufreq.c2
-rw-r--r--arch/ppc64/kernel/cputable.c365
-rw-r--r--arch/ppc64/kernel/head.S10
-rw-r--r--arch/ppc64/kernel/hvconsole.c51
-rw-r--r--arch/ppc64/kernel/iSeries_setup.c94
-rw-r--r--arch/ppc64/kernel/idle.c283
-rw-r--r--arch/ppc64/kernel/maple_setup.c3
-rw-r--r--arch/ppc64/kernel/misc.S6
-rw-r--r--arch/ppc64/kernel/pSeries_setup.c156
-rw-r--r--arch/ppc64/kernel/pmac_setup.c5
-rw-r--r--arch/ppc64/kernel/setup.c8
-rw-r--r--arch/ppc64/kernel/sys_ppc32.c54
-rw-r--r--arch/ppc64/kernel/sysfs.c14
-rw-r--r--arch/ppc64/kernel/vdso32/vdso32.lds.S4
-rw-r--r--arch/um/Kconfig6
-rw-r--r--arch/um/Kconfig_i38612
-rw-r--r--arch/um/Kconfig_x86_6412
-rw-r--r--arch/um/Makefile-i3862
-rw-r--r--arch/um/Makefile-x86_642
-rw-r--r--arch/um/defconfig58
-rw-r--r--arch/um/drivers/line.c37
-rw-r--r--arch/um/include/mem.h1
-rw-r--r--arch/um/include/registers.h1
-rw-r--r--arch/um/include/sysdep-i386/ptrace_user.h13
-rw-r--r--arch/um/include/sysdep-i386/stub.h65
-rw-r--r--arch/um/include/sysdep-x86_64/ptrace_user.h14
-rw-r--r--arch/um/include/sysdep-x86_64/stub.h58
-rw-r--r--arch/um/include/time_user.h1
-rw-r--r--arch/um/include/tlb.h30
-rw-r--r--arch/um/kernel/dyn.lds.S6
-rw-r--r--arch/um/kernel/physmem.c8
-rw-r--r--arch/um/kernel/process.c28
-rw-r--r--arch/um/kernel/skas/Makefile7
-rw-r--r--arch/um/kernel/skas/clone.c44
-rw-r--r--arch/um/kernel/skas/exec_kern.c2
-rw-r--r--arch/um/kernel/skas/include/mm_id.h17
-rw-r--r--arch/um/kernel/skas/include/mmu-skas.h7
-rw-r--r--arch/um/kernel/skas/include/skas.h16
-rw-r--r--arch/um/kernel/skas/include/stub-data.h18
-rw-r--r--arch/um/kernel/skas/mem.c6
-rw-r--r--arch/um/kernel/skas/mem_user.c225
-rw-r--r--arch/um/kernel/skas/mmu.c141
-rw-r--r--arch/um/kernel/skas/process.c216
-rw-r--r--arch/um/kernel/skas/process_kern.c33
-rw-r--r--arch/um/kernel/skas/tlb.c29
-rw-r--r--arch/um/kernel/time.c7
-rw-r--r--arch/um/kernel/tlb.c132
-rw-r--r--arch/um/kernel/tt/tlb.c4
-rw-r--r--arch/um/kernel/uml.lds.S7
-rw-r--r--arch/um/os-Linux/sys-i386/registers.c5
-rw-r--r--arch/um/os-Linux/sys-x86_64/registers.c5
-rw-r--r--arch/um/scripts/Makefile.rules5
-rw-r--r--arch/um/sys-i386/Makefile12
-rw-r--r--arch/um/sys-i386/stub.S8
-rw-r--r--arch/um/sys-i386/stub_segv.c30
-rw-r--r--arch/um/sys-x86_64/Makefile12
-rw-r--r--arch/um/sys-x86_64/stub.S15
-rw-r--r--arch/um/sys-x86_64/stub_segv.c31
-rw-r--r--arch/x86_64/kernel/setup.c4
-rw-r--r--arch/x86_64/kernel/suspend.c1
-rw-r--r--arch/x86_64/kernel/vmlinux.lds.S4
-rw-r--r--arch/xtensa/kernel/syscalls.c152
-rw-r--r--arch/xtensa/kernel/syscalls.h57
-rw-r--r--drivers/bluetooth/bluecard_cs.c7
-rw-r--r--drivers/bluetooth/bt3c_cs.c7
-rw-r--r--drivers/bluetooth/btuart_cs.c7
-rw-r--r--drivers/bluetooth/dtl1_cs.c7
-rw-r--r--drivers/char/Makefile2
-rw-r--r--drivers/char/hvc_console.c429
-rw-r--r--drivers/char/hvc_vio.c152
-rw-r--r--drivers/char/hvsi.c8
-rw-r--r--drivers/char/n_tty.c33
-rw-r--r--drivers/char/pcmcia/synclink_cs.c7
-rw-r--r--drivers/char/random.c2
-rw-r--r--drivers/char/sysrq.c2
-rw-r--r--drivers/cpufreq/cpufreq.c4
-rw-r--r--drivers/ide/legacy/ide-cs.c7
-rw-r--r--drivers/infiniband/Kconfig10
-rw-r--r--drivers/infiniband/core/Makefile5
-rw-r--r--drivers/infiniband/core/uverbs.h132
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c1006
-rw-r--r--drivers/infiniband/core/uverbs_main.c698
-rw-r--r--drivers/infiniband/core/uverbs_mem.c221
-rw-r--r--drivers/infiniband/core/verbs.c32
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cq.c76
-rw-r--r--drivers/infiniband/hw/mthca/mthca_dev.h6
-rw-r--r--drivers/infiniband/hw/mthca/mthca_main.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_memfree.c141
-rw-r--r--drivers/infiniband/hw/mthca/mthca_memfree.h14
-rw-r--r--drivers/infiniband/hw/mthca/mthca_pd.c24
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c330
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.h16
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c215
-rw-r--r--drivers/infiniband/hw/mthca/mthca_user.h81
-rw-r--r--drivers/infiniband/include/ib_user_verbs.h389
-rw-r--r--drivers/infiniband/include/ib_verbs.h124
-rw-r--r--drivers/isdn/hardware/avm/avm_cs.c7
-rw-r--r--drivers/isdn/hisax/avma1_cs.c7
-rw-r--r--drivers/isdn/hisax/elsa_cs.c7
-rw-r--r--drivers/isdn/hisax/sedlbauer_cs.c7
-rw-r--r--drivers/isdn/hisax/teles_cs.c7
-rw-r--r--drivers/md/dm-raid1.c1
-rw-r--r--drivers/media/common/saa7146_core.c13
-rw-r--r--drivers/media/dvb/Kconfig4
-rw-r--r--drivers/media/dvb/Makefile2
-rw-r--r--drivers/media/dvb/b2c2/Kconfig14
-rw-r--r--drivers/media/dvb/b2c2/Makefile2
-rw-r--r--drivers/media/dvb/b2c2/flexcop-common.h6
-rw-r--r--drivers/media/dvb/b2c2/flexcop-dma.c165
-rw-r--r--drivers/media/dvb/b2c2/flexcop-hw-filter.c12
-rw-r--r--drivers/media/dvb/b2c2/flexcop-misc.c12
-rw-r--r--drivers/media/dvb/b2c2/flexcop-pci.c122
-rw-r--r--drivers/media/dvb/b2c2/flexcop-reg.h548
-rw-r--r--drivers/media/dvb/b2c2/flexcop-usb.c2
-rw-r--r--drivers/media/dvb/b2c2/flexcop.c34
-rw-r--r--drivers/media/dvb/b2c2/flexcop.h1
-rw-r--r--drivers/media/dvb/b2c2/flexcop_ibi_value_be.h458
-rw-r--r--drivers/media/dvb/b2c2/flexcop_ibi_value_le.h458
-rw-r--r--drivers/media/dvb/b2c2/skystar2.c2644
-rw-r--r--drivers/media/dvb/bt8xx/dst.c233
-rw-r--r--drivers/media/dvb/bt8xx/dst_ca.c349
-rw-r--r--drivers/media/dvb/bt8xx/dst_common.h3
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c4
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c19
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c44
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h22
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig34
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile3
-rw-r--r--drivers/media/dvb/dvb-usb/a800.c10
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c295
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.h30
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mb.c62
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mc.c2
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.c73
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u-fe.c76
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u.c96
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u.h42
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-common.h4
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h10
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-init.c4
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c14
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-urb.c182
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb.h26
-rw-r--r--drivers/media/dvb/dvb-usb/nova-t-usb2.c2
-rw-r--r--drivers/media/dvb/dvb-usb/umt-010.c2
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045.c45
-rw-r--r--drivers/media/dvb/frontends/Kconfig13
-rw-r--r--drivers/media/dvb/frontends/Makefile2
-rw-r--r--drivers/media/dvb/frontends/cx22702.c29
-rw-r--r--drivers/media/dvb/frontends/cx22702.h5
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c85
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h6
-rw-r--r--drivers/media/dvb/frontends/l64781.c9
-rw-r--r--drivers/media/dvb/frontends/lgdt3302.c611
-rw-r--r--drivers/media/dvb/frontends/lgdt3302.h49
-rw-r--r--drivers/media/dvb/frontends/lgdt3302_priv.h72
-rw-r--r--drivers/media/dvb/frontends/s5h1420.c800
-rw-r--r--drivers/media/dvb/frontends/s5h1420.h41
-rw-r--r--drivers/media/dvb/frontends/stv0297.c8
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c235
-rw-r--r--drivers/media/dvb/frontends/tda1004x.h31
-rw-r--r--drivers/media/dvb/pluto2/Kconfig16
-rw-r--r--drivers/media/dvb/pluto2/Makefile3
-rw-r--r--drivers/media/dvb/pluto2/pluto2.c809
-rw-r--r--drivers/media/dvb/ttpci/Kconfig9
-rw-r--r--drivers/media/dvb/ttpci/av7110.c251
-rw-r--r--drivers/media/dvb/ttpci/av7110.h7
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.c220
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.h4
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.c395
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.h12
-rw-r--r--drivers/media/dvb/ttpci/av7110_ipack.c2
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c10
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c21
-rw-r--r--drivers/media/dvb/ttpci/budget.c99
-rw-r--r--drivers/media/dvb/ttusb-budget/Kconfig1
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c50
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusb_dec.c11
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusbdecfe.c14
-rw-r--r--drivers/media/video/Kconfig1
-rw-r--r--drivers/media/video/cx88/cx88-cards.c65
-rw-r--r--drivers/media/video/cx88/cx88-core.c19
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c66
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c3
-rw-r--r--drivers/media/video/cx88/cx88-input.c96
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c13
-rw-r--r--drivers/media/video/cx88/cx88-video.c59
-rw-r--r--drivers/media/video/cx88/cx88.h10
-rw-r--r--drivers/message/fusion/mptbase.c14
-rw-r--r--drivers/message/fusion/mptscsih.h2
-rw-r--r--drivers/message/i2o/config-osm.c2
-rw-r--r--drivers/mtd/maps/pcmciamtd.c7
-rw-r--r--drivers/net/pcmcia/3c574_cs.c7
-rw-r--r--drivers/net/pcmcia/3c589_cs.c7
-rw-r--r--drivers/net/pcmcia/axnet_cs.c7
-rw-r--r--drivers/net/pcmcia/com20020_cs.c7
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c7
-rw-r--r--drivers/net/pcmcia/ibmtr_cs.c7
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c7
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c7
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c6
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c7
-rw-r--r--drivers/net/skge.c4
-rw-r--r--drivers/net/sungem.c4
-rw-r--r--drivers/net/sungem_phy.c69
-rw-r--r--drivers/net/sungem_phy.h3
-rw-r--r--drivers/net/typhoon.c6
-rw-r--r--drivers/net/wireless/airo_cs.c7
-rw-r--r--drivers/net/wireless/atmel_cs.c17
-rw-r--r--drivers/net/wireless/netwave_cs.c7
-rw-r--r--drivers/net/wireless/orinoco_cs.c7
-rw-r--r--drivers/net/wireless/ray_cs.c7
-rw-r--r--drivers/net/wireless/wavelan_cs.c7
-rw-r--r--drivers/net/wireless/wavelan_cs.p.h1
-rw-r--r--drivers/net/wireless/wl3501_cs.c19
-rw-r--r--drivers/parport/parport_cs.c7
-rw-r--r--drivers/pci/pcie/portdrv_core.c6
-rw-r--r--drivers/pcmcia/Kconfig17
-rw-r--r--drivers/pcmcia/au1000_generic.h1
-rw-r--r--drivers/pcmcia/au1000_pb1x00.c1
-rw-r--r--drivers/pcmcia/au1000_xxs1500.c1
-rw-r--r--drivers/pcmcia/cardbus.c1
-rw-r--r--drivers/pcmcia/cs.c16
-rw-r--r--drivers/pcmcia/cs_internal.h16
-rw-r--r--drivers/pcmcia/ds.c99
-rw-r--r--drivers/pcmcia/hd64465_ss.c1
-rw-r--r--drivers/pcmcia/i82365.c9
-rw-r--r--drivers/pcmcia/m32r_cfc.c1
-rw-r--r--drivers/pcmcia/m32r_pcc.c1
-rw-r--r--drivers/pcmcia/pcmcia_compat.c48
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c27
-rw-r--r--drivers/pcmcia/pcmcia_resource.c143
-rw-r--r--drivers/pcmcia/sa1100_generic.c1
-rw-r--r--drivers/pcmcia/soc_common.h1
-rw-r--r--drivers/pcmcia/socket_sysfs.c1
-rw-r--r--drivers/pcmcia/tcic.c1
-rw-r--r--drivers/pcmcia/ti113x.h4
-rw-r--r--drivers/pcmcia/yenta_socket.c11
-rw-r--r--drivers/scsi/pcmcia/aha152x_stub.c7
-rw-r--r--drivers/scsi/pcmcia/fdomain_stub.c7
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c17
-rw-r--r--drivers/scsi/pcmcia/qlogic_stub.c4
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c5
-rw-r--r--drivers/serial/serial_cs.c7
-rw-r--r--drivers/telephony/ixj_pcmcia.c7
-rw-r--r--drivers/usb/host/sl811_cs.c7
-rw-r--r--drivers/video/fbsysfs.c2
-rw-r--r--drivers/video/logo/Kconfig5
-rw-r--r--drivers/video/logo/Makefile1
-rw-r--r--drivers/video/logo/logo.c5
-rw-r--r--drivers/video/logo/logo_m32r_clut224.ppm1292
-rw-r--r--drivers/video/s1d13xxxfb.c10
-rw-r--r--drivers/video/savage/savagefb_driver.c2
-rw-r--r--fs/Kconfig8
-rw-r--r--fs/autofs4/waitq.c4
-rw-r--r--fs/bio.c2
-rw-r--r--fs/buffer.c25
-rw-r--r--fs/dcookies.c6
-rw-r--r--fs/ext3/inode.c2
-rw-r--r--fs/hppfs/hppfs_kern.c7
-rw-r--r--fs/inode.c4
-rw-r--r--fs/ioprio.c4
-rw-r--r--fs/locks.c4
-rw-r--r--fs/namei.c2
-rw-r--r--fs/namespace.c130
-rw-r--r--fs/nfsd/nfs4proc.c6
-rw-r--r--fs/nfsd/nfs4recover.c32
-rw-r--r--fs/nfsd/nfs4state.c231
-rw-r--r--fs/nfsd/nfs4xdr.c15
-rw-r--r--fs/nfsd/vfs.c2
-rw-r--r--fs/super.c1
-rw-r--r--include/asm-alpha/pgtable.h2
-rw-r--r--include/asm-i386/mmzone.h24
-rw-r--r--include/asm-i386/processor.h8
-rw-r--r--include/asm-m32r/s1d13806.h199
-rw-r--r--include/asm-ppc/unistd.h2
-rw-r--r--include/asm-ppc64/cputable.h3
-rw-r--r--include/asm-ppc64/hvconsole.h17
-rw-r--r--include/asm-ppc64/machdep.h5
-rw-r--r--include/asm-ppc64/processor.h26
-rw-r--r--include/asm-ppc64/unistd.h6
-rw-r--r--include/asm-um/mmu_context.h6
-rw-r--r--include/asm-x86_64/proto.h7
-rw-r--r--include/asm-xtensa/unistd.h98
-rw-r--r--include/linux/buffer_head.h3
-rw-r--r--include/linux/cache.h6
-rw-r--r--include/linux/cpufreq.h2
-rw-r--r--include/linux/fs.h1
-rw-r--r--include/linux/gfp.h4
-rw-r--r--include/linux/ioprio.h3
-rw-r--r--include/linux/mount.h6
-rw-r--r--include/linux/namespace.h3
-rw-r--r--include/linux/nfsd/nfsd.h2
-rw-r--r--include/linux/nfsd/state.h9
-rw-r--r--include/linux/slab.h4
-rw-r--r--include/linux/string.h2
-rw-r--r--include/linux/swap.h2
-rw-r--r--include/linux/syscalls.h3
-rw-r--r--include/pcmcia/cs.h42
-rw-r--r--include/pcmcia/cs_types.h4
-rw-r--r--include/pcmcia/ds.h20
-rw-r--r--include/pcmcia/version.h3
-rw-r--r--ipc/compat.c1
-rw-r--r--kernel/power/disk.c10
-rw-r--r--kernel/power/process.c6
-rw-r--r--kernel/power/swsusp.c33
-rw-r--r--kernel/profile.c4
-rw-r--r--kernel/sched.c7
-rw-r--r--lib/radix-tree.c2
-rw-r--r--mm/mempool.c2
-rw-r--r--mm/oom_kill.c10
-rw-r--r--mm/page_alloc.c8
-rw-r--r--mm/slab.c12
-rw-r--r--net/sunrpc/xprt.c2
-rw-r--r--security/keys/keyring.c15
-rw-r--r--sound/oss/cs46xx.c6
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf.c20
-rw-r--r--sound/pcmcia/vx/vx_entry.c12
-rw-r--r--sound/pcmcia/vx/vxpocket.c1
344 files changed, 14701 insertions, 7136 deletions
diff --git a/Documentation/dvb/README.dvb-usb b/Documentation/dvb/README.dvb-usb
index c7ed01b9f8f..ac0797ea646 100644
--- a/Documentation/dvb/README.dvb-usb
+++ b/Documentation/dvb/README.dvb-usb
@@ -13,14 +13,17 @@ different way: With the help of a dvb-usb-framework.
The framework provides generic functions (mostly kernel API calls), such as:
- Transport Stream URB handling in conjunction with dvb-demux-feed-control
- (bulk and isoc (TODO) are supported)
+ (bulk and isoc are supported)
- registering the device for the DVB-API
- registering an I2C-adapter if applicable
- remote-control/input-device handling
- firmware requesting and loading (currently just for the Cypress USB
- controller)
+ controllers)
- other functions/methods which can be shared by several drivers (such as
functions for bulk-control-commands)
+- TODO: a I2C-chunker. It creates device-specific chunks of register-accesses
+ depending on length of a register and the number of values that can be
+ multi-written and multi-read.
The source code of the particular DVB USB devices does just the communication
with the device via the bus. The connection between the DVB-API-functionality
@@ -36,93 +39,18 @@ the dvb-usb-lib.
TODO: dynamic enabling and disabling of the pid-filter in regard to number of
feeds requested.
-Supported devices USB1.1
+Supported devices
========================
-Produced and reselled by Twinhan:
----------------------------------
-- TwinhanDTV USB-Ter DVB-T Device (VP7041)
- http://www.twinhan.com/product_terrestrial_3.asp
+See the LinuxTV DVB Wiki at www.linuxtv.org for a complete list of
+cards/drivers/firmwares:
-- TwinhanDTV Magic Box (VP7041e)
- http://www.twinhan.com/product_terrestrial_4.asp
-
-- HAMA DVB-T USB device
- http://www.hama.de/portal/articleId*110620/action*2598
-
-- CTS Portable (Chinese Television System) (2)
- http://www.2cts.tv/ctsportable/
-
-- Unknown USB DVB-T device with vendor ID Hyper-Paltek
-
-
-Produced and reselled by KWorld:
---------------------------------
-- KWorld V-Stream XPERT DTV DVB-T USB
- http://www.kworld.com.tw/en/product/DVBT-USB/DVBT-USB.html
-
-- JetWay DTV DVB-T USB
- http://www.jetway.com.tw/evisn/product/lcd-tv/DVT-USB/dtv-usb.htm
-
-- ADSTech Instant TV DVB-T USB
- http://www.adstech.com/products/PTV-333/intro/PTV-333_intro.asp?pid=PTV-333
-
-
-Others:
--------
-- Ultima Electronic/Artec T1 USB TVBOX (AN2135, AN2235, AN2235 with Panasonic Tuner)
- http://82.161.246.249/products-tvbox.html
-
-- Compro Videomate DVB-U2000 - DVB-T USB (2)
- http://www.comprousa.com/products/vmu2000.htm
-
-- Grandtec USB DVB-T
- http://www.grand.com.tw/
-
-- AVerMedia AverTV DVBT USB
- http://www.avermedia.com/
-
-- DiBcom USB DVB-T reference device (non-public)
-
-
-Supported devices USB2.0-only
-=============================
-- Twinhan MagicBox II
- http://www.twinhan.com/product_terrestrial_7.asp
-
-- TwinhanDTV Alpha
- http://www.twinhan.com/product_terrestrial_8.asp
-
-- DigitalNow TinyUSB 2 DVB-t Receiver
- http://www.digitalnow.com.au/DigitalNow%20tinyUSB2%20Specifications.html
-
-- Hanftek UMT-010
- http://www.globalsources.com/si/6008819757082/ProductDetail/Digital-TV/product_id-100046529
-
-
-Supported devices USB2.0 and USB1.1
-=============================
-- Typhoon/Yakumo/HAMA/Yuan DVB-T mobile USB2.0
- http://www.yakumo.de/produkte/index.php?pid=1&ag=DVB-T
- http://www.yuan.com.tw/en/products/vdo_ub300.html
- http://www.hama.de/portal/articleId*114663/action*2563
- http://www.anubisline.com/english/articlec.asp?id=50502&catid=002
-
-- Artec T1 USB TVBOX (FX2) (2)
-
-- Hauppauge WinTV NOVA-T USB2
- http://www.hauppauge.com/
-
-- KWorld/ADSTech Instant DVB-T USB2.0 (DiB3000M-B)
-
-- DiBcom USB2.0 DVB-T reference device (non-public)
-
-- AVerMedia AverTV A800 DVB-T USB2.0
-
-1) It is working almost - work-in-progress.
-2) No test reports received yet.
+http://www.linuxtv.org/wiki/index.php/DVB_USB
0. History & News:
+ 2005-06-30 - added support for WideView WT-220U (Thanks to Steve Chang)
+ 2005-05-30 - added basic isochronous support to the dvb-usb-framework
+ added support for Conexant Hybrid reference design and Nebula DigiTV USB
2005-04-17 - all dibusb devices ported to make use of the dvb-usb-framework
2005-04-02 - re-enabled and improved remote control code.
2005-03-31 - ported the Yakumo/Hama/Typhoon DVB-T USB2.0 device to dvb-usb.
@@ -137,7 +65,7 @@ Supported devices USB2.0 and USB1.1
2005-01-31 - distorted streaming is gone for USB1.1 devices
2005-01-13 - moved the mirrored pid_filter_table back to dvb-dibusb
- first almost working version for HanfTek UMT-010
- - found out, that Yakumo/HAMA/Typhoon are predessors of the HanfTek UMT-010
+ - found out, that Yakumo/HAMA/Typhoon are predecessors of the HanfTek UMT-010
2005-01-10 - refactoring completed, now everything is very delightful
- tuner quirks for some weird devices (Artec T1 AN2235 device has sometimes a
Panasonic Tuner assembled). Tunerprobing implemented. Thanks a lot to Gunnar Wittich.
@@ -187,25 +115,13 @@ Supported devices USB2.0 and USB1.1
1. How to use?
1.1. Firmware
-Most of the USB drivers need to download a firmware to start working.
-
-for USB1.1 (AN2135) you need: dvb-usb-dibusb-5.0.0.11.fw
-for USB2.0 HanfTek: dvb-usb-umt-010-02.fw
-for USB2.0 DiBcom: dvb-usb-dibusb-6.0.0.8.fw
-for USB2.0 AVerMedia AverTV DVB-T USB2: dvb-usb-avertv-a800-01.fw
-for USB2.0 TwinhanDTV Alpha/MagicBox II: dvb-usb-vp7045-01.fw
-
-The files can be found on http://www.linuxtv.org/download/firmware/ .
+Most of the USB drivers need to download a firmware to the device before start
+working.
-We do not have the permission (yet) to publish the following firmware-files.
-You'll need to extract them from the windows drivers.
+Have a look at the Wikipage for the DVB-USB-drivers to find out, which firmware
+you need for your device:
-You should be able to use "get_dvb_firmware dvb-usb" to get the firmware:
-
-for USB1.1 (AN2235) (a few Artec T1 devices): dvb-usb-dibusb-an2235-01.fw
-for USB2.0 Hauppauge: dvb-usb-nova-t-usb2-01.fw
-for USB2.0 ADSTech/Kworld USB2.0: dvb-usb-adstech-usb2-01.fw
-for USB2.0 Yakumo/Typhoon/Hama: dvb-usb-dtt200u-01.fw
+http://www.linuxtv.org/wiki/index.php/DVB_USB
1.2. Compiling
@@ -289,6 +205,9 @@ Patches, comments and suggestions are very very welcome.
Gunnar Wittich and Joachim von Caron for their trust for providing
root-shells on their machines to implement support for new devices.
+ Allan Third and Michael Hutchinson for their help to write the Nebula
+ digitv-driver.
+
Glen Harris for bringing up, that there is a new dibusb-device and Jiun-Kuei
Jung from AVerMedia who kindly provided a special firmware to get the device
up and running in Linux.
@@ -296,7 +215,12 @@ Patches, comments and suggestions are very very welcome.
Jennifer Chen, Jeff and Jack from Twinhan for kindly supporting by
writing the vp7045-driver.
- Some guys on the linux-dvb mailing list for encouraging me
+ Steve Chang from WideView for providing information for new devices and
+ firmware files.
+
+ Michael Paxton for submitting remote control keymaps.
+
+ Some guys on the linux-dvb mailing list for encouraging me.
Peter Schildmann >peter.schildmann-nospam-at-web.de< for his
user-level firmware loader, which saves a lot of time
@@ -305,4 +229,4 @@ Patches, comments and suggestions are very very welcome.
Ulf Hermenau for helping me out with traditional chinese.
André Smoktun and Christian Frömmel for supporting me with
- hardware and listening to my problems very patient.
+ hardware and listening to my problems very patiently.
diff --git a/Documentation/dvb/bt8xx.txt b/Documentation/dvb/bt8xx.txt
index 3a326079475..e6b8d05bc08 100644
--- a/Documentation/dvb/bt8xx.txt
+++ b/Documentation/dvb/bt8xx.txt
@@ -1,66 +1,55 @@
-How to get the Nebula, PCTV and Twinhan DST cards working
-=========================================================
+How to get the Nebula Electronics DigiTV, Pinnacle PCTV Sat, Twinhan DST + clones working
+=========================================================================================
-This class of cards has a bt878a as the PCI interface, and
-require the bttv driver.
+1) General information
+======================
-Please pay close attention to the warning about the bttv module
-options below for the DST card.
+This class of cards has a bt878a chip as the PCI interface.
+The different card drivers require the bttv driver to provide the means
+to access the i2c bus and the gpio pins of the bt8xx chipset.
-1) General informations
-=======================
+2) Compilation rules for Kernel >= 2.6.12
+=========================================
-These drivers require the bttv driver to provide the means to access
-the i2c bus and the gpio pins of the bt8xx chipset.
+Enable the following options:
-Because of this, you need to enable
"Device drivers" => "Multimedia devices"
- => "Video For Linux" => "BT848 Video For Linux"
-
-Furthermore you need to enable
+ => "Video For Linux" => "BT848 Video For Linux"
"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
- => "DVB for Linux" "DVB Core Support" "Nebula/Pinnacle PCTV/TwinHan PCI Cards"
+ => "DVB for Linux" "DVB Core Support" "Nebula/Pinnacle PCTV/TwinHan PCI Cards"
-2) Loading Modules
-==================
+3) Loading Modules, described by two approaches
+===============================================
In general you need to load the bttv driver, which will handle the gpio and
-i2c communication for us, plus the common dvb-bt8xx device driver.
-The frontends for Nebula (nxt6000), Pinnacle PCTV (cx24110) and
-TwinHan (dst) are loaded automatically by the dvb-bt8xx device driver.
+i2c communication for us, plus the common dvb-bt8xx device driver,
+which is called the backend.
+The frontends for Nebula DigiTV (nxt6000), Pinnacle PCTV Sat (cx24110),
+TwinHan DST + clones (dst and dst-ca) are loaded automatically by the backend.
+For further details about TwinHan DST + clones see /Documentation/dvb/ci.txt.
-3a) Nebula / Pinnacle PCTV
---------------------------
+3a) The manual approach
+-----------------------
- $ modprobe bttv (normally bttv is being loaded automatically by kmod)
- $ modprobe dvb-bt8xx (or just place dvb-bt8xx in /etc/modules for automatic loading)
+Loading modules:
+modprobe bttv
+modprobe dvb-bt8xx
+Unloading modules:
+modprobe -r dvb-bt8xx
+modprobe -r bttv
-3b) TwinHan and Clones
+3b) The automatic approach
--------------------------
- $ modprobe bttv i2c_hw=1 card=0x71
- $ modprobe dvb-bt8xx
- $ modprobe dst
-
-The value 0x71 will override the PCI type detection for dvb-bt8xx,
-which is necessary for TwinHan cards.
-
-If you're having an older card (blue color circuit) and card=0x71 locks
-your machine, try using 0x68, too. If that does not work, ask on the
-mailing list.
-
-The DST module takes a couple of useful parameters:
+If not already done by installation, place a line either in
+/etc/modules.conf or in /etc/modprobe.conf containing this text:
+alias char-major-81 bttv
-a. verbose takes values 0 to 5. These values control the verbosity level.
-b. debug takes values 0 and 1. You can either disable or enable debugging.
-c. dst_addons takes values 0 and 0x20:
-- A value of 0 means it is a FTA card.
-- A value of 0x20 means it has a Conditional Access slot.
+Then place a line in /etc/modules containing this text:
+dvb-bt8xx
-The autodetected values are determined by the "response string"
-of the card, which you can see in your logs:
-e.g.: dst_get_device_id: Recognize [DSTMCI]
+Reboot your system and have fun!
--
Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham, Uwe Bugla
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 1d227ee3792..12dde43fe65 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -119,3 +119,19 @@ Why: Match the other drivers' name for the same function, duplicate names
will be available until removal of old names.
Who: Grant Coady <gcoady@gmail.com>
+---------------------------
+
+What: PCMCIA control ioctl (needed for pcmcia-cs [cardmgr, cardctl])
+When: November 2005
+Files: drivers/pcmcia/: pcmcia_ioctl.c
+Why: With the 16-bit PCMCIA subsystem now behaving (almost) like a
+ normal hotpluggable bus, and with it using the default kernel
+ infrastructure (hotplug, driver core, sysfs) keeping the PCMCIA
+ control ioctl needed by cardmgr and cardctl from pcmcia-cs is
+ unnecessary, and makes further cleanups and integration of the
+ PCMCIA subsystem into the Linux kernel device driver model more
+ difficult. The features provided by cardmgr and cardctl are either
+ handled by the kernel itself now or are available in the new
+ pcmciautils package available at
+ http://kernel.org/pub/linux/utils/kernel/pcmcia/
+Who: Dominik Brodowski <linux@brodo.de>
diff --git a/Documentation/infiniband/user_verbs.txt b/Documentation/infiniband/user_verbs.txt
new file mode 100644
index 00000000000..f847501e50b
--- /dev/null
+++ b/Documentation/infiniband/user_verbs.txt
@@ -0,0 +1,69 @@
+USERSPACE VERBS ACCESS
+
+ The ib_uverbs module, built by enabling CONFIG_INFINIBAND_USER_VERBS,
+ enables direct userspace access to IB hardware via "verbs," as
+ described in chapter 11 of the InfiniBand Architecture Specification.
+
+ To use the verbs, the libibverbs library, available from
+ <http://openib.org/>, is required. libibverbs contains a
+ device-independent API for using the ib_uverbs interface.
+ libibverbs also requires appropriate device-dependent kernel and
+ userspace driver for your InfiniBand hardware. For example, to use
+ a Mellanox HCA, you will need the ib_mthca kernel module and the
+ libmthca userspace driver be installed.
+
+User-kernel communication
+
+ Userspace communicates with the kernel for slow path, resource
+ management operations via the /dev/infiniband/uverbsN character
+ devices. Fast path operations are typically performed by writing
+ directly to hardware registers mmap()ed into userspace, with no
+ system call or context switch into the kernel.
+
+ Commands are sent to the kernel via write()s on these device files.
+ The ABI is defined in drivers/infiniband/include/ib_user_verbs.h.
+ The structs for commands that require a response from the kernel
+ contain a 64-bit field used to pass a pointer to an output buffer.
+ Status is returned to userspace as the return value of the write()
+ system call.
+
+Resource management
+
+ Since creation and destruction of all IB resources is done by
+ commands passed through a file descriptor, the kernel can keep track
+ of which resources are attached to a given userspace context. The
+ ib_uverbs module maintains idr tables that are used to translate
+ between kernel pointers and opaque userspace handles, so that kernel
+ pointers are never exposed to userspace and userspace cannot trick
+ the kernel into following a bogus pointer.
+
+ This also allows the kernel to clean up when a process exits and
+ prevent one process from touching another process's resources.
+
+Memory pinning
+
+ Direct userspace I/O requires that memory regions that are potential
+ I/O targets be kept resident at the same physical address. The
+ ib_uverbs module manages pinning and unpinning memory regions via
+ get_user_pages() and put_page() calls. It also accounts for the
+ amount of memory pinned in the process's locked_vm, and checks that
+ unprivileged processes do not exceed their RLIMIT_MEMLOCK limit.
+
+ Pages that are pinned multiple times are counted each time they are
+ pinned, so the value of locked_vm may be an overestimate of the
+ number of pages pinned by a process.
+
+/dev files
+
+ To create the appropriate character device files automatically with
+ udev, a rule like
+
+ KERNEL="uverbs*", NAME="infiniband/%k"
+
+ can be used. This will create device nodes named
+
+ /dev/infiniband/uverbs0
+
+ and so on. Since the InfiniBand userspace verbs should be safe for
+ use by non-privileged processes, it may be useful to add an
+ appropriate MODE or GROUP to the udev rule.
diff --git a/Documentation/power/video.txt b/Documentation/power/video.txt
index 881a37e3eeb..7a4a5036d12 100644
--- a/Documentation/power/video.txt
+++ b/Documentation/power/video.txt
@@ -117,6 +117,7 @@ IBM Thinkpad X40 Type 2371-7JG s3_bios,s3_mode (4)
Medion MD4220 ??? (*)
Samsung P35 vbetool needed (6)
Sharp PC-AR10 (ATI rage) none (1)
+Sony Vaio PCG-C1VRX/K s3_bios (2)
Sony Vaio PCG-F403 ??? (*)
Sony Vaio PCG-N505SN ??? (*)
Sony Vaio vgn-s260 X or boot-radeon can init it (5)
diff --git a/MAINTAINERS b/MAINTAINERS
index 302b3196000..37fb1e2ec68 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -370,6 +370,10 @@ W: http://www.thekelleys.org.uk/atmel
W: http://atmelwlandriver.sourceforge.net/
S: Maintained
+AUDIT SUBSYSTEM
+L: linux-audit@redhat.com (subscribers-only)
+S: Maintained
+
AX.25 NETWORK LAYER
P: Ralf Baechle
M: ralf@linux-mips.org
@@ -1803,8 +1807,9 @@ M: greg@kroah.com
S: Maintained
PCMCIA SUBSYSTEM
+P: Linux PCMCIA Team
L: http://lists.infradead.org/mailman/listinfo/linux-pcmcia
-S: Unmaintained
+S: Maintained
PCNET32 NETWORK DRIVER
P: Thomas Bogendörfer
diff --git a/Makefile b/Makefile
index 278d50992c7..9cf07e7b9f8 100644
--- a/Makefile
+++ b/Makefile
@@ -792,6 +792,9 @@ export CPPFLAGS_vmlinux.lds += -P -C -U$(ARCH)
$(Q)$(MAKE) $(build)=$(@D) $@
%.o: %.c scripts FORCE
$(Q)$(MAKE) $(build)=$(@D) $@
+%.ko: scripts FORCE
+ $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) $(build)=$(@D) $(@:.ko=.o)
+ $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost
%/: scripts prepare FORCE
$(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) $(build)=$(@D)
%.lst: %.c scripts FORCE
@@ -1033,6 +1036,7 @@ help:
@echo ' modules_install - Install all modules'
@echo ' dir/ - Build all files in dir and below'
@echo ' dir/file.[ois] - Build specified target only'
+ @echo ' dir/file.ko - Build module including final link'
@echo ' rpm - Build a kernel as an RPM package'
@echo ' tags/TAGS - Generate tags file for editors'
@echo ' cscope - Generate cscope index'
@@ -1149,7 +1153,7 @@ endif # KBUILD_EXTMOD
#(which is the most common case IMHO) to avoid unneeded clutter in the big tags file.
#Adding $(srctree) adds about 20M on i386 to the size of the output file!
-ifeq ($(KBUILD_OUTPUT),)
+ifeq ($(src),$(obj))
__srctree =
else
__srctree = $(srctree)/
diff --git a/arch/frv/defconfig b/arch/frv/defconfig
new file mode 100644
index 00000000000..b6e4ca5efb5
--- /dev/null
+++ b/arch/frv/defconfig
@@ -0,0 +1,627 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11.8
+# Fri May 13 17:16:03 2005
+#
+CONFIG_FRV=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_GENERIC_CALIBRATE_DELAY is not set
+# CONFIG_GENERIC_HARDIRQS is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_KOBJECT_UEVENT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Fujitsu FR-V system setup
+#
+CONFIG_MMU=y
+CONFIG_FRV_OUTOFLINE_ATOMIC_OPS=y
+CONFIG_HIGHMEM=y
+CONFIG_HIGHPTE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_FRV_DEFL_CACHE_WBACK is not set
+# CONFIG_FRV_DEFL_CACHE_WBEHIND is not set
+CONFIG_FRV_DEFL_CACHE_WTHRU=y
+# CONFIG_FRV_DEFL_CACHE_DISABLED is not set
+
+#
+# CPU core support
+#
+CONFIG_CPU_FR451=y
+CONFIG_CPU_FR451_COMPILE=y
+CONFIG_FRV_L1_CACHE_SHIFT=5
+CONFIG_MB93091_VDK=y
+# CONFIG_MB93093_PDK is not set
+CONFIG_MB93090_MB00=y
+# CONFIG_MB93091_NO_MB is not set
+# CONFIG_GPREL_DATA_8 is not set
+CONFIG_GPREL_DATA_4=y
+# CONFIG_GPREL_DATA_NONE is not set
+CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+# CONFIG_PCI_NAMES is not set
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Executable formats
+#
+# CONFIG_BINFMT_ELF is not set
+CONFIG_BINFMT_ELF_FDPIC=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+# CONFIG_FORK_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_KGDBOE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+CONFIG_NE2K_PCI=y
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISER4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_FRAME_POINTER is not set
+# CONFIG_EARLY_PRINTK is not set
+CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_GDBSTUB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index 2203a9d2021..4553ffd94b1 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -435,6 +435,11 @@ void __devinit identify_cpu(struct cpuinfo_x86 *c)
if (c == &boot_cpu_data)
sysenter_setup();
enable_sep_cpu();
+
+ if (c == &boot_cpu_data)
+ mtrr_bp_init();
+ else
+ mtrr_ap_init();
}
#ifdef CONFIG_X86_HT
diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
index 96a75d04583..a2c33c1a46c 100644
--- a/arch/i386/kernel/cpu/intel.c
+++ b/arch/i386/kernel/cpu/intel.c
@@ -25,7 +25,7 @@ extern int trap_init_f00f_bug(void);
/*
* Alignment at which movsl is preferred for bulk memory copies.
*/
-struct movsl_mask movsl_mask;
+struct movsl_mask movsl_mask __read_mostly;
#endif
void __devinit early_intel_workaround(struct cpuinfo_x86 *c)
diff --git a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c
index 64d91f73a0a..169ac8e0db6 100644
--- a/arch/i386/kernel/cpu/mtrr/generic.c
+++ b/arch/i386/kernel/cpu/mtrr/generic.c
@@ -67,13 +67,6 @@ void __init get_mtrr_state(void)
mtrr_state.enabled = (lo & 0xc00) >> 10;
}
-/* Free resources associated with a struct mtrr_state */
-void __init finalize_mtrr_state(void)
-{
- kfree(mtrr_state.var_ranges);
- mtrr_state.var_ranges = NULL;
-}
-
/* Some BIOS's are fucked and don't set all MTRRs the same! */
void __init mtrr_state_warn(void)
{
@@ -334,6 +327,9 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base,
*/
{
unsigned long flags;
+ struct mtrr_var_range *vr;
+
+ vr = &mtrr_state.var_ranges[reg];
local_irq_save(flags);
prepare_set();
@@ -342,11 +338,15 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base,
/* The invalid bit is kept in the mask, so we simply clear the
relevant mask register to disable a range. */
mtrr_wrmsr(MTRRphysMask_MSR(reg), 0, 0);
+ memset(vr, 0, sizeof(struct mtrr_var_range));
} else {
- mtrr_wrmsr(MTRRphysBase_MSR(reg), base << PAGE_SHIFT | type,
- (base & size_and_mask) >> (32 - PAGE_SHIFT));
- mtrr_wrmsr(MTRRphysMask_MSR(reg), -size << PAGE_SHIFT | 0x800,
- (-size & size_and_mask) >> (32 - PAGE_SHIFT));
+ vr->base_lo = base << PAGE_SHIFT | type;
+ vr->base_hi = (base & size_and_mask) >> (32 - PAGE_SHIFT);
+ vr->mask_lo = -size << PAGE_SHIFT | 0x800;
+ vr->mask_hi = (-size & size_and_mask) >> (32 - PAGE_SHIFT);
+
+ mtrr_wrmsr(MTRRphysBase_MSR(reg), vr->base_lo, vr->base_hi);
+ mtrr_wrmsr(MTRRphysMask_MSR(reg), vr->mask_lo, vr->mask_hi);
}
post_set();
diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
index d66b09e0c82..764cac64e21 100644
--- a/arch/i386/kernel/cpu/mtrr/main.c
+++ b/arch/i386/kernel/cpu/mtrr/main.c
@@ -332,6 +332,8 @@ int mtrr_add_page(unsigned long base, unsigned long size,
error = -EINVAL;
+ /* No CPU hotplug when we change MTRR entries */
+ lock_cpu_hotplug();
/* Search for existing MTRR */
down(&main_lock);
for (i = 0; i < num_var_ranges; ++i) {
@@ -372,6 +374,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
error = i;
out:
up(&main_lock);
+ unlock_cpu_hotplug();
return error;
}
@@ -461,6 +464,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
return -ENXIO;
max = num_var_ranges;
+ /* No CPU hotplug when we change MTRR entries */
+ lock_cpu_hotplug();
down(&main_lock);
if (reg < 0) {
/* Search for existing MTRR */
@@ -501,6 +506,7 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
error = reg;
out:
up(&main_lock);
+ unlock_cpu_hotplug();
return error;
}
/**
@@ -544,21 +550,9 @@ static void __init init_ifs(void)
centaur_init_mtrr();
}
-static void __init init_other_cpus(void)
-{
- if (use_intel())
- get_mtrr_state();
-
- /* bring up the other processors */
- set_mtrr(~0U,0,0,0);
-
- if (use_intel()) {
- finalize_mtrr_state();
- mtrr_state_warn();
- }
-}
-
-
+/* The suspend/resume methods are only for CPU without MTRR. CPU using generic
+ * MTRR driver doesn't require this
+ */
struct mtrr_value {
mtrr_type ltype;
unsigned long lbase;
@@ -611,13 +605,13 @@ static struct sysdev_driver mtrr_sysdev_driver = {
/**
- * mtrr_init - initialize mtrrs on the boot CPU
+ * mtrr_bp_init - initialize mtrrs on the boot CPU
*
* This needs to be called early; before any of the other CPUs are
* initialized (i.e. before smp_init()).
*
*/
-static int __init mtrr_init(void)
+void __init mtrr_bp_init(void)
{
init_ifs();
@@ -674,12 +668,48 @@ static int __init mtrr_init(void)
if (mtrr_if) {
set_num_var_ranges();
init_table();
- init_other_cpus();
-
- return sysdev_driver_register(&cpu_sysdev_class,
- &mtrr_sysdev_driver);
+ if (use_intel())
+ get_mtrr_state();
}
- return -ENXIO;
}
-subsys_initcall(mtrr_init);
+void mtrr_ap_init(void)
+{
+ unsigned long flags;
+
+ if (!mtrr_if || !use_intel())
+ return;
+ /*
+ * Ideally we should hold main_lock here to avoid mtrr entries changed,
+ * but this routine will be called in cpu boot time, holding the lock
+ * breaks it. This routine is called in two cases: 1.very earily time
+ * of software resume, when there absolutely isn't mtrr entry changes;
+ * 2.cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug lock to
+ * prevent mtrr entry changes
+ */
+ local_irq_save(flags);
+
+ mtrr_if->set_all();
+
+ local_irq_restore(flags);
+}
+
+static int __init mtrr_init_finialize(void)
+{
+ if (!mtrr_if)
+ return 0;
+ if (use_intel())
+ mtrr_state_warn();
+ else {
+ /* The CPUs haven't MTRR and seemes not support SMP. They have
+ * specific drivers, we use a tricky method to support
+ * suspend/resume for them.
+ * TBD: is there any system with such CPU which supports
+ * suspend/resume? if no, we should remove the code.
+ */
+ sysdev_driver_register(&cpu_sysdev_class,
+ &mtrr_sysdev_driver);
+ }
+ return 0;
+}
+subsys_initcall(mtrr_init_finialize);
diff --git a/arch/i386/kernel/cpu/mtrr/mtrr.h b/arch/i386/kernel/cpu/mtrr/mtrr.h
index de135124559..99c9f268204 100644
--- a/arch/i386/kernel/cpu/mtrr/mtrr.h
+++ b/arch/i386/kernel/cpu/mtrr/mtrr.h
@@ -91,7 +91,6 @@ extern struct mtrr_ops * mtrr_if;
extern unsigned int num_var_ranges;
-void finalize_mtrr_state(void);
void mtrr_state_warn(void);
char *mtrr_attrib_to_str(int x);
void mtrr_wrmsr(unsigned, unsigned, unsigned);
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index d66bf489a2e..8ac8e9fd561 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -68,21 +68,21 @@ EXPORT_SYMBOL(smp_num_siblings);
#endif
/* Package ID of each logical CPU */
-int phys_proc_id[NR_CPUS] = {[0 ... NR_CPUS-1] = BAD_APICID};
+int phys_proc_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
EXPORT_SYMBOL(phys_proc_id);
/* Core ID of each logical CPU */
-int cpu_core_id[NR_CPUS] = {[0 ... NR_CPUS-1] = BAD_APICID};
+int cpu_core_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
EXPORT_SYMBOL(cpu_core_id);
-cpumask_t cpu_sibling_map[NR_CPUS];
+cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
EXPORT_SYMBOL(cpu_sibling_map);
-cpumask_t cpu_core_map[NR_CPUS];
+cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
EXPORT_SYMBOL(cpu_core_map);
/* bitmap of online cpus */
-cpumask_t cpu_online_map;
+cpumask_t cpu_online_map __read_mostly;
EXPORT_SYMBOL(cpu_online_map);
cpumask_t cpu_callin_map;
@@ -100,7 +100,7 @@ static int __devinitdata tsc_sync_disabled;
struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
EXPORT_SYMBOL(cpu_data);
-u8 x86_cpu_to_apicid[NR_CPUS] =
+u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly =
{ [0 ... NR_CPUS-1] = 0xff };
EXPORT_SYMBOL(x86_cpu_to_apicid);
@@ -550,10 +550,10 @@ extern struct {
#ifdef CONFIG_NUMA
/* which logical CPUs are on which nodes */
-cpumask_t node_2_cpu_mask[MAX_NUMNODES] =
+cpumask_t node_2_cpu_mask[MAX_NUMNODES] __read_mostly =
{ [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE };
/* which node each logical CPU is on */
-int cpu_2_node[NR_CPUS] = { [0 ... NR_CPUS-1] = 0 };
+int cpu_2_node[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = 0 };
EXPORT_SYMBOL(cpu_2_node);
/* set up a mapping between cpu and node. */
@@ -581,7 +581,7 @@ static inline void unmap_cpu_to_node(int cpu)
#endif /* CONFIG_NUMA */
-u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
+u8 cpu_2_logical_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
static void map_cpu_to_logical_apicid(void)
{
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index 2854c357377..0ee9dee8af0 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -91,7 +91,7 @@ EXPORT_SYMBOL(rtc_lock);
DEFINE_SPINLOCK(i8253_lock);
EXPORT_SYMBOL(i8253_lock);
-struct timer_opts *cur_timer = &timer_none;
+struct timer_opts *cur_timer __read_mostly = &timer_none;
/*
* This is a special lock that is owned by the CPU and holds the index
diff --git a/arch/i386/kernel/timers/timer_hpet.c b/arch/i386/kernel/timers/timer_hpet.c
index d766e0963ac..ef8dac5dd33 100644
--- a/arch/i386/kernel/timers/timer_hpet.c
+++ b/arch/i386/kernel/timers/timer_hpet.c
@@ -18,7 +18,7 @@
#include "mach_timer.h"
#include <asm/hpet.h>
-static unsigned long hpet_usec_quotient; /* convert hpet clks to usec */
+static unsigned long __read_mostly hpet_usec_quotient; /* convert hpet clks to usec */
static unsigned long tsc_hpet_quotient; /* convert tsc to hpet clks */
static unsigned long hpet_last; /* hpet counter value at last tick*/
static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */
@@ -180,7 +180,7 @@ static int __init init_hpet(char* override)
/************************************************************/
/* tsc timer_opts struct */
-static struct timer_opts timer_hpet = {
+static struct timer_opts timer_hpet __read_mostly = {
.name = "hpet",
.mark_offset = mark_offset_hpet,
.get_offset = get_offset_hpet,
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
index 7e01a528a83..761972f8cb6 100644
--- a/arch/i386/kernel/vmlinux.lds.S
+++ b/arch/i386/kernel/vmlinux.lds.S
@@ -57,6 +57,9 @@ SECTIONS
*(.data.cacheline_aligned)
}
+ /* rarely changed data like cpu maps */
+ . = ALIGN(32);
+ .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { *(.data.read_mostly) }
_edata = .; /* End of data section */
. = ALIGN(THREAD_SIZE); /* init_task */
diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c
index 6b25afc933b..f379b8d6755 100644
--- a/arch/i386/mm/ioremap.c
+++ b/arch/i386/mm/ioremap.c
@@ -228,7 +228,8 @@ EXPORT_SYMBOL(ioremap_nocache);
void iounmap(volatile void __iomem *addr)
{
struct vm_struct *p;
- if ((void __force *) addr <= high_memory)
+
+ if ((void __force *)addr <= high_memory)
return;
/*
@@ -241,9 +242,10 @@ void iounmap(volatile void __iomem *addr)
return;
write_lock(&vmlist_lock);
- p = __remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr));
+ p = __remove_vm_area((void *)(PAGE_MASK & (unsigned long __force)addr));
if (!p) {
printk(KERN_WARNING "iounmap: bad address %p\n", addr);
+ dump_stack();
goto out_unlock;
}
diff --git a/arch/i386/power/cpu.c b/arch/i386/power/cpu.c
index 0e6b45b6125..c547c1af6fa 100644
--- a/arch/i386/power/cpu.c
+++ b/arch/i386/power/cpu.c
@@ -137,6 +137,7 @@ void __restore_processor_state(struct saved_context *ctxt)
fix_processor_context();
do_fpu_end();
+ mtrr_ap_init();
}
void restore_processor_state(void)
diff --git a/arch/m32r/kernel/setup_m32700ut.c b/arch/m32r/kernel/setup_m32700ut.c
index b014e2c1e52..a146b24a556 100644
--- a/arch/m32r/kernel/setup_m32700ut.c
+++ b/arch/m32r/kernel/setup_m32700ut.c
@@ -3,8 +3,8 @@
*
* Setup routines for Renesas M32700UT Board
*
- * Copyright (c) 2002 Hiroyuki Kondo, Hirokazu Takata,
- * Hitoshi Yamamoto, Takeo Takahashi
+ * Copyright (c) 2002-2005 Hiroyuki Kondo, Hirokazu Takata,
+ * Hitoshi Yamamoto, Takeo Takahashi
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file "COPYING" in the main directory of this
@@ -435,7 +435,7 @@ void __init init_IRQ(void)
icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
enable_m32700ut_irq(M32R_IRQ_INT2);
-//#if defined(CONFIG_VIDEO_M32R_AR)
+#if defined(CONFIG_VIDEO_M32R_AR)
/*
* INT3# is used for AR
*/
@@ -445,9 +445,11 @@ void __init init_IRQ(void)
irq_desc[M32R_IRQ_INT3].depth = 1;
icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
disable_m32700ut_irq(M32R_IRQ_INT3);
-//#endif /* CONFIG_VIDEO_M32R_AR */
+#endif /* CONFIG_VIDEO_M32R_AR */
}
+#if defined(CONFIG_SMC91X)
+
#define LAN_IOSTART 0x300
#define LAN_IOEND 0x320
static struct resource smc91x_resources[] = {
@@ -469,10 +471,55 @@ static struct platform_device smc91x_device = {
.num_resources = ARRAY_SIZE(smc91x_resources),
.resource = smc91x_resources,
};
+#endif
+
+#if defined(CONFIG_FB_S1D13XXX)
+
+#include <video/s1d13xxxfb.h>
+#include <asm/s1d13806.h>
+
+static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
+ .initregs = s1d13xxxfb_initregs,
+ .initregssize = ARRAY_SIZE(s1d13xxxfb_initregs),
+ .platform_init_video = NULL,
+#ifdef CONFIG_PM
+ .platform_suspend_video = NULL,
+ .platform_resume_video = NULL,
+#endif
+};
+
+static struct resource s1d13xxxfb_resources[] = {
+ [0] = {
+ .start = 0x10600000UL,
+ .end = 0x1073FFFFUL,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0x10400000UL,
+ .end = 0x104001FFUL,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device s1d13xxxfb_device = {
+ .name = S1D_DEVICENAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &s1d13xxxfb_data,
+ },
+ .num_resources = ARRAY_SIZE(s1d13xxxfb_resources),
+ .resource = s1d13xxxfb_resources,
+};
+#endif
static int __init platform_init(void)
{
+#if defined(CONFIG_SMC91X)
platform_device_register(&smc91x_device);
+#endif
+#if defined(CONFIG_FB_S1D13XXX)
+ platform_device_register(&s1d13xxxfb_device);
+#endif
return 0;
}
arch_initcall(platform_init);
diff --git a/arch/m32r/kernel/setup_mappi.c b/arch/m32r/kernel/setup_mappi.c
index aaf8e569b93..4e709809efc 100644
--- a/arch/m32r/kernel/setup_mappi.c
+++ b/arch/m32r/kernel/setup_mappi.c
@@ -3,14 +3,15 @@
*
* Setup routines for Renesas MAPPI Board
*
- * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata,
- * Hitoshi Yamamoto
+ * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
+ * Hitoshi Yamamoto
*/
#include <linux/config.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/device.h>
#include <asm/system.h>
#include <asm/m32r.h>
@@ -158,3 +159,49 @@ void __init init_IRQ(void)
disable_mappi_irq(M32R_IRQ_INT2);
#endif /* CONFIG_M32RPCC */
}
+
+#if defined(CONFIG_FB_S1D13XXX)
+
+#include <video/s1d13xxxfb.h>
+#include <asm/s1d13806.h>
+
+static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
+ .initregs = s1d13xxxfb_initregs,
+ .initregssize = ARRAY_SIZE(s1d13xxxfb_initregs),
+ .platform_init_video = NULL,
+#ifdef CONFIG_PM
+ .platform_suspend_video = NULL,
+ .platform_resume_video = NULL,
+#endif
+};
+
+static struct resource s1d13xxxfb_resources[] = {
+ [0] = {
+ .start = 0x10200000UL,
+ .end = 0x1033FFFFUL,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0x10000000UL,
+ .end = 0x100001FFUL,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device s1d13xxxfb_device = {
+ .name = S1D_DEVICENAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &s1d13xxxfb_data,
+ },
+ .num_resources = ARRAY_SIZE(s1d13xxxfb_resources),
+ .resource = s1d13xxxfb_resources,
+};
+
+static int __init platform_init(void)
+{
+ platform_device_register(&s1d13xxxfb_device);
+ return 0;
+}
+arch_initcall(platform_init);
+#endif
diff --git a/arch/m32r/kernel/setup_mappi2.c b/arch/m32r/kernel/setup_mappi2.c
index 38d5e9a4142..a1d801598aa 100644
--- a/arch/m32r/kernel/setup_mappi2.c
+++ b/arch/m32r/kernel/setup_mappi2.c
@@ -3,8 +3,8 @@
*
* Setup routines for Renesas MAPPI-II(M3A-ZA36) Board
*
- * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata,
- * Hitoshi Yamamoto, Mamoru Sakugawa
+ * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
+ * Hitoshi Yamamoto, Mamoru Sakugawa
*/
#include <linux/config.h>
diff --git a/arch/m32r/kernel/setup_mappi3.c b/arch/m32r/kernel/setup_mappi3.c
index 3d60a85aaec..a76412e883e 100644
--- a/arch/m32r/kernel/setup_mappi3.c
+++ b/arch/m32r/kernel/setup_mappi3.c
@@ -3,8 +3,8 @@
*
* Setup routines for Renesas MAPPI-III(M3A-2170) Board
*
- * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
- * Hitoshi Yamamoto, Mamoru Sakugawa
+ * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
+ * Hitoshi Yamamoto, Mamoru Sakugawa
*/
#include <linux/config.h>
@@ -178,6 +178,8 @@ void __init init_IRQ(void)
#endif /* CONFIG_M32R_CFC */
}
+#if defined(CONFIG_SMC91X)
+
#define LAN_IOSTART 0x300
#define LAN_IOEND 0x320
static struct resource smc91x_resources[] = {
@@ -200,9 +202,55 @@ static struct platform_device smc91x_device = {
.resource = smc91x_resources,
};
+#endif
+
+#if defined(CONFIG_FB_S1D13XXX)
+
+#include <video/s1d13xxxfb.h>
+#include <asm/s1d13806.h>
+
+static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
+ .initregs = s1d13xxxfb_initregs,
+ .initregssize = ARRAY_SIZE(s1d13xxxfb_initregs),
+ .platform_init_video = NULL,
+#ifdef CONFIG_PM
+ .platform_suspend_video = NULL,
+ .platform_resume_video = NULL,
+#endif
+};
+
+static struct resource s1d13xxxfb_resources[] = {
+ [0] = {
+ .start = 0x1d600000UL,
+ .end = 0x1d73FFFFUL,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0x1d400000UL,
+ .end = 0x1d4001FFUL,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device s1d13xxxfb_device = {
+ .name = S1D_DEVICENAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &s1d13xxxfb_data,
+ },
+ .num_resources = ARRAY_SIZE(s1d13xxxfb_resources),
+ .resource = s1d13xxxfb_resources,
+};
+#endif
+
static int __init platform_init(void)
{
+#if defined(CONFIG_SMC91X)
platform_device_register(&smc91x_device);
+#endif
+#if defined(CONFIG_FB_S1D13XXX)
+ platform_device_register(&s1d13xxxfb_device);
+#endif
return 0;
}
arch_initcall(platform_init);
diff --git a/arch/m32r/kernel/setup_oaks32r.c b/arch/m32r/kernel/setup_oaks32r.c
index d656640badc..45add5b76f1 100644
--- a/arch/m32r/kernel/setup_oaks32r.c
+++ b/arch/m32r/kernel/setup_oaks32r.c
@@ -3,8 +3,8 @@
*
* Setup routines for OAKS32R Board
*
- * Copyright (c) 2002-2004 Hiroyuki Kondo, Hirokazu Takata,
- * Hitoshi Yamamoto, Mamoru Sakugawa
+ * Copyright (c) 2002-2005 Hiroyuki Kondo, Hirokazu Takata,
+ * Hitoshi Yamamoto, Mamoru Sakugawa
*/
#include <linux/config.h>
@@ -139,5 +139,4 @@ void __init init_IRQ(void)
icu_data[M32R_IRQ_SIO1_S].icucr = 0;
disable_oaks32r_irq(M32R_IRQ_SIO1_S);
#endif /* CONFIG_SERIAL_M32R_SIO */
-
}
diff --git a/arch/m32r/kernel/setup_opsput.c b/arch/m32r/kernel/setup_opsput.c
index 86f4cf2a86c..f0301f58bcc 100644
--- a/arch/m32r/kernel/setup_opsput.c
+++ b/arch/m32r/kernel/setup_opsput.c
@@ -3,7 +3,7 @@
*
* Setup routines for Renesas OPSPUT Board
*
- * Copyright (c) 2002-2004
+ * Copyright (c) 2002-2005
* Hiroyuki Kondo, Hirokazu Takata,
* Hitoshi Yamamoto, Takeo Takahashi, Mamoru Sakugawa
*
@@ -439,7 +439,7 @@ void __init init_IRQ(void)
icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
enable_opsput_irq(M32R_IRQ_INT2);
-//#if defined(CONFIG_VIDEO_M32R_AR)
+#if defined(CONFIG_VIDEO_M32R_AR)
/*
* INT3# is used for AR
*/
@@ -449,9 +449,11 @@ void __init init_IRQ(void)
irq_desc[M32R_IRQ_INT3].depth = 1;
icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
disable_opsput_irq(M32R_IRQ_INT3);
-//#endif /* CONFIG_VIDEO_M32R_AR */
+#endif /* CONFIG_VIDEO_M32R_AR */
}
+#if defined(CONFIG_SMC91X)
+
#define LAN_IOSTART 0x300
#define LAN_IOEND 0x320
static struct resource smc91x_resources[] = {
@@ -473,10 +475,55 @@ static struct platform_device smc91x_device = {
.num_resources = ARRAY_SIZE(smc91x_resources),
.resource = smc91x_resources,
};
+#endif
+
+#if defined(CONFIG_FB_S1D13XXX)
+
+#include <video/s1d13xxxfb.h>
+#include <asm/s1d13806.h>
+
+static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
+ .initregs = s1d13xxxfb_initregs,
+ .initregssize = ARRAY_SIZE(s1d13xxxfb_initregs),
+ .platform_init_video = NULL,
+#ifdef CONFIG_PM
+ .platform_suspend_video = NULL,
+ .platform_resume_video = NULL,
+#endif
+};
+
+static struct resource s1d13xxxfb_resources[] = {
+ [0] = {
+ .start = 0x10600000UL,
+ .end = 0x1073FFFFUL,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0x10400000UL,
+ .end = 0x104001FFUL,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device s1d13xxxfb_device = {
+ .name = S1D_DEVICENAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &s1d13xxxfb_data,
+ },
+ .num_resources = ARRAY_SIZE(s1d13xxxfb_resources),
+ .resource = s1d13xxxfb_resources,
+};
+#endif
static int __init platform_init(void)
{
+#if defined(CONFIG_SMC91X)
platform_device_register(&smc91x_device);
+#endif
+#if defined(CONFIG_FB_S1D13XXX)
+ platform_device_register(&s1d13xxxfb_device);
+#endif
return 0;
}
arch_initcall(platform_init);
diff --git a/arch/ppc/platforms/pmac_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c
index 5fdd4f607a4..c0605244edd 100644
--- a/arch/ppc/platforms/pmac_cpufreq.c
+++ b/arch/ppc/platforms/pmac_cpufreq.c
@@ -452,7 +452,7 @@ static u32 __pmac read_gpio(struct device_node *np)
return offset;
}
-static int __pmac pmac_cpufreq_suspend(struct cpufreq_policy *policy, u32 state)
+static int __pmac pmac_cpufreq_suspend(struct cpufreq_policy *policy, pm_message_t pmsg)
{
/* Ok, this could be made a bit smarter, but let's be robust for now. We
* always force a speed change to high speed before sleep, to make sure
diff --git a/arch/ppc64/kernel/cputable.c b/arch/ppc64/kernel/cputable.c
index 1d162c7c59d..8d4c46f6f0b 100644
--- a/arch/ppc64/kernel/cputable.c
+++ b/arch/ppc64/kernel/cputable.c
@@ -49,160 +49,219 @@ extern void __setup_cpu_be(unsigned long offset, struct cpu_spec* spec);
#endif
struct cpu_spec cpu_specs[] = {
- { /* Power3 */
- 0xffff0000, 0x00400000, "POWER3 (630)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_IABR | CPU_FTR_PMC8,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power3,
- COMMON_PPC64_FW
- },
- { /* Power3+ */
- 0xffff0000, 0x00410000, "POWER3 (630+)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_IABR | CPU_FTR_PMC8,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power3,
- COMMON_PPC64_FW
- },
- { /* Northstar */
- 0xffff0000, 0x00330000, "RS64-II (northstar)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power3,
- COMMON_PPC64_FW
- },
- { /* Pulsar */
- 0xffff0000, 0x00340000, "RS64-III (pulsar)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power3,
- COMMON_PPC64_FW
- },
- { /* I-star */
- 0xffff0000, 0x00360000, "RS64-III (icestar)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power3,
- COMMON_PPC64_FW
- },
- { /* S-star */
- 0xffff0000, 0x00370000, "RS64-IV (sstar)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power3,
- COMMON_PPC64_FW
- },
- { /* Power4 */
- 0xffff0000, 0x00350000, "POWER4 (gp)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power4,
- COMMON_PPC64_FW
- },
- { /* Power4+ */
- 0xffff0000, 0x00380000, "POWER4+ (gq)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power4,
- COMMON_PPC64_FW
- },
- { /* PPC970 */
- 0xffff0000, 0x00390000, "PPC970",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
- CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
- COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP,
- 128, 128,
- __setup_cpu_ppc970,
- COMMON_PPC64_FW
- },
- { /* PPC970FX */
- 0xffff0000, 0x003c0000, "PPC970FX",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
- CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
- COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP,
- 128, 128,
- __setup_cpu_ppc970,
- COMMON_PPC64_FW
- },
- { /* Power5 */
- 0xffff0000, 0x003a0000, "POWER5 (gr)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT |
- CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE |
- CPU_FTR_MMCRA_SIHV,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power4,
- COMMON_PPC64_FW
- },
- { /* Power5 */
- 0xffff0000, 0x003b0000, "POWER5 (gs)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT |
- CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE |
- CPU_FTR_MMCRA_SIHV,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power4,
- COMMON_PPC64_FW
- },
- { /* BE DD1.x */
- 0xffff0000, 0x00700000, "Broadband Engine",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
- CPU_FTR_SMT,
- COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP,
- 128, 128,
- __setup_cpu_be,
- COMMON_PPC64_FW
- },
- { /* default match */
- 0x00000000, 0x00000000, "POWER4 (compatible)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power4,
- COMMON_PPC64_FW
- }
+ { /* Power3 */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00400000,
+ .cpu_name = "POWER3 (630)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+ CPU_FTR_PMC8,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power3,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* Power3+ */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00410000,
+ .cpu_name = "POWER3 (630+)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+ CPU_FTR_PMC8,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power3,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* Northstar */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00330000,
+ .cpu_name = "RS64-II (northstar)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+ CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power3,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* Pulsar */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00340000,
+ .cpu_name = "RS64-III (pulsar)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+ CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power3,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* I-star */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00360000,
+ .cpu_name = "RS64-III (icestar)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+ CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power3,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* S-star */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00370000,
+ .cpu_name = "RS64-IV (sstar)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+ CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power3,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* Power4 */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00350000,
+ .cpu_name = "POWER4 (gp)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power4,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* Power4+ */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00380000,
+ .cpu_name = "POWER4+ (gq)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power4,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* PPC970 */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00390000,
+ .cpu_name = "PPC970",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
+ CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+ .cpu_user_features = COMMON_USER_PPC64 |
+ PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_ppc970,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* PPC970FX */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x003c0000,
+ .cpu_name = "PPC970FX",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
+ CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+ .cpu_user_features = COMMON_USER_PPC64 |
+ PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_ppc970,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* Power5 */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x003a0000,
+ .cpu_name = "POWER5 (gr)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT |
+ CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE |
+ CPU_FTR_MMCRA_SIHV,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power4,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* Power5 */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x003b0000,
+ .cpu_name = "POWER5 (gs)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT |
+ CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE |
+ CPU_FTR_MMCRA_SIHV,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power4,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* BE DD1.x */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00700000,
+ .cpu_name = "Broadband Engine",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
+ CPU_FTR_SMT,
+ .cpu_user_features = COMMON_USER_PPC64 |
+ PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_be,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* default match */
+ .pvr_mask = 0x00000000,
+ .pvr_value = 0x00000000,
+ .cpu_name = "POWER4 (compatible)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+ CPU_FTR_PPCAS_ARCH_V2,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power4,
+ .firmware_features = COMMON_PPC64_FW,
+ }
};
firmware_feature_t firmware_features_table[FIRMWARE_MAX_FEATURES] = {
- {FW_FEATURE_PFT, "hcall-pft"},
- {FW_FEATURE_TCE, "hcall-tce"},
- {FW_FEATURE_SPRG0, "hcall-sprg0"},
- {FW_FEATURE_DABR, "hcall-dabr"},
- {FW_FEATURE_COPY, "hcall-copy"},
- {FW_FEATURE_ASR, "hcall-asr"},
- {FW_FEATURE_DEBUG, "hcall-debug"},
- {FW_FEATURE_PERF, "hcall-perf"},
- {FW_FEATURE_DUMP, "hcall-dump"},
- {FW_FEATURE_INTERRUPT, "hcall-interrupt"},
- {FW_FEATURE_MIGRATE, "hcall-migrate"},
- {FW_FEATURE_PERFMON, "hcall-perfmon"},
- {FW_FEATURE_CRQ, "hcall-crq"},
- {FW_FEATURE_VIO, "hcall-vio"},
- {FW_FEATURE_RDMA, "hcall-rdma"},
- {FW_FEATURE_LLAN, "hcall-lLAN"},
- {FW_FEATURE_BULK, "hcall-bulk"},
- {FW_FEATURE_XDABR, "hcall-xdabr"},
- {FW_FEATURE_MULTITCE, "hcall-multi-tce"},
- {FW_FEATURE_SPLPAR, "hcall-splpar"},
+ {FW_FEATURE_PFT, "hcall-pft"},
+ {FW_FEATURE_TCE, "hcall-tce"},
+ {FW_FEATURE_SPRG0, "hcall-sprg0"},
+ {FW_FEATURE_DABR, "hcall-dabr"},
+ {FW_FEATURE_COPY, "hcall-copy"},
+ {FW_FEATURE_ASR, "hcall-asr"},
+ {FW_FEATURE_DEBUG, "hcall-debug"},
+ {FW_FEATURE_PERF, "hcall-perf"},
+ {FW_FEATURE_DUMP, "hcall-dump"},
+ {FW_FEATURE_INTERRUPT, "hcall-interrupt"},
+ {FW_FEATURE_MIGRATE, "hcall-migrate"},
+ {FW_FEATURE_PERFMON, "hcall-perfmon"},
+ {FW_FEATURE_CRQ, "hcall-crq"},
+ {FW_FEATURE_VIO, "hcall-vio"},
+ {FW_FEATURE_RDMA, "hcall-rdma"},
+ {FW_FEATURE_LLAN, "hcall-lLAN"},
+ {FW_FEATURE_BULK, "hcall-bulk"},
+ {FW_FEATURE_XDABR, "hcall-xdabr"},
+ {FW_FEATURE_MULTITCE, "hcall-multi-tce"},
+ {FW_FEATURE_SPLPAR, "hcall-splpar"},
};
diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
index 675c2708588..93ebcac0d5a 100644
--- a/arch/ppc64/kernel/head.S
+++ b/arch/ppc64/kernel/head.S
@@ -308,6 +308,7 @@ exception_marker:
label##_pSeries: \
HMT_MEDIUM; \
mtspr SPRG1,r13; /* save r13 */ \
+ RUNLATCH_ON(r13); \
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
#define STD_EXCEPTION_ISERIES(n, label, area) \
@@ -315,6 +316,7 @@ label##_pSeries: \
label##_iSeries: \
HMT_MEDIUM; \
mtspr SPRG1,r13; /* save r13 */ \
+ RUNLATCH_ON(r13); \
EXCEPTION_PROLOG_ISERIES_1(area); \
EXCEPTION_PROLOG_ISERIES_2; \
b label##_common
@@ -324,6 +326,7 @@ label##_iSeries: \
label##_iSeries: \
HMT_MEDIUM; \
mtspr SPRG1,r13; /* save r13 */ \
+ RUNLATCH_ON(r13); \
EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \
lbz r10,PACAPROCENABLED(r13); \
cmpwi 0,r10,0; \
@@ -393,6 +396,7 @@ __start_interrupts:
_machine_check_pSeries:
HMT_MEDIUM
mtspr SPRG1,r13 /* save r13 */
+ RUNLATCH_ON(r13)
EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
. = 0x300
@@ -419,6 +423,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
data_access_slb_pSeries:
HMT_MEDIUM
mtspr SPRG1,r13
+ RUNLATCH_ON(r13)
mfspr r13,SPRG3 /* get paca address into r13 */
std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */
std r10,PACA_EXSLB+EX_R10(r13)
@@ -439,6 +444,7 @@ data_access_slb_pSeries:
instruction_access_slb_pSeries:
HMT_MEDIUM
mtspr SPRG1,r13
+ RUNLATCH_ON(r13)
mfspr r13,SPRG3 /* get paca address into r13 */
std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */
std r10,PACA_EXSLB+EX_R10(r13)
@@ -464,6 +470,7 @@ instruction_access_slb_pSeries:
.globl system_call_pSeries
system_call_pSeries:
HMT_MEDIUM
+ RUNLATCH_ON(r9)
mr r9,r13
mfmsr r10
mfspr r13,SPRG3
@@ -707,11 +714,13 @@ fwnmi_data_area:
system_reset_fwnmi:
HMT_MEDIUM
mtspr SPRG1,r13 /* save r13 */
+ RUNLATCH_ON(r13)
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
.globl machine_check_fwnmi
machine_check_fwnmi:
HMT_MEDIUM
mtspr SPRG1,r13 /* save r13 */
+ RUNLATCH_ON(r13)
EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
/*
@@ -848,6 +857,7 @@ unrecov_fer:
.align 7
.globl data_access_common
data_access_common:
+ RUNLATCH_ON(r10) /* It wont fit in the 0x300 handler */
mfspr r10,DAR
std r10,PACA_EXGEN+EX_DAR(r13)
mfspr r10,DSISR
diff --git a/arch/ppc64/kernel/hvconsole.c b/arch/ppc64/kernel/hvconsole.c
index c72fb8ffe97..138e128a388 100644
--- a/arch/ppc64/kernel/hvconsole.c
+++ b/arch/ppc64/kernel/hvconsole.c
@@ -27,7 +27,6 @@
#include <linux/module.h>
#include <asm/hvcall.h>
#include <asm/hvconsole.h>
-#include <asm/prom.h>
/**
* hvc_get_chars - retrieve characters from firmware for denoted vterm adatper
@@ -42,29 +41,14 @@ int hvc_get_chars(uint32_t vtermno, char *buf, int count)
unsigned long got;
if (plpar_hcall(H_GET_TERM_CHAR, vtermno, 0, 0, 0, &got,
- (unsigned long *)buf, (unsigned long *)buf+1) == H_Success) {
- /*
- * Work around a HV bug where it gives us a null
- * after every \r. -- paulus
- */
- if (got > 0) {
- int i;
- for (i = 1; i < got; ++i) {
- if (buf[i] == 0 && buf[i-1] == '\r') {
- --got;
- if (i < got)
- memmove(&buf[i], &buf[i+1],
- got - i);
- }
- }
- }
+ (unsigned long *)buf, (unsigned long *)buf+1) == H_Success)
return got;
- }
return 0;
}
EXPORT_SYMBOL(hvc_get_chars);
+
/**
* hvc_put_chars: send characters to firmware for denoted vterm adapter
* @vtermno: The vtermno or unit_address of the adapter from which the data
@@ -88,34 +72,3 @@ int hvc_put_chars(uint32_t vtermno, const char *buf, int count)
}
EXPORT_SYMBOL(hvc_put_chars);
-
-/*
- * We hope/assume that the first vty found corresponds to the first console
- * device.
- */
-int hvc_find_vtys(void)
-{
- struct device_node *vty;
- int num_found = 0;
-
- for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL;
- vty = of_find_node_by_name(vty, "vty")) {
- uint32_t *vtermno;
-
- /* We have statically defined space for only a certain number of
- * console adapters. */
- if (num_found >= MAX_NR_HVC_CONSOLES)
- break;
-
- vtermno = (uint32_t *)get_property(vty, "reg", NULL);
- if (!vtermno)
- continue;
-
- if (device_is_compatible(vty, "hvterm1")) {
- hvc_instantiate(*vtermno, num_found);
- ++num_found;
- }
- }
-
- return num_found;
-}
diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c
index b3f770f6d40..077c82fc9f3 100644
--- a/arch/ppc64/kernel/iSeries_setup.c
+++ b/arch/ppc64/kernel/iSeries_setup.c
@@ -834,6 +834,92 @@ static int __init iSeries_src_init(void)
late_initcall(iSeries_src_init);
+static inline void process_iSeries_events(void)
+{
+ asm volatile ("li 0,0x5555; sc" : : : "r0", "r3");
+}
+
+static void yield_shared_processor(void)
+{
+ unsigned long tb;
+
+ HvCall_setEnabledInterrupts(HvCall_MaskIPI |
+ HvCall_MaskLpEvent |
+ HvCall_MaskLpProd |
+ HvCall_MaskTimeout);
+
+ tb = get_tb();
+ /* Compute future tb value when yield should expire */
+ HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy);
+
+ /*
+ * The decrementer stops during the yield. Force a fake decrementer
+ * here and let the timer_interrupt code sort out the actual time.
+ */
+ get_paca()->lppaca.int_dword.fields.decr_int = 1;
+ process_iSeries_events();
+}
+
+static int iseries_shared_idle(void)
+{
+ while (1) {
+ while (!need_resched() && !hvlpevent_is_pending()) {
+ local_irq_disable();
+ ppc64_runlatch_off();
+
+ /* Recheck with irqs off */
+ if (!need_resched() && !hvlpevent_is_pending())
+ yield_shared_processor();
+
+ HMT_medium();
+ local_irq_enable();
+ }
+
+ ppc64_runlatch_on();
+
+ if (hvlpevent_is_pending())
+ process_iSeries_events();
+
+ schedule();
+ }
+
+ return 0;
+}
+
+static int iseries_dedicated_idle(void)
+{
+ long oldval;
+
+ while (1) {
+ oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
+
+ if (!oldval) {
+ set_thread_flag(TIF_POLLING_NRFLAG);
+
+ while (!need_resched()) {
+ ppc64_runlatch_off();
+ HMT_low();
+
+ if (hvlpevent_is_pending()) {
+ HMT_medium();
+ ppc64_runlatch_on();
+ process_iSeries_events();
+ }
+ }
+
+ HMT_medium();
+ clear_thread_flag(TIF_POLLING_NRFLAG);
+ } else {
+ set_need_resched();
+ }
+
+ ppc64_runlatch_on();
+ schedule();
+ }
+
+ return 0;
+}
+
#ifndef CONFIG_PCI
void __init iSeries_init_IRQ(void) { }
#endif
@@ -859,5 +945,13 @@ void __init iSeries_early_setup(void)
ppc_md.get_rtc_time = iSeries_get_rtc_time;
ppc_md.calibrate_decr = iSeries_calibrate_decr;
ppc_md.progress = iSeries_progress;
+
+ if (get_paca()->lppaca.shared_proc) {
+ ppc_md.idle_loop = iseries_shared_idle;
+ printk(KERN_INFO "Using shared processor idle loop\n");
+ } else {
+ ppc_md.idle_loop = iseries_dedicated_idle;
+ printk(KERN_INFO "Using dedicated idle loop\n");
+ }
}
diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c
index 08952c7e621..954395d4263 100644
--- a/arch/ppc64/kernel/idle.c
+++ b/arch/ppc64/kernel/idle.c
@@ -20,109 +20,18 @@
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/cpu.h>
-#include <linux/module.h>
#include <linux/sysctl.h>
-#include <linux/smp.h>
#include <asm/system.h>
#include <asm/processor.h>
-#include <asm/mmu.h>
#include <asm/cputable.h>
#include <asm/time.h>
-#include <asm/iSeries/HvCall.h>
-#include <asm/iSeries/ItLpQueue.h>
-#include <asm/plpar_wrappers.h>
#include <asm/systemcfg.h>
+#include <asm/machdep.h>
extern void power4_idle(void);
-static int (*idle_loop)(void);
-
-#ifdef CONFIG_PPC_ISERIES
-static unsigned long maxYieldTime = 0;
-static unsigned long minYieldTime = 0xffffffffffffffffUL;
-
-static inline void process_iSeries_events(void)
-{
- asm volatile ("li 0,0x5555; sc" : : : "r0", "r3");
-}
-
-static void yield_shared_processor(void)
-{
- unsigned long tb;
- unsigned long yieldTime;
-
- HvCall_setEnabledInterrupts(HvCall_MaskIPI |
- HvCall_MaskLpEvent |
- HvCall_MaskLpProd |
- HvCall_MaskTimeout);
-
- tb = get_tb();
- /* Compute future tb value when yield should expire */
- HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy);
-
- yieldTime = get_tb() - tb;
- if (yieldTime > maxYieldTime)
- maxYieldTime = yieldTime;
-
- if (yieldTime < minYieldTime)
- minYieldTime = yieldTime;
-
- /*
- * The decrementer stops during the yield. Force a fake decrementer
- * here and let the timer_interrupt code sort out the actual time.
- */
- get_paca()->lppaca.int_dword.fields.decr_int = 1;
- process_iSeries_events();
-}
-
-static int iSeries_idle(void)
-{
- struct paca_struct *lpaca;
- long oldval;
-
- /* ensure iSeries run light will be out when idle */
- ppc64_runlatch_off();
-
- lpaca = get_paca();
-
- while (1) {
- if (lpaca->lppaca.shared_proc) {
- if (hvlpevent_is_pending())
- process_iSeries_events();
- if (!need_resched())
- yield_shared_processor();
- } else {
- oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
-
- if (!oldval) {
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- while (!need_resched()) {
- HMT_medium();
- if (hvlpevent_is_pending())
- process_iSeries_events();
- HMT_low();
- }
-
- HMT_medium();
- clear_thread_flag(TIF_POLLING_NRFLAG);
- } else {
- set_need_resched();
- }
- }
-
- ppc64_runlatch_on();
- schedule();
- ppc64_runlatch_off();
- }
-
- return 0;
-}
-
-#else
-
-static int default_idle(void)
+int default_idle(void)
{
long oldval;
unsigned int cpu = smp_processor_id();
@@ -134,7 +43,8 @@ static int default_idle(void)
set_thread_flag(TIF_POLLING_NRFLAG);
while (!need_resched() && !cpu_is_offline(cpu)) {
- barrier();
+ ppc64_runlatch_off();
+
/*
* Go into low thread priority and possibly
* low power mode.
@@ -149,6 +59,7 @@ static int default_idle(void)
set_need_resched();
}
+ ppc64_runlatch_on();
schedule();
if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
cpu_die();
@@ -157,127 +68,19 @@ static int default_idle(void)
return 0;
}
-#ifdef CONFIG_PPC_PSERIES
-
-DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
-
-int dedicated_idle(void)
+int native_idle(void)
{
- long oldval;
- struct paca_struct *lpaca = get_paca(), *ppaca;
- unsigned long start_snooze;
- unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
- unsigned int cpu = smp_processor_id();
-
- ppaca = &paca[cpu ^ 1];
-
while (1) {
- /*
- * Indicate to the HV that we are idle. Now would be
- * a good time to find other work to dispatch.
- */
- lpaca->lppaca.idle = 1;
-
- oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
- if (!oldval) {
- set_thread_flag(TIF_POLLING_NRFLAG);
- start_snooze = __get_tb() +
- *smt_snooze_delay * tb_ticks_per_usec;
- while (!need_resched() && !cpu_is_offline(cpu)) {
- /*
- * Go into low thread priority and possibly
- * low power mode.
- */
- HMT_low();
- HMT_very_low();
-
- if (*smt_snooze_delay == 0 ||
- __get_tb() < start_snooze)
- continue;
-
- HMT_medium();
-
- if (!(ppaca->lppaca.idle)) {
- local_irq_disable();
-
- /*
- * We are about to sleep the thread
- * and so wont be polling any
- * more.
- */
- clear_thread_flag(TIF_POLLING_NRFLAG);
-
- /*
- * SMT dynamic mode. Cede will result
- * in this thread going dormant, if the
- * partner thread is still doing work.
- * Thread wakes up if partner goes idle,
- * an interrupt is presented, or a prod
- * occurs. Returning from the cede
- * enables external interrupts.
- */
- if (!need_resched())
- cede_processor();
- else
- local_irq_enable();
- } else {
- /*
- * Give the HV an opportunity at the
- * processor, since we are not doing
- * any work.
- */
- poll_pending();
- }
- }
-
- clear_thread_flag(TIF_POLLING_NRFLAG);
- } else {
- set_need_resched();
- }
-
- HMT_medium();
- lpaca->lppaca.idle = 0;
- schedule();
- if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
- cpu_die();
- }
- return 0;
-}
-
-static int shared_idle(void)
-{
- struct paca_struct *lpaca = get_paca();
- unsigned int cpu = smp_processor_id();
-
- while (1) {
- /*
- * Indicate to the HV that we are idle. Now would be
- * a good time to find other work to dispatch.
- */
- lpaca->lppaca.idle = 1;
+ ppc64_runlatch_off();
- while (!need_resched() && !cpu_is_offline(cpu)) {
- local_irq_disable();
+ if (!need_resched())
+ power4_idle();
- /*
- * Yield the processor to the hypervisor. We return if
- * an external interrupt occurs (which are driven prior
- * to returning here) or if a prod occurs from another
- * processor. When returning here, external interrupts
- * are enabled.
- *
- * Check need_resched() again with interrupts disabled
- * to avoid a race.
- */
- if (!need_resched())
- cede_processor();
- else
- local_irq_enable();
+ if (need_resched()) {
+ ppc64_runlatch_on();
+ schedule();
}
- HMT_medium();
- lpaca->lppaca.idle = 0;
- schedule();
if (cpu_is_offline(smp_processor_id()) &&
system_state == SYSTEM_RUNNING)
cpu_die();
@@ -286,29 +89,10 @@ static int shared_idle(void)
return 0;
}
-#endif /* CONFIG_PPC_PSERIES */
-
-static int native_idle(void)
-{
- while(1) {
- /* check CPU type here */
- if (!need_resched())
- power4_idle();
- if (need_resched())
- schedule();
-
- if (cpu_is_offline(raw_smp_processor_id()) &&
- system_state == SYSTEM_RUNNING)
- cpu_die();
- }
- return 0;
-}
-
-#endif /* CONFIG_PPC_ISERIES */
-
void cpu_idle(void)
{
- idle_loop();
+ BUG_ON(NULL == ppc_md.idle_loop);
+ ppc_md.idle_loop();
}
int powersave_nap;
@@ -342,42 +126,3 @@ register_powersave_nap_sysctl(void)
}
__initcall(register_powersave_nap_sysctl);
#endif
-
-int idle_setup(void)
-{
- /*
- * Move that junk to each platform specific file, eventually define
- * a pSeries_idle for shared processor stuff
- */
-#ifdef CONFIG_PPC_ISERIES
- idle_loop = iSeries_idle;
- return 1;
-#else
- idle_loop = default_idle;
-#endif
-#ifdef CONFIG_PPC_PSERIES
- if (systemcfg->platform & PLATFORM_PSERIES) {
- if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
- if (get_paca()->lppaca.shared_proc) {
- printk(KERN_INFO "Using shared processor idle loop\n");
- idle_loop = shared_idle;
- } else {
- printk(KERN_INFO "Using dedicated idle loop\n");
- idle_loop = dedicated_idle;
- }
- } else {
- printk(KERN_INFO "Using default idle loop\n");
- idle_loop = default_idle;
- }
- }
-#endif /* CONFIG_PPC_PSERIES */
-#ifndef CONFIG_PPC_ISERIES
- if (systemcfg->platform == PLATFORM_POWERMAC ||
- systemcfg->platform == PLATFORM_MAPLE) {
- printk(KERN_INFO "Using native/NAP idle loop\n");
- idle_loop = native_idle;
- }
-#endif /* CONFIG_PPC_ISERIES */
-
- return 1;
-}
diff --git a/arch/ppc64/kernel/maple_setup.c b/arch/ppc64/kernel/maple_setup.c
index da8900b51f4..bb55b5a5691 100644
--- a/arch/ppc64/kernel/maple_setup.c
+++ b/arch/ppc64/kernel/maple_setup.c
@@ -177,6 +177,8 @@ void __init maple_setup_arch(void)
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
#endif
+
+ printk(KERN_INFO "Using native/NAP idle loop\n");
}
/*
@@ -297,4 +299,5 @@ struct machdep_calls __initdata maple_md = {
.get_rtc_time = maple_get_rtc_time,
.calibrate_decr = generic_calibrate_decr,
.progress = maple_progress,
+ .idle_loop = native_idle,
};
diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
index f3dea0c5a88..59f4f997381 100644
--- a/arch/ppc64/kernel/misc.S
+++ b/arch/ppc64/kernel/misc.S
@@ -1124,9 +1124,11 @@ _GLOBAL(sys_call_table32)
.llong .compat_sys_mq_getsetattr
.llong .compat_sys_kexec_load
.llong .sys32_add_key
- .llong .sys32_request_key
+ .llong .sys32_request_key /* 270 */
.llong .compat_sys_keyctl
.llong .compat_sys_waitid
+ .llong .sys32_ioprio_set
+ .llong .sys32_ioprio_get
.balign 8
_GLOBAL(sys_call_table)
@@ -1403,3 +1405,5 @@ _GLOBAL(sys_call_table)
.llong .sys_request_key /* 270 */
.llong .sys_keyctl
.llong .sys_waitid
+ .llong .sys_ioprio_set
+ .llong .sys_ioprio_get
diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c
index 44d9af72d22..5bec956e44a 100644
--- a/arch/ppc64/kernel/pSeries_setup.c
+++ b/arch/ppc64/kernel/pSeries_setup.c
@@ -19,6 +19,7 @@
#undef DEBUG
#include <linux/config.h>
+#include <linux/cpu.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -82,6 +83,9 @@ int fwnmi_active; /* TRUE if an FWNMI handler is present */
extern void pSeries_system_reset_exception(struct pt_regs *regs);
extern int pSeries_machine_check_exception(struct pt_regs *regs);
+static int pseries_shared_idle(void);
+static int pseries_dedicated_idle(void);
+
static volatile void __iomem * chrp_int_ack_special;
struct mpic *pSeries_mpic;
@@ -229,6 +233,20 @@ static void __init pSeries_setup_arch(void)
if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)
vpa_init(boot_cpuid);
+
+ /* Choose an idle loop */
+ if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
+ if (get_paca()->lppaca.shared_proc) {
+ printk(KERN_INFO "Using shared processor idle loop\n");
+ ppc_md.idle_loop = pseries_shared_idle;
+ } else {
+ printk(KERN_INFO "Using dedicated idle loop\n");
+ ppc_md.idle_loop = pseries_dedicated_idle;
+ }
+ } else {
+ printk(KERN_INFO "Using default idle loop\n");
+ ppc_md.idle_loop = default_idle;
+ }
}
static int __init pSeries_init_panel(void)
@@ -418,6 +436,144 @@ static int __init pSeries_probe(int platform)
return 1;
}
+DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
+
+static inline void dedicated_idle_sleep(unsigned int cpu)
+{
+ struct paca_struct *ppaca = &paca[cpu ^ 1];
+
+ /* Only sleep if the other thread is not idle */
+ if (!(ppaca->lppaca.idle)) {
+ local_irq_disable();
+
+ /*
+ * We are about to sleep the thread and so wont be polling any
+ * more.
+ */
+ clear_thread_flag(TIF_POLLING_NRFLAG);
+
+ /*
+ * SMT dynamic mode. Cede will result in this thread going
+ * dormant, if the partner thread is still doing work. Thread
+ * wakes up if partner goes idle, an interrupt is presented, or
+ * a prod occurs. Returning from the cede enables external
+ * interrupts.
+ */
+ if (!need_resched())
+ cede_processor();
+ else
+ local_irq_enable();
+ } else {
+ /*
+ * Give the HV an opportunity at the processor, since we are
+ * not doing any work.
+ */
+ poll_pending();
+ }
+}
+
+static int pseries_dedicated_idle(void)
+{
+ long oldval;
+ struct paca_struct *lpaca = get_paca();
+ unsigned int cpu = smp_processor_id();
+ unsigned long start_snooze;
+ unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
+
+ while (1) {
+ /*
+ * Indicate to the HV that we are idle. Now would be
+ * a good time to find other work to dispatch.
+ */
+ lpaca->lppaca.idle = 1;
+
+ oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
+ if (!oldval) {
+ set_thread_flag(TIF_POLLING_NRFLAG);
+
+ start_snooze = __get_tb() +
+ *smt_snooze_delay * tb_ticks_per_usec;
+
+ while (!need_resched() && !cpu_is_offline(cpu)) {
+ ppc64_runlatch_off();
+
+ /*
+ * Go into low thread priority and possibly
+ * low power mode.
+ */
+ HMT_low();
+ HMT_very_low();
+
+ if (*smt_snooze_delay != 0 &&
+ __get_tb() > start_snooze) {
+ HMT_medium();
+ dedicated_idle_sleep(cpu);
+ }
+
+ }
+
+ HMT_medium();
+ clear_thread_flag(TIF_POLLING_NRFLAG);
+ } else {
+ set_need_resched();
+ }
+
+ lpaca->lppaca.idle = 0;
+ ppc64_runlatch_on();
+
+ schedule();
+
+ if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
+ cpu_die();
+ }
+}
+
+static int pseries_shared_idle(void)
+{
+ struct paca_struct *lpaca = get_paca();
+ unsigned int cpu = smp_processor_id();
+
+ while (1) {
+ /*
+ * Indicate to the HV that we are idle. Now would be
+ * a good time to find other work to dispatch.
+ */
+ lpaca->lppaca.idle = 1;
+
+ while (!need_resched() && !cpu_is_offline(cpu)) {
+ local_irq_disable();
+ ppc64_runlatch_off();
+
+ /*
+ * Yield the processor to the hypervisor. We return if
+ * an external interrupt occurs (which are driven prior
+ * to returning here) or if a prod occurs from another
+ * processor. When returning here, external interrupts
+ * are enabled.
+ *
+ * Check need_resched() again with interrupts disabled
+ * to avoid a race.
+ */
+ if (!need_resched())
+ cede_processor();
+ else
+ local_irq_enable();
+
+ HMT_medium();
+ }
+
+ lpaca->lppaca.idle = 0;
+ ppc64_runlatch_on();
+
+ schedule();
+
+ if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
+ cpu_die();
+ }
+
+ return 0;
+}
+
struct machdep_calls __initdata pSeries_md = {
.probe = pSeries_probe,
.setup_arch = pSeries_setup_arch,
diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c
index 6cf03d387b9..3013cdb5f93 100644
--- a/arch/ppc64/kernel/pmac_setup.c
+++ b/arch/ppc64/kernel/pmac_setup.c
@@ -186,6 +186,8 @@ void __init pmac_setup_arch(void)
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
#endif
+
+ printk(KERN_INFO "Using native/NAP idle loop\n");
}
#ifdef CONFIG_SCSI
@@ -507,5 +509,6 @@ struct machdep_calls __initdata pmac_md = {
.calibrate_decr = pmac_calibrate_decr,
.feature_call = pmac_do_feature_call,
.progress = pmac_progress,
- .check_legacy_ioport = pmac_check_legacy_ioport
+ .check_legacy_ioport = pmac_check_legacy_ioport,
+ .idle_loop = native_idle,
};
diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c
index d5e4866e9ac..d1b33f0b26c 100644
--- a/arch/ppc64/kernel/setup.c
+++ b/arch/ppc64/kernel/setup.c
@@ -96,7 +96,6 @@ extern void udbg_init_maple_realmode(void);
extern unsigned long klimit;
extern void mm_init_ppc64(void);
-extern int idle_setup(void);
extern void stab_initialize(unsigned long stab);
extern void htab_initialize(void);
extern void early_init_devtree(void *flat_dt);
@@ -1081,8 +1080,11 @@ void __init setup_arch(char **cmdline_p)
ppc_md.setup_arch();
- /* Select the correct idle loop for the platform. */
- idle_setup();
+ /* Use the default idle loop if the platform hasn't provided one. */
+ if (NULL == ppc_md.idle_loop) {
+ ppc_md.idle_loop = default_idle;
+ printk(KERN_INFO "Using default idle loop\n");
+ }
paging_init();
ppc64_boot_msg(0x15, "Setup Done");
diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c
index 118436e8085..206619080e6 100644
--- a/arch/ppc64/kernel/sys_ppc32.c
+++ b/arch/ppc64/kernel/sys_ppc32.c
@@ -30,47 +30,26 @@
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
-#include <linux/slab.h>
-#include <linux/uio.h>
-#include <linux/aio.h>
-#include <linux/nfs_fs.h>
-#include <linux/module.h>
-#include <linux/sunrpc/svc.h>
-#include <linux/nfsd/nfsd.h>
-#include <linux/nfsd/cache.h>
-#include <linux/nfsd/xdr.h>
-#include <linux/nfsd/syscall.h>
#include <linux/poll.h>
#include <linux/personality.h>
#include <linux/stat.h>
-#include <linux/filter.h>
-#include <linux/highmem.h>
-#include <linux/highuid.h>
#include <linux/mman.h>
-#include <linux/ipv6.h>
#include <linux/in.h>
-#include <linux/icmpv6.h>
#include <linux/syscalls.h>
#include <linux/unistd.h>
#include <linux/sysctl.h>
#include <linux/binfmts.h>
-#include <linux/dnotify.h>
#include <linux/security.h>
#include <linux/compat.h>
#include <linux/ptrace.h>
-#include <linux/aio_abi.h>
#include <linux/elf.h>
-#include <net/scm.h>
-#include <net/sock.h>
-
#include <asm/ptrace.h>
#include <asm/types.h>
#include <asm/ipc.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/semaphore.h>
-#include <asm/ppcdebug.h>
#include <asm/time.h>
#include <asm/mmu_context.h>
#include <asm/systemcfg.h>
@@ -350,8 +329,6 @@ asmlinkage long sys32_adjtimex(struct timex32 __user *utp)
return ret;
}
-
-/* These are here just in case some old sparc32 binary calls it. */
asmlinkage long sys32_pause(void)
{
current->state = TASK_INTERRUPTIBLE;
@@ -360,8 +337,6 @@ asmlinkage long sys32_pause(void)
return -ERESTARTNOHAND;
}
-
-
static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
{
long usec;
@@ -847,16 +822,6 @@ asmlinkage long sys32_getpgid(u32 pid)
}
-/* Note: it is necessary to treat which and who as unsigned ints,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long sys32_getpriority(u32 which, u32 who)
-{
- return sys_getpriority((int)which, (int)who);
-}
-
/* Note: it is necessary to treat pid as an unsigned int,
* with the corresponding cast to a signed int to insure that the
@@ -1048,6 +1013,11 @@ asmlinkage long sys32_setpgid(u32 pid, u32 pgid)
return sys_setpgid((int)pid, (int)pgid);
}
+long sys32_getpriority(u32 which, u32 who)
+{
+ /* sign extend which and who */
+ return sys_getpriority((int)which, (int)who);
+}
long sys32_setpriority(u32 which, u32 who, u32 niceval)
{
@@ -1055,6 +1025,18 @@ long sys32_setpriority(u32 which, u32 who, u32 niceval)
return sys_setpriority((int)which, (int)who, (int)niceval);
}
+long sys32_ioprio_get(u32 which, u32 who)
+{
+ /* sign extend which and who */
+ return sys_ioprio_get((int)which, (int)who);
+}
+
+long sys32_ioprio_set(u32 which, u32 who, u32 ioprio)
+{
+ /* sign extend which, who and ioprio */
+ return sys_ioprio_set((int)which, (int)who, (int)ioprio);
+}
+
/* Note: it is necessary to treat newmask as an unsigned int,
* with the corresponding cast to a signed int to insure that the
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -1273,8 +1255,6 @@ long ppc32_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low,
(u64)len_high << 32 | len_low, advice);
}
-extern asmlinkage long sys_timer_create(clockid_t, sigevent_t __user *, timer_t __user *);
-
long ppc32_timer_create(clockid_t clock,
struct compat_sigevent __user *ev32,
timer_t __user *timer_id)
diff --git a/arch/ppc64/kernel/sysfs.c b/arch/ppc64/kernel/sysfs.c
index 2f704a2cafb..02b8ac4e016 100644
--- a/arch/ppc64/kernel/sysfs.c
+++ b/arch/ppc64/kernel/sysfs.c
@@ -112,7 +112,6 @@ void ppc64_enable_pmcs(void)
unsigned long hid0;
#ifdef CONFIG_PPC_PSERIES
unsigned long set, reset;
- int ret;
#endif /* CONFIG_PPC_PSERIES */
/* Only need to enable them once */
@@ -145,11 +144,7 @@ void ppc64_enable_pmcs(void)
case PLATFORM_PSERIES_LPAR:
set = 1UL << 63;
reset = 0;
- ret = plpar_hcall_norets(H_PERFMON, set, reset);
- if (ret)
- printk(KERN_ERR "H_PERFMON call on cpu %u "
- "returned %d\n",
- smp_processor_id(), ret);
+ plpar_hcall_norets(H_PERFMON, set, reset);
break;
#endif /* CONFIG_PPC_PSERIES */
@@ -161,13 +156,6 @@ void ppc64_enable_pmcs(void)
/* instruct hypervisor to maintain PMCs */
if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)
get_paca()->lppaca.pmcregs_in_use = 1;
-
- /*
- * On SMT machines we have to set the run latch in the ctrl register
- * in order to make PMC6 spin.
- */
- if (cpu_has_feature(CPU_FTR_SMT))
- ppc64_runlatch_on();
#endif /* CONFIG_PPC_PSERIES */
}
diff --git a/arch/ppc64/kernel/vdso32/vdso32.lds.S b/arch/ppc64/kernel/vdso32/vdso32.lds.S
index 11290c902ba..6f87a916a39 100644
--- a/arch/ppc64/kernel/vdso32/vdso32.lds.S
+++ b/arch/ppc64/kernel/vdso32/vdso32.lds.S
@@ -40,9 +40,9 @@ SECTIONS
.gcc_except_table : { *(.gcc_except_table) }
.fixup : { *(.fixup) }
- .got ALIGN(4) : { *(.got.plt) *(.got) }
-
.dynamic : { *(.dynamic) } :text :dynamic
+ .got : { *(.got) }
+ .plt : { *(.plt) }
_end = .;
__end = .;
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index 9469e77303e..6682c788364 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -128,7 +128,6 @@ config HOSTFS
config HPPFS
tristate "HoneyPot ProcFS (EXPERIMENTAL)"
- depends on BROKEN
help
hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc
entries to be overridden, removed, or fabricated from the host.
@@ -141,8 +140,9 @@ config HPPFS
You only need this if you are setting up a UML honeypot. Otherwise,
it is safe to say 'N' here.
- If you are actively using it, please ask for it to be fixed. In this
- moment, it does not work on 2.6 (it works somehow on 2.4).
+ If you are actively using it, please report any problems, since it's
+ getting fixed. In this moment, it is experimental on 2.6 (it works on
+ 2.4).
config MCONSOLE
bool "Management console"
diff --git a/arch/um/Kconfig_i386 b/arch/um/Kconfig_i386
index e41f3748d30..27c18a8d9d1 100644
--- a/arch/um/Kconfig_i386
+++ b/arch/um/Kconfig_i386
@@ -19,6 +19,18 @@ config 3_LEVEL_PGTABLES
memory. All the memory that can't be mapped directly will be treated
as high memory.
+config STUB_CODE
+ hex
+ default 0xbfffe000
+
+config STUB_DATA
+ hex
+ default 0xbffff000
+
+config STUB_START
+ hex
+ default STUB_CODE
+
config ARCH_HAS_SC_SIGNALS
bool
default y
diff --git a/arch/um/Kconfig_x86_64 b/arch/um/Kconfig_x86_64
index f162f50f0b1..735a047c890 100644
--- a/arch/um/Kconfig_x86_64
+++ b/arch/um/Kconfig_x86_64
@@ -14,6 +14,18 @@ config 3_LEVEL_PGTABLES
bool
default y
+config STUB_CODE
+ hex
+ default 0x7fbfffe000
+
+config STUB_DATA
+ hex
+ default 0x7fbffff000
+
+config STUB_START
+ hex
+ default STUB_CODE
+
config ARCH_HAS_SC_SIGNALS
bool
default n
diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386
index 29e182d5a83..301059062a3 100644
--- a/arch/um/Makefile-i386
+++ b/arch/um/Makefile-i386
@@ -8,7 +8,7 @@ ifeq ($(CONFIG_MODE_SKAS),y)
endif
endif
-CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH)
+CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) $(STUB_CFLAGS)
ARCH_USER_CFLAGS :=
ifneq ($(CONFIG_GPROF),y)
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64
index 32144562c27..d80bd0052e6 100644
--- a/arch/um/Makefile-x86_64
+++ b/arch/um/Makefile-x86_64
@@ -4,7 +4,7 @@
SUBARCH_LIBS := arch/um/sys-x86_64/
START := 0x60000000
-CFLAGS += -U__$(SUBARCH)__ -fno-builtin
+CFLAGS += -U__$(SUBARCH)__ -fno-builtin $(STUB_CFLAGS)
ARCH_USER_CFLAGS := -D__x86_64__
ELF_ARCH := i386:x86-64
diff --git a/arch/um/defconfig b/arch/um/defconfig
index 4067c3aa5b6..80d30d19d75 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc3-skas3-v9-pre2
-# Sun Apr 24 19:46:10 2005
+# Linux kernel version: 2.6.12-rc6-mm1
+# Tue Jun 14 18:22:21 2005
#
CONFIG_GENERIC_HARDIRQS=y
CONFIG_UML=y
@@ -13,23 +13,32 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y
#
# UML-specific options
#
-CONFIG_MODE_TT=y
+# CONFIG_MODE_TT is not set
+# CONFIG_STATIC_LINK is not set
CONFIG_MODE_SKAS=y
CONFIG_UML_X86=y
# CONFIG_64BIT is not set
CONFIG_TOP_ADDR=0xc0000000
# CONFIG_3_LEVEL_PGTABLES is not set
+CONFIG_STUB_CODE=0xbfffe000
+CONFIG_STUB_DATA=0xbffff000
+CONFIG_STUB_START=0xbfffe000
CONFIG_ARCH_HAS_SC_SIGNALS=y
CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y
-CONFIG_LD_SCRIPT_STATIC=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_LD_SCRIPT_DYN=y
CONFIG_NET=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
-CONFIG_HOSTFS=y
+# CONFIG_HOSTFS is not set
CONFIG_MCONSOLE=y
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_HOST_2G_2G is not set
-# CONFIG_SMP is not set
CONFIG_NEST_LEVEL=0
CONFIG_KERNEL_HALF_GIGS=1
# CONFIG_HIGHMEM is not set
@@ -63,6 +72,8 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
@@ -81,6 +92,7 @@ CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
@@ -115,6 +127,7 @@ CONFIG_UML_SOUND=m
CONFIG_SOUND=m
CONFIG_HOSTAUDIO=m
CONFIG_UML_RANDOM=y
+# CONFIG_MMAPPER is not set
#
# Block devices
@@ -176,6 +189,17 @@ CONFIG_INET=y
# CONFIG_INET_TUNNEL is not set
CONFIG_IP_TCPDIAG=y
# CONFIG_IP_TCPDIAG_IPV6 is not set
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_WESTWOOD=y
+CONFIG_TCP_CONG_HTCP=y
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
# CONFIG_IPV6 is not set
# CONFIG_NETFILTER is not set
@@ -206,11 +230,15 @@ CONFIG_IP_TCPDIAG=y
# Network testing
#
# CONFIG_NET_PKTGEN is not set
+# CONFIG_KGDBOE is not set
# CONFIG_NETPOLL is not set
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
# CONFIG_NET_POLL_CONTROLLER is not set
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
CONFIG_DUMMY=m
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
@@ -227,6 +255,7 @@ CONFIG_PPP=m
# CONFIG_PPP_SYNC_TTY is not set
# CONFIG_PPP_DEFLATE is not set
# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
# CONFIG_PPPOE is not set
CONFIG_SLIP=m
# CONFIG_SLIP_COMPRESSED is not set
@@ -240,10 +269,12 @@ CONFIG_SLIP=m
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
# CONFIG_EXT3_FS_XATTR is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISER4_FS is not set
CONFIG_REISERFS_FS=y
# CONFIG_REISERFS_CHECK is not set
# CONFIG_REISERFS_PROC_INFO is not set
@@ -256,6 +287,7 @@ CONFIG_REISERFS_FS=y
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
CONFIG_QUOTA=y
# CONFIG_QFMT_V1 is not set
# CONFIG_QFMT_V2 is not set
@@ -265,6 +297,12 @@ CONFIG_AUTOFS_FS=m
CONFIG_AUTOFS4_FS=m
#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+# CONFIG_FUSE_FS is not set
+
+#
# CD-ROM/DVD Filesystems
#
CONFIG_ISO9660_FS=m
@@ -291,6 +329,8 @@ CONFIG_TMPFS=y
# CONFIG_TMPFS_XATTR is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_RELAYFS_FS is not set
#
# Miscellaneous filesystems
@@ -319,6 +359,7 @@ CONFIG_RAMFS=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
#
# Partition Types
@@ -404,14 +445,15 @@ CONFIG_CRC32=m
# CONFIG_PRINTK_TIME is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_SLAB=y
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_FS is not set
CONFIG_FRAME_POINTER=y
-CONFIG_PT_PROXY=y
+# CONFIG_GPROF is not set
# CONFIG_GCOV is not set
# CONFIG_SYSCALL_DEBUG is not set
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 2bb4c4f5dec..e0fdffa2d54 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -663,11 +663,15 @@ struct tty_driver *line_register_devfs(struct lines *set,
return driver;
}
+static spinlock_t winch_handler_lock;
+LIST_HEAD(winch_handlers);
+
void lines_init(struct line *lines, int nlines)
{
struct line *line;
int i;
+ spin_lock_init(&winch_handler_lock);
for(i = 0; i < nlines; i++){
line = &lines[i];
INIT_LIST_HEAD(&line->chan_list);
@@ -724,31 +728,30 @@ irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused)
return IRQ_HANDLED;
}
-DECLARE_MUTEX(winch_handler_sem);
-LIST_HEAD(winch_handlers);
-
void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty)
{
struct winch *winch;
- down(&winch_handler_sem);
winch = kmalloc(sizeof(*winch), GFP_KERNEL);
if (winch == NULL) {
printk("register_winch_irq - kmalloc failed\n");
- goto out;
+ return;
}
+
*winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list),
.fd = fd,
.tty_fd = tty_fd,
.pid = pid,
.tty = tty });
+
+ spin_lock(&winch_handler_lock);
list_add(&winch->list, &winch_handlers);
+ spin_unlock(&winch_handler_lock);
+
if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
"winch", winch) < 0)
printk("register_winch_irq - failed to register IRQ\n");
- out:
- up(&winch_handler_sem);
}
static void unregister_winch(struct tty_struct *tty)
@@ -756,7 +759,7 @@ static void unregister_winch(struct tty_struct *tty)
struct list_head *ele;
struct winch *winch, *found = NULL;
- down(&winch_handler_sem);
+ spin_lock(&winch_handler_lock);
list_for_each(ele, &winch_handlers){
winch = list_entry(ele, struct winch, list);
if(winch->tty == tty){
@@ -764,20 +767,25 @@ static void unregister_winch(struct tty_struct *tty)
break;
}
}
-
if(found == NULL)
- goto out;
+ goto err;
+
+ list_del(&winch->list);
+ spin_unlock(&winch_handler_lock);
if(winch->pid != -1)
os_kill_process(winch->pid, 1);
free_irq(WINCH_IRQ, winch);
- list_del(&winch->list);
kfree(winch);
- out:
- up(&winch_handler_sem);
+
+ return;
+err:
+ spin_unlock(&winch_handler_lock);
}
+/* XXX: No lock as it's an exitcall... is this valid? Depending on cleanup
+ * order... are we sure that nothing else is done on the list? */
static void winch_cleanup(void)
{
struct list_head *ele;
@@ -786,6 +794,9 @@ static void winch_cleanup(void)
list_for_each(ele, &winch_handlers){
winch = list_entry(ele, struct winch, list);
if(winch->fd != -1){
+ /* Why is this different from the above free_irq(),
+ * which deactivates SIGIO? This searches the FD
+ * somewhere else and removes it from the list... */
deactivate_fd(winch->fd, WINCH_IRQ);
os_close_file(winch->fd);
}
diff --git a/arch/um/include/mem.h b/arch/um/include/mem.h
index 10c46c38949..99d3ad4a03e 100644
--- a/arch/um/include/mem.h
+++ b/arch/um/include/mem.h
@@ -13,6 +13,7 @@ extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w);
extern int is_remapped(void *virt);
extern int physmem_remove_mapping(void *virt);
extern void physmem_forget_descriptor(int fd);
+extern unsigned long to_phys(void *virt);
#endif
diff --git a/arch/um/include/registers.h b/arch/um/include/registers.h
index 8744abb5224..0a35e6d0baa 100644
--- a/arch/um/include/registers.h
+++ b/arch/um/include/registers.h
@@ -14,6 +14,7 @@ extern int restore_fp_registers(int pid, unsigned long *fp_regs);
extern void save_registers(int pid, union uml_pt_regs *regs);
extern void restore_registers(int pid, union uml_pt_regs *regs);
extern void init_registers(int pid);
+extern void get_safe_registers(unsigned long * regs);
#endif
diff --git a/arch/um/include/sysdep-i386/ptrace_user.h b/arch/um/include/sysdep-i386/ptrace_user.h
index eca8066e7a4..899aa4b2a78 100644
--- a/arch/um/include/sysdep-i386/ptrace_user.h
+++ b/arch/um/include/sysdep-i386/ptrace_user.h
@@ -20,11 +20,24 @@
#define PT_SYSCALL_ARG3_OFFSET PT_OFFSET(EDX)
#define PT_SYSCALL_ARG4_OFFSET PT_OFFSET(ESI)
#define PT_SYSCALL_ARG5_OFFSET PT_OFFSET(EDI)
+#define PT_SYSCALL_ARG6_OFFSET PT_OFFSET(EBP)
#define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX)
+#define REGS_SYSCALL_NR EAX /* This is used before a system call */
+#define REGS_SYSCALL_ARG1 EBX
+#define REGS_SYSCALL_ARG2 ECX
+#define REGS_SYSCALL_ARG3 EDX
+#define REGS_SYSCALL_ARG4 ESI
+#define REGS_SYSCALL_ARG5 EDI
+#define REGS_SYSCALL_ARG6 EBP
+
+#define REGS_IP_INDEX EIP
+#define REGS_SP_INDEX UESP
+
#define PT_IP_OFFSET PT_OFFSET(EIP)
#define PT_IP(regs) ((regs)[EIP])
+#define PT_SP_OFFSET PT_OFFSET(UESP)
#define PT_SP(regs) ((regs)[UESP])
#ifndef FRAME_SIZE
diff --git a/arch/um/include/sysdep-i386/stub.h b/arch/um/include/sysdep-i386/stub.h
new file mode 100644
index 00000000000..d3699fe1c61
--- /dev/null
+++ b/arch/um/include/sysdep-i386/stub.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_STUB_H
+#define __SYSDEP_STUB_H
+
+#include <asm/ptrace.h>
+#include <asm/unistd.h>
+
+extern void stub_segv_handler(int sig);
+extern void stub_clone_handler(void);
+
+#define STUB_SYSCALL_RET EAX
+#define STUB_MMAP_NR __NR_mmap2
+#define MMAP_OFFSET(o) ((o) >> PAGE_SHIFT)
+
+static inline long stub_syscall2(long syscall, long arg1, long arg2)
+{
+ long ret;
+
+ __asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx");
+ __asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx");
+ __asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax");
+ __asm__("int $0x80;" : : : "%eax");
+ __asm__ __volatile__("movl %%eax, %0; " : "=g" (ret) :);
+ return(ret);
+}
+
+static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3)
+{
+ __asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx");
+ return(stub_syscall2(syscall, arg1, arg2));
+}
+
+static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3,
+ long arg4)
+{
+ __asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi");
+ return(stub_syscall3(syscall, arg1, arg2, arg3));
+}
+
+static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3,
+ long arg4, long arg5, long arg6)
+{
+ long ret;
+ __asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax");
+ __asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx");
+ __asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx");
+ __asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx");
+ __asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi");
+ __asm__("movl %0, %%edi; " : : "g" (arg5) : "%edi");
+ __asm__ __volatile__("pushl %%ebp ; movl %1, %%ebp; "
+ "int $0x80; popl %%ebp ; "
+ "movl %%eax, %0; " : "=g" (ret) : "g" (arg6) : "%eax");
+ return(ret);
+}
+
+static inline void trap_myself(void)
+{
+ __asm("int3");
+}
+
+#endif
diff --git a/arch/um/include/sysdep-x86_64/ptrace_user.h b/arch/um/include/sysdep-x86_64/ptrace_user.h
index 31729973fb1..128faf02736 100644
--- a/arch/um/include/sysdep-x86_64/ptrace_user.h
+++ b/arch/um/include/sysdep-x86_64/ptrace_user.h
@@ -55,6 +55,20 @@
#define PTRACE_OLDSETOPTIONS 21
#endif
+/* These are before the system call, so the the system call number is RAX
+ * rather than ORIG_RAX, and arg4 is R10 rather than RCX
+ */
+#define REGS_SYSCALL_NR PT_INDEX(RAX)
+#define REGS_SYSCALL_ARG1 PT_INDEX(RDI)
+#define REGS_SYSCALL_ARG2 PT_INDEX(RSI)
+#define REGS_SYSCALL_ARG3 PT_INDEX(RDX)
+#define REGS_SYSCALL_ARG4 PT_INDEX(R10)
+#define REGS_SYSCALL_ARG5 PT_INDEX(R8)
+#define REGS_SYSCALL_ARG6 PT_INDEX(R9)
+
+#define REGS_IP_INDEX PT_INDEX(RIP)
+#define REGS_SP_INDEX PT_INDEX(RSP)
+
#endif
/*
diff --git a/arch/um/include/sysdep-x86_64/stub.h b/arch/um/include/sysdep-x86_64/stub.h
new file mode 100644
index 00000000000..f599058d826
--- /dev/null
+++ b/arch/um/include/sysdep-x86_64/stub.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_STUB_H
+#define __SYSDEP_STUB_H
+
+#include <asm/ptrace.h>
+#include <asm/unistd.h>
+#include <sysdep/ptrace_user.h>
+
+extern void stub_segv_handler(int sig);
+extern void stub_clone_handler(void);
+
+#define STUB_SYSCALL_RET PT_INDEX(RAX)
+#define STUB_MMAP_NR __NR_mmap
+#define MMAP_OFFSET(o) (o)
+
+static inline long stub_syscall2(long syscall, long arg1, long arg2)
+{
+ long ret;
+
+ __asm__("movq %0, %%rsi; " : : "g" (arg2) : "%rsi");
+ __asm__("movq %0, %%rdi; " : : "g" (arg1) : "%rdi");
+ __asm__("movq %0, %%rax; " : : "g" (syscall) : "%rax");
+ __asm__("syscall;" : : : "%rax", "%r11", "%rcx");
+ __asm__ __volatile__("movq %%rax, %0; " : "=g" (ret) :);
+ return(ret);
+}
+
+static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3)
+{
+ __asm__("movq %0, %%rdx; " : : "g" (arg3) : "%rdx");
+ return(stub_syscall2(syscall, arg1, arg2));
+}
+
+static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3,
+ long arg4)
+{
+ __asm__("movq %0, %%r10; " : : "g" (arg4) : "%r10");
+ return(stub_syscall3(syscall, arg1, arg2, arg3));
+}
+
+static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3,
+ long arg4, long arg5, long arg6)
+{
+ __asm__("movq %0, %%r9; " : : "g" (arg6) : "%r9");
+ __asm__("movq %0, %%r8; " : : "g" (arg5) : "%r8");
+ return(stub_syscall4(syscall, arg1, arg2, arg3, arg4));
+}
+
+static inline void trap_myself(void)
+{
+ __asm("int3");
+}
+
+#endif
diff --git a/arch/um/include/time_user.h b/arch/um/include/time_user.h
index f64ef77019a..17d7ef2141f 100644
--- a/arch/um/include/time_user.h
+++ b/arch/um/include/time_user.h
@@ -10,6 +10,7 @@ extern void timer(void);
extern void switch_timers(int to_real);
extern void idle_sleep(int secs);
extern void enable_timer(void);
+extern void prepare_timer(void * ptr);
extern void disable_timer(void);
extern unsigned long time_lock(void);
extern void time_unlock(unsigned long);
diff --git a/arch/um/include/tlb.h b/arch/um/include/tlb.h
index da1097285b8..c6f9628f39b 100644
--- a/arch/um/include/tlb.h
+++ b/arch/um/include/tlb.h
@@ -37,31 +37,25 @@ struct host_vm_op {
extern void mprotect_kernel_vm(int w);
extern void force_flush_all(void);
extern void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
- unsigned long end_addr, int force, int data,
- void (*do_ops)(int, struct host_vm_op *, int));
+ unsigned long end_addr, int force,
+ void (*do_ops)(union mm_context *,
+ struct host_vm_op *, int));
extern int flush_tlb_kernel_range_common(unsigned long start,
unsigned long end);
extern int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
int r, int w, int x, struct host_vm_op *ops, int index,
- int last_filled, int data,
- void (*do_ops)(int, struct host_vm_op *, int));
+ int last_filled, union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *,
+ int));
extern int add_munmap(unsigned long addr, unsigned long len,
struct host_vm_op *ops, int index, int last_filled,
- int data, void (*do_ops)(int, struct host_vm_op *, int));
+ union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *,
+ int));
extern int add_mprotect(unsigned long addr, unsigned long len, int r, int w,
int x, struct host_vm_op *ops, int index,
- int last_filled, int data,
- void (*do_ops)(int, struct host_vm_op *, int));
+ int last_filled, union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *,
+ int));
#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index 715b0838a68..3942a5f245d 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -67,6 +67,12 @@ SECTIONS
*(.stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
+
+ . = ALIGN(4096);
+ __syscall_stub_start = .;
+ *(.__syscall_stub*)
+ __syscall_stub_end = .;
+ . = ALIGN(4096);
} =0x90909090
.fini : {
KEEP (*(.fini))
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
index 420e6d51fa0..a24e3b7f4bf 100644
--- a/arch/um/kernel/physmem.c
+++ b/arch/um/kernel/physmem.c
@@ -353,6 +353,8 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+extern int __syscall_stub_start, __binary_start;
+
void setup_physmem(unsigned long start, unsigned long reserve_end,
unsigned long len, unsigned long highmem)
{
@@ -371,6 +373,12 @@ void setup_physmem(unsigned long start, unsigned long reserve_end,
exit(1);
}
+ /* Special kludge - This page will be mapped in to userspace processes
+ * from physmem_fd, so it needs to be written out there.
+ */
+ os_seek_file(physmem_fd, __pa(&__syscall_stub_start));
+ os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE);
+
bootmap_size = init_bootmem(pfn, pfn + delta);
free_bootmem(__pa(reserve_end) + bootmap_size,
len - bootmap_size - reserve);
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 1b5ef3e96c7..c45a60e9c92 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -32,6 +32,7 @@
#include "uml-config.h"
#include "choose-mode.h"
#include "mode.h"
+#include "tempfile.h"
#ifdef UML_CONFIG_MODE_SKAS
#include "skas.h"
#include "skas_ptrace.h"
@@ -358,11 +359,16 @@ void forward_pending_sigio(int target)
kill(target, SIGIO);
}
+int ptrace_faultinfo = 0;
+int proc_mm = 1;
+
+extern void *__syscall_stub_start, __syscall_stub_end;
+
#ifdef UML_CONFIG_MODE_SKAS
-static inline int check_skas3_ptrace_support(void)
+static inline void check_skas3_ptrace_support(void)
{
struct ptrace_faultinfo fi;
- int pid, n, ret = 1;
+ int pid, n;
printf("Checking for the skas3 patch in the host...");
pid = start_ptraced_child();
@@ -374,33 +380,31 @@ static inline int check_skas3_ptrace_support(void)
else {
perror("not found");
}
- ret = 0;
- } else {
+ }
+ else {
+ ptrace_faultinfo = 1;
printf("found\n");
}
init_registers(pid);
stop_ptraced_child(pid, 1, 1);
-
- return(ret);
}
int can_do_skas(void)
{
- int ret = 1;
-
printf("Checking for /proc/mm...");
if (os_access("/proc/mm", OS_ACC_W_OK) < 0) {
+ proc_mm = 0;
printf("not found\n");
- ret = 0;
goto out;
- } else {
+ }
+ else {
printf("found\n");
}
- ret = check_skas3_ptrace_support();
out:
- return ret;
+ check_skas3_ptrace_support();
+ return 1;
}
#else
int can_do_skas(void)
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
index ff69c4b312c..d296d55ade4 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -3,11 +3,14 @@
# Licensed under the GPL
#
-obj-y := exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
+obj-y := clone.o exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
syscall_kern.o syscall_user.o tlb.o trap_user.o uaccess.o \
subdir- := util
-USER_OBJS := process.o
+USER_OBJS := process.o clone.o
include arch/um/scripts/Makefile.rules
+
+# clone.o is in the stub, so it can't be built with profiling
+$(obj)/clone.o : c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c
new file mode 100644
index 00000000000..4dc55f10cd1
--- /dev/null
+++ b/arch/um/kernel/skas/clone.c
@@ -0,0 +1,44 @@
+#include <sched.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <asm/unistd.h>
+#include <asm/page.h>
+#include "ptrace_user.h"
+#include "skas.h"
+#include "stub-data.h"
+#include "uml-config.h"
+#include "sysdep/stub.h"
+
+/* This is in a separate file because it needs to be compiled with any
+ * extraneous gcc flags (-pg, -fprofile-arcs, -ftest-coverage) disabled
+ */
+void __attribute__ ((__section__ (".__syscall_stub")))
+stub_clone_handler(void)
+{
+ long err;
+ struct stub_data *from = (struct stub_data *) UML_CONFIG_STUB_DATA;
+
+ err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
+ UML_CONFIG_STUB_DATA + PAGE_SIZE / 2 -
+ sizeof(void *));
+ if(err != 0)
+ goto out;
+
+ err = stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0);
+ if(err)
+ goto out;
+
+ err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL,
+ (long) &from->timer, 0);
+ if(err)
+ goto out;
+
+ err = stub_syscall6(STUB_MMAP_NR, UML_CONFIG_STUB_DATA, PAGE_SIZE,
+ PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED,
+ from->fd, from->offset);
+ out:
+ /* save current result. Parent: pid; child: retcode of mmap */
+ from->err = err;
+ trap_myself();
+}
diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c
index c6b4d5dba78..77ed7bbab21 100644
--- a/arch/um/kernel/skas/exec_kern.c
+++ b/arch/um/kernel/skas/exec_kern.c
@@ -18,7 +18,7 @@
void flush_thread_skas(void)
{
force_flush_all();
- switch_mm_skas(current->mm->context.skas.mm_fd);
+ switch_mm_skas(&current->mm->context.skas.id);
}
void start_thread_skas(struct pt_regs *regs, unsigned long eip,
diff --git a/arch/um/kernel/skas/include/mm_id.h b/arch/um/kernel/skas/include/mm_id.h
new file mode 100644
index 00000000000..48dd0989dda
--- /dev/null
+++ b/arch/um/kernel/skas/include/mm_id.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MM_ID_H
+#define __MM_ID_H
+
+struct mm_id {
+ union {
+ int mm_fd;
+ int pid;
+ } u;
+ unsigned long stack;
+};
+
+#endif
diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h
index 4cd60d7213f..278b72f1d9a 100644
--- a/arch/um/kernel/skas/include/mmu-skas.h
+++ b/arch/um/kernel/skas/include/mmu-skas.h
@@ -6,10 +6,15 @@
#ifndef __SKAS_MMU_H
#define __SKAS_MMU_H
+#include "mm_id.h"
+
struct mmu_context_skas {
- int mm_fd;
+ struct mm_id id;
+ unsigned long last_page_table;
};
+extern void switch_mm_skas(struct mm_id * mm_idp);
+
#endif
/*
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h
index 96b51dba347..d983ea84254 100644
--- a/arch/um/kernel/skas/include/skas.h
+++ b/arch/um/kernel/skas/include/skas.h
@@ -6,9 +6,11 @@
#ifndef __SKAS_H
#define __SKAS_H
+#include "mm_id.h"
#include "sysdep/ptrace.h"
extern int userspace_pid[];
+extern int proc_mm, ptrace_faultinfo;
extern void switch_threads(void *me, void *next);
extern void thread_wait(void *sw, void *fb);
@@ -22,16 +24,18 @@ extern void new_thread_proc(void *stack, void (*handler)(int sig));
extern void remove_sigstack(void);
extern void new_thread_handler(int sig);
extern void handle_syscall(union uml_pt_regs *regs);
-extern void map(int fd, unsigned long virt, unsigned long len, int r, int w,
- int x, int phys_fd, unsigned long long offset);
-extern int unmap(int fd, void *addr, unsigned long len);
-extern int protect(int fd, unsigned long addr, unsigned long len,
- int r, int w, int x);
+extern int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
+ int r, int w, int x, int phys_fd, unsigned long long offset);
+extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len);
+extern int protect(struct mm_id * mm_idp, unsigned long addr,
+ unsigned long len, int r, int w, int x);
extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
extern int new_mm(int from);
-extern void start_userspace(int cpu);
+extern int start_userspace(unsigned long stub_stack);
+extern int copy_context_skas0(unsigned long stack, int pid);
extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
extern long execute_syscall_skas(void *r);
+extern unsigned long current_stub_stack(void);
#endif
diff --git a/arch/um/kernel/skas/include/stub-data.h b/arch/um/kernel/skas/include/stub-data.h
new file mode 100644
index 00000000000..f6ed92c3727
--- /dev/null
+++ b/arch/um/kernel/skas/include/stub-data.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __STUB_DATA_H
+#define __STUB_DATA_H
+
+#include <sys/time.h>
+
+struct stub_data {
+ long offset;
+ int fd;
+ struct itimerval timer;
+ long err;
+};
+
+#endif
diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c
index 438db2f4345..147466d7ff4 100644
--- a/arch/um/kernel/skas/mem.c
+++ b/arch/um/kernel/skas/mem.c
@@ -5,7 +5,9 @@
#include "linux/config.h"
#include "linux/mm.h"
+#include "asm/pgtable.h"
#include "mem_user.h"
+#include "skas.h"
unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
unsigned long *task_size_out)
@@ -18,7 +20,9 @@ unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
*task_size_out = CONFIG_HOST_TASK_SIZE;
#else
*host_size_out = top;
- *task_size_out = top;
+ if (proc_mm && ptrace_faultinfo)
+ *task_size_out = top;
+ else *task_size_out = CONFIG_STUB_START & PGDIR_MASK;
#endif
return(((unsigned long) set_task_sizes_skas) & ~0xffffff);
}
diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c
index 1310bf1e88d..b0980ff3bd9 100644
--- a/arch/um/kernel/skas/mem_user.c
+++ b/arch/um/kernel/skas/mem_user.c
@@ -3,100 +3,171 @@
* Licensed under the GPL
*/
+#include <signal.h>
#include <errno.h>
#include <sys/mman.h>
+#include <sys/wait.h>
+#include <asm/page.h>
+#include <asm/unistd.h>
#include "mem_user.h"
#include "mem.h"
+#include "mm_id.h"
#include "user.h"
#include "os.h"
#include "proc_mm.h"
-
-void map(int fd, unsigned long virt, unsigned long len, int r, int w,
- int x, int phys_fd, unsigned long long offset)
+#include "ptrace_user.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "task.h"
+#include "registers.h"
+#include "uml-config.h"
+#include "sysdep/ptrace.h"
+#include "sysdep/stub.h"
+#include "skas.h"
+
+extern unsigned long syscall_stub, __syscall_stub_start;
+
+extern void wait_stub_done(int pid, int sig, char * fname);
+
+static long run_syscall_stub(struct mm_id * mm_idp, int syscall,
+ unsigned long *args)
{
- struct proc_mm_op map;
- int prot, n;
-
- prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
- (x ? PROT_EXEC : 0);
-
- map = ((struct proc_mm_op) { .op = MM_MMAP,
- .u =
- { .mmap =
- { .addr = virt,
- .len = len,
- .prot = prot,
- .flags = MAP_SHARED |
- MAP_FIXED,
- .fd = phys_fd,
- .offset = offset
- } } } );
- n = os_write_file(fd, &map, sizeof(map));
- if(n != sizeof(map))
- printk("map : /proc/mm map failed, err = %d\n", -n);
+ int n, pid = mm_idp->u.pid;
+ unsigned long regs[MAX_REG_NR];
+
+ get_safe_registers(regs);
+ regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
+ ((unsigned long) &syscall_stub -
+ (unsigned long) &__syscall_stub_start);
+ /* XXX Don't have a define for starting a syscall */
+ regs[REGS_SYSCALL_NR] = syscall;
+ regs[REGS_SYSCALL_ARG1] = args[0];
+ regs[REGS_SYSCALL_ARG2] = args[1];
+ regs[REGS_SYSCALL_ARG3] = args[2];
+ regs[REGS_SYSCALL_ARG4] = args[3];
+ regs[REGS_SYSCALL_ARG5] = args[4];
+ regs[REGS_SYSCALL_ARG6] = args[5];
+ n = ptrace_setregs(pid, regs);
+ if(n < 0){
+ printk("run_syscall_stub : PTRACE_SETREGS failed, "
+ "errno = %d\n", n);
+ return(n);
+ }
+
+ wait_stub_done(pid, 0, "run_syscall_stub");
+
+ return(*((unsigned long *) mm_idp->stack));
}
-int unmap(int fd, void *addr, unsigned long len)
+int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len,
+ int r, int w, int x, int phys_fd, unsigned long long offset)
{
- struct proc_mm_op unmap;
- int n;
-
- unmap = ((struct proc_mm_op) { .op = MM_MUNMAP,
- .u =
- { .munmap =
- { .addr = (unsigned long) addr,
- .len = len } } } );
- n = os_write_file(fd, &unmap, sizeof(unmap));
- if(n != sizeof(unmap)) {
- if(n < 0)
- return(n);
- else if(n > 0)
- return(-EIO);
- }
-
- return(0);
+ int prot, n;
+
+ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
+ (x ? PROT_EXEC : 0);
+
+ if(proc_mm){
+ struct proc_mm_op map;
+ int fd = mm_idp->u.mm_fd;
+ map = ((struct proc_mm_op) { .op = MM_MMAP,
+ .u =
+ { .mmap =
+ { .addr = virt,
+ .len = len,
+ .prot = prot,
+ .flags = MAP_SHARED |
+ MAP_FIXED,
+ .fd = phys_fd,
+ .offset= offset
+ } } } );
+ n = os_write_file(fd, &map, sizeof(map));
+ if(n != sizeof(map))
+ printk("map : /proc/mm map failed, err = %d\n", -n);
+ }
+ else {
+ long res;
+ unsigned long args[] = { virt, len, prot,
+ MAP_SHARED | MAP_FIXED, phys_fd,
+ MMAP_OFFSET(offset) };
+
+ res = run_syscall_stub(mm_idp, STUB_MMAP_NR, args);
+ if((void *) res == MAP_FAILED)
+ printk("mmap stub failed, errno = %d\n", res);
+ }
+
+ return 0;
}
-int protect(int fd, unsigned long addr, unsigned long len, int r, int w,
- int x, int must_succeed)
+int unmap(struct mm_id *mm_idp, void *addr, unsigned long len)
{
- struct proc_mm_op protect;
- int prot, n;
-
- prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
- (x ? PROT_EXEC : 0);
-
- protect = ((struct proc_mm_op) { .op = MM_MPROTECT,
- .u =
- { .mprotect =
- { .addr = (unsigned long) addr,
- .len = len,
- .prot = prot } } } );
-
- n = os_write_file(fd, &protect, sizeof(protect));
- if(n != sizeof(protect)) {
- if(n == 0) return(0);
-
- if(must_succeed)
- panic("protect failed, err = %d", -n);
-
- return(-EIO);
- }
+ int n;
+
+ if(proc_mm){
+ struct proc_mm_op unmap;
+ int fd = mm_idp->u.mm_fd;
+ unmap = ((struct proc_mm_op) { .op = MM_MUNMAP,
+ .u =
+ { .munmap =
+ { .addr =
+ (unsigned long) addr,
+ .len = len } } } );
+ n = os_write_file(fd, &unmap, sizeof(unmap));
+ if(n != sizeof(unmap)) {
+ if(n < 0)
+ return(n);
+ else if(n > 0)
+ return(-EIO);
+ }
+ }
+ else {
+ int res;
+ unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
+ 0 };
+
+ res = run_syscall_stub(mm_idp, __NR_munmap, args);
+ if(res < 0)
+ printk("munmap stub failed, errno = %d\n", res);
+ }
+
+ return(0);
+}
- return(0);
+int protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len,
+ int r, int w, int x)
+{
+ struct proc_mm_op protect;
+ int prot, n;
+
+ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
+ (x ? PROT_EXEC : 0);
+
+ if(proc_mm){
+ int fd = mm_idp->u.mm_fd;
+ protect = ((struct proc_mm_op) { .op = MM_MPROTECT,
+ .u =
+ { .mprotect =
+ { .addr =
+ (unsigned long) addr,
+ .len = len,
+ .prot = prot } } } );
+
+ n = os_write_file(fd, &protect, sizeof(protect));
+ if(n != sizeof(protect))
+ panic("protect failed, err = %d", -n);
+ }
+ else {
+ int res;
+ unsigned long args[] = { addr, len, prot, 0, 0, 0 };
+
+ res = run_syscall_stub(mm_idp, __NR_mprotect, args);
+ if(res < 0)
+ panic("mprotect stub failed, errno = %d\n", res);
+ }
+
+ return(0);
}
void before_mem_skas(unsigned long unused)
{
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 6cb9a6d028a..d232daa42c3 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -3,46 +3,143 @@
* Licensed under the GPL
*/
+#include "linux/config.h"
#include "linux/sched.h"
#include "linux/list.h"
#include "linux/spinlock.h"
#include "linux/slab.h"
+#include "linux/errno.h"
+#include "linux/mm.h"
#include "asm/current.h"
#include "asm/segment.h"
#include "asm/mmu.h"
+#include "asm/pgalloc.h"
+#include "asm/pgtable.h"
#include "os.h"
#include "skas.h"
+extern int __syscall_stub_start;
+
+static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
+ unsigned long kernel)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ spin_lock(&mm->page_table_lock);
+ pgd = pgd_offset(mm, proc);
+ pud = pud_alloc(mm, pgd, proc);
+ if (!pud)
+ goto out;
+
+ pmd = pmd_alloc(mm, pud, proc);
+ if (!pmd)
+ goto out_pmd;
+
+ pte = pte_alloc_map(mm, pmd, proc);
+ if (!pte)
+ goto out_pte;
+
+ /* There's an interaction between the skas0 stub pages, stack
+ * randomization, and the BUG at the end of exit_mmap. exit_mmap
+ * checks that the number of page tables freed is the same as had
+ * been allocated. If the stack is on the last page table page,
+ * then the stack pte page will be freed, and if not, it won't. To
+ * avoid having to know where the stack is, or if the process mapped
+ * something at the top of its address space for some other reason,
+ * we set TASK_SIZE to end at the start of the last page table.
+ * This keeps exit_mmap off the last page, but introduces a leak
+ * of that page. So, we hang onto it here and free it in
+ * destroy_context_skas.
+ */
+
+ mm->context.skas.last_page_table = pmd_page_kernel(*pmd);
+
+ *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT));
+ *pte = pte_mkexec(*pte);
+ *pte = pte_wrprotect(*pte);
+ spin_unlock(&mm->page_table_lock);
+ return(0);
+
+ out_pmd:
+ pud_free(pud);
+ out_pte:
+ pmd_free(pmd);
+ out:
+ spin_unlock(&mm->page_table_lock);
+ return(-ENOMEM);
+}
+
int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
{
- int from;
+ struct mm_struct *cur_mm = current->mm;
+ struct mm_id *cur_mm_id = &cur_mm->context.skas.id;
+ struct mm_id *mm_id = &mm->context.skas.id;
+ unsigned long stack;
+ int from, ret;
- if((current->mm != NULL) && (current->mm != &init_mm))
- from = current->mm->context.skas.mm_fd;
- else from = -1;
+ if(proc_mm){
+ if((cur_mm != NULL) && (cur_mm != &init_mm))
+ from = cur_mm->context.skas.id.u.mm_fd;
+ else from = -1;
- mm->context.skas.mm_fd = new_mm(from);
- if(mm->context.skas.mm_fd < 0){
- printk("init_new_context_skas - new_mm failed, errno = %d\n",
- mm->context.skas.mm_fd);
- return(mm->context.skas.mm_fd);
+ ret = new_mm(from);
+ if(ret < 0){
+ printk("init_new_context_skas - new_mm failed, "
+ "errno = %d\n", ret);
+ return ret;
+ }
+ mm_id->u.mm_fd = ret;
}
+ else {
+ /* This zeros the entry that pgd_alloc didn't, needed since
+ * we are about to reinitialize it, and want mm.nr_ptes to
+ * be accurate.
+ */
+ mm->pgd[USER_PTRS_PER_PGD] = __pgd(0);
- return(0);
+ ret = init_stub_pte(mm, CONFIG_STUB_CODE,
+ (unsigned long) &__syscall_stub_start);
+ if(ret)
+ goto out;
+
+ ret = -ENOMEM;
+ stack = get_zeroed_page(GFP_KERNEL);
+ if(stack == 0)
+ goto out;
+ mm_id->stack = stack;
+
+ ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack);
+ if(ret)
+ goto out_free;
+
+ mm->nr_ptes--;
+
+ if((cur_mm != NULL) && (cur_mm != &init_mm))
+ mm_id->u.pid = copy_context_skas0(stack,
+ cur_mm_id->u.pid);
+ else mm_id->u.pid = start_userspace(stack);
+ }
+
+ return 0;
+
+ out_free:
+ free_page(mm_id->stack);
+ out:
+ return ret;
}
void destroy_context_skas(struct mm_struct *mm)
{
- os_close_file(mm->context.skas.mm_fd);
-}
+ struct mmu_context_skas *mmu = &mm->context.skas;
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+ if(proc_mm)
+ os_close_file(mmu->id.u.mm_fd);
+ else {
+ os_kill_ptraced_process(mmu->id.u.pid, 1);
+ free_page(mmu->id.stack);
+ free_page(mmu->last_page_table);
+ }
+}
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index 773cd2b525f..ba671dab887 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002- 2004 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
@@ -13,7 +13,9 @@
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/user.h>
+#include <sys/time.h>
#include <asm/unistd.h>
+#include <asm/types.h>
#include "user.h"
#include "ptrace_user.h"
#include "time_user.h"
@@ -21,13 +23,18 @@
#include "user_util.h"
#include "kern_util.h"
#include "skas.h"
+#include "stub-data.h"
+#include "mm_id.h"
#include "sysdep/sigcontext.h"
+#include "sysdep/stub.h"
#include "os.h"
#include "proc_mm.h"
#include "skas_ptrace.h"
#include "chan_user.h"
#include "signal_user.h"
#include "registers.h"
+#include "mem.h"
+#include "uml-config.h"
#include "process.h"
int is_skas_winch(int pid, int fd, void *data)
@@ -39,20 +46,55 @@ int is_skas_winch(int pid, int fd, void *data)
return(1);
}
-void get_skas_faultinfo(int pid, struct faultinfo * fi)
+void wait_stub_done(int pid, int sig, char * fname)
{
- int err;
-
- err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
- if(err)
- panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
- "errno = %d\n", errno);
+ int n, status, err;
+
+ do {
+ if ( sig != -1 ) {
+ err = ptrace(PTRACE_CONT, pid, 0, sig);
+ if(err)
+ panic("%s : continue failed, errno = %d\n",
+ fname, errno);
+ }
+ sig = 0;
+
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
+ } while((n >= 0) && WIFSTOPPED(status) &&
+ (WSTOPSIG(status) == SIGVTALRM));
+
+ if((n < 0) || !WIFSTOPPED(status) ||
+ (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status != SIGTRAP))){
+ panic("%s : failed to wait for SIGUSR1/SIGTRAP, "
+ "pid = %d, n = %d, errno = %d, status = 0x%x\n",
+ fname, pid, n, errno, status);
+ }
+}
- /* Special handling for i386, which has different structs */
- if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
- memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
- sizeof(struct faultinfo) -
- sizeof(struct ptrace_faultinfo));
+void get_skas_faultinfo(int pid, struct faultinfo * fi)
+{
+ int err;
+
+ if(ptrace_faultinfo){
+ err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
+ if(err)
+ panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
+ "errno = %d\n", errno);
+
+ /* Special handling for i386, which has different structs */
+ if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
+ memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
+ sizeof(struct faultinfo) -
+ sizeof(struct ptrace_faultinfo));
+ }
+ else {
+ wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo");
+
+ /* faultinfo is prepared by the stub-segv-handler at start of
+ * the stub stack page. We just have to copy it.
+ */
+ memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
+ }
}
static void handle_segv(int pid, union uml_pt_regs * regs)
@@ -91,11 +133,56 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu
handle_syscall(regs);
}
-static int userspace_tramp(void *arg)
+extern int __syscall_stub_start;
+
+static int userspace_tramp(void *stack)
{
- init_new_thread_signals(0);
- enable_timer();
+ void *addr;
+
ptrace(PTRACE_TRACEME, 0, 0, 0);
+
+ init_new_thread_signals(1);
+ enable_timer();
+
+ if(!proc_mm){
+ /* This has a pte, but it can't be mapped in with the usual
+ * tlb_flush mechanism because this is part of that mechanism
+ */
+ int fd;
+ __u64 offset;
+
+ fd = phys_mapping(to_phys(&__syscall_stub_start), &offset);
+ addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(),
+ PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
+ if(addr == MAP_FAILED){
+ printk("mapping mmap stub failed, errno = %d\n",
+ errno);
+ exit(1);
+ }
+
+ if(stack != NULL){
+ fd = phys_mapping(to_phys(stack), &offset);
+ addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(),
+ PROT_READ | PROT_WRITE,
+ MAP_FIXED | MAP_SHARED, fd, offset);
+ if(addr == MAP_FAILED){
+ printk("mapping segfault stack failed, "
+ "errno = %d\n", errno);
+ exit(1);
+ }
+ }
+ }
+ if(!ptrace_faultinfo && (stack != NULL)){
+ unsigned long v = UML_CONFIG_STUB_CODE +
+ (unsigned long) stub_segv_handler -
+ (unsigned long) &__syscall_stub_start;
+
+ set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size());
+ set_handler(SIGSEGV, (void *) v, SA_ONSTACK,
+ SIGIO, SIGWINCH, SIGALRM, SIGVTALRM,
+ SIGUSR1, -1);
+ }
+
os_stop_process(os_getpid());
return(0);
}
@@ -105,11 +192,11 @@ static int userspace_tramp(void *arg)
#define NR_CPUS 1
int userspace_pid[NR_CPUS];
-void start_userspace(int cpu)
+int start_userspace(unsigned long stub_stack)
{
void *stack;
unsigned long sp;
- int pid, status, n;
+ int pid, status, n, flags;
stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@@ -117,8 +204,9 @@ void start_userspace(int cpu)
panic("start_userspace : mmap failed, errno = %d", errno);
sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
- pid = clone(userspace_tramp, (void *) sp,
- CLONE_FILES | CLONE_VM | SIGCHLD, NULL);
+ flags = CLONE_FILES | SIGCHLD;
+ if(proc_mm) flags |= CLONE_VM;
+ pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
if(pid < 0)
panic("start_userspace : clone failed, errno = %d", errno);
@@ -140,7 +228,7 @@ void start_userspace(int cpu)
if(munmap(stack, PAGE_SIZE) < 0)
panic("start_userspace : munmap failed, errno = %d\n", errno);
- userspace_pid[cpu] = pid;
+ return(pid);
}
void userspace(union uml_pt_regs *regs)
@@ -174,7 +262,9 @@ void userspace(union uml_pt_regs *regs)
if(WIFSTOPPED(status)){
switch(WSTOPSIG(status)){
case SIGSEGV:
- handle_segv(pid, regs);
+ if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo)
+ user_signal(SIGSEGV, regs, pid);
+ else handle_segv(pid, regs);
break;
case SIGTRAP + 0x80:
handle_trap(pid, regs, local_using_sysemu);
@@ -194,6 +284,7 @@ void userspace(union uml_pt_regs *regs)
printk("userspace - child stopped with signal "
"%d\n", WSTOPSIG(status));
}
+ pid = userspace_pid[0];
interrupt_end();
/* Avoid -ERESTARTSYS handling in host */
@@ -207,6 +298,67 @@ void userspace(union uml_pt_regs *regs)
#define INIT_JMP_HALT 3
#define INIT_JMP_REBOOT 4
+
+int copy_context_skas0(unsigned long new_stack, int pid)
+{
+ int err;
+ unsigned long regs[MAX_REG_NR];
+ unsigned long current_stack = current_stub_stack();
+ struct stub_data *data = (struct stub_data *) current_stack;
+ struct stub_data *child_data = (struct stub_data *) new_stack;
+ __u64 new_offset;
+ int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset);
+
+ /* prepare offset and fd of child's stack as argument for parent's
+ * and child's mmap2 calls
+ */
+ *data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset),
+ .fd = new_fd,
+ .timer = ((struct itimerval)
+ { { 0, 1000000 / hz() },
+ { 0, 1000000 / hz() }})});
+ get_safe_registers(regs);
+
+ /* Set parent's instruction pointer to start of clone-stub */
+ regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
+ (unsigned long) stub_clone_handler -
+ (unsigned long) &__syscall_stub_start;
+ regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE -
+ sizeof(void *);
+ err = ptrace_setregs(pid, regs);
+ if(err < 0)
+ panic("copy_context_skas0 : PTRACE_SETREGS failed, "
+ "pid = %d, errno = %d\n", pid, errno);
+
+ /* set a well known return code for detection of child write failure */
+ child_data->err = 12345678;
+
+ /* Wait, until parent has finished its work: read child's pid from
+ * parent's stack, and check, if bad result.
+ */
+ wait_stub_done(pid, 0, "copy_context_skas0");
+
+ pid = data->err;
+ if(pid < 0)
+ panic("copy_context_skas0 - stub-parent reports error %d\n",
+ pid);
+
+ /* Wait, until child has finished too: read child's result from
+ * child's stack and check it.
+ */
+ wait_stub_done(pid, -1, "copy_context_skas0");
+ if (child_data->err != UML_CONFIG_STUB_DATA)
+ panic("copy_context_skas0 - stub-child reports error %d\n",
+ child_data->err);
+
+ if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
+ (void *)PTRACE_O_TRACESYSGOOD) < 0)
+ panic("copy_context_skas0 : PTRACE_SETOPTIONS failed, "
+ "errno = %d\n", errno);
+
+ return pid;
+}
+
void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
void (*handler)(int))
{
@@ -334,21 +486,19 @@ void reboot_skas(void)
siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT);
}
-void switch_mm_skas(int mm_fd)
+void switch_mm_skas(struct mm_id *mm_idp)
{
int err;
#warning need cpu pid in switch_mm_skas
- err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd);
- if(err)
- panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n",
- errno);
-}
-
-void kill_off_processes_skas(void)
-{
-#warning need to loop over userspace_pids in kill_off_processes_skas
- os_kill_ptraced_process(userspace_pid[0], 1);
+ if(proc_mm){
+ err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0,
+ mm_idp->u.mm_fd);
+ if(err)
+ panic("switch_mm_skas - PTRACE_SWITCH_MM failed, "
+ "errno = %d\n", errno);
+ }
+ else userspace_pid[0] = mm_idp->u.pid;
}
/*
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
index 0a7b8aa55db..cbabab104ac 100644
--- a/arch/um/kernel/skas/process_kern.c
+++ b/arch/um/kernel/skas/process_kern.c
@@ -175,9 +175,12 @@ static int start_kernel_proc(void *unused)
return(0);
}
+extern int userspace_pid[];
+
int start_uml_skas(void)
{
- start_userspace(0);
+ if(proc_mm)
+ userspace_pid[0] = start_userspace(0);
init_new_thread_signals(1);
@@ -199,3 +202,31 @@ int thread_pid_skas(struct task_struct *task)
#warning Need to look up userspace_pid by cpu
return(userspace_pid[0]);
}
+
+void kill_off_processes_skas(void)
+{
+ if(proc_mm)
+#warning need to loop over userspace_pids in kill_off_processes_skas
+ os_kill_ptraced_process(userspace_pid[0], 1);
+ else {
+ struct task_struct *p;
+ int pid, me;
+
+ me = os_getpid();
+ for_each_process(p){
+ if(p->mm == NULL)
+ continue;
+
+ pid = p->mm->context.skas.id.u.pid;
+ os_kill_ptraced_process(pid, 1);
+ }
+ }
+}
+
+unsigned long current_stub_stack(void)
+{
+ if(current->mm == NULL)
+ return(0);
+
+ return(current->mm->context.skas.id.stack);
+}
diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
index b8c5e71763d..6230999c672 100644
--- a/arch/um/kernel/skas/tlb.c
+++ b/arch/um/kernel/skas/tlb.c
@@ -6,6 +6,7 @@
#include "linux/stddef.h"
#include "linux/sched.h"
+#include "linux/config.h"
#include "linux/mm.h"
#include "asm/page.h"
#include "asm/pgtable.h"
@@ -17,7 +18,7 @@
#include "os.h"
#include "tlb.h"
-static void do_ops(int fd, struct host_vm_op *ops, int last)
+static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
{
struct host_vm_op *op;
int i;
@@ -26,18 +27,18 @@ static void do_ops(int fd, struct host_vm_op *ops, int last)
op = &ops[i];
switch(op->type){
case MMAP:
- map(fd, op->u.mmap.addr, op->u.mmap.len,
+ map(&mmu->skas.id, op->u.mmap.addr, op->u.mmap.len,
op->u.mmap.r, op->u.mmap.w, op->u.mmap.x,
op->u.mmap.fd, op->u.mmap.offset);
break;
case MUNMAP:
- unmap(fd, (void *) op->u.munmap.addr,
+ unmap(&mmu->skas.id, (void *) op->u.munmap.addr,
op->u.munmap.len);
break;
case MPROTECT:
- protect(fd, op->u.mprotect.addr, op->u.mprotect.len,
- op->u.mprotect.r, op->u.mprotect.w,
- op->u.mprotect.x);
+ protect(&mmu->skas.id, op->u.mprotect.addr,
+ op->u.mprotect.len, op->u.mprotect.r,
+ op->u.mprotect.w, op->u.mprotect.x);
break;
default:
printk("Unknown op type %d in do_ops\n", op->type);
@@ -46,12 +47,15 @@ static void do_ops(int fd, struct host_vm_op *ops, int last)
}
}
+extern int proc_mm;
+
static void fix_range(struct mm_struct *mm, unsigned long start_addr,
unsigned long end_addr, int force)
{
- int fd = mm->context.skas.mm_fd;
+ if(!proc_mm && (end_addr > CONFIG_STUB_START))
+ end_addr = CONFIG_STUB_START;
- fix_range_common(mm, start_addr, end_addr, force, fd, do_ops);
+ fix_range_common(mm, start_addr, end_addr, force, do_ops);
}
void __flush_tlb_one_skas(unsigned long addr)
@@ -69,17 +73,20 @@ void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start,
void flush_tlb_mm_skas(struct mm_struct *mm)
{
+ unsigned long end;
+
/* Don't bother flushing if this address space is about to be
* destroyed.
*/
if(atomic_read(&mm->mm_users) == 0)
return;
- fix_range(mm, 0, host_task_size, 0);
- flush_tlb_kernel_range_common(start_vm, end_vm);
+ end = proc_mm ? task_size : CONFIG_STUB_START;
+ fix_range(mm, 0, end, 0);
}
void force_flush_all_skas(void)
{
- fix_range(current->mm, 0, host_task_size, 1);
+ unsigned long end = proc_mm ? task_size : CONFIG_STUB_START;
+ fix_range(current->mm, 0, end, 1);
}
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index f829b309b63..c40b611e3d9 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -48,6 +48,13 @@ void enable_timer(void)
set_interval(ITIMER_VIRTUAL);
}
+void prepare_timer(void * ptr)
+{
+ int usec = 1000000/hz();
+ *(struct itimerval *)ptr = ((struct itimerval) { { 0, usec },
+ { 0, usec }});
+}
+
void disable_timer(void)
{
struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index eda477edfdf..83ec8d4747f 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -18,13 +18,15 @@
#define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
- unsigned long end_addr, int force, int data,
- void (*do_ops)(int, struct host_vm_op *, int))
+ unsigned long end_addr, int force,
+ void (*do_ops)(union mm_context *, struct host_vm_op *,
+ int))
{
pgd_t *npgd;
pud_t *npud;
pmd_t *npmd;
pte_t *npte;
+ union mm_context *mmu = &mm->context;
unsigned long addr, end;
int r, w, x;
struct host_vm_op ops[16];
@@ -40,7 +42,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
end = end_addr;
if(force || pgd_newpage(*npgd)){
op_index = add_munmap(addr, end - addr, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
pgd_mkuptodate(*npgd);
}
@@ -55,7 +57,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
end = end_addr;
if(force || pud_newpage(*npud)){
op_index = add_munmap(addr, end - addr, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
pud_mkuptodate(*npud);
}
@@ -70,7 +72,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
end = end_addr;
if(force || pmd_newpage(*npmd)){
op_index = add_munmap(addr, end - addr, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
pmd_mkuptodate(*npmd);
}
@@ -93,21 +95,21 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
op_index = add_mmap(addr,
pte_val(*npte) & PAGE_MASK,
PAGE_SIZE, r, w, x, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
else op_index = add_munmap(addr, PAGE_SIZE, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
}
else if(pte_newprot(*npte))
op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
*npte = pte_mkuptodate(*npte);
addr += PAGE_SIZE;
}
- (*do_ops)(data, ops, op_index);
+ (*do_ops)(mmu, ops, op_index);
}
int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
@@ -195,51 +197,6 @@ int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
return(updated);
}
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
-{
- address &= PAGE_MASK;
- flush_tlb_range(vma, address, address + PAGE_SIZE);
-}
-
-void flush_tlb_all(void)
-{
- flush_tlb_mm(current->mm);
-}
-
-void flush_tlb_kernel_range(unsigned long start, unsigned long end)
-{
- CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
- flush_tlb_kernel_range_common, start, end);
-}
-
-void flush_tlb_kernel_vm(void)
-{
- CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
- flush_tlb_kernel_range_common(start_vm, end_vm));
-}
-
-void __flush_tlb_one(unsigned long addr)
-{
- CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
-}
-
-void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
- unsigned long end)
-{
- CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
- end);
-}
-
-void flush_tlb_mm(struct mm_struct *mm)
-{
- CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
-}
-
-void force_flush_all(void)
-{
- CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
-}
-
pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
{
return(pgd_offset(mm, address));
@@ -270,9 +227,9 @@ pte_t *addr_pte(struct task_struct *task, unsigned long addr)
}
int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
- int r, int w, int x, struct host_vm_op *ops, int index,
- int last_filled, int data,
- void (*do_ops)(int, struct host_vm_op *, int))
+ int r, int w, int x, struct host_vm_op *ops, int index,
+ int last_filled, union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *, int))
{
__u64 offset;
struct host_vm_op *last;
@@ -292,7 +249,7 @@ int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
}
if(index == last_filled){
- (*do_ops)(data, ops, last_filled);
+ (*do_ops)(mmu, ops, last_filled);
index = -1;
}
@@ -310,8 +267,8 @@ int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
}
int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
- int index, int last_filled, int data,
- void (*do_ops)(int, struct host_vm_op *, int))
+ int index, int last_filled, union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *, int))
{
struct host_vm_op *last;
@@ -325,7 +282,7 @@ int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
}
if(index == last_filled){
- (*do_ops)(data, ops, last_filled);
+ (*do_ops)(mmu, ops, last_filled);
index = -1;
}
@@ -337,8 +294,9 @@ int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
}
int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
- struct host_vm_op *ops, int index, int last_filled, int data,
- void (*do_ops)(int, struct host_vm_op *, int))
+ struct host_vm_op *ops, int index, int last_filled,
+ union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *, int))
{
struct host_vm_op *last;
@@ -354,7 +312,7 @@ int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
}
if(index == last_filled){
- (*do_ops)(data, ops, last_filled);
+ (*do_ops)(mmu, ops, last_filled);
index = -1;
}
@@ -367,3 +325,49 @@ int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
.x = x } } });
return(index);
}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
+{
+ address &= PAGE_MASK;
+ flush_tlb_range(vma, address, address + PAGE_SIZE);
+}
+
+void flush_tlb_all(void)
+{
+ flush_tlb_mm(current->mm);
+}
+
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+ CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
+ flush_tlb_kernel_range_common, start, end);
+}
+
+void flush_tlb_kernel_vm(void)
+{
+ CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
+ flush_tlb_kernel_range_common(start_vm, end_vm));
+}
+
+void __flush_tlb_one(unsigned long addr)
+{
+ CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
+}
+
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
+{
+ CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
+ end);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+ CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
+}
+
+void force_flush_all(void)
+{
+ CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
+}
+
diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c
index 203216ad86f..2eefb43bc9c 100644
--- a/arch/um/kernel/tt/tlb.c
+++ b/arch/um/kernel/tt/tlb.c
@@ -17,7 +17,7 @@
#include "os.h"
#include "tlb.h"
-static void do_ops(int unused, struct host_vm_op *ops, int last)
+static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
{
struct host_vm_op *op;
int i;
@@ -55,7 +55,7 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr,
panic("fix_range fixing wrong address space, current = 0x%p",
current);
- fix_range_common(mm, start_addr, end_addr, force, 0, do_ops);
+ fix_range_common(mm, start_addr, end_addr, force, do_ops);
}
atomic_t vmchange_seq = ATOMIC_INIT(1);
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index 61dfd4fef75..163476a8cb1 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -30,6 +30,7 @@ SECTIONS
_einittext = .;
}
. = ALIGN(4096);
+
.text :
{
*(.text)
@@ -39,6 +40,12 @@ SECTIONS
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t*)
+
+ . = ALIGN(4096);
+ __syscall_stub_start = .;
+ *(.__syscall_stub*)
+ __syscall_stub_end = .;
+ . = ALIGN(4096);
}
#include "asm/common.lds.S"
diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c
index 9a0ad094d92..3125d320722 100644
--- a/arch/um/os-Linux/sys-i386/registers.c
+++ b/arch/um/os-Linux/sys-i386/registers.c
@@ -121,6 +121,11 @@ void init_registers(int pid)
err);
}
+void get_safe_registers(unsigned long *regs)
+{
+ memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long));
+}
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/os-Linux/sys-x86_64/registers.c b/arch/um/os-Linux/sys-x86_64/registers.c
index 6286c974bbe..44438d15c3d 100644
--- a/arch/um/os-Linux/sys-x86_64/registers.c
+++ b/arch/um/os-Linux/sys-x86_64/registers.c
@@ -69,6 +69,11 @@ void init_registers(int pid)
err);
}
+void get_safe_registers(unsigned long *regs)
+{
+ memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long));
+}
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules
index 7459d09c233..17f305b6bad 100644
--- a/arch/um/scripts/Makefile.rules
+++ b/arch/um/scripts/Makefile.rules
@@ -16,6 +16,11 @@ define unprofile
endef
+# The stubs and unmap.o can't try to call mcount or update basic block data
+define unprofile
+ $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1)))
+endef
+
quiet_cmd_make_link = SYMLINK $@
cmd_make_link = ln -sf $(srctree)/arch/$(SUBARCH)/$($(notdir $@)-dir)/$(notdir $@) $@
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
index 095bcdb0b9c..77c3c4d29f5 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -1,6 +1,6 @@
obj-y = bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
- ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o \
- sys_call_table.o
+ ptrace_user.o semaphore.o signal.o sigcontext.o stub.o stub_segv.o \
+ syscalls.o sysrq.o sys_call_table.o
obj-$(CONFIG_HIGHMEM) += highmem.o
obj-$(CONFIG_MODULES) += module.o
@@ -16,6 +16,14 @@ semaphore.c-dir = kernel
highmem.c-dir = mm
module.c-dir = kernel
+STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
+
+# _cflags works with kernel files, not with userspace ones, but c_flags does,
+# why ask why?
+$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS)
+
+$(obj)/stub.o : a_flags = $(STUB_CFLAGS)
+
subdir- := util
include arch/um/scripts/Makefile.unmap
diff --git a/arch/um/sys-i386/stub.S b/arch/um/sys-i386/stub.S
new file mode 100644
index 00000000000..2f2c70a8f04
--- /dev/null
+++ b/arch/um/sys-i386/stub.S
@@ -0,0 +1,8 @@
+#include "uml-config.h"
+
+ .globl syscall_stub
+.section .__syscall_stub, "x"
+syscall_stub:
+ int $0x80
+ mov %eax, UML_CONFIG_STUB_DATA
+ int3
diff --git a/arch/um/sys-i386/stub_segv.c b/arch/um/sys-i386/stub_segv.c
new file mode 100644
index 00000000000..b251442ad0b
--- /dev/null
+++ b/arch/um/sys-i386/stub_segv.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include <asm/sigcontext.h>
+#include <asm/unistd.h>
+#include "uml-config.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/faultinfo.h"
+
+void __attribute__ ((__section__ (".__syscall_stub")))
+stub_segv_handler(int sig)
+{
+ struct sigcontext *sc = (struct sigcontext *) (&sig + 1);
+
+ GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA),
+ sc);
+
+ __asm__("movl %0, %%eax ; int $0x80": : "g" (__NR_getpid));
+ __asm__("movl %%eax, %%ebx ; movl %0, %%eax ; movl %1, %%ecx ;"
+ "int $0x80": : "g" (__NR_kill), "g" (SIGUSR1));
+ /* Pop the frame pointer and return address since we need to leave
+ * the stack in its original form when we do the sigreturn here, by
+ * hand.
+ */
+ __asm__("popl %%eax ; popl %%eax ; popl %%eax ; movl %0, %%eax ; "
+ "int $0x80" : : "g" (__NR_sigreturn));
+}
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile
index 2bc6f684901..7488206ce6f 100644
--- a/arch/um/sys-x86_64/Makefile
+++ b/arch/um/sys-x86_64/Makefile
@@ -6,8 +6,8 @@
#XXX: why into lib-y?
lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \
- ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o \
- syscalls.o sysrq.o thunk.o syscall_table.o
+ ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o stub.o \
+ stub_segv.o syscalls.o syscall_table.o sysrq.o thunk.o
obj-y := ksyms.o
obj-$(CONFIG_MODULES) += module.o um_module.o
@@ -28,6 +28,14 @@ semaphore.c-dir = kernel
thunk.S-dir = lib
module.c-dir = kernel
+STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
+
+# _cflags works with kernel files, not with userspace ones, but c_flags does,
+# why ask why?
+$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS)
+
+$(obj)/stub.o : a_flags = $(STUB_CFLAGS)
+
subdir- := util
include arch/um/scripts/Makefile.unmap
diff --git a/arch/um/sys-x86_64/stub.S b/arch/um/sys-x86_64/stub.S
new file mode 100644
index 00000000000..31c14925716
--- /dev/null
+++ b/arch/um/sys-x86_64/stub.S
@@ -0,0 +1,15 @@
+#include "uml-config.h"
+
+ .globl syscall_stub
+.section .__syscall_stub, "x"
+syscall_stub:
+ syscall
+ /* We don't have 64-bit constants, so this constructs the address
+ * we need.
+ */
+ movq $(UML_CONFIG_STUB_DATA >> 32), %rbx
+ salq $32, %rbx
+ movq $(UML_CONFIG_STUB_DATA & 0xffffffff), %rcx
+ or %rcx, %rbx
+ movq %rax, (%rbx)
+ int3
diff --git a/arch/um/sys-x86_64/stub_segv.c b/arch/um/sys-x86_64/stub_segv.c
new file mode 100644
index 00000000000..161d1fe9c03
--- /dev/null
+++ b/arch/um/sys-x86_64/stub_segv.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include <linux/compiler.h>
+#include <asm/unistd.h>
+#include "uml-config.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/faultinfo.h"
+
+void __attribute__ ((__section__ (".__syscall_stub")))
+stub_segv_handler(int sig)
+{
+ struct ucontext *uc;
+
+ __asm__("movq %%rdx, %0" : "=g" (uc) :);
+ GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA),
+ &uc->uc_mcontext);
+
+ __asm__("movq %0, %%rax ; syscall": : "g" (__NR_getpid));
+ __asm__("movq %%rax, %%rdi ; movq %0, %%rax ; movq %1, %%rsi ;"
+ "syscall": : "g" (__NR_kill), "g" (SIGUSR1));
+ /* Two popqs to restore the stack to the state just before entering
+ * the handler, one pops the return address, the other pops the frame
+ * pointer.
+ */
+ __asm__("popq %%rax ; popq %%rax ; movq %0, %%rax ; syscall" : : "g"
+ (__NR_rt_sigreturn));
+}
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index b02d921da4f..5fd03225058 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -1076,6 +1076,10 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
#ifdef CONFIG_X86_MCE
mcheck_init(c);
#endif
+ if (c == &boot_cpu_data)
+ mtrr_bp_init();
+ else
+ mtrr_ap_init();
#ifdef CONFIG_NUMA
if (c != &boot_cpu_data)
numa_add_cpu(c - cpu_data);
diff --git a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c
index 6c0f402e3a8..0612640d91b 100644
--- a/arch/x86_64/kernel/suspend.c
+++ b/arch/x86_64/kernel/suspend.c
@@ -119,6 +119,7 @@ void __restore_processor_state(struct saved_context *ctxt)
fix_processor_context();
do_fpu_end();
+ mtrr_ap_init();
}
void restore_processor_state(void)
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index 73389f51c4e..61c12758ca7 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -56,6 +56,10 @@ SECTIONS
.data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
*(.data.cacheline_aligned)
}
+ . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+ .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) {
+ *(.data.read_mostly)
+ }
#define VSYSCALL_ADDR (-10*1024*1024)
#define VSYSCALL_PHYS_ADDR ((LOADADDR(.data.cacheline_aligned) + SIZEOF(.data.cacheline_aligned) + 4095) & ~(4095))
diff --git a/arch/xtensa/kernel/syscalls.c b/arch/xtensa/kernel/syscalls.c
index abc8ed6c702..3540d8b119f 100644
--- a/arch/xtensa/kernel/syscalls.c
+++ b/arch/xtensa/kernel/syscalls.c
@@ -46,8 +46,6 @@
extern void do_syscall_trace(void);
typedef int (*syscall_t)(void *a0,...);
-extern int (*do_syscalls)(struct pt_regs *regs, syscall_t fun,
- int narg);
extern syscall_t sys_call_table[];
extern unsigned char sys_narg_table[];
@@ -72,10 +70,8 @@ int sys_pipe(int __user *userfds)
/*
* Common code for old and new mmaps.
*/
-
-static inline long do_mmap2(unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff)
+long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
+ unsigned long flags, unsigned long fd, unsigned long pgoff)
{
int error = -EBADF;
struct file * file = NULL;
@@ -97,29 +93,6 @@ out:
return error;
}
-unsigned long old_mmap(unsigned long addr, size_t len, int prot,
- int flags, int fd, off_t offset)
-{
- return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
-}
-
-long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
- unsigned long flags, unsigned long fd, unsigned long pgoff)
-{
- return do_mmap2(addr, len, prot, flags, fd, pgoff);
-}
-
-int sys_fork(struct pt_regs *regs)
-{
- return do_fork(SIGCHLD, regs->areg[1], regs, 0, NULL, NULL);
-}
-
-int sys_vfork(struct pt_regs *regs)
-{
- return do_fork(CLONE_VFORK|CLONE_VM|SIGCHLD, regs->areg[1],
- regs, 0, NULL, NULL);
-}
-
int sys_clone(struct pt_regs *regs)
{
unsigned long clone_flags;
@@ -162,30 +135,6 @@ int sys_uname(struct old_utsname * name)
return -EFAULT;
}
-int sys_olduname(struct oldold_utsname * name)
-{
- int error;
-
- if (!name)
- return -EFAULT;
- if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
- return -EFAULT;
-
- error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
- error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
- error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
- error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
- error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
- error -= __put_user(0,name->release+__OLD_UTS_LEN);
- error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
- error -= __put_user(0,name->version+__OLD_UTS_LEN);
- error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
- error -= __put_user(0,name->machine+__OLD_UTS_LEN);
-
- return error ? -EFAULT : 0;
-}
-
-
/*
* Build the string table for the builtin "poor man's strace".
*/
@@ -319,100 +268,3 @@ void system_call (struct pt_regs *regs)
regs->areg[2] = res;
do_syscall_trace();
}
-
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly.
- */
-
-int sys_ipc (uint call, int first, int second,
- int third, void __user *ptr, long fifth)
-{
- int version, ret;
-
- version = call >> 16; /* hack for backward compatibility */
- call &= 0xffff;
- ret = -ENOSYS;
-
- switch (call) {
- case SEMOP:
- ret = sys_semtimedop (first, (struct sembuf __user *)ptr,
- second, NULL);
- break;
-
- case SEMTIMEDOP:
- ret = sys_semtimedop (first, (struct sembuf __user *)ptr,
- second, (const struct timespec *) fifth);
- break;
-
- case SEMGET:
- ret = sys_semget (first, second, third);
- break;
-
- case SEMCTL: {
- union semun fourth;
-
- if (ptr && !get_user(fourth.__pad, (void *__user *) ptr))
- ret = sys_semctl (first, second, third, fourth);
- break;
- }
-
- case MSGSND:
- ret = sys_msgsnd (first, (struct msgbuf __user*) ptr,
- second, third);
- break;
-
- case MSGRCV:
- switch (version) {
- case 0: {
- struct ipc_kludge tmp;
-
- if (ptr && !copy_from_user(&tmp,
- (struct ipc_kludge *) ptr,
- sizeof (tmp)))
- ret = sys_msgrcv (first, tmp.msgp, second,
- tmp.msgtyp, third);
- break;
- }
-
- default:
- ret = sys_msgrcv (first, (struct msgbuf __user *) ptr,
- second, 0, third);
- break;
- }
- break;
-
- case MSGGET:
- ret = sys_msgget ((key_t) first, second);
- break;
-
- case MSGCTL:
- ret = sys_msgctl (first, second, (struct msqid_ds __user*) ptr);
- break;
-
- case SHMAT: {
- ulong raddr;
- ret = do_shmat (first, (char __user *) ptr, second, &raddr);
-
- if (!ret)
- ret = put_user (raddr, (ulong __user *) third);
-
- break;
- }
-
- case SHMDT:
- ret = sys_shmdt ((char __user *)ptr);
- break;
-
- case SHMGET:
- ret = sys_shmget (first, second, third);
- break;
-
- case SHMCTL:
- ret = sys_shmctl (first, second, (struct shmid_ds __user*) ptr);
- break;
- }
- return ret;
-}
-
diff --git a/arch/xtensa/kernel/syscalls.h b/arch/xtensa/kernel/syscalls.h
index 5b3f75f50fe..07580696b60 100644
--- a/arch/xtensa/kernel/syscalls.h
+++ b/arch/xtensa/kernel/syscalls.h
@@ -25,20 +25,19 @@
*/
SYSCALL(0, 0) /* 00 */
-
SYSCALL(sys_exit, 1)
-SYSCALL(sys_fork, 0)
+SYSCALL(sys_ni_syscall, 0)
SYSCALL(sys_read, 3)
SYSCALL(sys_write, 3)
SYSCALL(sys_open, 3) /* 05 */
SYSCALL(sys_close, 1)
-SYSCALL(sys_waitpid, 3)
+SYSCALL(sys_ni_syscall, 3)
SYSCALL(sys_creat, 2)
SYSCALL(sys_link, 2)
SYSCALL(sys_unlink, 1) /* 10 */
SYSCALL(sys_execve, 0)
SYSCALL(sys_chdir, 1)
-SYSCALL(sys_time, 1)
+SYSCALL(sys_ni_syscall, 1)
SYSCALL(sys_mknod, 3)
SYSCALL(sys_chmod, 2) /* 15 */
SYSCALL(sys_lchown, 3)
@@ -47,19 +46,19 @@ SYSCALL(sys_stat, 2)
SYSCALL(sys_lseek, 3)
SYSCALL(sys_getpid, 0) /* 20 */
SYSCALL(sys_mount, 5)
-SYSCALL(sys_oldumount, 1)
+SYSCALL(sys_ni_syscall, 1)
SYSCALL(sys_setuid, 1)
SYSCALL(sys_getuid, 0)
-SYSCALL(sys_stime, 1) /* 25 */
+SYSCALL(sys_ni_syscall, 1) /* 25 */
SYSCALL(sys_ptrace, 4)
-SYSCALL(sys_alarm, 1)
+SYSCALL(sys_ni_syscall, 1)
SYSCALL(sys_fstat, 2)
-SYSCALL(sys_pause, 0)
+SYSCALL(sys_ni_syscall, 0)
SYSCALL(sys_utime, 2) /* 30 */
SYSCALL(sys_ni_syscall, 0)
SYSCALL(sys_ni_syscall, 0)
SYSCALL(sys_access, 2)
-SYSCALL(sys_nice, 1)
+SYSCALL(sys_ni_syscall, 1)
SYSCALL(sys_ni_syscall, 0) /* 35 */
SYSCALL(sys_sync, 0)
SYSCALL(sys_kill, 2)
@@ -73,7 +72,7 @@ SYSCALL(sys_ni_syscall, 0)
SYSCALL(sys_brk, 1) /* 45 */
SYSCALL(sys_setgid, 1)
SYSCALL(sys_getgid, 0)
-SYSCALL(sys_ni_syscall, 0) /* was signal(2) */
+SYSCALL(sys_ni_syscall, 0)
SYSCALL(sys_geteuid, 0)
SYSCALL(sys_getegid, 0) /* 50 */
SYSCALL(sys_acct, 1)
@@ -84,21 +83,21 @@ SYSCALL(sys_fcntl, 3) /* 55 */
SYSCALL(sys_ni_syscall, 2)
SYSCALL(sys_setpgid, 2)
SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_olduname, 1)
+SYSCALL(sys_ni_syscall, 0)
SYSCALL(sys_umask, 1) /* 60 */
SYSCALL(sys_chroot, 1)
SYSCALL(sys_ustat, 2)
SYSCALL(sys_dup2, 2)
SYSCALL(sys_getppid, 0)
-SYSCALL(sys_getpgrp, 0) /* 65 */
+SYSCALL(sys_ni_syscall, 0) /* 65 */
SYSCALL(sys_setsid, 0)
SYSCALL(sys_sigaction, 3)
-SYSCALL(sys_sgetmask, 0)
-SYSCALL(sys_ssetmask, 1)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_ni_syscall, 1)
SYSCALL(sys_setreuid, 2) /* 70 */
SYSCALL(sys_setregid, 2)
SYSCALL(sys_sigsuspend, 0)
-SYSCALL(sys_sigpending, 1)
+SYSCALL(sys_ni_syscall, 1)
SYSCALL(sys_sethostname, 2)
SYSCALL(sys_setrlimit, 2) /* 75 */
SYSCALL(sys_getrlimit, 2)
@@ -107,15 +106,15 @@ SYSCALL(sys_gettimeofday, 2)
SYSCALL(sys_settimeofday, 2)
SYSCALL(sys_getgroups, 2) /* 80 */
SYSCALL(sys_setgroups, 2)
-SYSCALL(sys_ni_syscall, 0) /* old_select */
+SYSCALL(sys_ni_syscall, 0)
SYSCALL(sys_symlink, 2)
SYSCALL(sys_lstat, 2)
SYSCALL(sys_readlink, 3) /* 85 */
SYSCALL(sys_uselib, 1)
SYSCALL(sys_swapon, 2)
SYSCALL(sys_reboot, 3)
-SYSCALL(old_readdir, 3)
-SYSCALL(old_mmap, 6) /* 90 */
+SYSCALL(sys_ni_syscall, 3)
+SYSCALL(sys_ni_syscall, 6) /* 90 */
SYSCALL(sys_munmap, 2)
SYSCALL(sys_truncate, 2)
SYSCALL(sys_ftruncate, 2)
@@ -127,7 +126,7 @@ SYSCALL(sys_ni_syscall, 0)
SYSCALL(sys_statfs, 2)
SYSCALL(sys_fstatfs, 2) /* 100 */
SYSCALL(sys_ni_syscall, 3)
-SYSCALL(sys_socketcall, 2)
+SYSCALL(sys_ni_syscall, 2)
SYSCALL(sys_syslog, 3)
SYSCALL(sys_setitimer, 3)
SYSCALL(sys_getitimer, 2) /* 105 */
@@ -137,32 +136,32 @@ SYSCALL(sys_newfstat, 2)
SYSCALL(sys_uname, 1)
SYSCALL(sys_ni_syscall, 0) /* 110 */
SYSCALL(sys_vhangup, 0)
-SYSCALL(sys_ni_syscall, 0) /* was sys_idle() */
+SYSCALL(sys_ni_syscall, 0)
SYSCALL(sys_ni_syscall, 0)
SYSCALL(sys_wait4, 4)
SYSCALL(sys_swapoff, 1) /* 115 */
SYSCALL(sys_sysinfo, 1)
-SYSCALL(sys_ipc, 5) /* 6 really, but glibc uses only 5) */
+SYSCALL(sys_ni_syscall, 0)
SYSCALL(sys_fsync, 1)
SYSCALL(sys_sigreturn, 0)
SYSCALL(sys_clone, 0) /* 120 */
SYSCALL(sys_setdomainname, 2)
SYSCALL(sys_newuname, 1)
-SYSCALL(sys_ni_syscall, 0) /* sys_modify_ldt */
+SYSCALL(sys_ni_syscall, 0)
SYSCALL(sys_adjtimex, 1)
SYSCALL(sys_mprotect, 3) /* 125 */
-SYSCALL(sys_sigprocmask, 3)
-SYSCALL(sys_ni_syscall, 2) /* old sys_create_module */
+SYSCALL(sys_ni_syscall, 3)
+SYSCALL(sys_ni_syscall, 2)
SYSCALL(sys_init_module, 2)
SYSCALL(sys_delete_module, 1)
-SYSCALL(sys_ni_syscall, 1) /* old sys_get_kernel_sysm */ /* 130 */
+SYSCALL(sys_ni_syscall, 1) /* 130 */
SYSCALL(sys_quotactl, 0)
SYSCALL(sys_getpgid, 1)
SYSCALL(sys_fchdir, 1)
SYSCALL(sys_bdflush, 2)
SYSCALL(sys_sysfs, 3) /* 135 */
SYSCALL(sys_personality, 1)
-SYSCALL(sys_ni_syscall, 0) /* for afs_syscall */
+SYSCALL(sys_ni_syscall, 0)
SYSCALL(sys_setfsuid, 1)
SYSCALL(sys_setfsgid, 1)
SYSCALL(sys_llseek, 5) /* 140 */
@@ -212,7 +211,7 @@ SYSCALL(sys_socket, 3)
SYSCALL(sys_socketpair, 4)
SYSCALL(sys_setresuid, 3) /* 185 */
SYSCALL(sys_getresuid, 3)
-SYSCALL(sys_ni_syscall, 5) /* old sys_query_module */
+SYSCALL(sys_ni_syscall, 5)
SYSCALL(sys_poll, 3)
SYSCALL(sys_nfsservctl, 3)
SYSCALL(sys_setresgid, 3) /* 190 */
@@ -235,7 +234,7 @@ SYSCALL(sys_sigaltstack, 0)
SYSCALL(sys_sendfile, 4)
SYSCALL(sys_ni_syscall, 0)
SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_mmap2, 6) /* 210 */
+SYSCALL(sys_mmap, 6) /* 210 */
SYSCALL(sys_truncate64, 2)
SYSCALL(sys_ftruncate64, 2)
SYSCALL(sys_stat64, 2)
@@ -245,4 +244,4 @@ SYSCALL(sys_pivot_root, 2)
SYSCALL(sys_mincore, 3)
SYSCALL(sys_madvise, 3)
SYSCALL(sys_getdents64, 3)
-SYSCALL(sys_vfork, 0) /* 220 */
+SYSCALL(sys_ni_syscall, 0) /* 220 */
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index 5ef9adb9fe7..bd2ec7e284c 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -40,7 +40,6 @@
#include <linux/skbuff.h>
#include <asm/io.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -895,11 +894,6 @@ static dev_link_t *bluecard_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &bluecard_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -1103,6 +1097,7 @@ static struct pcmcia_driver bluecard_driver = {
.name = "bluecard_cs",
},
.attach = bluecard_attach,
+ .event = bluecard_event,
.detach = bluecard_detach,
.id_table = bluecard_ids,
};
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 9013cd759af..adf1750ea58 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -47,7 +47,6 @@
#include <linux/device.h>
#include <linux/firmware.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -696,11 +695,6 @@ static dev_link_t *bt3c_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &bt3c_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -947,6 +941,7 @@ static struct pcmcia_driver bt3c_driver = {
.name = "bt3c_cs",
},
.attach = bt3c_attach,
+ .event = bt3c_event,
.detach = bt3c_detach,
.id_table = bt3c_ids,
};
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index c479484a1f7..e4c59fdc0e1 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -43,7 +43,6 @@
#include <asm/system.h>
#include <asm/io.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -615,11 +614,6 @@ static dev_link_t *btuart_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &btuart_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -867,6 +861,7 @@ static struct pcmcia_driver btuart_driver = {
.name = "btuart_cs",
},
.attach = btuart_attach,
+ .event = btuart_event,
.detach = btuart_detach,
.id_table = btuart_ids,
};
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index bb12f7daeb9..e39868c3da4 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -43,7 +43,6 @@
#include <asm/system.h>
#include <asm/io.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -594,11 +593,6 @@ static dev_link_t *dtl1_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &dtl1_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -820,6 +814,7 @@ static struct pcmcia_driver dtl1_driver = {
.name = "dtl1_cs",
},
.attach = dtl1_attach,
+ .event = dtl1_event,
.detach = dtl1_detach,
.id_table = dtl1_ids,
};
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 1aff819f383..08f69287ea3 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -40,7 +40,7 @@ obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
obj-$(CONFIG_SX) += sx.o generic_serial.o
obj-$(CONFIG_RIO) += rio/ generic_serial.o
-obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o hvsi.o
+obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o hvc_vio.o hvsi.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
obj-$(CONFIG_MMTIMER) += mmtimer.o
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 88cd858f74d..cddb789902d 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -22,6 +22,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/config.h>
#include <linux/console.h>
#include <linux/cpumask.h>
#include <linux/init.h>
@@ -40,7 +41,6 @@
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/hvconsole.h>
-#include <asm/vio.h>
#define HVC_MAJOR 229
#define HVC_MINOR 0
@@ -61,16 +61,21 @@
*/
#define HVC_ALLOC_TTY_ADAPTERS 8
-static struct tty_driver *hvc_driver;
-#ifdef CONFIG_MAGIC_SYSRQ
-static int sysrq_pressed;
-#endif
-
#define N_OUTBUF 16
#define N_INBUF 16
#define __ALIGNED__ __attribute__((__aligned__(8)))
+static struct tty_driver *hvc_driver;
+static struct task_struct *hvc_task;
+
+/* Picks up late kicks after list walk but before schedule() */
+static int hvc_kicked;
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static int sysrq_pressed;
+#endif
+
struct hvc_struct {
spinlock_t lock;
int index;
@@ -80,11 +85,11 @@ struct hvc_struct {
char outbuf[N_OUTBUF] __ALIGNED__;
int n_outbuf;
uint32_t vtermno;
+ struct hv_ops *ops;
int irq_requested;
int irq;
struct list_head next;
struct kobject kobj; /* ref count & hvc_struct lifetime */
- struct vio_dev *vdev;
};
/* dynamic list of hvc_struct instances */
@@ -97,26 +102,185 @@ static struct list_head hvc_structs = LIST_HEAD_INIT(hvc_structs);
static DEFINE_SPINLOCK(hvc_structs_lock);
/*
+ * This value is used to assign a tty->index value to a hvc_struct based
+ * upon order of exposure via hvc_probe(), when we can not match it to
+ * a console canidate registered with hvc_instantiate().
+ */
+static int last_hvc = -1;
+
+/*
+ * Do not call this function with either the hvc_strucst_lock or the hvc_struct
+ * lock held. If successful, this function increments the kobject reference
+ * count against the target hvc_struct so it should be released when finished.
+ */
+struct hvc_struct *hvc_get_by_index(int index)
+{
+ struct hvc_struct *hp;
+ unsigned long flags;
+
+ spin_lock(&hvc_structs_lock);
+
+ list_for_each_entry(hp, &hvc_structs, next) {
+ spin_lock_irqsave(&hp->lock, flags);
+ if (hp->index == index) {
+ kobject_get(&hp->kobj);
+ spin_unlock_irqrestore(&hp->lock, flags);
+ spin_unlock(&hvc_structs_lock);
+ return hp;
+ }
+ spin_unlock_irqrestore(&hp->lock, flags);
+ }
+ hp = NULL;
+
+ spin_unlock(&hvc_structs_lock);
+ return hp;
+}
+
+
+/*
* Initial console vtermnos for console API usage prior to full console
* initialization. Any vty adapter outside this range will not have usable
* console interfaces but can still be used as a tty device. This has to be
* static because kmalloc will not work during early console init.
*/
-static uint32_t vtermnos[MAX_NR_HVC_CONSOLES];
+static struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES];
+static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] =
+ {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1};
-/* Used for accounting purposes */
-static int num_vterms = 0;
+/*
+ * Console APIs, NOT TTY. These APIs are available immediately when
+ * hvc_console_setup() finds adapters.
+ */
-static struct task_struct *hvc_task;
+void hvc_console_print(struct console *co, const char *b, unsigned count)
+{
+ char c[16] __ALIGNED__;
+ unsigned i = 0, n = 0;
+ int r, donecr = 0, index = co->index;
+
+ /* Console access attempt outside of acceptable console range. */
+ if (index >= MAX_NR_HVC_CONSOLES)
+ return;
+
+ /* This console adapter was removed so it is not useable. */
+ if (vtermnos[index] < 0)
+ return;
+
+ while (count > 0 || i > 0) {
+ if (count > 0 && i < sizeof(c)) {
+ if (b[n] == '\n' && !donecr) {
+ c[i++] = '\r';
+ donecr = 1;
+ } else {
+ c[i++] = b[n++];
+ donecr = 0;
+ --count;
+ }
+ } else {
+ r = cons_ops[index]->put_chars(vtermnos[index], c, i);
+ if (r < 0) {
+ /* throw away chars on error */
+ i = 0;
+ } else if (r > 0) {
+ i -= r;
+ if (i > 0)
+ memmove(c, c+r, i);
+ }
+ }
+ }
+}
+
+static struct tty_driver *hvc_console_device(struct console *c, int *index)
+{
+ if (vtermnos[c->index] == -1)
+ return NULL;
+
+ *index = c->index;
+ return hvc_driver;
+}
+
+static int __init hvc_console_setup(struct console *co, char *options)
+{
+ if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES)
+ return -ENODEV;
+
+ if (vtermnos[co->index] == -1)
+ return -ENODEV;
+
+ return 0;
+}
+
+struct console hvc_con_driver = {
+ .name = "hvc",
+ .write = hvc_console_print,
+ .device = hvc_console_device,
+ .setup = hvc_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
/*
- * This value is used to associate a tty->index value to a hvc_struct based
- * upon order of exposure via hvc_probe().
+ * Early console initialization. Preceeds driver initialization.
+ *
+ * (1) we are first, and the user specified another driver
+ * -- index will remain -1
+ * (2) we are first and the user specified no driver
+ * -- index will be set to 0, then we will fail setup.
+ * (3) we are first and the user specified our driver
+ * -- index will be set to user specified driver, and we will fail
+ * (4) we are after driver, and this initcall will register us
+ * -- if the user didn't specify a driver then the console will match
+ *
+ * Note that for cases 2 and 3, we will match later when the io driver
+ * calls hvc_instantiate() and call register again.
*/
-static int hvc_count = -1;
+static int __init hvc_console_init(void)
+{
+ register_console(&hvc_con_driver);
+ return 0;
+}
+console_initcall(hvc_console_init);
-/* Picks up late kicks after list walk but before schedule() */
-static int hvc_kicked;
+/*
+ * hvc_instantiate() is an early console discovery method which locates
+ * consoles * prior to the vio subsystem discovering them. Hotplugged
+ * vty adapters do NOT get an hvc_instantiate() callback since they
+ * appear after early console init.
+ */
+int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops)
+{
+ struct hvc_struct *hp;
+
+ if (index < 0 || index >= MAX_NR_HVC_CONSOLES)
+ return -1;
+
+ if (vtermnos[index] != -1)
+ return -1;
+
+ /* make sure no no tty has been registerd in this index */
+ hp = hvc_get_by_index(index);
+ if (hp) {
+ kobject_put(&hp->kobj);
+ return -1;
+ }
+
+ vtermnos[index] = vtermno;
+ cons_ops[index] = ops;
+
+ /* reserve all indices upto and including this index */
+ if (last_hvc < index)
+ last_hvc = index;
+
+ /* if this index is what the user requested, then register
+ * now (setup won't fail at this point). It's ok to just
+ * call register again if previously .setup failed.
+ */
+ if (index == hvc_con_driver.index)
+ register_console(&hvc_con_driver);
+
+ return 0;
+}
+EXPORT_SYMBOL(hvc_instantiate);
/* Wake the sleeping khvcd */
static void hvc_kick(void)
@@ -125,13 +289,17 @@ static void hvc_kick(void)
wake_up_process(hvc_task);
}
+static int hvc_poll(struct hvc_struct *hp);
+
/*
* NOTE: This API isn't used if the console adapter doesn't support interrupts.
* In this case the console is poll driven.
*/
static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
{
- hvc_kick();
+ /* if hvc_poll request a repoll, then kick the hvcd thread */
+ if (hvc_poll(dev_instance))
+ hvc_kick();
return IRQ_HANDLED;
}
@@ -141,34 +309,6 @@ static void hvc_unthrottle(struct tty_struct *tty)
}
/*
- * Do not call this function with either the hvc_strucst_lock or the hvc_struct
- * lock held. If successful, this function increments the kobject reference
- * count against the target hvc_struct so it should be released when finished.
- */
-struct hvc_struct *hvc_get_by_index(int index)
-{
- struct hvc_struct *hp;
- unsigned long flags;
-
- spin_lock(&hvc_structs_lock);
-
- list_for_each_entry(hp, &hvc_structs, next) {
- spin_lock_irqsave(&hp->lock, flags);
- if (hp->index == index) {
- kobject_get(&hp->kobj);
- spin_unlock_irqrestore(&hp->lock, flags);
- spin_unlock(&hvc_structs_lock);
- return hp;
- }
- spin_unlock_irqrestore(&hp->lock, flags);
- }
- hp = NULL;
-
- spin_unlock(&hvc_structs_lock);
- return hp;
-}
-
-/*
* The TTY interface won't be used until after the vio layer has exposed the vty
* adapter to the kernel.
*/
@@ -329,7 +469,7 @@ static void hvc_push(struct hvc_struct *hp)
{
int n;
- n = hvc_put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf);
+ n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf);
if (n <= 0) {
if (n == 0)
return;
@@ -467,7 +607,7 @@ static int hvc_poll(struct hvc_struct *hp)
break;
}
- n = hvc_get_chars(hp->vtermno, buf, count);
+ n = hp->ops->get_chars(hp->vtermno, buf, count);
if (n <= 0) {
/* Hangup the tty when disconnected from host */
if (n == -EPIPE) {
@@ -479,14 +619,17 @@ static int hvc_poll(struct hvc_struct *hp)
}
for (i = 0; i < n; ++i) {
#ifdef CONFIG_MAGIC_SYSRQ
- /* Handle the SysRq Hack */
- if (buf[i] == '\x0f') { /* ^O -- should support a sequence */
- sysrq_pressed = 1;
- continue;
- } else if (sysrq_pressed) {
- handle_sysrq(buf[i], NULL, tty);
- sysrq_pressed = 0;
- continue;
+ if (hp->index == hvc_con_driver.index) {
+ /* Handle the SysRq Hack */
+ /* XXX should support a sequence */
+ if (buf[i] == '\x0f') { /* ^O */
+ sysrq_pressed = 1;
+ continue;
+ } else if (sysrq_pressed) {
+ handle_sysrq(buf[i], NULL, tty);
+ sysrq_pressed = 0;
+ continue;
+ }
}
#endif /* CONFIG_MAGIC_SYSRQ */
tty_insert_flip_char(tty, buf[i], 0);
@@ -497,8 +640,8 @@ static int hvc_poll(struct hvc_struct *hp)
/*
* Account for the total amount read in one loop, and if above
- * 64 bytes, we do a quick schedule loop to let the tty grok the
- * data and eventually throttle us.
+ * 64 bytes, we do a quick schedule loop to let the tty grok
+ * the data and eventually throttle us.
*/
read_total += n;
if (read_total >= 64) {
@@ -542,7 +685,6 @@ int khvcd(void *unused)
if (cpus_empty(cpus_in_xmon)) {
spin_lock(&hvc_structs_lock);
list_for_each_entry(hp, &hvc_structs, next) {
- /*hp = list_entry(node, struct hvc_struct, * next); */
poll_mask |= hvc_poll(hp);
}
spin_unlock(&hvc_structs_lock);
@@ -577,14 +719,6 @@ static struct tty_operations hvc_ops = {
.chars_in_buffer = hvc_chars_in_buffer,
};
-char hvc_driver_name[] = "hvc_console";
-
-static struct vio_device_id hvc_driver_table[] __devinitdata= {
- {"serial", "hvterm1"},
- { NULL, }
-};
-MODULE_DEVICE_TABLE(vio, hvc_driver_table);
-
/* callback when the kboject ref count reaches zero. */
static void destroy_hvc_struct(struct kobject *kobj)
{
@@ -606,41 +740,51 @@ static struct kobj_type hvc_kobj_type = {
.release = destroy_hvc_struct,
};
-static int __devinit hvc_probe(
- struct vio_dev *dev,
- const struct vio_device_id *id)
+struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
+ struct hv_ops *ops)
{
struct hvc_struct *hp;
-
- /* probed with invalid parameters. */
- if (!dev || !id)
- return -EPERM;
+ int i;
hp = kmalloc(sizeof(*hp), GFP_KERNEL);
if (!hp)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
memset(hp, 0x00, sizeof(*hp));
- hp->vtermno = dev->unit_address;
- hp->vdev = dev;
- hp->vdev->dev.driver_data = hp;
- hp->irq = dev->irq;
+
+ hp->vtermno = vtermno;
+ hp->irq = irq;
+ hp->ops = ops;
kobject_init(&hp->kobj);
hp->kobj.ktype = &hvc_kobj_type;
spin_lock_init(&hp->lock);
spin_lock(&hvc_structs_lock);
- hp->index = ++hvc_count;
+
+ /*
+ * find index to use:
+ * see if this vterm id matches one registered for console.
+ */
+ for (i=0; i < MAX_NR_HVC_CONSOLES; i++)
+ if (vtermnos[i] == hp->vtermno)
+ break;
+
+ /* no matching slot, just use a counter */
+ if (i >= MAX_NR_HVC_CONSOLES)
+ i = ++last_hvc;
+
+ hp->index = i;
+
list_add_tail(&(hp->next), &hvc_structs);
spin_unlock(&hvc_structs_lock);
- return 0;
+ return hp;
}
+EXPORT_SYMBOL(hvc_alloc);
-static int __devexit hvc_remove(struct vio_dev *dev)
+int __devexit hvc_remove(struct hvc_struct *hp)
{
- struct hvc_struct *hp = dev->dev.driver_data;
unsigned long flags;
struct kobject *kobjp;
struct tty_struct *tty;
@@ -673,23 +817,14 @@ static int __devexit hvc_remove(struct vio_dev *dev)
tty_hangup(tty);
return 0;
}
-
-static struct vio_driver hvc_vio_driver = {
- .name = hvc_driver_name,
- .id_table = hvc_driver_table,
- .probe = hvc_probe,
- .remove = hvc_remove,
-};
+EXPORT_SYMBOL(hvc_remove);
/* Driver initialization. Follow console initialization. This is where the TTY
* interfaces start to become available. */
int __init hvc_init(void)
{
- int rc;
-
- /* We need more than num_vterms adapters due to hotplug additions. */
+ /* We need more than hvc_count adapters due to hotplug additions. */
hvc_driver = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS);
- /* hvc_driver = alloc_tty_driver(num_vterms); */
if (!hvc_driver)
return -ENOMEM;
@@ -716,116 +851,20 @@ int __init hvc_init(void)
return -EIO;
}
- /* Register as a vio device to receive callbacks */
- rc = vio_register_driver(&hvc_vio_driver);
-
- return rc;
+ return 0;
}
+module_init(hvc_init);
-/* This isn't particularily necessary due to this being a console driver but it
- * is nice to be thorough */
+/* This isn't particularily necessary due to this being a console driver
+ * but it is nice to be thorough.
+ */
static void __exit hvc_exit(void)
{
kthread_stop(hvc_task);
- vio_unregister_driver(&hvc_vio_driver);
tty_unregister_driver(hvc_driver);
/* return tty_struct instances allocated in hvc_init(). */
put_tty_driver(hvc_driver);
+ unregister_console(&hvc_con_driver);
}
-
-/*
- * Console APIs, NOT TTY. These APIs are available immediately when
- * hvc_console_setup() finds adapters.
- */
-
-/*
- * hvc_instantiate() is an early console discovery method which locates consoles
- * prior to the vio subsystem discovering them. Hotplugged vty adapters do NOT
- * get an hvc_instantiate() callback since the appear after early console init.
- */
-int hvc_instantiate(uint32_t vtermno, int index)
-{
- if (index < 0 || index >= MAX_NR_HVC_CONSOLES)
- return -1;
-
- if (vtermnos[index] != -1)
- return -1;
-
- vtermnos[index] = vtermno;
- return 0;
-}
-
-void hvc_console_print(struct console *co, const char *b, unsigned count)
-{
- char c[16] __ALIGNED__;
- unsigned i = 0, n = 0;
- int r, donecr = 0;
-
- /* Console access attempt outside of acceptable console range. */
- if (co->index >= MAX_NR_HVC_CONSOLES)
- return;
-
- /* This console adapter was removed so it is not useable. */
- if (vtermnos[co->index] < 0)
- return;
-
- while (count > 0 || i > 0) {
- if (count > 0 && i < sizeof(c)) {
- if (b[n] == '\n' && !donecr) {
- c[i++] = '\r';
- donecr = 1;
- } else {
- c[i++] = b[n++];
- donecr = 0;
- --count;
- }
- } else {
- r = hvc_put_chars(vtermnos[co->index], c, i);
- if (r < 0) {
- /* throw away chars on error */
- i = 0;
- } else if (r > 0) {
- i -= r;
- if (i > 0)
- memmove(c, c+r, i);
- }
- }
- }
-}
-
-static struct tty_driver *hvc_console_device(struct console *c, int *index)
-{
- *index = c->index;
- return hvc_driver;
-}
-
-static int __init hvc_console_setup(struct console *co, char *options)
-{
- return 0;
-}
-
-struct console hvc_con_driver = {
- .name = "hvc",
- .write = hvc_console_print,
- .device = hvc_console_device,
- .setup = hvc_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
-};
-
-/* Early console initialization. Preceeds driver initialization. */
-static int __init hvc_console_init(void)
-{
- int i;
-
- for (i=0; i<MAX_NR_HVC_CONSOLES; i++)
- vtermnos[i] = -1;
- num_vterms = hvc_find_vtys();
- register_console(&hvc_con_driver);
- return 0;
-}
-console_initcall(hvc_console_init);
-
-module_init(hvc_init);
module_exit(hvc_exit);
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
new file mode 100644
index 00000000000..60bb9152b83
--- /dev/null
+++ b/drivers/char/hvc_vio.c
@@ -0,0 +1,152 @@
+/*
+ * vio driver interface to hvc_console.c
+ *
+ * This code was moved here to allow the remaing code to be reused as a
+ * generic polling mode with semi-reliable transport driver core to the
+ * console and tty subsystems.
+ *
+ *
+ * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
+ * Copyright (C) 2001 Paul Mackerras <paulus@au.ibm.com>, IBM
+ * Copyright (C) 2004 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Additional Author(s):
+ * Ryan S. Arnold <rsa@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <asm/hvconsole.h>
+#include <asm/vio.h>
+#include <asm/prom.h>
+
+char hvc_driver_name[] = "hvc_console";
+
+static struct vio_device_id hvc_driver_table[] __devinitdata = {
+ {"serial", "hvterm1"},
+ { NULL, }
+};
+MODULE_DEVICE_TABLE(vio, hvc_driver_table);
+
+static int filtered_get_chars(uint32_t vtermno, char *buf, int count)
+{
+ unsigned long got;
+ int i;
+
+ got = hvc_get_chars(vtermno, buf, count);
+
+ /*
+ * Work around a HV bug where it gives us a null
+ * after every \r. -- paulus
+ */
+ for (i = 1; i < got; ++i) {
+ if (buf[i] == 0 && buf[i-1] == '\r') {
+ --got;
+ if (i < got)
+ memmove(&buf[i], &buf[i+1],
+ got - i);
+ }
+ }
+ return got;
+}
+
+static struct hv_ops hvc_get_put_ops = {
+ .get_chars = filtered_get_chars,
+ .put_chars = hvc_put_chars,
+};
+
+static int __devinit hvc_vio_probe(struct vio_dev *vdev,
+ const struct vio_device_id *id)
+{
+ struct hvc_struct *hp;
+
+ /* probed with invalid parameters. */
+ if (!vdev || !id)
+ return -EPERM;
+
+ hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops);
+ if (IS_ERR(hp))
+ return PTR_ERR(hp);
+ dev_set_drvdata(&vdev->dev, hp);
+
+ return 0;
+}
+
+static int __devexit hvc_vio_remove(struct vio_dev *vdev)
+{
+ struct hvc_struct *hp = dev_get_drvdata(&vdev->dev);
+
+ return hvc_remove(hp);
+}
+
+static struct vio_driver hvc_vio_driver = {
+ .name = hvc_driver_name,
+ .id_table = hvc_driver_table,
+ .probe = hvc_vio_probe,
+ .remove = hvc_vio_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ }
+};
+
+static int hvc_vio_init(void)
+{
+ int rc;
+
+ /* Register as a vio device to receive callbacks */
+ rc = vio_register_driver(&hvc_vio_driver);
+
+ return rc;
+}
+module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
+
+static void hvc_vio_exit(void)
+{
+ vio_unregister_driver(&hvc_vio_driver);
+}
+module_exit(hvc_vio_exit);
+
+/* the device tree order defines our numbering */
+static int hvc_find_vtys(void)
+{
+ struct device_node *vty;
+ int num_found = 0;
+
+ for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL;
+ vty = of_find_node_by_name(vty, "vty")) {
+ uint32_t *vtermno;
+
+ /* We have statically defined space for only a certain number
+ * of console adapters.
+ */
+ if (num_found >= MAX_NR_HVC_CONSOLES)
+ break;
+
+ vtermno = (uint32_t *)get_property(vty, "reg", NULL);
+ if (!vtermno)
+ continue;
+
+ if (device_is_compatible(vty, "hvterm1")) {
+ hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops);
+ ++num_found;
+ }
+ }
+
+ return num_found;
+}
+console_initcall(hvc_find_vtys);
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index f1f1192ba2b..a22aa940e01 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -291,15 +291,13 @@ static void dump_packet(uint8_t *packet)
dump_hex(packet, header->len);
}
-/* can't use hvc_get_chars because that strips CRs */
static int hvsi_read(struct hvsi_struct *hp, char *buf, int count)
{
unsigned long got;
- if (plpar_hcall(H_GET_TERM_CHAR, hp->vtermno, 0, 0, 0, &got,
- (unsigned long *)buf, (unsigned long *)buf+1) == H_Success)
- return got;
- return 0;
+ got = hvc_get_chars(hp->vtermno, buf, count);
+
+ return got;
}
static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index edba5a35bf2..09103b3d8f0 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -770,10 +770,8 @@ send_signal:
}
if (c == '\n') {
if (L_ECHO(tty) || L_ECHONL(tty)) {
- if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
+ if (tty->read_cnt >= N_TTY_BUF_SIZE-1)
put_char('\a', tty);
- return;
- }
opost('\n', tty);
}
goto handle_newline;
@@ -790,10 +788,8 @@ send_signal:
* XXX are EOL_CHAR and EOL2_CHAR echoed?!?
*/
if (L_ECHO(tty)) {
- if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
+ if (tty->read_cnt >= N_TTY_BUF_SIZE-1)
put_char('\a', tty);
- return;
- }
/* Record the column of first canon char. */
if (tty->canon_head == tty->read_head)
tty->canon_column = tty->column;
@@ -862,12 +858,9 @@ static int n_tty_receive_room(struct tty_struct *tty)
* that erase characters will be handled. Other excess
* characters will be beeped.
*/
- if (tty->icanon && !tty->canon_data)
- return N_TTY_BUF_SIZE;
-
- if (left > 0)
- return left;
- return 0;
+ if (left <= 0)
+ left = tty->icanon && !tty->canon_data;
+ return left;
}
/**
@@ -1473,13 +1466,17 @@ static ssize_t write_chan(struct tty_struct * tty, struct file * file,
if (tty->driver->flush_chars)
tty->driver->flush_chars(tty);
} else {
- c = tty->driver->write(tty, b, nr);
- if (c < 0) {
- retval = c;
- goto break_out;
+ while (nr > 0) {
+ c = tty->driver->write(tty, b, nr);
+ if (c < 0) {
+ retval = c;
+ goto break_out;
+ }
+ if (!c)
+ break;
+ b += c;
+ nr -= c;
}
- b += c;
- nr -= c;
}
if (!nr)
break;
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 8f36b1758eb..7a0c7464812 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -71,7 +71,6 @@
#include <linux/workqueue.h>
#include <linux/hdlc.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -593,11 +592,6 @@ static dev_link_t *mgslpc_attach(void)
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &mgslpc_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -3093,6 +3087,7 @@ static struct pcmcia_driver mgslpc_driver = {
.name = "synclink_cs",
},
.attach = mgslpc_attach,
+ .event = mgslpc_event,
.detach = mgslpc_detach,
.id_table = mgslpc_ids,
};
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 460b5d475ed..6b11d6b2129 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -271,7 +271,7 @@ static int random_write_wakeup_thresh = 128;
* samples to avoid wasting CPU time and reduce lock contention.
*/
-static int trickle_thresh = INPUT_POOL_WORDS * 28;
+static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28;
static DEFINE_PER_CPU(int, trickle_count) = 0;
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index af79805b557..12d563c648f 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -228,7 +228,7 @@ static struct sysrq_key_op sysrq_term_op = {
static void moom_callback(void *ignored)
{
- out_of_memory(GFP_KERNEL);
+ out_of_memory(GFP_KERNEL, 0);
}
static DECLARE_WORK(moom_work, moom_callback, NULL);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index bf62dfe4976..7a7859dd0d9 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -869,7 +869,7 @@ EXPORT_SYMBOL(cpufreq_get);
* cpufreq_suspend - let the low level driver prepare for suspend
*/
-static int cpufreq_suspend(struct sys_device * sysdev, u32 state)
+static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
{
int cpu = sysdev->id;
unsigned int ret = 0;
@@ -897,7 +897,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, u32 state)
}
if (cpufreq_driver->suspend) {
- ret = cpufreq_driver->suspend(cpu_policy, state);
+ ret = cpufreq_driver->suspend(cpu_policy, pmsg);
if (ret) {
printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
"step on CPU %u\n", cpu_policy->cpu);
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index 978d27d6452..aac59751e1b 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -46,7 +46,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -134,11 +133,6 @@ static dev_link_t *ide_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &ide_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -497,6 +491,7 @@ static struct pcmcia_driver ide_cs_driver = {
.name = "ide-cs",
},
.attach = ide_attach,
+ .event = ide_event,
.detach = ide_detach,
.id_table = ide_ids,
};
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index 3cc3ff0cccb..79c8e2dd9c3 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -7,6 +7,16 @@ config INFINIBAND
any protocols you wish to use as well as drivers for your
InfiniBand hardware.
+config INFINIBAND_USER_VERBS
+ tristate "InfiniBand userspace verbs support"
+ depends on INFINIBAND
+ ---help---
+ Userspace InfiniBand verbs support. This is the kernel side
+ of userspace verbs, which allows userspace processes to
+ directly access InfiniBand hardware for fast-path
+ operations. You will also need libibverbs and a hardware
+ driver library from <http://www.openib.org>.
+
source "drivers/infiniband/hw/mthca/Kconfig"
source "drivers/infiniband/ulp/ipoib/Kconfig"
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index d2dbfb52c0a..e1a7cf3e863 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -1,6 +1,7 @@
EXTRA_CFLAGS += -Idrivers/infiniband/include
-obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o ib_umad.o
+obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o ib_umad.o
+obj-$(CONFIG_INFINIBAND_USER_VERBS) += ib_uverbs.o
ib_core-y := packer.o ud_header.o verbs.o sysfs.o \
device.o fmr_pool.o cache.o
@@ -10,3 +11,5 @@ ib_mad-y := mad.o smi.o agent.o
ib_sa-y := sa_query.o
ib_umad-y := user_mad.o
+
+ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_mem.o
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
new file mode 100644
index 00000000000..57347f1e82c
--- /dev/null
+++ b/drivers/infiniband/core/uverbs.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ *
+ * $Id: uverbs.h 2559 2005-06-06 19:43:16Z roland $
+ */
+
+#ifndef UVERBS_H
+#define UVERBS_H
+
+/* Include device.h and fs.h until cdev.h is self-sufficient */
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/kref.h>
+#include <linux/idr.h>
+
+#include <ib_verbs.h>
+#include <ib_user_verbs.h>
+
+struct ib_uverbs_device {
+ int devnum;
+ struct cdev dev;
+ struct class_device class_dev;
+ struct ib_device *ib_dev;
+ int num_comp;
+};
+
+struct ib_uverbs_event_file {
+ struct kref ref;
+ struct ib_uverbs_file *uverbs_file;
+ spinlock_t lock;
+ int fd;
+ int is_async;
+ wait_queue_head_t poll_wait;
+ struct list_head event_list;
+};
+
+struct ib_uverbs_file {
+ struct kref ref;
+ struct ib_uverbs_device *device;
+ struct ib_ucontext *ucontext;
+ struct ib_event_handler event_handler;
+ struct ib_uverbs_event_file async_file;
+ struct ib_uverbs_event_file comp_file[1];
+};
+
+struct ib_uverbs_async_event {
+ struct ib_uverbs_async_event_desc desc;
+ struct list_head list;
+};
+
+struct ib_uverbs_comp_event {
+ struct ib_uverbs_comp_event_desc desc;
+ struct list_head list;
+};
+
+struct ib_uobject_mr {
+ struct ib_uobject uobj;
+ struct page *page_list;
+ struct scatterlist *sg_list;
+};
+
+extern struct semaphore ib_uverbs_idr_mutex;
+extern struct idr ib_uverbs_pd_idr;
+extern struct idr ib_uverbs_mr_idr;
+extern struct idr ib_uverbs_mw_idr;
+extern struct idr ib_uverbs_ah_idr;
+extern struct idr ib_uverbs_cq_idr;
+extern struct idr ib_uverbs_qp_idr;
+
+void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context);
+void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr);
+void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr);
+
+int ib_umem_get(struct ib_device *dev, struct ib_umem *mem,
+ void *addr, size_t size, int write);
+void ib_umem_release(struct ib_device *dev, struct ib_umem *umem);
+void ib_umem_release_on_close(struct ib_device *dev, struct ib_umem *umem);
+
+#define IB_UVERBS_DECLARE_CMD(name) \
+ ssize_t ib_uverbs_##name(struct ib_uverbs_file *file, \
+ const char __user *buf, int in_len, \
+ int out_len)
+
+IB_UVERBS_DECLARE_CMD(query_params);
+IB_UVERBS_DECLARE_CMD(get_context);
+IB_UVERBS_DECLARE_CMD(query_device);
+IB_UVERBS_DECLARE_CMD(query_port);
+IB_UVERBS_DECLARE_CMD(query_gid);
+IB_UVERBS_DECLARE_CMD(query_pkey);
+IB_UVERBS_DECLARE_CMD(alloc_pd);
+IB_UVERBS_DECLARE_CMD(dealloc_pd);
+IB_UVERBS_DECLARE_CMD(reg_mr);
+IB_UVERBS_DECLARE_CMD(dereg_mr);
+IB_UVERBS_DECLARE_CMD(create_cq);
+IB_UVERBS_DECLARE_CMD(destroy_cq);
+IB_UVERBS_DECLARE_CMD(create_qp);
+IB_UVERBS_DECLARE_CMD(modify_qp);
+IB_UVERBS_DECLARE_CMD(destroy_qp);
+IB_UVERBS_DECLARE_CMD(attach_mcast);
+IB_UVERBS_DECLARE_CMD(detach_mcast);
+
+#endif /* UVERBS_H */
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
new file mode 100644
index 00000000000..5f2bbcda4c7
--- /dev/null
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -0,0 +1,1006 @@
+/*
+ * Copyright (c) 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ *
+ * $Id: uverbs_cmd.c 2708 2005-06-24 17:27:21Z roland $
+ */
+
+#include <asm/uaccess.h>
+
+#include "uverbs.h"
+
+#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \
+ do { \
+ (udata)->inbuf = (void __user *) (ibuf); \
+ (udata)->outbuf = (void __user *) (obuf); \
+ (udata)->inlen = (ilen); \
+ (udata)->outlen = (olen); \
+ } while (0)
+
+ssize_t ib_uverbs_query_params(struct ib_uverbs_file *file,
+ const char __user *buf,
+ int in_len, int out_len)
+{
+ struct ib_uverbs_query_params cmd;
+ struct ib_uverbs_query_params_resp resp;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ memset(&resp, 0, sizeof resp);
+
+ resp.num_cq_events = file->device->num_comp;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp))
+ return -EFAULT;
+
+ return in_len;
+}
+
+ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
+ const char __user *buf,
+ int in_len, int out_len)
+{
+ struct ib_uverbs_get_context cmd;
+ struct ib_uverbs_get_context_resp resp;
+ struct ib_udata udata;
+ struct ib_device *ibdev = file->device->ib_dev;
+ int i;
+ int ret = in_len;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ INIT_UDATA(&udata, buf + sizeof cmd,
+ (unsigned long) cmd.response + sizeof resp,
+ in_len - sizeof cmd, out_len - sizeof resp);
+
+ file->ucontext = ibdev->alloc_ucontext(ibdev, &udata);
+ if (IS_ERR(file->ucontext)) {
+ ret = PTR_ERR(file->ucontext);
+ file->ucontext = NULL;
+ return ret;
+ }
+
+ file->ucontext->device = ibdev;
+ INIT_LIST_HEAD(&file->ucontext->pd_list);
+ INIT_LIST_HEAD(&file->ucontext->mr_list);
+ INIT_LIST_HEAD(&file->ucontext->mw_list);
+ INIT_LIST_HEAD(&file->ucontext->cq_list);
+ INIT_LIST_HEAD(&file->ucontext->qp_list);
+ INIT_LIST_HEAD(&file->ucontext->srq_list);
+ INIT_LIST_HEAD(&file->ucontext->ah_list);
+ spin_lock_init(&file->ucontext->lock);
+
+ resp.async_fd = file->async_file.fd;
+ for (i = 0; i < file->device->num_comp; ++i)
+ if (copy_to_user((void __user *) (unsigned long) cmd.cq_fd_tab +
+ i * sizeof (__u32),
+ &file->comp_file[i].fd, sizeof (__u32)))
+ goto err;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp))
+ goto err;
+
+ return in_len;
+
+err:
+ ibdev->dealloc_ucontext(file->ucontext);
+ file->ucontext = NULL;
+
+ return -EFAULT;
+}
+
+ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file,
+ const char __user *buf,
+ int in_len, int out_len)
+{
+ struct ib_uverbs_query_device cmd;
+ struct ib_uverbs_query_device_resp resp;
+ struct ib_device_attr attr;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ ret = ib_query_device(file->device->ib_dev, &attr);
+ if (ret)
+ return ret;
+
+ memset(&resp, 0, sizeof resp);
+
+ resp.fw_ver = attr.fw_ver;
+ resp.node_guid = attr.node_guid;
+ resp.sys_image_guid = attr.sys_image_guid;
+ resp.max_mr_size = attr.max_mr_size;
+ resp.page_size_cap = attr.page_size_cap;
+ resp.vendor_id = attr.vendor_id;
+ resp.vendor_part_id = attr.vendor_part_id;
+ resp.hw_ver = attr.hw_ver;
+ resp.max_qp = attr.max_qp;
+ resp.max_qp_wr = attr.max_qp_wr;
+ resp.device_cap_flags = attr.device_cap_flags;
+ resp.max_sge = attr.max_sge;
+ resp.max_sge_rd = attr.max_sge_rd;
+ resp.max_cq = attr.max_cq;
+ resp.max_cqe = attr.max_cqe;
+ resp.max_mr = attr.max_mr;
+ resp.max_pd = attr.max_pd;
+ resp.max_qp_rd_atom = attr.max_qp_rd_atom;
+ resp.max_ee_rd_atom = attr.max_ee_rd_atom;
+ resp.max_res_rd_atom = attr.max_res_rd_atom;
+ resp.max_qp_init_rd_atom = attr.max_qp_init_rd_atom;
+ resp.max_ee_init_rd_atom = attr.max_ee_init_rd_atom;
+ resp.atomic_cap = attr.atomic_cap;
+ resp.max_ee = attr.max_ee;
+ resp.max_rdd = attr.max_rdd;
+ resp.max_mw = attr.max_mw;
+ resp.max_raw_ipv6_qp = attr.max_raw_ipv6_qp;
+ resp.max_raw_ethy_qp = attr.max_raw_ethy_qp;
+ resp.max_mcast_grp = attr.max_mcast_grp;
+ resp.max_mcast_qp_attach = attr.max_mcast_qp_attach;
+ resp.max_total_mcast_qp_attach = attr.max_total_mcast_qp_attach;
+ resp.max_ah = attr.max_ah;
+ resp.max_fmr = attr.max_fmr;
+ resp.max_map_per_fmr = attr.max_map_per_fmr;
+ resp.max_srq = attr.max_srq;
+ resp.max_srq_wr = attr.max_srq_wr;
+ resp.max_srq_sge = attr.max_srq_sge;
+ resp.max_pkeys = attr.max_pkeys;
+ resp.local_ca_ack_delay = attr.local_ca_ack_delay;
+ resp.phys_port_cnt = file->device->ib_dev->phys_port_cnt;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp))
+ return -EFAULT;
+
+ return in_len;
+}
+
+ssize_t ib_uverbs_query_port(struct ib_uverbs_file *file,
+ const char __user *buf,
+ int in_len, int out_len)
+{
+ struct ib_uverbs_query_port cmd;
+ struct ib_uverbs_query_port_resp resp;
+ struct ib_port_attr attr;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ ret = ib_query_port(file->device->ib_dev, cmd.port_num, &attr);
+ if (ret)
+ return ret;
+
+ memset(&resp, 0, sizeof resp);
+
+ resp.state = attr.state;
+ resp.max_mtu = attr.max_mtu;
+ resp.active_mtu = attr.active_mtu;
+ resp.gid_tbl_len = attr.gid_tbl_len;
+ resp.port_cap_flags = attr.port_cap_flags;
+ resp.max_msg_sz = attr.max_msg_sz;
+ resp.bad_pkey_cntr = attr.bad_pkey_cntr;
+ resp.qkey_viol_cntr = attr.qkey_viol_cntr;
+ resp.pkey_tbl_len = attr.pkey_tbl_len;
+ resp.lid = attr.lid;
+ resp.sm_lid = attr.sm_lid;
+ resp.lmc = attr.lmc;
+ resp.max_vl_num = attr.max_vl_num;
+ resp.sm_sl = attr.sm_sl;
+ resp.subnet_timeout = attr.subnet_timeout;
+ resp.init_type_reply = attr.init_type_reply;
+ resp.active_width = attr.active_width;
+ resp.active_speed = attr.active_speed;
+ resp.phys_state = attr.phys_state;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp))
+ return -EFAULT;
+
+ return in_len;
+}
+
+ssize_t ib_uverbs_query_gid(struct ib_uverbs_file *file,
+ const char __user *buf,
+ int in_len, int out_len)
+{
+ struct ib_uverbs_query_gid cmd;
+ struct ib_uverbs_query_gid_resp resp;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ memset(&resp, 0, sizeof resp);
+
+ ret = ib_query_gid(file->device->ib_dev, cmd.port_num, cmd.index,
+ (union ib_gid *) resp.gid);
+ if (ret)
+ return ret;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp))
+ return -EFAULT;
+
+ return in_len;
+}
+
+ssize_t ib_uverbs_query_pkey(struct ib_uverbs_file *file,
+ const char __user *buf,
+ int in_len, int out_len)
+{
+ struct ib_uverbs_query_pkey cmd;
+ struct ib_uverbs_query_pkey_resp resp;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ memset(&resp, 0, sizeof resp);
+
+ ret = ib_query_pkey(file->device->ib_dev, cmd.port_num, cmd.index,
+ &resp.pkey);
+ if (ret)
+ return ret;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp))
+ return -EFAULT;
+
+ return in_len;
+}
+
+ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
+ const char __user *buf,
+ int in_len, int out_len)
+{
+ struct ib_uverbs_alloc_pd cmd;
+ struct ib_uverbs_alloc_pd_resp resp;
+ struct ib_udata udata;
+ struct ib_uobject *uobj;
+ struct ib_pd *pd;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ INIT_UDATA(&udata, buf + sizeof cmd,
+ (unsigned long) cmd.response + sizeof resp,
+ in_len - sizeof cmd, out_len - sizeof resp);
+
+ uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
+ if (!uobj)
+ return -ENOMEM;
+
+ uobj->context = file->ucontext;
+
+ pd = file->device->ib_dev->alloc_pd(file->device->ib_dev,
+ file->ucontext, &udata);
+ if (IS_ERR(pd)) {
+ ret = PTR_ERR(pd);
+ goto err;
+ }
+
+ pd->device = file->device->ib_dev;
+ pd->uobject = uobj;
+ atomic_set(&pd->usecnt, 0);
+
+retry:
+ if (!idr_pre_get(&ib_uverbs_pd_idr, GFP_KERNEL)) {
+ ret = -ENOMEM;
+ goto err_pd;
+ }
+
+ down(&ib_uverbs_idr_mutex);
+ ret = idr_get_new(&ib_uverbs_pd_idr, pd, &uobj->id);
+ up(&ib_uverbs_idr_mutex);
+
+ if (ret == -EAGAIN)
+ goto retry;
+ if (ret)
+ goto err_pd;
+
+ spin_lock_irq(&file->ucontext->lock);
+ list_add_tail(&uobj->list, &file->ucontext->pd_list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ memset(&resp, 0, sizeof resp);
+ resp.pd_handle = uobj->id;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp)) {
+ ret = -EFAULT;
+ goto err_list;
+ }
+
+ return in_len;
+
+err_list:
+ spin_lock_irq(&file->ucontext->lock);
+ list_del(&uobj->list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ down(&ib_uverbs_idr_mutex);
+ idr_remove(&ib_uverbs_pd_idr, uobj->id);
+ up(&ib_uverbs_idr_mutex);
+
+err_pd:
+ ib_dealloc_pd(pd);
+
+err:
+ kfree(uobj);
+ return ret;
+}
+
+ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file,
+ const char __user *buf,
+ int in_len, int out_len)
+{
+ struct ib_uverbs_dealloc_pd cmd;
+ struct ib_pd *pd;
+ struct ib_uobject *uobj;
+ int ret = -EINVAL;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ down(&ib_uverbs_idr_mutex);
+
+ pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
+ if (!pd || pd->uobject->context != file->ucontext)
+ goto out;
+
+ uobj = pd->uobject;
+
+ ret = ib_dealloc_pd(pd);
+ if (ret)
+ goto out;
+
+ idr_remove(&ib_uverbs_pd_idr, cmd.pd_handle);
+
+ spin_lock_irq(&file->ucontext->lock);
+ list_del(&uobj->list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ kfree(uobj);
+
+out:
+ up(&ib_uverbs_idr_mutex);
+
+ return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_reg_mr cmd;
+ struct ib_uverbs_reg_mr_resp resp;
+ struct ib_udata udata;
+ struct ib_umem_object *obj;
+ struct ib_pd *pd;
+ struct ib_mr *mr;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ INIT_UDATA(&udata, buf + sizeof cmd,
+ (unsigned long) cmd.response + sizeof resp,
+ in_len - sizeof cmd, out_len - sizeof resp);
+
+ if ((cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK))
+ return -EINVAL;
+
+ obj = kmalloc(sizeof *obj, GFP_KERNEL);
+ if (!obj)
+ return -ENOMEM;
+
+ obj->uobject.context = file->ucontext;
+
+ /*
+ * We ask for writable memory if any access flags other than
+ * "remote read" are set. "Local write" and "remote write"
+ * obviously require write access. "Remote atomic" can do
+ * things like fetch and add, which will modify memory, and
+ * "MW bind" can change permissions by binding a window.
+ */
+ ret = ib_umem_get(file->device->ib_dev, &obj->umem,
+ (void *) (unsigned long) cmd.start, cmd.length,
+ !!(cmd.access_flags & ~IB_ACCESS_REMOTE_READ));
+ if (ret)
+ goto err_free;
+
+ obj->umem.virt_base = cmd.hca_va;
+
+ down(&ib_uverbs_idr_mutex);
+
+ pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
+ if (!pd || pd->uobject->context != file->ucontext) {
+ ret = -EINVAL;
+ goto err_up;
+ }
+
+ if (!pd->device->reg_user_mr) {
+ ret = -ENOSYS;
+ goto err_up;
+ }
+
+ mr = pd->device->reg_user_mr(pd, &obj->umem, cmd.access_flags, &udata);
+ if (IS_ERR(mr)) {
+ ret = PTR_ERR(mr);
+ goto err_up;
+ }
+
+ mr->device = pd->device;
+ mr->pd = pd;
+ mr->uobject = &obj->uobject;
+ atomic_inc(&pd->usecnt);
+ atomic_set(&mr->usecnt, 0);
+
+ memset(&resp, 0, sizeof resp);
+ resp.lkey = mr->lkey;
+ resp.rkey = mr->rkey;
+
+retry:
+ if (!idr_pre_get(&ib_uverbs_mr_idr, GFP_KERNEL)) {
+ ret = -ENOMEM;
+ goto err_unreg;
+ }
+
+ ret = idr_get_new(&ib_uverbs_mr_idr, mr, &obj->uobject.id);
+
+ if (ret == -EAGAIN)
+ goto retry;
+ if (ret)
+ goto err_unreg;
+
+ resp.mr_handle = obj->uobject.id;
+
+ spin_lock_irq(&file->ucontext->lock);
+ list_add_tail(&obj->uobject.list, &file->ucontext->mr_list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp)) {
+ ret = -EFAULT;
+ goto err_list;
+ }
+
+ up(&ib_uverbs_idr_mutex);
+
+ return in_len;
+
+err_list:
+ spin_lock_irq(&file->ucontext->lock);
+ list_del(&obj->uobject.list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+err_unreg:
+ ib_dereg_mr(mr);
+
+err_up:
+ up(&ib_uverbs_idr_mutex);
+
+ ib_umem_release(file->device->ib_dev, &obj->umem);
+
+err_free:
+ kfree(obj);
+ return ret;
+}
+
+ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_dereg_mr cmd;
+ struct ib_mr *mr;
+ struct ib_umem_object *memobj;
+ int ret = -EINVAL;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ down(&ib_uverbs_idr_mutex);
+
+ mr = idr_find(&ib_uverbs_mr_idr, cmd.mr_handle);
+ if (!mr || mr->uobject->context != file->ucontext)
+ goto out;
+
+ memobj = container_of(mr->uobject, struct ib_umem_object, uobject);
+
+ ret = ib_dereg_mr(mr);
+ if (ret)
+ goto out;
+
+ idr_remove(&ib_uverbs_mr_idr, cmd.mr_handle);
+
+ spin_lock_irq(&file->ucontext->lock);
+ list_del(&memobj->uobject.list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ ib_umem_release(file->device->ib_dev, &memobj->umem);
+ kfree(memobj);
+
+out:
+ up(&ib_uverbs_idr_mutex);
+
+ return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_create_cq cmd;
+ struct ib_uverbs_create_cq_resp resp;
+ struct ib_udata udata;
+ struct ib_uobject *uobj;
+ struct ib_cq *cq;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ INIT_UDATA(&udata, buf + sizeof cmd,
+ (unsigned long) cmd.response + sizeof resp,
+ in_len - sizeof cmd, out_len - sizeof resp);
+
+ if (cmd.event_handler >= file->device->num_comp)
+ return -EINVAL;
+
+ uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
+ if (!uobj)
+ return -ENOMEM;
+
+ uobj->user_handle = cmd.user_handle;
+ uobj->context = file->ucontext;
+
+ cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe,
+ file->ucontext, &udata);
+ if (IS_ERR(cq)) {
+ ret = PTR_ERR(cq);
+ goto err;
+ }
+
+ cq->device = file->device->ib_dev;
+ cq->uobject = uobj;
+ cq->comp_handler = ib_uverbs_comp_handler;
+ cq->event_handler = ib_uverbs_cq_event_handler;
+ cq->cq_context = file;
+ atomic_set(&cq->usecnt, 0);
+
+retry:
+ if (!idr_pre_get(&ib_uverbs_cq_idr, GFP_KERNEL)) {
+ ret = -ENOMEM;
+ goto err_cq;
+ }
+
+ down(&ib_uverbs_idr_mutex);
+ ret = idr_get_new(&ib_uverbs_cq_idr, cq, &uobj->id);
+ up(&ib_uverbs_idr_mutex);
+
+ if (ret == -EAGAIN)
+ goto retry;
+ if (ret)
+ goto err_cq;
+
+ spin_lock_irq(&file->ucontext->lock);
+ list_add_tail(&uobj->list, &file->ucontext->cq_list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ memset(&resp, 0, sizeof resp);
+ resp.cq_handle = uobj->id;
+ resp.cqe = cq->cqe;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp)) {
+ ret = -EFAULT;
+ goto err_list;
+ }
+
+ return in_len;
+
+err_list:
+ spin_lock_irq(&file->ucontext->lock);
+ list_del(&uobj->list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ down(&ib_uverbs_idr_mutex);
+ idr_remove(&ib_uverbs_cq_idr, uobj->id);
+ up(&ib_uverbs_idr_mutex);
+
+err_cq:
+ ib_destroy_cq(cq);
+
+err:
+ kfree(uobj);
+ return ret;
+}
+
+ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_destroy_cq cmd;
+ struct ib_cq *cq;
+ struct ib_uobject *uobj;
+ int ret = -EINVAL;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ down(&ib_uverbs_idr_mutex);
+
+ cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
+ if (!cq || cq->uobject->context != file->ucontext)
+ goto out;
+
+ uobj = cq->uobject;
+
+ ret = ib_destroy_cq(cq);
+ if (ret)
+ goto out;
+
+ idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle);
+
+ spin_lock_irq(&file->ucontext->lock);
+ list_del(&uobj->list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ kfree(uobj);
+
+out:
+ up(&ib_uverbs_idr_mutex);
+
+ return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_create_qp cmd;
+ struct ib_uverbs_create_qp_resp resp;
+ struct ib_udata udata;
+ struct ib_uobject *uobj;
+ struct ib_pd *pd;
+ struct ib_cq *scq, *rcq;
+ struct ib_qp *qp;
+ struct ib_qp_init_attr attr;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ INIT_UDATA(&udata, buf + sizeof cmd,
+ (unsigned long) cmd.response + sizeof resp,
+ in_len - sizeof cmd, out_len - sizeof resp);
+
+ uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
+ if (!uobj)
+ return -ENOMEM;
+
+ down(&ib_uverbs_idr_mutex);
+
+ pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
+ scq = idr_find(&ib_uverbs_cq_idr, cmd.send_cq_handle);
+ rcq = idr_find(&ib_uverbs_cq_idr, cmd.recv_cq_handle);
+
+ if (!pd || pd->uobject->context != file->ucontext ||
+ !scq || scq->uobject->context != file->ucontext ||
+ !rcq || rcq->uobject->context != file->ucontext) {
+ ret = -EINVAL;
+ goto err_up;
+ }
+
+ attr.event_handler = ib_uverbs_qp_event_handler;
+ attr.qp_context = file;
+ attr.send_cq = scq;
+ attr.recv_cq = rcq;
+ attr.srq = NULL;
+ attr.sq_sig_type = cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;
+ attr.qp_type = cmd.qp_type;
+
+ attr.cap.max_send_wr = cmd.max_send_wr;
+ attr.cap.max_recv_wr = cmd.max_recv_wr;
+ attr.cap.max_send_sge = cmd.max_send_sge;
+ attr.cap.max_recv_sge = cmd.max_recv_sge;
+ attr.cap.max_inline_data = cmd.max_inline_data;
+
+ uobj->user_handle = cmd.user_handle;
+ uobj->context = file->ucontext;
+
+ qp = pd->device->create_qp(pd, &attr, &udata);
+ if (IS_ERR(qp)) {
+ ret = PTR_ERR(qp);
+ goto err_up;
+ }
+
+ qp->device = pd->device;
+ qp->pd = pd;
+ qp->send_cq = attr.send_cq;
+ qp->recv_cq = attr.recv_cq;
+ qp->srq = attr.srq;
+ qp->uobject = uobj;
+ qp->event_handler = attr.event_handler;
+ qp->qp_context = attr.qp_context;
+ qp->qp_type = attr.qp_type;
+ atomic_inc(&pd->usecnt);
+ atomic_inc(&attr.send_cq->usecnt);
+ atomic_inc(&attr.recv_cq->usecnt);
+ if (attr.srq)
+ atomic_inc(&attr.srq->usecnt);
+
+ memset(&resp, 0, sizeof resp);
+ resp.qpn = qp->qp_num;
+
+retry:
+ if (!idr_pre_get(&ib_uverbs_qp_idr, GFP_KERNEL)) {
+ ret = -ENOMEM;
+ goto err_destroy;
+ }
+
+ ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->id);
+
+ if (ret == -EAGAIN)
+ goto retry;
+ if (ret)
+ goto err_destroy;
+
+ resp.qp_handle = uobj->id;
+
+ spin_lock_irq(&file->ucontext->lock);
+ list_add_tail(&uobj->list, &file->ucontext->qp_list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp)) {
+ ret = -EFAULT;
+ goto err_list;
+ }
+
+ up(&ib_uverbs_idr_mutex);
+
+ return in_len;
+
+err_list:
+ spin_lock_irq(&file->ucontext->lock);
+ list_del(&uobj->list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+err_destroy:
+ ib_destroy_qp(qp);
+
+err_up:
+ up(&ib_uverbs_idr_mutex);
+
+ kfree(uobj);
+ return ret;
+}
+
+ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_modify_qp cmd;
+ struct ib_qp *qp;
+ struct ib_qp_attr *attr;
+ int ret;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ attr = kmalloc(sizeof *attr, GFP_KERNEL);
+ if (!attr)
+ return -ENOMEM;
+
+ down(&ib_uverbs_idr_mutex);
+
+ qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
+ if (!qp || qp->uobject->context != file->ucontext) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ attr->qp_state = cmd.qp_state;
+ attr->cur_qp_state = cmd.cur_qp_state;
+ attr->path_mtu = cmd.path_mtu;
+ attr->path_mig_state = cmd.path_mig_state;
+ attr->qkey = cmd.qkey;
+ attr->rq_psn = cmd.rq_psn;
+ attr->sq_psn = cmd.sq_psn;
+ attr->dest_qp_num = cmd.dest_qp_num;
+ attr->qp_access_flags = cmd.qp_access_flags;
+ attr->pkey_index = cmd.pkey_index;
+ attr->alt_pkey_index = cmd.pkey_index;
+ attr->en_sqd_async_notify = cmd.en_sqd_async_notify;
+ attr->max_rd_atomic = cmd.max_rd_atomic;
+ attr->max_dest_rd_atomic = cmd.max_dest_rd_atomic;
+ attr->min_rnr_timer = cmd.min_rnr_timer;
+ attr->port_num = cmd.port_num;
+ attr->timeout = cmd.timeout;
+ attr->retry_cnt = cmd.retry_cnt;
+ attr->rnr_retry = cmd.rnr_retry;
+ attr->alt_port_num = cmd.alt_port_num;
+ attr->alt_timeout = cmd.alt_timeout;
+
+ memcpy(attr->ah_attr.grh.dgid.raw, cmd.dest.dgid, 16);
+ attr->ah_attr.grh.flow_label = cmd.dest.flow_label;
+ attr->ah_attr.grh.sgid_index = cmd.dest.sgid_index;
+ attr->ah_attr.grh.hop_limit = cmd.dest.hop_limit;
+ attr->ah_attr.grh.traffic_class = cmd.dest.traffic_class;
+ attr->ah_attr.dlid = cmd.dest.dlid;
+ attr->ah_attr.sl = cmd.dest.sl;
+ attr->ah_attr.src_path_bits = cmd.dest.src_path_bits;
+ attr->ah_attr.static_rate = cmd.dest.static_rate;
+ attr->ah_attr.ah_flags = cmd.dest.is_global ? IB_AH_GRH : 0;
+ attr->ah_attr.port_num = cmd.dest.port_num;
+
+ memcpy(attr->alt_ah_attr.grh.dgid.raw, cmd.alt_dest.dgid, 16);
+ attr->alt_ah_attr.grh.flow_label = cmd.alt_dest.flow_label;
+ attr->alt_ah_attr.grh.sgid_index = cmd.alt_dest.sgid_index;
+ attr->alt_ah_attr.grh.hop_limit = cmd.alt_dest.hop_limit;
+ attr->alt_ah_attr.grh.traffic_class = cmd.alt_dest.traffic_class;
+ attr->alt_ah_attr.dlid = cmd.alt_dest.dlid;
+ attr->alt_ah_attr.sl = cmd.alt_dest.sl;
+ attr->alt_ah_attr.src_path_bits = cmd.alt_dest.src_path_bits;
+ attr->alt_ah_attr.static_rate = cmd.alt_dest.static_rate;
+ attr->alt_ah_attr.ah_flags = cmd.alt_dest.is_global ? IB_AH_GRH : 0;
+ attr->alt_ah_attr.port_num = cmd.alt_dest.port_num;
+
+ ret = ib_modify_qp(qp, attr, cmd.attr_mask);
+ if (ret)
+ goto out;
+
+ ret = in_len;
+
+out:
+ up(&ib_uverbs_idr_mutex);
+ kfree(attr);
+
+ return ret;
+}
+
+ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_destroy_qp cmd;
+ struct ib_qp *qp;
+ struct ib_uobject *uobj;
+ int ret = -EINVAL;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ down(&ib_uverbs_idr_mutex);
+
+ qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
+ if (!qp || qp->uobject->context != file->ucontext)
+ goto out;
+
+ uobj = qp->uobject;
+
+ ret = ib_destroy_qp(qp);
+ if (ret)
+ goto out;
+
+ idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle);
+
+ spin_lock_irq(&file->ucontext->lock);
+ list_del(&uobj->list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ kfree(uobj);
+
+out:
+ up(&ib_uverbs_idr_mutex);
+
+ return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_attach_mcast cmd;
+ struct ib_qp *qp;
+ int ret = -EINVAL;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ down(&ib_uverbs_idr_mutex);
+
+ qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
+ if (qp && qp->uobject->context == file->ucontext)
+ ret = ib_attach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid);
+
+ up(&ib_uverbs_idr_mutex);
+
+ return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_detach_mcast cmd;
+ struct ib_qp *qp;
+ int ret = -EINVAL;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ down(&ib_uverbs_idr_mutex);
+
+ qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
+ if (qp && qp->uobject->context == file->ucontext)
+ ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid);
+
+ up(&ib_uverbs_idr_mutex);
+
+ return ret ? ret : in_len;
+}
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
new file mode 100644
index 00000000000..fbbe03d8c90
--- /dev/null
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -0,0 +1,698 @@
+/*
+ * Copyright (c) 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ *
+ * $Id: uverbs_main.c 2733 2005-06-28 19:14:34Z roland $
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+#include <linux/mount.h>
+
+#include <asm/uaccess.h>
+
+#include "uverbs.h"
+
+MODULE_AUTHOR("Roland Dreier");
+MODULE_DESCRIPTION("InfiniBand userspace verbs access");
+MODULE_LICENSE("Dual BSD/GPL");
+
+#define INFINIBANDEVENTFS_MAGIC 0x49426576 /* "IBev" */
+
+enum {
+ IB_UVERBS_MAJOR = 231,
+ IB_UVERBS_BASE_MINOR = 192,
+ IB_UVERBS_MAX_DEVICES = 32
+};
+
+#define IB_UVERBS_BASE_DEV MKDEV(IB_UVERBS_MAJOR, IB_UVERBS_BASE_MINOR)
+
+DECLARE_MUTEX(ib_uverbs_idr_mutex);
+DEFINE_IDR(ib_uverbs_pd_idr);
+DEFINE_IDR(ib_uverbs_mr_idr);
+DEFINE_IDR(ib_uverbs_mw_idr);
+DEFINE_IDR(ib_uverbs_ah_idr);
+DEFINE_IDR(ib_uverbs_cq_idr);
+DEFINE_IDR(ib_uverbs_qp_idr);
+
+static spinlock_t map_lock;
+static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES);
+
+static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len) = {
+ [IB_USER_VERBS_CMD_QUERY_PARAMS] = ib_uverbs_query_params,
+ [IB_USER_VERBS_CMD_GET_CONTEXT] = ib_uverbs_get_context,
+ [IB_USER_VERBS_CMD_QUERY_DEVICE] = ib_uverbs_query_device,
+ [IB_USER_VERBS_CMD_QUERY_PORT] = ib_uverbs_query_port,
+ [IB_USER_VERBS_CMD_QUERY_GID] = ib_uverbs_query_gid,
+ [IB_USER_VERBS_CMD_QUERY_PKEY] = ib_uverbs_query_pkey,
+ [IB_USER_VERBS_CMD_ALLOC_PD] = ib_uverbs_alloc_pd,
+ [IB_USER_VERBS_CMD_DEALLOC_PD] = ib_uverbs_dealloc_pd,
+ [IB_USER_VERBS_CMD_REG_MR] = ib_uverbs_reg_mr,
+ [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr,
+ [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq,
+ [IB_USER_VERBS_CMD_DESTROY_CQ] = ib_uverbs_destroy_cq,
+ [IB_USER_VERBS_CMD_CREATE_QP] = ib_uverbs_create_qp,
+ [IB_USER_VERBS_CMD_MODIFY_QP] = ib_uverbs_modify_qp,
+ [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp,
+ [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast,
+ [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast,
+};
+
+static struct vfsmount *uverbs_event_mnt;
+
+static void ib_uverbs_add_one(struct ib_device *device);
+static void ib_uverbs_remove_one(struct ib_device *device);
+
+static int ib_dealloc_ucontext(struct ib_ucontext *context)
+{
+ struct ib_uobject *uobj, *tmp;
+
+ if (!context)
+ return 0;
+
+ down(&ib_uverbs_idr_mutex);
+
+ /* XXX Free AHs */
+
+ list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) {
+ struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id);
+ idr_remove(&ib_uverbs_qp_idr, uobj->id);
+ ib_destroy_qp(qp);
+ list_del(&uobj->list);
+ kfree(uobj);
+ }
+
+ list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) {
+ struct ib_cq *cq = idr_find(&ib_uverbs_cq_idr, uobj->id);
+ idr_remove(&ib_uverbs_cq_idr, uobj->id);
+ ib_destroy_cq(cq);
+ list_del(&uobj->list);
+ kfree(uobj);
+ }
+
+ /* XXX Free SRQs */
+ /* XXX Free MWs */
+
+ list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) {
+ struct ib_mr *mr = idr_find(&ib_uverbs_mr_idr, uobj->id);
+ struct ib_umem_object *memobj;
+
+ idr_remove(&ib_uverbs_mr_idr, uobj->id);
+ ib_dereg_mr(mr);
+
+ memobj = container_of(uobj, struct ib_umem_object, uobject);
+ ib_umem_release_on_close(mr->device, &memobj->umem);
+
+ list_del(&uobj->list);
+ kfree(memobj);
+ }
+
+ list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) {
+ struct ib_pd *pd = idr_find(&ib_uverbs_pd_idr, uobj->id);
+ idr_remove(&ib_uverbs_pd_idr, uobj->id);
+ ib_dealloc_pd(pd);
+ list_del(&uobj->list);
+ kfree(uobj);
+ }
+
+ up(&ib_uverbs_idr_mutex);
+
+ return context->device->dealloc_ucontext(context);
+}
+
+static void ib_uverbs_release_file(struct kref *ref)
+{
+ struct ib_uverbs_file *file =
+ container_of(ref, struct ib_uverbs_file, ref);
+
+ module_put(file->device->ib_dev->owner);
+ kfree(file);
+}
+
+static ssize_t ib_uverbs_event_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct ib_uverbs_event_file *file = filp->private_data;
+ void *event;
+ int eventsz;
+ int ret = 0;
+
+ spin_lock_irq(&file->lock);
+
+ while (list_empty(&file->event_list) && file->fd >= 0) {
+ spin_unlock_irq(&file->lock);
+
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ if (wait_event_interruptible(file->poll_wait,
+ !list_empty(&file->event_list) ||
+ file->fd < 0))
+ return -ERESTARTSYS;
+
+ spin_lock_irq(&file->lock);
+ }
+
+ if (file->fd < 0) {
+ spin_unlock_irq(&file->lock);
+ return -ENODEV;
+ }
+
+ if (file->is_async) {
+ event = list_entry(file->event_list.next,
+ struct ib_uverbs_async_event, list);
+ eventsz = sizeof (struct ib_uverbs_async_event_desc);
+ } else {
+ event = list_entry(file->event_list.next,
+ struct ib_uverbs_comp_event, list);
+ eventsz = sizeof (struct ib_uverbs_comp_event_desc);
+ }
+
+ if (eventsz > count) {
+ ret = -EINVAL;
+ event = NULL;
+ } else
+ list_del(file->event_list.next);
+
+ spin_unlock_irq(&file->lock);
+
+ if (event) {
+ if (copy_to_user(buf, event, eventsz))
+ ret = -EFAULT;
+ else
+ ret = eventsz;
+ }
+
+ kfree(event);
+
+ return ret;
+}
+
+static unsigned int ib_uverbs_event_poll(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ unsigned int pollflags = 0;
+ struct ib_uverbs_event_file *file = filp->private_data;
+
+ poll_wait(filp, &file->poll_wait, wait);
+
+ spin_lock_irq(&file->lock);
+ if (file->fd < 0)
+ pollflags = POLLERR;
+ else if (!list_empty(&file->event_list))
+ pollflags = POLLIN | POLLRDNORM;
+ spin_unlock_irq(&file->lock);
+
+ return pollflags;
+}
+
+static void ib_uverbs_event_release(struct ib_uverbs_event_file *file)
+{
+ struct list_head *entry, *tmp;
+
+ spin_lock_irq(&file->lock);
+ if (file->fd != -1) {
+ file->fd = -1;
+ list_for_each_safe(entry, tmp, &file->event_list)
+ if (file->is_async)
+ kfree(list_entry(entry, struct ib_uverbs_async_event, list));
+ else
+ kfree(list_entry(entry, struct ib_uverbs_comp_event, list));
+ }
+ spin_unlock_irq(&file->lock);
+}
+
+static int ib_uverbs_event_close(struct inode *inode, struct file *filp)
+{
+ struct ib_uverbs_event_file *file = filp->private_data;
+
+ ib_uverbs_event_release(file);
+ kref_put(&file->uverbs_file->ref, ib_uverbs_release_file);
+
+ return 0;
+}
+
+static struct file_operations uverbs_event_fops = {
+ /*
+ * No .owner field since we artificially create event files,
+ * so there is no increment to the module reference count in
+ * the open path. All event files come from a uverbs command
+ * file, which already takes a module reference, so this is OK.
+ */
+ .read = ib_uverbs_event_read,
+ .poll = ib_uverbs_event_poll,
+ .release = ib_uverbs_event_close
+};
+
+void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context)
+{
+ struct ib_uverbs_file *file = cq_context;
+ struct ib_uverbs_comp_event *entry;
+ unsigned long flags;
+
+ entry = kmalloc(sizeof *entry, GFP_ATOMIC);
+ if (!entry)
+ return;
+
+ entry->desc.cq_handle = cq->uobject->user_handle;
+
+ spin_lock_irqsave(&file->comp_file[0].lock, flags);
+ list_add_tail(&entry->list, &file->comp_file[0].event_list);
+ spin_unlock_irqrestore(&file->comp_file[0].lock, flags);
+
+ wake_up_interruptible(&file->comp_file[0].poll_wait);
+}
+
+static void ib_uverbs_async_handler(struct ib_uverbs_file *file,
+ __u64 element, __u64 event)
+{
+ struct ib_uverbs_async_event *entry;
+ unsigned long flags;
+
+ entry = kmalloc(sizeof *entry, GFP_ATOMIC);
+ if (!entry)
+ return;
+
+ entry->desc.element = element;
+ entry->desc.event_type = event;
+
+ spin_lock_irqsave(&file->async_file.lock, flags);
+ list_add_tail(&entry->list, &file->async_file.event_list);
+ spin_unlock_irqrestore(&file->async_file.lock, flags);
+
+ wake_up_interruptible(&file->async_file.poll_wait);
+}
+
+void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr)
+{
+ ib_uverbs_async_handler(context_ptr,
+ event->element.cq->uobject->user_handle,
+ event->event);
+}
+
+void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr)
+{
+ ib_uverbs_async_handler(context_ptr,
+ event->element.qp->uobject->user_handle,
+ event->event);
+}
+
+static void ib_uverbs_event_handler(struct ib_event_handler *handler,
+ struct ib_event *event)
+{
+ struct ib_uverbs_file *file =
+ container_of(handler, struct ib_uverbs_file, event_handler);
+
+ ib_uverbs_async_handler(file, event->element.port_num, event->event);
+}
+
+static int ib_uverbs_event_init(struct ib_uverbs_event_file *file,
+ struct ib_uverbs_file *uverbs_file)
+{
+ struct file *filp;
+
+ spin_lock_init(&file->lock);
+ INIT_LIST_HEAD(&file->event_list);
+ init_waitqueue_head(&file->poll_wait);
+ file->uverbs_file = uverbs_file;
+
+ file->fd = get_unused_fd();
+ if (file->fd < 0)
+ return file->fd;
+
+ filp = get_empty_filp();
+ if (!filp) {
+ put_unused_fd(file->fd);
+ return -ENFILE;
+ }
+
+ filp->f_op = &uverbs_event_fops;
+ filp->f_vfsmnt = mntget(uverbs_event_mnt);
+ filp->f_dentry = dget(uverbs_event_mnt->mnt_root);
+ filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
+ filp->f_flags = O_RDONLY;
+ filp->f_mode = FMODE_READ;
+ filp->private_data = file;
+
+ fd_install(file->fd, filp);
+
+ return 0;
+}
+
+static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct ib_uverbs_file *file = filp->private_data;
+ struct ib_uverbs_cmd_hdr hdr;
+
+ if (count < sizeof hdr)
+ return -EINVAL;
+
+ if (copy_from_user(&hdr, buf, sizeof hdr))
+ return -EFAULT;
+
+ if (hdr.in_words * 4 != count)
+ return -EINVAL;
+
+ if (hdr.command < 0 || hdr.command >= ARRAY_SIZE(uverbs_cmd_table))
+ return -EINVAL;
+
+ if (!file->ucontext &&
+ hdr.command != IB_USER_VERBS_CMD_QUERY_PARAMS &&
+ hdr.command != IB_USER_VERBS_CMD_GET_CONTEXT)
+ return -EINVAL;
+
+ return uverbs_cmd_table[hdr.command](file, buf + sizeof hdr,
+ hdr.in_words * 4, hdr.out_words * 4);
+}
+
+static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct ib_uverbs_file *file = filp->private_data;
+
+ if (!file->ucontext)
+ return -ENODEV;
+ else
+ return file->device->ib_dev->mmap(file->ucontext, vma);
+}
+
+static int ib_uverbs_open(struct inode *inode, struct file *filp)
+{
+ struct ib_uverbs_device *dev =
+ container_of(inode->i_cdev, struct ib_uverbs_device, dev);
+ struct ib_uverbs_file *file;
+ int i = 0;
+ int ret;
+
+ if (!try_module_get(dev->ib_dev->owner))
+ return -ENODEV;
+
+ file = kmalloc(sizeof *file +
+ (dev->num_comp - 1) * sizeof (struct ib_uverbs_event_file),
+ GFP_KERNEL);
+ if (!file)
+ return -ENOMEM;
+
+ file->device = dev;
+ kref_init(&file->ref);
+
+ file->ucontext = NULL;
+
+ ret = ib_uverbs_event_init(&file->async_file, file);
+ if (ret)
+ goto err;
+
+ file->async_file.is_async = 1;
+
+ kref_get(&file->ref);
+
+ for (i = 0; i < dev->num_comp; ++i) {
+ ret = ib_uverbs_event_init(&file->comp_file[i], file);
+ if (ret)
+ goto err_async;
+ kref_get(&file->ref);
+ file->comp_file[i].is_async = 0;
+ }
+
+
+ filp->private_data = file;
+
+ INIT_IB_EVENT_HANDLER(&file->event_handler, dev->ib_dev,
+ ib_uverbs_event_handler);
+ if (ib_register_event_handler(&file->event_handler))
+ goto err_async;
+
+ return 0;
+
+err_async:
+ while (i--)
+ ib_uverbs_event_release(&file->comp_file[i]);
+
+ ib_uverbs_event_release(&file->async_file);
+
+err:
+ kref_put(&file->ref, ib_uverbs_release_file);
+
+ return ret;
+}
+
+static int ib_uverbs_close(struct inode *inode, struct file *filp)
+{
+ struct ib_uverbs_file *file = filp->private_data;
+ int i;
+
+ ib_unregister_event_handler(&file->event_handler);
+ ib_uverbs_event_release(&file->async_file);
+ ib_dealloc_ucontext(file->ucontext);
+
+ for (i = 0; i < file->device->num_comp; ++i)
+ ib_uverbs_event_release(&file->comp_file[i]);
+
+ kref_put(&file->ref, ib_uverbs_release_file);
+
+ return 0;
+}
+
+static struct file_operations uverbs_fops = {
+ .owner = THIS_MODULE,
+ .write = ib_uverbs_write,
+ .open = ib_uverbs_open,
+ .release = ib_uverbs_close
+};
+
+static struct file_operations uverbs_mmap_fops = {
+ .owner = THIS_MODULE,
+ .write = ib_uverbs_write,
+ .mmap = ib_uverbs_mmap,
+ .open = ib_uverbs_open,
+ .release = ib_uverbs_close
+};
+
+static struct ib_client uverbs_client = {
+ .name = "uverbs",
+ .add = ib_uverbs_add_one,
+ .remove = ib_uverbs_remove_one
+};
+
+static ssize_t show_ibdev(struct class_device *class_dev, char *buf)
+{
+ struct ib_uverbs_device *dev =
+ container_of(class_dev, struct ib_uverbs_device, class_dev);
+
+ return sprintf(buf, "%s\n", dev->ib_dev->name);
+}
+static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);
+
+static void ib_uverbs_release_class_dev(struct class_device *class_dev)
+{
+ struct ib_uverbs_device *dev =
+ container_of(class_dev, struct ib_uverbs_device, class_dev);
+
+ cdev_del(&dev->dev);
+ clear_bit(dev->devnum, dev_map);
+ kfree(dev);
+}
+
+static struct class uverbs_class = {
+ .name = "infiniband_verbs",
+ .release = ib_uverbs_release_class_dev
+};
+
+static ssize_t show_abi_version(struct class *class, char *buf)
+{
+ return sprintf(buf, "%d\n", IB_USER_VERBS_ABI_VERSION);
+}
+static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL);
+
+static void ib_uverbs_add_one(struct ib_device *device)
+{
+ struct ib_uverbs_device *uverbs_dev;
+
+ if (!device->alloc_ucontext)
+ return;
+
+ uverbs_dev = kmalloc(sizeof *uverbs_dev, GFP_KERNEL);
+ if (!uverbs_dev)
+ return;
+
+ memset(uverbs_dev, 0, sizeof *uverbs_dev);
+
+ spin_lock(&map_lock);
+ uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES);
+ if (uverbs_dev->devnum >= IB_UVERBS_MAX_DEVICES) {
+ spin_unlock(&map_lock);
+ goto err;
+ }
+ set_bit(uverbs_dev->devnum, dev_map);
+ spin_unlock(&map_lock);
+
+ uverbs_dev->ib_dev = device;
+ uverbs_dev->num_comp = 1;
+
+ if (device->mmap)
+ cdev_init(&uverbs_dev->dev, &uverbs_mmap_fops);
+ else
+ cdev_init(&uverbs_dev->dev, &uverbs_fops);
+ uverbs_dev->dev.owner = THIS_MODULE;
+ kobject_set_name(&uverbs_dev->dev.kobj, "uverbs%d", uverbs_dev->devnum);
+ if (cdev_add(&uverbs_dev->dev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1))
+ goto err;
+
+ uverbs_dev->class_dev.class = &uverbs_class;
+ uverbs_dev->class_dev.dev = device->dma_device;
+ uverbs_dev->class_dev.devt = uverbs_dev->dev.dev;
+ snprintf(uverbs_dev->class_dev.class_id, BUS_ID_SIZE, "uverbs%d", uverbs_dev->devnum);
+ if (class_device_register(&uverbs_dev->class_dev))
+ goto err_cdev;
+
+ if (class_device_create_file(&uverbs_dev->class_dev, &class_device_attr_ibdev))
+ goto err_class;
+
+ ib_set_client_data(device, &uverbs_client, uverbs_dev);
+
+ return;
+
+err_class:
+ class_device_unregister(&uverbs_dev->class_dev);
+
+err_cdev:
+ cdev_del(&uverbs_dev->dev);
+ clear_bit(uverbs_dev->devnum, dev_map);
+
+err:
+ kfree(uverbs_dev);
+ return;
+}
+
+static void ib_uverbs_remove_one(struct ib_device *device)
+{
+ struct ib_uverbs_device *uverbs_dev = ib_get_client_data(device, &uverbs_client);
+
+ if (!uverbs_dev)
+ return;
+
+ class_device_unregister(&uverbs_dev->class_dev);
+}
+
+static struct super_block *uverbs_event_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data)
+{
+ return get_sb_pseudo(fs_type, "infinibandevent:", NULL,
+ INFINIBANDEVENTFS_MAGIC);
+}
+
+static struct file_system_type uverbs_event_fs = {
+ /* No owner field so module can be unloaded */
+ .name = "infinibandeventfs",
+ .get_sb = uverbs_event_get_sb,
+ .kill_sb = kill_litter_super
+};
+
+static int __init ib_uverbs_init(void)
+{
+ int ret;
+
+ spin_lock_init(&map_lock);
+
+ ret = register_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES,
+ "infiniband_verbs");
+ if (ret) {
+ printk(KERN_ERR "user_verbs: couldn't register device number\n");
+ goto out;
+ }
+
+ ret = class_register(&uverbs_class);
+ if (ret) {
+ printk(KERN_ERR "user_verbs: couldn't create class infiniband_verbs\n");
+ goto out_chrdev;
+ }
+
+ ret = class_create_file(&uverbs_class, &class_attr_abi_version);
+ if (ret) {
+ printk(KERN_ERR "user_verbs: couldn't create abi_version attribute\n");
+ goto out_class;
+ }
+
+ ret = register_filesystem(&uverbs_event_fs);
+ if (ret) {
+ printk(KERN_ERR "user_verbs: couldn't register infinibandeventfs\n");
+ goto out_class;
+ }
+
+ uverbs_event_mnt = kern_mount(&uverbs_event_fs);
+ if (IS_ERR(uverbs_event_mnt)) {
+ ret = PTR_ERR(uverbs_event_mnt);
+ printk(KERN_ERR "user_verbs: couldn't mount infinibandeventfs\n");
+ goto out_fs;
+ }
+
+ ret = ib_register_client(&uverbs_client);
+ if (ret) {
+ printk(KERN_ERR "user_verbs: couldn't register client\n");
+ goto out_mnt;
+ }
+
+ return 0;
+
+out_mnt:
+ mntput(uverbs_event_mnt);
+
+out_fs:
+ unregister_filesystem(&uverbs_event_fs);
+
+out_class:
+ class_unregister(&uverbs_class);
+
+out_chrdev:
+ unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES);
+
+out:
+ return ret;
+}
+
+static void __exit ib_uverbs_cleanup(void)
+{
+ ib_unregister_client(&uverbs_client);
+ mntput(uverbs_event_mnt);
+ unregister_filesystem(&uverbs_event_fs);
+ class_unregister(&uverbs_class);
+ unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES);
+}
+
+module_init(ib_uverbs_init);
+module_exit(ib_uverbs_cleanup);
diff --git a/drivers/infiniband/core/uverbs_mem.c b/drivers/infiniband/core/uverbs_mem.c
new file mode 100644
index 00000000000..ed550f6595b
--- /dev/null
+++ b/drivers/infiniband/core/uverbs_mem.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ *
+ * $Id: uverbs_mem.c 2743 2005-06-28 22:27:59Z roland $
+ */
+
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+
+#include "uverbs.h"
+
+struct ib_umem_account_work {
+ struct work_struct work;
+ struct mm_struct *mm;
+ unsigned long diff;
+};
+
+
+static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int dirty)
+{
+ struct ib_umem_chunk *chunk, *tmp;
+ int i;
+
+ list_for_each_entry_safe(chunk, tmp, &umem->chunk_list, list) {
+ dma_unmap_sg(dev->dma_device, chunk->page_list,
+ chunk->nents, DMA_BIDIRECTIONAL);
+ for (i = 0; i < chunk->nents; ++i) {
+ if (umem->writable && dirty)
+ set_page_dirty_lock(chunk->page_list[i].page);
+ put_page(chunk->page_list[i].page);
+ }
+
+ kfree(chunk);
+ }
+}
+
+int ib_umem_get(struct ib_device *dev, struct ib_umem *mem,
+ void *addr, size_t size, int write)
+{
+ struct page **page_list;
+ struct ib_umem_chunk *chunk;
+ unsigned long locked;
+ unsigned long lock_limit;
+ unsigned long cur_base;
+ unsigned long npages;
+ int ret = 0;
+ int off;
+ int i;
+
+ if (!can_do_mlock())
+ return -EPERM;
+
+ page_list = (struct page **) __get_free_page(GFP_KERNEL);
+ if (!page_list)
+ return -ENOMEM;
+
+ mem->user_base = (unsigned long) addr;
+ mem->length = size;
+ mem->offset = (unsigned long) addr & ~PAGE_MASK;
+ mem->page_size = PAGE_SIZE;
+ mem->writable = write;
+
+ INIT_LIST_HEAD(&mem->chunk_list);
+
+ npages = PAGE_ALIGN(size + mem->offset) >> PAGE_SHIFT;
+
+ down_write(&current->mm->mmap_sem);
+
+ locked = npages + current->mm->locked_vm;
+ lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
+
+ if ((locked > lock_limit) && !capable(CAP_IPC_LOCK)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cur_base = (unsigned long) addr & PAGE_MASK;
+
+ while (npages) {
+ ret = get_user_pages(current, current->mm, cur_base,
+ min_t(int, npages,
+ PAGE_SIZE / sizeof (struct page *)),
+ 1, !write, page_list, NULL);
+
+ if (ret < 0)
+ goto out;
+
+ cur_base += ret * PAGE_SIZE;
+ npages -= ret;
+
+ off = 0;
+
+ while (ret) {
+ chunk = kmalloc(sizeof *chunk + sizeof (struct scatterlist) *
+ min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK),
+ GFP_KERNEL);
+ if (!chunk) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ chunk->nents = min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK);
+ for (i = 0; i < chunk->nents; ++i) {
+ chunk->page_list[i].page = page_list[i + off];
+ chunk->page_list[i].offset = 0;
+ chunk->page_list[i].length = PAGE_SIZE;
+ }
+
+ chunk->nmap = dma_map_sg(dev->dma_device,
+ &chunk->page_list[0],
+ chunk->nents,
+ DMA_BIDIRECTIONAL);
+ if (chunk->nmap <= 0) {
+ for (i = 0; i < chunk->nents; ++i)
+ put_page(chunk->page_list[i].page);
+ kfree(chunk);
+
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret -= chunk->nents;
+ off += chunk->nents;
+ list_add_tail(&chunk->list, &mem->chunk_list);
+ }
+
+ ret = 0;
+ }
+
+out:
+ if (ret < 0)
+ __ib_umem_release(dev, mem, 0);
+ else
+ current->mm->locked_vm = locked;
+
+ up_write(&current->mm->mmap_sem);
+ free_page((unsigned long) page_list);
+
+ return ret;
+}
+
+void ib_umem_release(struct ib_device *dev, struct ib_umem *umem)
+{
+ __ib_umem_release(dev, umem, 1);
+
+ down_write(&current->mm->mmap_sem);
+ current->mm->locked_vm -=
+ PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT;
+ up_write(&current->mm->mmap_sem);
+}
+
+static void ib_umem_account(void *work_ptr)
+{
+ struct ib_umem_account_work *work = work_ptr;
+
+ down_write(&work->mm->mmap_sem);
+ work->mm->locked_vm -= work->diff;
+ up_write(&work->mm->mmap_sem);
+ mmput(work->mm);
+ kfree(work);
+}
+
+void ib_umem_release_on_close(struct ib_device *dev, struct ib_umem *umem)
+{
+ struct ib_umem_account_work *work;
+ struct mm_struct *mm;
+
+ __ib_umem_release(dev, umem, 1);
+
+ mm = get_task_mm(current);
+ if (!mm)
+ return;
+
+ /*
+ * We may be called with the mm's mmap_sem already held. This
+ * can happen when a userspace munmap() is the call that drops
+ * the last reference to our file and calls our release
+ * method. If there are memory regions to destroy, we'll end
+ * up here and not be able to take the mmap_sem. Therefore we
+ * defer the vm_locked accounting to the system workqueue.
+ */
+
+ work = kmalloc(sizeof *work, GFP_KERNEL);
+ if (!work)
+ return;
+
+ INIT_WORK(&work->work, ib_umem_account, work);
+ work->mm = mm;
+ work->diff = PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT;
+
+ schedule_work(&work->work);
+}
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 7c08ed0cd7d..2516f964651 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -4,6 +4,7 @@
* Copyright (c) 2004 Intel Corporation. All rights reserved.
* Copyright (c) 2004 Topspin Corporation. All rights reserved.
* Copyright (c) 2004 Voltaire Corporation. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -47,10 +48,11 @@ struct ib_pd *ib_alloc_pd(struct ib_device *device)
{
struct ib_pd *pd;
- pd = device->alloc_pd(device);
+ pd = device->alloc_pd(device, NULL, NULL);
if (!IS_ERR(pd)) {
- pd->device = device;
+ pd->device = device;
+ pd->uobject = NULL;
atomic_set(&pd->usecnt, 0);
}
@@ -76,8 +78,9 @@ struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
ah = pd->device->create_ah(pd, ah_attr);
if (!IS_ERR(ah)) {
- ah->device = pd->device;
- ah->pd = pd;
+ ah->device = pd->device;
+ ah->pd = pd;
+ ah->uobject = NULL;
atomic_inc(&pd->usecnt);
}
@@ -122,7 +125,7 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
{
struct ib_qp *qp;
- qp = pd->device->create_qp(pd, qp_init_attr);
+ qp = pd->device->create_qp(pd, qp_init_attr, NULL);
if (!IS_ERR(qp)) {
qp->device = pd->device;
@@ -130,6 +133,7 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
qp->send_cq = qp_init_attr->send_cq;
qp->recv_cq = qp_init_attr->recv_cq;
qp->srq = qp_init_attr->srq;
+ qp->uobject = NULL;
qp->event_handler = qp_init_attr->event_handler;
qp->qp_context = qp_init_attr->qp_context;
qp->qp_type = qp_init_attr->qp_type;
@@ -197,10 +201,11 @@ struct ib_cq *ib_create_cq(struct ib_device *device,
{
struct ib_cq *cq;
- cq = device->create_cq(device, cqe);
+ cq = device->create_cq(device, cqe, NULL, NULL);
if (!IS_ERR(cq)) {
cq->device = device;
+ cq->uobject = NULL;
cq->comp_handler = comp_handler;
cq->event_handler = event_handler;
cq->cq_context = cq_context;
@@ -245,8 +250,9 @@ struct ib_mr *ib_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
mr = pd->device->get_dma_mr(pd, mr_access_flags);
if (!IS_ERR(mr)) {
- mr->device = pd->device;
- mr->pd = pd;
+ mr->device = pd->device;
+ mr->pd = pd;
+ mr->uobject = NULL;
atomic_inc(&pd->usecnt);
atomic_set(&mr->usecnt, 0);
}
@@ -267,8 +273,9 @@ struct ib_mr *ib_reg_phys_mr(struct ib_pd *pd,
mr_access_flags, iova_start);
if (!IS_ERR(mr)) {
- mr->device = pd->device;
- mr->pd = pd;
+ mr->device = pd->device;
+ mr->pd = pd;
+ mr->uobject = NULL;
atomic_inc(&pd->usecnt);
atomic_set(&mr->usecnt, 0);
}
@@ -344,8 +351,9 @@ struct ib_mw *ib_alloc_mw(struct ib_pd *pd)
mw = pd->device->alloc_mw(pd);
if (!IS_ERR(mw)) {
- mw->device = pd->device;
- mw->pd = pd;
+ mw->device = pd->device;
+ mw->pd = pd;
+ mw->uobject = NULL;
atomic_inc(&pd->usecnt);
}
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index 766e9031ec4..b5aea7b869f 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -742,6 +743,7 @@ err_out:
}
int mthca_init_cq(struct mthca_dev *dev, int nent,
+ struct mthca_ucontext *ctx, u32 pdn,
struct mthca_cq *cq)
{
int size = nent * MTHCA_CQ_ENTRY_SIZE;
@@ -753,30 +755,33 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
might_sleep();
- cq->ibcq.cqe = nent - 1;
+ cq->ibcq.cqe = nent - 1;
+ cq->is_kernel = !ctx;
cq->cqn = mthca_alloc(&dev->cq_table.alloc);
if (cq->cqn == -1)
return -ENOMEM;
if (mthca_is_memfree(dev)) {
- cq->arm_sn = 1;
-
err = mthca_table_get(dev, dev->cq_table.table, cq->cqn);
if (err)
goto err_out;
- err = -ENOMEM;
+ if (cq->is_kernel) {
+ cq->arm_sn = 1;
+
+ err = -ENOMEM;
- cq->set_ci_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_SET_CI,
- cq->cqn, &cq->set_ci_db);
- if (cq->set_ci_db_index < 0)
- goto err_out_icm;
+ cq->set_ci_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_SET_CI,
+ cq->cqn, &cq->set_ci_db);
+ if (cq->set_ci_db_index < 0)
+ goto err_out_icm;
- cq->arm_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_ARM,
- cq->cqn, &cq->arm_db);
- if (cq->arm_db_index < 0)
- goto err_out_ci;
+ cq->arm_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_ARM,
+ cq->cqn, &cq->arm_db);
+ if (cq->arm_db_index < 0)
+ goto err_out_ci;
+ }
}
mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
@@ -785,12 +790,14 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
cq_context = mailbox->buf;
- err = mthca_alloc_cq_buf(dev, size, cq);
- if (err)
- goto err_out_mailbox;
+ if (cq->is_kernel) {
+ err = mthca_alloc_cq_buf(dev, size, cq);
+ if (err)
+ goto err_out_mailbox;
- for (i = 0; i < nent; ++i)
- set_cqe_hw(get_cqe(cq, i));
+ for (i = 0; i < nent; ++i)
+ set_cqe_hw(get_cqe(cq, i));
+ }
spin_lock_init(&cq->lock);
atomic_set(&cq->refcount, 1);
@@ -801,11 +808,14 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
MTHCA_CQ_STATE_DISARMED |
MTHCA_CQ_FLAG_TR);
cq_context->start = cpu_to_be64(0);
- cq_context->logsize_usrpage = cpu_to_be32((ffs(nent) - 1) << 24 |
- dev->driver_uar.index);
+ cq_context->logsize_usrpage = cpu_to_be32((ffs(nent) - 1) << 24);
+ if (ctx)
+ cq_context->logsize_usrpage |= cpu_to_be32(ctx->uar.index);
+ else
+ cq_context->logsize_usrpage |= cpu_to_be32(dev->driver_uar.index);
cq_context->error_eqn = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn);
cq_context->comp_eqn = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_COMP].eqn);
- cq_context->pd = cpu_to_be32(dev->driver_pd.pd_num);
+ cq_context->pd = cpu_to_be32(pdn);
cq_context->lkey = cpu_to_be32(cq->mr.ibmr.lkey);
cq_context->cqn = cpu_to_be32(cq->cqn);
@@ -843,18 +853,20 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
return 0;
err_out_free_mr:
- mthca_free_mr(dev, &cq->mr);
- mthca_free_cq_buf(dev, cq);
+ if (cq->is_kernel) {
+ mthca_free_mr(dev, &cq->mr);
+ mthca_free_cq_buf(dev, cq);
+ }
err_out_mailbox:
mthca_free_mailbox(dev, mailbox);
err_out_arm:
- if (mthca_is_memfree(dev))
+ if (cq->is_kernel && mthca_is_memfree(dev))
mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
err_out_ci:
- if (mthca_is_memfree(dev))
+ if (cq->is_kernel && mthca_is_memfree(dev))
mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
err_out_icm:
@@ -892,7 +904,8 @@ void mthca_free_cq(struct mthca_dev *dev,
int j;
printk(KERN_ERR "context for CQN %x (cons index %x, next sw %d)\n",
- cq->cqn, cq->cons_index, !!next_cqe_sw(cq));
+ cq->cqn, cq->cons_index,
+ cq->is_kernel ? !!next_cqe_sw(cq) : 0);
for (j = 0; j < 16; ++j)
printk(KERN_ERR "[%2x] %08x\n", j * 4, be32_to_cpu(ctx[j]));
}
@@ -910,12 +923,13 @@ void mthca_free_cq(struct mthca_dev *dev,
atomic_dec(&cq->refcount);
wait_event(cq->wait, !atomic_read(&cq->refcount));
- mthca_free_mr(dev, &cq->mr);
- mthca_free_cq_buf(dev, cq);
-
- if (mthca_is_memfree(dev)) {
- mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
- mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
+ if (cq->is_kernel) {
+ mthca_free_mr(dev, &cq->mr);
+ mthca_free_cq_buf(dev, cq);
+ if (mthca_is_memfree(dev)) {
+ mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
+ mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
+ }
}
mthca_table_put(dev, dev->cq_table.table, cq->cqn);
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index 4127f09dc5e..5ecdd2eeeb0 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -378,7 +379,7 @@ void mthca_unregister_device(struct mthca_dev *dev);
int mthca_uar_alloc(struct mthca_dev *dev, struct mthca_uar *uar);
void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar);
-int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd);
+int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd);
void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd);
struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size);
@@ -413,6 +414,7 @@ int mthca_poll_cq(struct ib_cq *ibcq, int num_entries,
int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify);
int mthca_arbel_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify);
int mthca_init_cq(struct mthca_dev *dev, int nent,
+ struct mthca_ucontext *ctx, u32 pdn,
struct mthca_cq *cq);
void mthca_free_cq(struct mthca_dev *dev,
struct mthca_cq *cq);
@@ -438,12 +440,14 @@ int mthca_alloc_qp(struct mthca_dev *dev,
struct mthca_cq *recv_cq,
enum ib_qp_type type,
enum ib_sig_type send_policy,
+ struct ib_qp_cap *cap,
struct mthca_qp *qp);
int mthca_alloc_sqp(struct mthca_dev *dev,
struct mthca_pd *pd,
struct mthca_cq *send_cq,
struct mthca_cq *recv_cq,
enum ib_sig_type send_policy,
+ struct ib_qp_cap *cap,
int qpn,
int port,
struct mthca_sqp *sqp);
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index 09519b604c0..2ef916859e1 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -665,7 +665,7 @@ static int __devinit mthca_setup_hca(struct mthca_dev *dev)
goto err_pd_table_free;
}
- err = mthca_pd_alloc(dev, &dev->driver_pd);
+ err = mthca_pd_alloc(dev, 1, &dev->driver_pd);
if (err) {
mthca_err(dev, "Failed to create driver PD, "
"aborting.\n");
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
index 6d3b05dd9e3..2a864615035 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -47,6 +48,15 @@ enum {
MTHCA_TABLE_CHUNK_SIZE = 1 << 18
};
+struct mthca_user_db_table {
+ struct semaphore mutex;
+ struct {
+ u64 uvirt;
+ struct scatterlist mem;
+ int refcount;
+ } page[0];
+};
+
void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm)
{
struct mthca_icm_chunk *chunk, *tmp;
@@ -344,13 +354,133 @@ void mthca_free_icm_table(struct mthca_dev *dev, struct mthca_icm_table *table)
kfree(table);
}
-static u64 mthca_uarc_virt(struct mthca_dev *dev, int page)
+static u64 mthca_uarc_virt(struct mthca_dev *dev, struct mthca_uar *uar, int page)
{
return dev->uar_table.uarc_base +
- dev->driver_uar.index * dev->uar_table.uarc_size +
+ uar->index * dev->uar_table.uarc_size +
page * 4096;
}
+int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
+ struct mthca_user_db_table *db_tab, int index, u64 uaddr)
+{
+ int ret = 0;
+ u8 status;
+ int i;
+
+ if (!mthca_is_memfree(dev))
+ return 0;
+
+ if (index < 0 || index > dev->uar_table.uarc_size / 8)
+ return -EINVAL;
+
+ down(&db_tab->mutex);
+
+ i = index / MTHCA_DB_REC_PER_PAGE;
+
+ if ((db_tab->page[i].refcount >= MTHCA_DB_REC_PER_PAGE) ||
+ (db_tab->page[i].uvirt && db_tab->page[i].uvirt != uaddr) ||
+ (uaddr & 4095)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (db_tab->page[i].refcount) {
+ ++db_tab->page[i].refcount;
+ goto out;
+ }
+
+ ret = get_user_pages(current, current->mm, uaddr & PAGE_MASK, 1, 1, 0,
+ &db_tab->page[i].mem.page, NULL);
+ if (ret < 0)
+ goto out;
+
+ db_tab->page[i].mem.length = 4096;
+ db_tab->page[i].mem.offset = uaddr & ~PAGE_MASK;
+
+ ret = pci_map_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
+ if (ret < 0) {
+ put_page(db_tab->page[i].mem.page);
+ goto out;
+ }
+
+ ret = mthca_MAP_ICM_page(dev, sg_dma_address(&db_tab->page[i].mem),
+ mthca_uarc_virt(dev, uar, i), &status);
+ if (!ret && status)
+ ret = -EINVAL;
+ if (ret) {
+ pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
+ put_page(db_tab->page[i].mem.page);
+ goto out;
+ }
+
+ db_tab->page[i].uvirt = uaddr;
+ db_tab->page[i].refcount = 1;
+
+out:
+ up(&db_tab->mutex);
+ return ret;
+}
+
+void mthca_unmap_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
+ struct mthca_user_db_table *db_tab, int index)
+{
+ if (!mthca_is_memfree(dev))
+ return;
+
+ /*
+ * To make our bookkeeping simpler, we don't unmap DB
+ * pages until we clean up the whole db table.
+ */
+
+ down(&db_tab->mutex);
+
+ --db_tab->page[index / MTHCA_DB_REC_PER_PAGE].refcount;
+
+ up(&db_tab->mutex);
+}
+
+struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev)
+{
+ struct mthca_user_db_table *db_tab;
+ int npages;
+ int i;
+
+ if (!mthca_is_memfree(dev))
+ return NULL;
+
+ npages = dev->uar_table.uarc_size / 4096;
+ db_tab = kmalloc(sizeof *db_tab + npages * sizeof *db_tab->page, GFP_KERNEL);
+ if (!db_tab)
+ return ERR_PTR(-ENOMEM);
+
+ init_MUTEX(&db_tab->mutex);
+ for (i = 0; i < npages; ++i) {
+ db_tab->page[i].refcount = 0;
+ db_tab->page[i].uvirt = 0;
+ }
+
+ return db_tab;
+}
+
+void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar,
+ struct mthca_user_db_table *db_tab)
+{
+ int i;
+ u8 status;
+
+ if (!mthca_is_memfree(dev))
+ return;
+
+ for (i = 0; i < dev->uar_table.uarc_size / 4096; ++i) {
+ if (db_tab->page[i].uvirt) {
+ mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, uar, i), 1, &status);
+ pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
+ put_page(db_tab->page[i].mem.page);
+ }
+ }
+}
+
int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db)
{
int group;
@@ -407,7 +537,8 @@ int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db)
}
memset(page->db_rec, 0, 4096);
- ret = mthca_MAP_ICM_page(dev, page->mapping, mthca_uarc_virt(dev, i), &status);
+ ret = mthca_MAP_ICM_page(dev, page->mapping,
+ mthca_uarc_virt(dev, &dev->driver_uar, i), &status);
if (!ret && status)
ret = -EINVAL;
if (ret) {
@@ -461,7 +592,7 @@ void mthca_free_db(struct mthca_dev *dev, int type, int db_index)
if (bitmap_empty(page->used, MTHCA_DB_REC_PER_PAGE) &&
i >= dev->db_tab->max_group1 - 1) {
- mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, i), 1, &status);
+ mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status);
dma_free_coherent(&dev->pdev->dev, 4096,
page->db_rec, page->mapping);
@@ -530,7 +661,7 @@ void mthca_cleanup_db_tab(struct mthca_dev *dev)
if (!bitmap_empty(dev->db_tab->page[i].used, MTHCA_DB_REC_PER_PAGE))
mthca_warn(dev, "Kernel UARC page %d not empty\n", i);
- mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, i), 1, &status);
+ mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status);
dma_free_coherent(&dev->pdev->dev, 4096,
dev->db_tab->page[i].db_rec,
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.h b/drivers/infiniband/hw/mthca/mthca_memfree.h
index fe7be2a6bc4..4761d844cb5 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.h
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.h
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -148,7 +149,7 @@ struct mthca_db_table {
struct semaphore mutex;
};
-enum {
+enum mthca_db_type {
MTHCA_DB_TYPE_INVALID = 0x0,
MTHCA_DB_TYPE_CQ_SET_CI = 0x1,
MTHCA_DB_TYPE_CQ_ARM = 0x2,
@@ -158,6 +159,17 @@ enum {
MTHCA_DB_TYPE_GROUP_SEP = 0x7
};
+struct mthca_user_db_table;
+struct mthca_uar;
+
+int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
+ struct mthca_user_db_table *db_tab, int index, u64 uaddr);
+void mthca_unmap_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
+ struct mthca_user_db_table *db_tab, int index);
+struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev);
+void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar,
+ struct mthca_user_db_table *db_tab);
+
int mthca_init_db_tab(struct mthca_dev *dev);
void mthca_cleanup_db_tab(struct mthca_dev *dev);
int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db);
diff --git a/drivers/infiniband/hw/mthca/mthca_pd.c b/drivers/infiniband/hw/mthca/mthca_pd.c
index ea66847e4ea..c2c899844e9 100644
--- a/drivers/infiniband/hw/mthca/mthca_pd.c
+++ b/drivers/infiniband/hw/mthca/mthca_pd.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -37,23 +38,27 @@
#include "mthca_dev.h"
-int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd)
+int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd)
{
- int err;
+ int err = 0;
might_sleep();
+ pd->privileged = privileged;
+
atomic_set(&pd->sqp_count, 0);
pd->pd_num = mthca_alloc(&dev->pd_table.alloc);
if (pd->pd_num == -1)
return -ENOMEM;
- err = mthca_mr_alloc_notrans(dev, pd->pd_num,
- MTHCA_MPT_FLAG_LOCAL_READ |
- MTHCA_MPT_FLAG_LOCAL_WRITE,
- &pd->ntmr);
- if (err)
- mthca_free(&dev->pd_table.alloc, pd->pd_num);
+ if (privileged) {
+ err = mthca_mr_alloc_notrans(dev, pd->pd_num,
+ MTHCA_MPT_FLAG_LOCAL_READ |
+ MTHCA_MPT_FLAG_LOCAL_WRITE,
+ &pd->ntmr);
+ if (err)
+ mthca_free(&dev->pd_table.alloc, pd->pd_num);
+ }
return err;
}
@@ -61,7 +66,8 @@ int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd)
void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd)
{
might_sleep();
- mthca_free_mr(dev, &pd->ntmr);
+ if (pd->privileged)
+ mthca_free_mr(dev, &pd->ntmr);
mthca_free(&dev->pd_table.alloc, pd->pd_num);
}
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 0b5adfd9159..7a58ce90e17 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -34,9 +35,12 @@
*/
#include <ib_smi.h>
+#include <linux/mm.h>
#include "mthca_dev.h"
#include "mthca_cmd.h"
+#include "mthca_user.h"
+#include "mthca_memfree.h"
static int mthca_query_device(struct ib_device *ibdev,
struct ib_device_attr *props)
@@ -284,7 +288,78 @@ static int mthca_query_gid(struct ib_device *ibdev, u8 port,
return err;
}
-static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev)
+static struct ib_ucontext *mthca_alloc_ucontext(struct ib_device *ibdev,
+ struct ib_udata *udata)
+{
+ struct mthca_alloc_ucontext_resp uresp;
+ struct mthca_ucontext *context;
+ int err;
+
+ memset(&uresp, 0, sizeof uresp);
+
+ uresp.qp_tab_size = to_mdev(ibdev)->limits.num_qps;
+ if (mthca_is_memfree(to_mdev(ibdev)))
+ uresp.uarc_size = to_mdev(ibdev)->uar_table.uarc_size;
+ else
+ uresp.uarc_size = 0;
+
+ context = kmalloc(sizeof *context, GFP_KERNEL);
+ if (!context)
+ return ERR_PTR(-ENOMEM);
+
+ err = mthca_uar_alloc(to_mdev(ibdev), &context->uar);
+ if (err) {
+ kfree(context);
+ return ERR_PTR(err);
+ }
+
+ context->db_tab = mthca_init_user_db_tab(to_mdev(ibdev));
+ if (IS_ERR(context->db_tab)) {
+ err = PTR_ERR(context->db_tab);
+ mthca_uar_free(to_mdev(ibdev), &context->uar);
+ kfree(context);
+ return ERR_PTR(err);
+ }
+
+ if (ib_copy_to_udata(udata, &uresp, sizeof uresp)) {
+ mthca_cleanup_user_db_tab(to_mdev(ibdev), &context->uar, context->db_tab);
+ mthca_uar_free(to_mdev(ibdev), &context->uar);
+ kfree(context);
+ return ERR_PTR(-EFAULT);
+ }
+
+ return &context->ibucontext;
+}
+
+static int mthca_dealloc_ucontext(struct ib_ucontext *context)
+{
+ mthca_cleanup_user_db_tab(to_mdev(context->device), &to_mucontext(context)->uar,
+ to_mucontext(context)->db_tab);
+ mthca_uar_free(to_mdev(context->device), &to_mucontext(context)->uar);
+ kfree(to_mucontext(context));
+
+ return 0;
+}
+
+static int mthca_mmap_uar(struct ib_ucontext *context,
+ struct vm_area_struct *vma)
+{
+ if (vma->vm_end - vma->vm_start != PAGE_SIZE)
+ return -EINVAL;
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ if (remap_pfn_range(vma, vma->vm_start,
+ to_mucontext(context)->uar.pfn,
+ PAGE_SIZE, vma->vm_page_prot))
+ return -EAGAIN;
+
+ return 0;
+}
+
+static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev,
+ struct ib_ucontext *context,
+ struct ib_udata *udata)
{
struct mthca_pd *pd;
int err;
@@ -293,12 +368,20 @@ static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev)
if (!pd)
return ERR_PTR(-ENOMEM);
- err = mthca_pd_alloc(to_mdev(ibdev), pd);
+ err = mthca_pd_alloc(to_mdev(ibdev), !context, pd);
if (err) {
kfree(pd);
return ERR_PTR(err);
}
+ if (context) {
+ if (ib_copy_to_udata(udata, &pd->pd_num, sizeof (__u32))) {
+ mthca_pd_free(to_mdev(ibdev), pd);
+ kfree(pd);
+ return ERR_PTR(-EFAULT);
+ }
+ }
+
return &pd->ibpd;
}
@@ -338,8 +421,10 @@ static int mthca_ah_destroy(struct ib_ah *ah)
}
static struct ib_qp *mthca_create_qp(struct ib_pd *pd,
- struct ib_qp_init_attr *init_attr)
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata)
{
+ struct mthca_create_qp ucmd;
struct mthca_qp *qp;
int err;
@@ -348,41 +433,82 @@ static struct ib_qp *mthca_create_qp(struct ib_pd *pd,
case IB_QPT_UC:
case IB_QPT_UD:
{
+ struct mthca_ucontext *context;
+
qp = kmalloc(sizeof *qp, GFP_KERNEL);
if (!qp)
return ERR_PTR(-ENOMEM);
- qp->sq.max = init_attr->cap.max_send_wr;
- qp->rq.max = init_attr->cap.max_recv_wr;
- qp->sq.max_gs = init_attr->cap.max_send_sge;
- qp->rq.max_gs = init_attr->cap.max_recv_sge;
+ if (pd->uobject) {
+ context = to_mucontext(pd->uobject->context);
+
+ if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
+ return ERR_PTR(-EFAULT);
+
+ err = mthca_map_user_db(to_mdev(pd->device), &context->uar,
+ context->db_tab,
+ ucmd.sq_db_index, ucmd.sq_db_page);
+ if (err) {
+ kfree(qp);
+ return ERR_PTR(err);
+ }
+
+ err = mthca_map_user_db(to_mdev(pd->device), &context->uar,
+ context->db_tab,
+ ucmd.rq_db_index, ucmd.rq_db_page);
+ if (err) {
+ mthca_unmap_user_db(to_mdev(pd->device),
+ &context->uar,
+ context->db_tab,
+ ucmd.sq_db_index);
+ kfree(qp);
+ return ERR_PTR(err);
+ }
+
+ qp->mr.ibmr.lkey = ucmd.lkey;
+ qp->sq.db_index = ucmd.sq_db_index;
+ qp->rq.db_index = ucmd.rq_db_index;
+ }
err = mthca_alloc_qp(to_mdev(pd->device), to_mpd(pd),
to_mcq(init_attr->send_cq),
to_mcq(init_attr->recv_cq),
init_attr->qp_type, init_attr->sq_sig_type,
- qp);
+ &init_attr->cap, qp);
+
+ if (err && pd->uobject) {
+ context = to_mucontext(pd->uobject->context);
+
+ mthca_unmap_user_db(to_mdev(pd->device),
+ &context->uar,
+ context->db_tab,
+ ucmd.sq_db_index);
+ mthca_unmap_user_db(to_mdev(pd->device),
+ &context->uar,
+ context->db_tab,
+ ucmd.rq_db_index);
+ }
+
qp->ibqp.qp_num = qp->qpn;
break;
}
case IB_QPT_SMI:
case IB_QPT_GSI:
{
+ /* Don't allow userspace to create special QPs */
+ if (pd->uobject)
+ return ERR_PTR(-EINVAL);
+
qp = kmalloc(sizeof (struct mthca_sqp), GFP_KERNEL);
if (!qp)
return ERR_PTR(-ENOMEM);
- qp->sq.max = init_attr->cap.max_send_wr;
- qp->rq.max = init_attr->cap.max_recv_wr;
- qp->sq.max_gs = init_attr->cap.max_send_sge;
- qp->rq.max_gs = init_attr->cap.max_recv_sge;
-
qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_SMI ? 0 : 1;
err = mthca_alloc_sqp(to_mdev(pd->device), to_mpd(pd),
to_mcq(init_attr->send_cq),
to_mcq(init_attr->recv_cq),
- init_attr->sq_sig_type,
+ init_attr->sq_sig_type, &init_attr->cap,
qp->ibqp.qp_num, init_attr->port_num,
to_msqp(qp));
break;
@@ -397,42 +523,115 @@ static struct ib_qp *mthca_create_qp(struct ib_pd *pd,
return ERR_PTR(err);
}
- init_attr->cap.max_inline_data = 0;
+ init_attr->cap.max_inline_data = 0;
+ init_attr->cap.max_send_wr = qp->sq.max;
+ init_attr->cap.max_recv_wr = qp->rq.max;
+ init_attr->cap.max_send_sge = qp->sq.max_gs;
+ init_attr->cap.max_recv_sge = qp->rq.max_gs;
return &qp->ibqp;
}
static int mthca_destroy_qp(struct ib_qp *qp)
{
+ if (qp->uobject) {
+ mthca_unmap_user_db(to_mdev(qp->device),
+ &to_mucontext(qp->uobject->context)->uar,
+ to_mucontext(qp->uobject->context)->db_tab,
+ to_mqp(qp)->sq.db_index);
+ mthca_unmap_user_db(to_mdev(qp->device),
+ &to_mucontext(qp->uobject->context)->uar,
+ to_mucontext(qp->uobject->context)->db_tab,
+ to_mqp(qp)->rq.db_index);
+ }
mthca_free_qp(to_mdev(qp->device), to_mqp(qp));
kfree(qp);
return 0;
}
-static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries)
+static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries,
+ struct ib_ucontext *context,
+ struct ib_udata *udata)
{
+ struct mthca_create_cq ucmd;
struct mthca_cq *cq;
int nent;
int err;
+ if (context) {
+ if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
+ return ERR_PTR(-EFAULT);
+
+ err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,
+ to_mucontext(context)->db_tab,
+ ucmd.set_db_index, ucmd.set_db_page);
+ if (err)
+ return ERR_PTR(err);
+
+ err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,
+ to_mucontext(context)->db_tab,
+ ucmd.arm_db_index, ucmd.arm_db_page);
+ if (err)
+ goto err_unmap_set;
+ }
+
cq = kmalloc(sizeof *cq, GFP_KERNEL);
- if (!cq)
- return ERR_PTR(-ENOMEM);
+ if (!cq) {
+ err = -ENOMEM;
+ goto err_unmap_arm;
+ }
+
+ if (context) {
+ cq->mr.ibmr.lkey = ucmd.lkey;
+ cq->set_ci_db_index = ucmd.set_db_index;
+ cq->arm_db_index = ucmd.arm_db_index;
+ }
for (nent = 1; nent <= entries; nent <<= 1)
; /* nothing */
- err = mthca_init_cq(to_mdev(ibdev), nent, cq);
- if (err) {
- kfree(cq);
- cq = ERR_PTR(err);
+ err = mthca_init_cq(to_mdev(ibdev), nent,
+ context ? to_mucontext(context) : NULL,
+ context ? ucmd.pdn : to_mdev(ibdev)->driver_pd.pd_num,
+ cq);
+ if (err)
+ goto err_free;
+
+ if (context && ib_copy_to_udata(udata, &cq->cqn, sizeof (__u32))) {
+ mthca_free_cq(to_mdev(ibdev), cq);
+ goto err_free;
}
return &cq->ibcq;
+
+err_free:
+ kfree(cq);
+
+err_unmap_arm:
+ if (context)
+ mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,
+ to_mucontext(context)->db_tab, ucmd.arm_db_index);
+
+err_unmap_set:
+ if (context)
+ mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,
+ to_mucontext(context)->db_tab, ucmd.set_db_index);
+
+ return ERR_PTR(err);
}
static int mthca_destroy_cq(struct ib_cq *cq)
{
+ if (cq->uobject) {
+ mthca_unmap_user_db(to_mdev(cq->device),
+ &to_mucontext(cq->uobject->context)->uar,
+ to_mucontext(cq->uobject->context)->db_tab,
+ to_mcq(cq)->arm_db_index);
+ mthca_unmap_user_db(to_mdev(cq->device),
+ &to_mucontext(cq->uobject->context)->uar,
+ to_mucontext(cq->uobject->context)->db_tab,
+ to_mcq(cq)->set_ci_db_index);
+ }
mthca_free_cq(to_mdev(cq->device), to_mcq(cq));
kfree(cq);
@@ -568,6 +767,87 @@ static struct ib_mr *mthca_reg_phys_mr(struct ib_pd *pd,
return &mr->ibmr;
}
+static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
+ int acc, struct ib_udata *udata)
+{
+ struct mthca_dev *dev = to_mdev(pd->device);
+ struct ib_umem_chunk *chunk;
+ struct mthca_mr *mr;
+ u64 *pages;
+ int shift, n, len;
+ int i, j, k;
+ int err = 0;
+
+ shift = ffs(region->page_size) - 1;
+
+ mr = kmalloc(sizeof *mr, GFP_KERNEL);
+ if (!mr)
+ return ERR_PTR(-ENOMEM);
+
+ n = 0;
+ list_for_each_entry(chunk, &region->chunk_list, list)
+ n += chunk->nents;
+
+ mr->mtt = mthca_alloc_mtt(dev, n);
+ if (IS_ERR(mr->mtt)) {
+ err = PTR_ERR(mr->mtt);
+ goto err;
+ }
+
+ pages = (u64 *) __get_free_page(GFP_KERNEL);
+ if (!pages) {
+ err = -ENOMEM;
+ goto err_mtt;
+ }
+
+ i = n = 0;
+
+ list_for_each_entry(chunk, &region->chunk_list, list)
+ for (j = 0; j < chunk->nmap; ++j) {
+ len = sg_dma_len(&chunk->page_list[j]) >> shift;
+ for (k = 0; k < len; ++k) {
+ pages[i++] = sg_dma_address(&chunk->page_list[j]) +
+ region->page_size * k;
+ /*
+ * Be friendly to WRITE_MTT command
+ * and leave two empty slots for the
+ * index and reserved fields of the
+ * mailbox.
+ */
+ if (i == PAGE_SIZE / sizeof (u64) - 2) {
+ err = mthca_write_mtt(dev, mr->mtt,
+ n, pages, i);
+ if (err)
+ goto mtt_done;
+ n += i;
+ i = 0;
+ }
+ }
+ }
+
+ if (i)
+ err = mthca_write_mtt(dev, mr->mtt, n, pages, i);
+mtt_done:
+ free_page((unsigned long) pages);
+ if (err)
+ goto err_mtt;
+
+ err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, shift, region->virt_base,
+ region->length, convert_access(acc), mr);
+
+ if (err)
+ goto err_mtt;
+
+ return &mr->ibmr;
+
+err_mtt:
+ mthca_free_mtt(dev, mr->mtt);
+
+err:
+ kfree(mr);
+ return ERR_PTR(err);
+}
+
static int mthca_dereg_mr(struct ib_mr *mr)
{
struct mthca_mr *mmr = to_mmr(mr);
@@ -692,6 +972,8 @@ int mthca_register_device(struct mthca_dev *dev)
int i;
strlcpy(dev->ib_dev.name, "mthca%d", IB_DEVICE_NAME_MAX);
+ dev->ib_dev.owner = THIS_MODULE;
+
dev->ib_dev.node_type = IB_NODE_CA;
dev->ib_dev.phys_port_cnt = dev->limits.num_ports;
dev->ib_dev.dma_device = &dev->pdev->dev;
@@ -701,6 +983,9 @@ int mthca_register_device(struct mthca_dev *dev)
dev->ib_dev.modify_port = mthca_modify_port;
dev->ib_dev.query_pkey = mthca_query_pkey;
dev->ib_dev.query_gid = mthca_query_gid;
+ dev->ib_dev.alloc_ucontext = mthca_alloc_ucontext;
+ dev->ib_dev.dealloc_ucontext = mthca_dealloc_ucontext;
+ dev->ib_dev.mmap = mthca_mmap_uar;
dev->ib_dev.alloc_pd = mthca_alloc_pd;
dev->ib_dev.dealloc_pd = mthca_dealloc_pd;
dev->ib_dev.create_ah = mthca_ah_create;
@@ -713,6 +998,7 @@ int mthca_register_device(struct mthca_dev *dev)
dev->ib_dev.poll_cq = mthca_poll_cq;
dev->ib_dev.get_dma_mr = mthca_get_dma_mr;
dev->ib_dev.reg_phys_mr = mthca_reg_phys_mr;
+ dev->ib_dev.reg_user_mr = mthca_reg_user_mr;
dev->ib_dev.dereg_mr = mthca_dereg_mr;
if (dev->mthca_flags & MTHCA_FLAG_FMR) {
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h
index 4d976cccb1a..1d032791cc8 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.h
+++ b/drivers/infiniband/hw/mthca/mthca_provider.h
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -54,6 +55,14 @@ struct mthca_uar {
int index;
};
+struct mthca_user_db_table;
+
+struct mthca_ucontext {
+ struct ib_ucontext ibucontext;
+ struct mthca_uar uar;
+ struct mthca_user_db_table *db_tab;
+};
+
struct mthca_mtt;
struct mthca_mr {
@@ -83,6 +92,7 @@ struct mthca_pd {
u32 pd_num;
atomic_t sqp_count;
struct mthca_mr ntmr;
+ int privileged;
};
struct mthca_eq {
@@ -167,6 +177,7 @@ struct mthca_cq {
int cqn;
u32 cons_index;
int is_direct;
+ int is_kernel;
/* Next fields are Arbel only */
int set_ci_db_index;
@@ -236,6 +247,11 @@ struct mthca_sqp {
dma_addr_t header_dma;
};
+static inline struct mthca_ucontext *to_mucontext(struct ib_ucontext *ibucontext)
+{
+ return container_of(ibucontext, struct mthca_ucontext, ibucontext);
+}
+
static inline struct mthca_fmr *to_mfmr(struct ib_fmr *ibmr)
{
return container_of(ibmr, struct mthca_fmr, ibmr);
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 163a8ef4186..f7126b14d5a 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -46,7 +47,9 @@ enum {
MTHCA_MAX_DIRECT_QP_SIZE = 4 * PAGE_SIZE,
MTHCA_ACK_REQ_FREQ = 10,
MTHCA_FLIGHT_LIMIT = 9,
- MTHCA_UD_HEADER_SIZE = 72 /* largest UD header possible */
+ MTHCA_UD_HEADER_SIZE = 72, /* largest UD header possible */
+ MTHCA_INLINE_HEADER_SIZE = 4, /* data segment overhead for inline */
+ MTHCA_INLINE_CHUNK_SIZE = 16 /* inline data segment chunk */
};
enum {
@@ -689,7 +692,11 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
/* leave arbel_sched_queue as 0 */
- qp_context->usr_page = cpu_to_be32(dev->driver_uar.index);
+ if (qp->ibqp.uobject)
+ qp_context->usr_page =
+ cpu_to_be32(to_mucontext(qp->ibqp.uobject->context)->uar.index);
+ else
+ qp_context->usr_page = cpu_to_be32(dev->driver_uar.index);
qp_context->local_qpn = cpu_to_be32(qp->qpn);
if (attr_mask & IB_QP_DEST_QPN) {
qp_context->remote_qpn = cpu_to_be32(attr->dest_qp_num);
@@ -954,6 +961,15 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
qp->send_wqe_offset = ALIGN(qp->rq.max << qp->rq.wqe_shift,
1 << qp->sq.wqe_shift);
+
+ /*
+ * If this is a userspace QP, we don't actually have to
+ * allocate anything. All we need is to calculate the WQE
+ * sizes and the send_wqe_offset, so we're done now.
+ */
+ if (pd->ibpd.uobject)
+ return 0;
+
size = PAGE_ALIGN(qp->send_wqe_offset +
(qp->sq.max << qp->sq.wqe_shift));
@@ -1053,10 +1069,32 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
return err;
}
-static int mthca_alloc_memfree(struct mthca_dev *dev,
+static void mthca_free_wqe_buf(struct mthca_dev *dev,
struct mthca_qp *qp)
{
- int ret = 0;
+ int i;
+ int size = PAGE_ALIGN(qp->send_wqe_offset +
+ (qp->sq.max << qp->sq.wqe_shift));
+
+ if (qp->is_direct) {
+ dma_free_coherent(&dev->pdev->dev, size, qp->queue.direct.buf,
+ pci_unmap_addr(&qp->queue.direct, mapping));
+ } else {
+ for (i = 0; i < size / PAGE_SIZE; ++i) {
+ dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+ qp->queue.page_list[i].buf,
+ pci_unmap_addr(&qp->queue.page_list[i],
+ mapping));
+ }
+ }
+
+ kfree(qp->wrid);
+}
+
+static int mthca_map_memfree(struct mthca_dev *dev,
+ struct mthca_qp *qp)
+{
+ int ret;
if (mthca_is_memfree(dev)) {
ret = mthca_table_get(dev, dev->qp_table.qp_table, qp->qpn);
@@ -1067,35 +1105,15 @@ static int mthca_alloc_memfree(struct mthca_dev *dev,
if (ret)
goto err_qpc;
- ret = mthca_table_get(dev, dev->qp_table.rdb_table,
- qp->qpn << dev->qp_table.rdb_shift);
- if (ret)
- goto err_eqpc;
-
- qp->rq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_RQ,
- qp->qpn, &qp->rq.db);
- if (qp->rq.db_index < 0) {
- ret = -ENOMEM;
- goto err_rdb;
- }
+ ret = mthca_table_get(dev, dev->qp_table.rdb_table,
+ qp->qpn << dev->qp_table.rdb_shift);
+ if (ret)
+ goto err_eqpc;
- qp->sq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_SQ,
- qp->qpn, &qp->sq.db);
- if (qp->sq.db_index < 0) {
- ret = -ENOMEM;
- goto err_rq_db;
- }
}
return 0;
-err_rq_db:
- mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
-
-err_rdb:
- mthca_table_put(dev, dev->qp_table.rdb_table,
- qp->qpn << dev->qp_table.rdb_shift);
-
err_eqpc:
mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
@@ -1105,6 +1123,35 @@ err_qpc:
return ret;
}
+static void mthca_unmap_memfree(struct mthca_dev *dev,
+ struct mthca_qp *qp)
+{
+ mthca_table_put(dev, dev->qp_table.rdb_table,
+ qp->qpn << dev->qp_table.rdb_shift);
+ mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
+ mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn);
+}
+
+static int mthca_alloc_memfree(struct mthca_dev *dev,
+ struct mthca_qp *qp)
+{
+ int ret = 0;
+
+ if (mthca_is_memfree(dev)) {
+ qp->rq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_RQ,
+ qp->qpn, &qp->rq.db);
+ if (qp->rq.db_index < 0)
+ return ret;
+
+ qp->sq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_SQ,
+ qp->qpn, &qp->sq.db);
+ if (qp->sq.db_index < 0)
+ mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
+ }
+
+ return ret;
+}
+
static void mthca_free_memfree(struct mthca_dev *dev,
struct mthca_qp *qp)
{
@@ -1112,11 +1159,6 @@ static void mthca_free_memfree(struct mthca_dev *dev,
mthca_free_db(dev, MTHCA_DB_TYPE_SQ, qp->sq.db_index);
mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
}
-
- mthca_table_put(dev, dev->qp_table.rdb_table,
- qp->qpn << dev->qp_table.rdb_shift);
- mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
- mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn);
}
static void mthca_wq_init(struct mthca_wq* wq)
@@ -1147,13 +1189,28 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev,
mthca_wq_init(&qp->sq);
mthca_wq_init(&qp->rq);
- ret = mthca_alloc_memfree(dev, qp);
+ ret = mthca_map_memfree(dev, qp);
if (ret)
return ret;
ret = mthca_alloc_wqe_buf(dev, pd, qp);
if (ret) {
- mthca_free_memfree(dev, qp);
+ mthca_unmap_memfree(dev, qp);
+ return ret;
+ }
+
+ /*
+ * If this is a userspace QP, we're done now. The doorbells
+ * will be allocated and buffers will be initialized in
+ * userspace.
+ */
+ if (pd->ibpd.uobject)
+ return 0;
+
+ ret = mthca_alloc_memfree(dev, qp);
+ if (ret) {
+ mthca_free_wqe_buf(dev, qp);
+ mthca_unmap_memfree(dev, qp);
return ret;
}
@@ -1186,22 +1243,39 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev,
return 0;
}
-static void mthca_align_qp_size(struct mthca_dev *dev, struct mthca_qp *qp)
+static int mthca_set_qp_size(struct mthca_dev *dev, struct ib_qp_cap *cap,
+ struct mthca_qp *qp)
{
- int i;
-
- if (!mthca_is_memfree(dev))
- return;
+ /* Sanity check QP size before proceeding */
+ if (cap->max_send_wr > 65536 || cap->max_recv_wr > 65536 ||
+ cap->max_send_sge > 64 || cap->max_recv_sge > 64)
+ return -EINVAL;
- for (i = 0; 1 << i < qp->rq.max; ++i)
- ; /* nothing */
+ if (mthca_is_memfree(dev)) {
+ qp->rq.max = cap->max_recv_wr ?
+ roundup_pow_of_two(cap->max_recv_wr) : 0;
+ qp->sq.max = cap->max_send_wr ?
+ roundup_pow_of_two(cap->max_send_wr) : 0;
+ } else {
+ qp->rq.max = cap->max_recv_wr;
+ qp->sq.max = cap->max_send_wr;
+ }
- qp->rq.max = 1 << i;
+ qp->rq.max_gs = cap->max_recv_sge;
+ qp->sq.max_gs = max_t(int, cap->max_send_sge,
+ ALIGN(cap->max_inline_data + MTHCA_INLINE_HEADER_SIZE,
+ MTHCA_INLINE_CHUNK_SIZE) /
+ sizeof (struct mthca_data_seg));
- for (i = 0; 1 << i < qp->sq.max; ++i)
- ; /* nothing */
+ /*
+ * For MLX transport we need 2 extra S/G entries:
+ * one for the header and one for the checksum at the end
+ */
+ if ((qp->transport == MLX && qp->sq.max_gs + 2 > dev->limits.max_sg) ||
+ qp->sq.max_gs > dev->limits.max_sg || qp->rq.max_gs > dev->limits.max_sg)
+ return -EINVAL;
- qp->sq.max = 1 << i;
+ return 0;
}
int mthca_alloc_qp(struct mthca_dev *dev,
@@ -1210,11 +1284,14 @@ int mthca_alloc_qp(struct mthca_dev *dev,
struct mthca_cq *recv_cq,
enum ib_qp_type type,
enum ib_sig_type send_policy,
+ struct ib_qp_cap *cap,
struct mthca_qp *qp)
{
int err;
- mthca_align_qp_size(dev, qp);
+ err = mthca_set_qp_size(dev, cap, qp);
+ if (err)
+ return err;
switch (type) {
case IB_QPT_RC: qp->transport = RC; break;
@@ -1247,14 +1324,17 @@ int mthca_alloc_sqp(struct mthca_dev *dev,
struct mthca_cq *send_cq,
struct mthca_cq *recv_cq,
enum ib_sig_type send_policy,
+ struct ib_qp_cap *cap,
int qpn,
int port,
struct mthca_sqp *sqp)
{
- int err = 0;
u32 mqpn = qpn * 2 + dev->qp_table.sqp_start + port - 1;
+ int err;
- mthca_align_qp_size(dev, &sqp->qp);
+ err = mthca_set_qp_size(dev, cap, &sqp->qp);
+ if (err)
+ return err;
sqp->header_buf_size = sqp->qp.sq.max * MTHCA_UD_HEADER_SIZE;
sqp->header_buf = dma_alloc_coherent(&dev->pdev->dev, sqp->header_buf_size,
@@ -1313,8 +1393,6 @@ void mthca_free_qp(struct mthca_dev *dev,
struct mthca_qp *qp)
{
u8 status;
- int size;
- int i;
struct mthca_cq *send_cq;
struct mthca_cq *recv_cq;
@@ -1344,31 +1422,22 @@ void mthca_free_qp(struct mthca_dev *dev,
if (qp->state != IB_QPS_RESET)
mthca_MODIFY_QP(dev, MTHCA_TRANS_ANY2RST, qp->qpn, 0, NULL, 0, &status);
- mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn);
- if (qp->ibqp.send_cq != qp->ibqp.recv_cq)
- mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn);
-
- mthca_free_mr(dev, &qp->mr);
-
- size = PAGE_ALIGN(qp->send_wqe_offset +
- (qp->sq.max << qp->sq.wqe_shift));
+ /*
+ * If this is a userspace QP, the buffers, MR, CQs and so on
+ * will be cleaned up in userspace, so all we have to do is
+ * unref the mem-free tables and free the QPN in our table.
+ */
+ if (!qp->ibqp.uobject) {
+ mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn);
+ if (qp->ibqp.send_cq != qp->ibqp.recv_cq)
+ mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn);
- if (qp->is_direct) {
- pci_free_consistent(dev->pdev, size,
- qp->queue.direct.buf,
- pci_unmap_addr(&qp->queue.direct, mapping));
- } else {
- for (i = 0; i < size / PAGE_SIZE; ++i) {
- pci_free_consistent(dev->pdev, PAGE_SIZE,
- qp->queue.page_list[i].buf,
- pci_unmap_addr(&qp->queue.page_list[i],
- mapping));
- }
+ mthca_free_mr(dev, &qp->mr);
+ mthca_free_memfree(dev, qp);
+ mthca_free_wqe_buf(dev, qp);
}
- kfree(qp->wrid);
-
- mthca_free_memfree(dev, qp);
+ mthca_unmap_memfree(dev, qp);
if (is_sqp(dev, qp)) {
atomic_dec(&(to_mpd(qp->ibqp.pd)->sqp_count));
diff --git a/drivers/infiniband/hw/mthca/mthca_user.h b/drivers/infiniband/hw/mthca/mthca_user.h
new file mode 100644
index 00000000000..3024c1b4547
--- /dev/null
+++ b/drivers/infiniband/hw/mthca/mthca_user.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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 MTHCA_USER_H
+#define MTHCA_USER_H
+
+#include <linux/types.h>
+
+/*
+ * Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
+
+struct mthca_alloc_ucontext_resp {
+ __u32 qp_tab_size;
+ __u32 uarc_size;
+};
+
+struct mthca_alloc_pd_resp {
+ __u32 pdn;
+ __u32 reserved;
+};
+
+struct mthca_create_cq {
+ __u32 lkey;
+ __u32 pdn;
+ __u64 arm_db_page;
+ __u64 set_db_page;
+ __u32 arm_db_index;
+ __u32 set_db_index;
+};
+
+struct mthca_create_cq_resp {
+ __u32 cqn;
+ __u32 reserved;
+};
+
+struct mthca_create_qp {
+ __u32 lkey;
+ __u32 reserved;
+ __u64 sq_db_page;
+ __u64 rq_db_page;
+ __u32 sq_db_index;
+ __u32 rq_db_index;
+};
+
+#endif /* MTHCA_USER_H */
diff --git a/drivers/infiniband/include/ib_user_verbs.h b/drivers/infiniband/include/ib_user_verbs.h
new file mode 100644
index 00000000000..7c613706af7
--- /dev/null
+++ b/drivers/infiniband/include/ib_user_verbs.h
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ *
+ * $Id: ib_user_verbs.h 2708 2005-06-24 17:27:21Z roland $
+ */
+
+#ifndef IB_USER_VERBS_H
+#define IB_USER_VERBS_H
+
+#include <linux/types.h>
+
+/*
+ * Increment this value if any changes that break userspace ABI
+ * compatibility are made.
+ */
+#define IB_USER_VERBS_ABI_VERSION 1
+
+enum {
+ IB_USER_VERBS_CMD_QUERY_PARAMS,
+ IB_USER_VERBS_CMD_GET_CONTEXT,
+ IB_USER_VERBS_CMD_QUERY_DEVICE,
+ IB_USER_VERBS_CMD_QUERY_PORT,
+ IB_USER_VERBS_CMD_QUERY_GID,
+ IB_USER_VERBS_CMD_QUERY_PKEY,
+ IB_USER_VERBS_CMD_ALLOC_PD,
+ IB_USER_VERBS_CMD_DEALLOC_PD,
+ IB_USER_VERBS_CMD_CREATE_AH,
+ IB_USER_VERBS_CMD_MODIFY_AH,
+ IB_USER_VERBS_CMD_QUERY_AH,
+ IB_USER_VERBS_CMD_DESTROY_AH,
+ IB_USER_VERBS_CMD_REG_MR,
+ IB_USER_VERBS_CMD_REG_SMR,
+ IB_USER_VERBS_CMD_REREG_MR,
+ IB_USER_VERBS_CMD_QUERY_MR,
+ IB_USER_VERBS_CMD_DEREG_MR,
+ IB_USER_VERBS_CMD_ALLOC_MW,
+ IB_USER_VERBS_CMD_BIND_MW,
+ IB_USER_VERBS_CMD_DEALLOC_MW,
+ IB_USER_VERBS_CMD_CREATE_CQ,
+ IB_USER_VERBS_CMD_RESIZE_CQ,
+ IB_USER_VERBS_CMD_DESTROY_CQ,
+ IB_USER_VERBS_CMD_POLL_CQ,
+ IB_USER_VERBS_CMD_PEEK_CQ,
+ IB_USER_VERBS_CMD_REQ_NOTIFY_CQ,
+ IB_USER_VERBS_CMD_CREATE_QP,
+ IB_USER_VERBS_CMD_QUERY_QP,
+ IB_USER_VERBS_CMD_MODIFY_QP,
+ IB_USER_VERBS_CMD_DESTROY_QP,
+ IB_USER_VERBS_CMD_POST_SEND,
+ IB_USER_VERBS_CMD_POST_RECV,
+ IB_USER_VERBS_CMD_ATTACH_MCAST,
+ IB_USER_VERBS_CMD_DETACH_MCAST
+};
+
+/*
+ * Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
+
+struct ib_uverbs_async_event_desc {
+ __u64 element;
+ __u32 event_type; /* enum ib_event_type */
+ __u32 reserved;
+};
+
+struct ib_uverbs_comp_event_desc {
+ __u64 cq_handle;
+};
+
+/*
+ * All commands from userspace should start with a __u32 command field
+ * followed by __u16 in_words and out_words fields (which give the
+ * length of the command block and response buffer if any in 32-bit
+ * words). The kernel driver will read these fields first and read
+ * the rest of the command struct based on these value.
+ */
+
+struct ib_uverbs_cmd_hdr {
+ __u32 command;
+ __u16 in_words;
+ __u16 out_words;
+};
+
+/*
+ * No driver_data for "query params" command, since this is intended
+ * to be a core function with no possible device dependence.
+ */
+struct ib_uverbs_query_params {
+ __u64 response;
+};
+
+struct ib_uverbs_query_params_resp {
+ __u32 num_cq_events;
+};
+
+struct ib_uverbs_get_context {
+ __u64 response;
+ __u64 cq_fd_tab;
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_get_context_resp {
+ __u32 async_fd;
+ __u32 reserved;
+};
+
+struct ib_uverbs_query_device {
+ __u64 response;
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_query_device_resp {
+ __u64 fw_ver;
+ __u64 node_guid;
+ __u64 sys_image_guid;
+ __u64 max_mr_size;
+ __u64 page_size_cap;
+ __u32 vendor_id;
+ __u32 vendor_part_id;
+ __u32 hw_ver;
+ __u32 max_qp;
+ __u32 max_qp_wr;
+ __u32 device_cap_flags;
+ __u32 max_sge;
+ __u32 max_sge_rd;
+ __u32 max_cq;
+ __u32 max_cqe;
+ __u32 max_mr;
+ __u32 max_pd;
+ __u32 max_qp_rd_atom;
+ __u32 max_ee_rd_atom;
+ __u32 max_res_rd_atom;
+ __u32 max_qp_init_rd_atom;
+ __u32 max_ee_init_rd_atom;
+ __u32 atomic_cap;
+ __u32 max_ee;
+ __u32 max_rdd;
+ __u32 max_mw;
+ __u32 max_raw_ipv6_qp;
+ __u32 max_raw_ethy_qp;
+ __u32 max_mcast_grp;
+ __u32 max_mcast_qp_attach;
+ __u32 max_total_mcast_qp_attach;
+ __u32 max_ah;
+ __u32 max_fmr;
+ __u32 max_map_per_fmr;
+ __u32 max_srq;
+ __u32 max_srq_wr;
+ __u32 max_srq_sge;
+ __u16 max_pkeys;
+ __u8 local_ca_ack_delay;
+ __u8 phys_port_cnt;
+ __u8 reserved[4];
+};
+
+struct ib_uverbs_query_port {
+ __u64 response;
+ __u8 port_num;
+ __u8 reserved[7];
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_query_port_resp {
+ __u32 port_cap_flags;
+ __u32 max_msg_sz;
+ __u32 bad_pkey_cntr;
+ __u32 qkey_viol_cntr;
+ __u32 gid_tbl_len;
+ __u16 pkey_tbl_len;
+ __u16 lid;
+ __u16 sm_lid;
+ __u8 state;
+ __u8 max_mtu;
+ __u8 active_mtu;
+ __u8 lmc;
+ __u8 max_vl_num;
+ __u8 sm_sl;
+ __u8 subnet_timeout;
+ __u8 init_type_reply;
+ __u8 active_width;
+ __u8 active_speed;
+ __u8 phys_state;
+ __u8 reserved[3];
+};
+
+struct ib_uverbs_query_gid {
+ __u64 response;
+ __u8 port_num;
+ __u8 index;
+ __u8 reserved[6];
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_query_gid_resp {
+ __u8 gid[16];
+};
+
+struct ib_uverbs_query_pkey {
+ __u64 response;
+ __u8 port_num;
+ __u8 index;
+ __u8 reserved[6];
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_query_pkey_resp {
+ __u16 pkey;
+ __u16 reserved;
+};
+
+struct ib_uverbs_alloc_pd {
+ __u64 response;
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_alloc_pd_resp {
+ __u32 pd_handle;
+};
+
+struct ib_uverbs_dealloc_pd {
+ __u32 pd_handle;
+};
+
+struct ib_uverbs_reg_mr {
+ __u64 response;
+ __u64 start;
+ __u64 length;
+ __u64 hca_va;
+ __u32 pd_handle;
+ __u32 access_flags;
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_reg_mr_resp {
+ __u32 mr_handle;
+ __u32 lkey;
+ __u32 rkey;
+};
+
+struct ib_uverbs_dereg_mr {
+ __u32 mr_handle;
+};
+
+struct ib_uverbs_create_cq {
+ __u64 response;
+ __u64 user_handle;
+ __u32 cqe;
+ __u32 event_handler;
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_create_cq_resp {
+ __u32 cq_handle;
+ __u32 cqe;
+};
+
+struct ib_uverbs_destroy_cq {
+ __u32 cq_handle;
+};
+
+struct ib_uverbs_create_qp {
+ __u64 response;
+ __u64 user_handle;
+ __u32 pd_handle;
+ __u32 send_cq_handle;
+ __u32 recv_cq_handle;
+ __u32 srq_handle;
+ __u32 max_send_wr;
+ __u32 max_recv_wr;
+ __u32 max_send_sge;
+ __u32 max_recv_sge;
+ __u32 max_inline_data;
+ __u8 sq_sig_all;
+ __u8 qp_type;
+ __u8 is_srq;
+ __u8 reserved;
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_create_qp_resp {
+ __u32 qp_handle;
+ __u32 qpn;
+};
+
+/*
+ * This struct needs to remain a multiple of 8 bytes to keep the
+ * alignment of the modify QP parameters.
+ */
+struct ib_uverbs_qp_dest {
+ __u8 dgid[16];
+ __u32 flow_label;
+ __u16 dlid;
+ __u16 reserved;
+ __u8 sgid_index;
+ __u8 hop_limit;
+ __u8 traffic_class;
+ __u8 sl;
+ __u8 src_path_bits;
+ __u8 static_rate;
+ __u8 is_global;
+ __u8 port_num;
+};
+
+struct ib_uverbs_modify_qp {
+ struct ib_uverbs_qp_dest dest;
+ struct ib_uverbs_qp_dest alt_dest;
+ __u32 qp_handle;
+ __u32 attr_mask;
+ __u32 qkey;
+ __u32 rq_psn;
+ __u32 sq_psn;
+ __u32 dest_qp_num;
+ __u32 qp_access_flags;
+ __u16 pkey_index;
+ __u16 alt_pkey_index;
+ __u8 qp_state;
+ __u8 cur_qp_state;
+ __u8 path_mtu;
+ __u8 path_mig_state;
+ __u8 en_sqd_async_notify;
+ __u8 max_rd_atomic;
+ __u8 max_dest_rd_atomic;
+ __u8 min_rnr_timer;
+ __u8 port_num;
+ __u8 timeout;
+ __u8 retry_cnt;
+ __u8 rnr_retry;
+ __u8 alt_port_num;
+ __u8 alt_timeout;
+ __u8 reserved[2];
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_modify_qp_resp {
+};
+
+struct ib_uverbs_destroy_qp {
+ __u32 qp_handle;
+};
+
+struct ib_uverbs_attach_mcast {
+ __u8 gid[16];
+ __u32 qp_handle;
+ __u16 mlid;
+ __u16 reserved;
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_detach_mcast {
+ __u8 gid[16];
+ __u32 qp_handle;
+ __u16 mlid;
+ __u16 reserved;
+ __u64 driver_data[0];
+};
+
+#endif /* IB_USER_VERBS_H */
diff --git a/drivers/infiniband/include/ib_verbs.h b/drivers/infiniband/include/ib_verbs.h
index cf01f044a22..e5bd9a10c20 100644
--- a/drivers/infiniband/include/ib_verbs.h
+++ b/drivers/infiniband/include/ib_verbs.h
@@ -4,6 +4,7 @@
* Copyright (c) 2004 Intel Corporation. All rights reserved.
* Copyright (c) 2004 Topspin Corporation. All rights reserved.
* Copyright (c) 2004 Voltaire Corporation. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -41,7 +42,10 @@
#include <linux/types.h>
#include <linux/device.h>
+
#include <asm/atomic.h>
+#include <asm/scatterlist.h>
+#include <asm/uaccess.h>
union ib_gid {
u8 raw[16];
@@ -544,7 +548,7 @@ struct ib_send_wr {
int num_sge;
enum ib_wr_opcode opcode;
int send_flags;
- u32 imm_data;
+ __be32 imm_data;
union {
struct {
u64 remote_addr;
@@ -618,29 +622,86 @@ struct ib_fmr_attr {
u8 page_size;
};
+struct ib_ucontext {
+ struct ib_device *device;
+ struct list_head pd_list;
+ struct list_head mr_list;
+ struct list_head mw_list;
+ struct list_head cq_list;
+ struct list_head qp_list;
+ struct list_head srq_list;
+ struct list_head ah_list;
+ spinlock_t lock;
+};
+
+struct ib_uobject {
+ u64 user_handle; /* handle given to us by userspace */
+ struct ib_ucontext *context; /* associated user context */
+ struct list_head list; /* link to context's list */
+ u32 id; /* index into kernel idr */
+};
+
+struct ib_umem {
+ unsigned long user_base;
+ unsigned long virt_base;
+ size_t length;
+ int offset;
+ int page_size;
+ int writable;
+ struct list_head chunk_list;
+};
+
+struct ib_umem_chunk {
+ struct list_head list;
+ int nents;
+ int nmap;
+ struct scatterlist page_list[0];
+};
+
+struct ib_udata {
+ void __user *inbuf;
+ void __user *outbuf;
+ size_t inlen;
+ size_t outlen;
+};
+
+#define IB_UMEM_MAX_PAGE_CHUNK \
+ ((PAGE_SIZE - offsetof(struct ib_umem_chunk, page_list)) / \
+ ((void *) &((struct ib_umem_chunk *) 0)->page_list[1] - \
+ (void *) &((struct ib_umem_chunk *) 0)->page_list[0]))
+
+struct ib_umem_object {
+ struct ib_uobject uobject;
+ struct ib_umem umem;
+};
+
struct ib_pd {
- struct ib_device *device;
- atomic_t usecnt; /* count all resources */
+ struct ib_device *device;
+ struct ib_uobject *uobject;
+ atomic_t usecnt; /* count all resources */
};
struct ib_ah {
struct ib_device *device;
struct ib_pd *pd;
+ struct ib_uobject *uobject;
};
typedef void (*ib_comp_handler)(struct ib_cq *cq, void *cq_context);
struct ib_cq {
- struct ib_device *device;
- ib_comp_handler comp_handler;
- void (*event_handler)(struct ib_event *, void *);
- void * cq_context;
- int cqe;
- atomic_t usecnt; /* count number of work queues */
+ struct ib_device *device;
+ struct ib_uobject *uobject;
+ ib_comp_handler comp_handler;
+ void (*event_handler)(struct ib_event *, void *);
+ void * cq_context;
+ int cqe;
+ atomic_t usecnt; /* count number of work queues */
};
struct ib_srq {
struct ib_device *device;
+ struct ib_uobject *uobject;
struct ib_pd *pd;
void *srq_context;
atomic_t usecnt;
@@ -652,6 +713,7 @@ struct ib_qp {
struct ib_cq *send_cq;
struct ib_cq *recv_cq;
struct ib_srq *srq;
+ struct ib_uobject *uobject;
void (*event_handler)(struct ib_event *, void *);
void *qp_context;
u32 qp_num;
@@ -659,16 +721,18 @@ struct ib_qp {
};
struct ib_mr {
- struct ib_device *device;
- struct ib_pd *pd;
- u32 lkey;
- u32 rkey;
- atomic_t usecnt; /* count number of MWs */
+ struct ib_device *device;
+ struct ib_pd *pd;
+ struct ib_uobject *uobject;
+ u32 lkey;
+ u32 rkey;
+ atomic_t usecnt; /* count number of MWs */
};
struct ib_mw {
struct ib_device *device;
struct ib_pd *pd;
+ struct ib_uobject *uobject;
u32 rkey;
};
@@ -737,7 +801,14 @@ struct ib_device {
int (*modify_port)(struct ib_device *device,
u8 port_num, int port_modify_mask,
struct ib_port_modify *port_modify);
- struct ib_pd * (*alloc_pd)(struct ib_device *device);
+ struct ib_ucontext * (*alloc_ucontext)(struct ib_device *device,
+ struct ib_udata *udata);
+ int (*dealloc_ucontext)(struct ib_ucontext *context);
+ int (*mmap)(struct ib_ucontext *context,
+ struct vm_area_struct *vma);
+ struct ib_pd * (*alloc_pd)(struct ib_device *device,
+ struct ib_ucontext *context,
+ struct ib_udata *udata);
int (*dealloc_pd)(struct ib_pd *pd);
struct ib_ah * (*create_ah)(struct ib_pd *pd,
struct ib_ah_attr *ah_attr);
@@ -747,7 +818,8 @@ struct ib_device {
struct ib_ah_attr *ah_attr);
int (*destroy_ah)(struct ib_ah *ah);
struct ib_qp * (*create_qp)(struct ib_pd *pd,
- struct ib_qp_init_attr *qp_init_attr);
+ struct ib_qp_init_attr *qp_init_attr,
+ struct ib_udata *udata);
int (*modify_qp)(struct ib_qp *qp,
struct ib_qp_attr *qp_attr,
int qp_attr_mask);
@@ -762,8 +834,9 @@ struct ib_device {
int (*post_recv)(struct ib_qp *qp,
struct ib_recv_wr *recv_wr,
struct ib_recv_wr **bad_recv_wr);
- struct ib_cq * (*create_cq)(struct ib_device *device,
- int cqe);
+ struct ib_cq * (*create_cq)(struct ib_device *device, int cqe,
+ struct ib_ucontext *context,
+ struct ib_udata *udata);
int (*destroy_cq)(struct ib_cq *cq);
int (*resize_cq)(struct ib_cq *cq, int *cqe);
int (*poll_cq)(struct ib_cq *cq, int num_entries,
@@ -780,6 +853,10 @@ struct ib_device {
int num_phys_buf,
int mr_access_flags,
u64 *iova_start);
+ struct ib_mr * (*reg_user_mr)(struct ib_pd *pd,
+ struct ib_umem *region,
+ int mr_access_flags,
+ struct ib_udata *udata);
int (*query_mr)(struct ib_mr *mr,
struct ib_mr_attr *mr_attr);
int (*dereg_mr)(struct ib_mr *mr);
@@ -817,6 +894,7 @@ struct ib_device {
struct ib_mad *in_mad,
struct ib_mad *out_mad);
+ struct module *owner;
struct class_device class_dev;
struct kobject ports_parent;
struct list_head port_list;
@@ -852,6 +930,16 @@ void *ib_get_client_data(struct ib_device *device, struct ib_client *client);
void ib_set_client_data(struct ib_device *device, struct ib_client *client,
void *data);
+static inline int ib_copy_from_udata(void *dest, struct ib_udata *udata, size_t len)
+{
+ return copy_from_user(dest, udata->inbuf, len) ? -EFAULT : 0;
+}
+
+static inline int ib_copy_to_udata(struct ib_udata *udata, void *src, size_t len)
+{
+ return copy_to_user(udata->outbuf, src, len) ? -EFAULT : 0;
+}
+
int ib_register_event_handler (struct ib_event_handler *event_handler);
int ib_unregister_event_handler(struct ib_event_handler *event_handler);
void ib_dispatch_event(struct ib_event *event);
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index ee750e9456d..db9bad2b3d1 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -22,7 +22,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -161,11 +160,6 @@ static dev_link_t *avmcs_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &avmcs_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -500,6 +494,7 @@ static struct pcmcia_driver avmcs_driver = {
.name = "avm_cs",
},
.attach = avmcs_attach,
+ .event = avmcs_event,
.detach = avmcs_detach,
.id_table = avmcs_ids,
};
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
index 67c60e04a37..0e22991635e 100644
--- a/drivers/isdn/hisax/avma1_cs.c
+++ b/drivers/isdn/hisax/avma1_cs.c
@@ -21,7 +21,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -183,11 +182,6 @@ static dev_link_t *avma1cs_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &avma1cs_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -514,6 +508,7 @@ static struct pcmcia_driver avma1cs_driver = {
.name = "avma1_cs",
},
.attach = avma1cs_attach,
+ .event = avma1cs_event,
.detach = avma1cs_detach,
.id_table = avma1cs_ids,
};
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
index 9146be54704..6fc6868de0b 100644
--- a/drivers/isdn/hisax/elsa_cs.c
+++ b/drivers/isdn/hisax/elsa_cs.c
@@ -47,7 +47,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -212,11 +211,6 @@ static dev_link_t *elsa_cs_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &elsa_cs_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -521,6 +515,7 @@ static struct pcmcia_driver elsa_cs_driver = {
.name = "elsa_cs",
},
.attach = elsa_cs_attach,
+ .event = elsa_cs_event,
.detach = elsa_cs_detach,
.id_table = elsa_ids,
};
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index 058147a6957..c6b5bf7d2ac 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -47,7 +47,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -226,11 +225,6 @@ static dev_link_t *sedlbauer_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &sedlbauer_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -634,6 +628,7 @@ static struct pcmcia_driver sedlbauer_driver = {
.name = "sedlbauer_cs",
},
.attach = sedlbauer_attach,
+ .event = sedlbauer_event,
.detach = sedlbauer_detach,
.id_table = sedlbauer_ids,
};
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
index 107376ff5b9..0ddef1bf778 100644
--- a/drivers/isdn/hisax/teles_cs.c
+++ b/drivers/isdn/hisax/teles_cs.c
@@ -28,7 +28,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -193,11 +192,6 @@ static dev_link_t *teles_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &teles_cs_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -501,6 +495,7 @@ static struct pcmcia_driver teles_cs_driver = {
.name = "teles_cs",
},
.attach = teles_attach,
+ .event = teles_cs_event,
.detach = teles_detach,
.id_table = teles_ids,
};
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 6e3cf7e1345..12031c9d3f1 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -1060,6 +1060,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}
ti->private = ms;
+ ti->split_io = ms->rh.region_size;
r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client);
if (r) {
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index 50e8b865401..cd5828b5e9e 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -62,13 +62,15 @@ void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
{
unsigned long start;
+ int err;
/* wait for registers to be programmed */
start = jiffies;
while (1) {
- if (saa7146_read(dev, MC2) & 2)
- break;
- if (time_after(jiffies, start + HZ/20)) {
+ err = time_after(jiffies, start + HZ/20);
+ if (saa7146_read(dev, MC2) & 2)
+ break;
+ if (err) {
DEB_S(("timed out while waiting for registers getting programmed\n"));
return -ETIMEDOUT;
}
@@ -79,10 +81,11 @@ int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
/* wait for transfer to complete */
start = jiffies;
while (1) {
+ err = time_after(jiffies, start + HZ/4);
if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
break;
saa7146_read(dev, MC2);
- if (time_after(jiffies, start + HZ/4)) {
+ if (err) {
DEB_S(("timed out while waiting for transfer completion\n"));
return -ETIMEDOUT;
}
@@ -512,7 +515,7 @@ int saa7146_register_extension(struct saa7146_extension* ext)
ext->driver.remove = saa7146_remove_one;
printk("saa7146: register extension '%s'.\n",ext->name);
- return pci_module_init(&ext->driver);
+ return pci_register_driver(&ext->driver);
}
int saa7146_unregister_extension(struct saa7146_extension* ext)
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index 01387f883cd..3f0ec6be03a 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -40,6 +40,10 @@ comment "Supported BT878 Adapters"
depends on DVB_CORE && PCI
source "drivers/media/dvb/bt8xx/Kconfig"
+comment "Supported Pluto2 Adapters"
+ depends on DVB_CORE && PCI
+source "drivers/media/dvb/pluto2/Kconfig"
+
comment "Supported DVB Frontends"
depends on DVB_CORE
source "drivers/media/dvb/frontends/Kconfig"
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile
index 3c6ff161910..a7ad0841e6f 100644
--- a/drivers/media/dvb/Makefile
+++ b/drivers/media/dvb/Makefile
@@ -2,4 +2,4 @@
# Makefile for the kernel multimedia device drivers.
#
-obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/
+obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index fafd0ab3a28..d7417eac2ab 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -35,17 +35,3 @@ config DVB_B2C2_FLEXCOP_DEBUG
help
Say Y if you want to enable the module option to control debug messages
of all B2C2 FlexCop drivers.
-
-config DVB_B2C2_SKYSTAR
- tristate "B2C2/Technisat Air/Sky/CableStar 2 PCI"
- depends on DVB_CORE && PCI
- select DVB_STV0299
- select DVB_MT352
- select DVB_MT312
- select DVB_NXT2002
- help
- Support for the Skystar2 PCI DVB card by Technisat, which
- is equipped with the FlexCopII chipset by B2C2, and
- for the B2C2/BBTI Air2PC-ATSC card.
-
- Say Y if you own such a device and want to use it.
diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile
index 7703812af34..1a1c3bca55f 100644
--- a/drivers/media/dvb/b2c2/Makefile
+++ b/drivers/media/dvb/b2c2/Makefile
@@ -9,6 +9,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
-obj-$(CONFIG_DVB_B2C2_SKYSTAR) += skystar2.o
-
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h
index 773d158032d..a94912ac187 100644
--- a/drivers/media/dvb/b2c2/flexcop-common.h
+++ b/drivers/media/dvb/b2c2/flexcop-common.h
@@ -108,6 +108,8 @@ void flexcop_device_kfree(struct flexcop_device*);
int flexcop_device_initialize(struct flexcop_device*);
void flexcop_device_exit(struct flexcop_device *fc);
+void flexcop_reset_block_300(struct flexcop_device *fc);
+
/* from flexcop-dma.c */
int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size);
void flexcop_dma_free(struct flexcop_dma *dma);
@@ -115,7 +117,8 @@ void flexcop_dma_free(struct flexcop_dma *dma);
int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
-int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index);
+int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx);
+int flexcop_dma_xfer_control(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index, int onoff);
int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles);
int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets);
@@ -151,6 +154,7 @@ int flexcop_sram_init(struct flexcop_device *fc);
/* from flexcop-misc.c */
void flexcop_determine_revision(struct flexcop_device *fc);
void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const char *suffix);
+void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num);
/* from flexcop-hw-filter.c */
int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff);
diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c
index 8d270607536..cf4ed1df608 100644
--- a/drivers/media/dvb/b2c2/flexcop-dma.c
+++ b/drivers/media/dvb/b2c2/flexcop-dma.c
@@ -37,22 +37,90 @@ void flexcop_dma_free(struct flexcop_dma *dma)
}
EXPORT_SYMBOL(flexcop_dma_free);
-int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+int flexcop_dma_config(struct flexcop_device *fc,
+ struct flexcop_dma *dma,
+ flexcop_dma_index_t dma_idx)
{
- flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+ flexcop_ibi_value v0x0,v0x4,v0xc;
+ v0x0.raw = v0x4.raw = v0xc.raw = 0;
- if (no & FC_DMA_1)
- v.ctrl_208.DMA1_Timer_Enable_sig = onoff;
+ v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2;
+ v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2;
+ v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;
- if (no & FC_DMA_2)
- v.ctrl_208.DMA2_Timer_Enable_sig = onoff;
+ if ((dma_idx & FC_DMA_1) == dma_idx) {
+ fc->write_ibi_reg(fc,dma1_000,v0x0);
+ fc->write_ibi_reg(fc,dma1_004,v0x4);
+ fc->write_ibi_reg(fc,dma1_00c,v0xc);
+ } else if ((dma_idx & FC_DMA_2) == dma_idx) {
+ fc->write_ibi_reg(fc,dma2_010,v0x0);
+ fc->write_ibi_reg(fc,dma2_014,v0x4);
+ fc->write_ibi_reg(fc,dma2_01c,v0xc);
+ } else {
+ err("either DMA1 or DMA2 can be configured at the within one flexcop_dma_config call.");
+ return -EINVAL;
+ }
- fc->write_ibi_reg(fc,ctrl_208,v);
return 0;
}
-EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
+EXPORT_SYMBOL(flexcop_dma_config);
+
+/* start the DMA transfers, but not the DMA IRQs */
+int flexcop_dma_xfer_control(struct flexcop_device *fc,
+ flexcop_dma_index_t dma_idx,
+ flexcop_dma_addr_index_t index,
+ int onoff)
+{
+ flexcop_ibi_value v0x0,v0xc;
+ flexcop_ibi_register r0x0,r0xc;
+
+ if ((dma_idx & FC_DMA_1) == dma_idx) {
+ r0x0 = dma1_000;
+ r0xc = dma1_00c;
+ } else if ((dma_idx & FC_DMA_2) == dma_idx) {
+ r0x0 = dma2_010;
+ r0xc = dma2_01c;
+ } else {
+ err("either transfer DMA1 or DMA2 can be started within one flexcop_dma_xfer_control call.");
+ return -EINVAL;
+ }
+
+ v0x0 = fc->read_ibi_reg(fc,r0x0);
+ v0xc = fc->read_ibi_reg(fc,r0xc);
+
+ deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
+ deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);
+
+ if (index & FC_DMA_SUBADDR_0)
+ v0x0.dma_0x0.dma_0start = onoff;
+
+ if (index & FC_DMA_SUBADDR_1)
+ v0xc.dma_0xc.dma_1start = onoff;
+
+ fc->write_ibi_reg(fc,r0x0,v0x0);
+ fc->write_ibi_reg(fc,r0xc,v0xc);
+
+ deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
+ deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);
+ return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_xfer_control);
+
+static int flexcop_dma_remap(struct flexcop_device *fc,
+ flexcop_dma_index_t dma_idx,
+ int onoff)
+{
+ flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c;
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+ deb_info("%s\n",__FUNCTION__);
+ v.dma_0xc.remap_enable = onoff;
+ fc->write_ibi_reg(fc,r,v);
+ return 0;
+}
-int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+int flexcop_dma_control_size_irq(struct flexcop_device *fc,
+ flexcop_dma_index_t no,
+ int onoff)
{
flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
@@ -67,75 +135,64 @@ int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t
}
EXPORT_SYMBOL(flexcop_dma_control_size_irq);
-int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+int flexcop_dma_control_timer_irq(struct flexcop_device *fc,
+ flexcop_dma_index_t no,
+ int onoff)
{
flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
if (no & FC_DMA_1)
- v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff;
+ v.ctrl_208.DMA1_Timer_Enable_sig = onoff;
if (no & FC_DMA_2)
- v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff;
+ v.ctrl_208.DMA2_Timer_Enable_sig = onoff;
fc->write_ibi_reg(fc,ctrl_208,v);
return 0;
}
-EXPORT_SYMBOL(flexcop_dma_control_packet_irq);
+EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
-int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index)
+/* 1 cycles = 1.97 msec */
+int flexcop_dma_config_timer(struct flexcop_device *fc,
+ flexcop_dma_index_t dma_idx,
+ u8 cycles)
{
+ flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
- flexcop_ibi_value v0x0,v0x4,v0xc;
- v0x0.raw = v0x4.raw = v0xc.raw = 0;
-
- v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2;
- v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2;
- v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;
-
- if (index & FC_DMA_SUBADDR_0)
- v0x0.dma_0x0.dma_0start = 1;
-
- if (index & FC_DMA_SUBADDR_1)
- v0xc.dma_0xc.dma_1start = 1;
-
- if (dma_idx & FC_DMA_1) {
- fc->write_ibi_reg(fc,dma1_000,v0x0);
- fc->write_ibi_reg(fc,dma1_004,v0x4);
- fc->write_ibi_reg(fc,dma1_00c,v0xc);
- } else { /* (dma_idx & FC_DMA_2) */
- fc->write_ibi_reg(fc,dma2_010,v0x0);
- fc->write_ibi_reg(fc,dma2_014,v0x4);
- fc->write_ibi_reg(fc,dma2_01c,v0xc);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(flexcop_dma_config);
+ flexcop_dma_remap(fc,dma_idx,0);
-static int flexcop_dma_remap(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, int onoff)
-{
- flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c;
- flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
- v.dma_0xc.remap_enable = onoff;
+ deb_info("%s\n",__FUNCTION__);
+ v.dma_0x4_write.dmatimer = cycles;
fc->write_ibi_reg(fc,r,v);
return 0;
}
+EXPORT_SYMBOL(flexcop_dma_config_timer);
-/* 1 cycles = 1.97 msec */
-int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles)
+/* packet IRQ does not exist in FCII or FCIIb - according to data book and tests */
+int flexcop_dma_control_packet_irq(struct flexcop_device *fc,
+ flexcop_dma_index_t no,
+ int onoff)
{
- flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
- flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
- flexcop_dma_remap(fc,dma_idx,0);
+ deb_rdump("reg: %03x: %x\n",ctrl_208,v.raw);
+ if (no & FC_DMA_1)
+ v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff;
+
+ if (no & FC_DMA_2)
+ v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff;
+
+ fc->write_ibi_reg(fc,ctrl_208,v);
+ deb_rdump("reg: %03x: %x\n",ctrl_208,v.raw);
- v.dma_0x4_write.dmatimer = cycles >> 1;
- fc->write_ibi_reg(fc,r,v);
return 0;
}
-EXPORT_SYMBOL(flexcop_dma_config_timer);
+EXPORT_SYMBOL(flexcop_dma_control_packet_irq);
-int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets)
+int flexcop_dma_config_packet_count(struct flexcop_device *fc,
+ flexcop_dma_index_t dma_idx,
+ u8 packets)
{
flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c
index 2baf43d3ce8..75cf237196e 100644
--- a/drivers/media/dvb/b2c2/flexcop-hw-filter.c
+++ b/drivers/media/dvb/b2c2/flexcop-hw-filter.c
@@ -10,6 +10,8 @@
static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff)
{
flexcop_set_ibi_value(ctrl_208,Rcv_Data_sig,onoff);
+
+ deb_ts("rcv_data is now: '%s'\n",onoff ? "on" : "off");
}
void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff)
@@ -151,7 +153,7 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d
{
int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32;
- fc->feedcount += onoff ? 1 : -1;
+ fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */
if (dvbdmxfeed->index >= max_pid_filter)
fc->extra_feedcount += onoff ? 1 : -1;
@@ -178,8 +180,14 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d
/* if it was the first or last feed request change the stream-status */
if (fc->feedcount == onoff) {
flexcop_rcv_data_ctrl(fc,onoff);
- if (fc->stream_control)
+ if (fc->stream_control) /* device specific stream control */
fc->stream_control(fc,onoff);
+
+ /* feeding stopped -> reset the flexcop filter*/
+ if (onoff == 0) {
+ flexcop_reset_block_300(fc);
+ flexcop_hw_filter_init(fc);
+ }
}
return 0;
diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c
index 23082545651..3a08d38b318 100644
--- a/drivers/media/dvb/b2c2/flexcop-misc.c
+++ b/drivers/media/dvb/b2c2/flexcop-misc.c
@@ -65,3 +65,15 @@ void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const
flexcop_device_names[fc->dev_type],flexcop_bus_names[fc->bus_type],
flexcop_revision_names[fc->rev],suffix);
}
+
+void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num)
+{
+ flexcop_ibi_value v;
+ int i;
+ for (i = 0; i < num; i++) {
+ v = fc->read_ibi_reg(fc,reg+4*i);
+ deb_rdump("0x%03x: %08x, ",reg+4*i, v.raw);
+ }
+ deb_rdump("\n");
+}
+EXPORT_SYMBOL(flexcop_dump_reg);
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c
index ed717c0073d..2f76eb3fea4 100644
--- a/drivers/media/dvb/b2c2/flexcop-pci.c
+++ b/drivers/media/dvb/b2c2/flexcop-pci.c
@@ -13,6 +13,10 @@ static int enable_pid_filtering = 1;
module_param(enable_pid_filtering, int, 0444);
MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1");
+static int irq_chk_intv;
+module_param(irq_chk_intv, int, 0644);
+MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently just debugging).");
+
#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
#define dprintk(level,args...) \
do { if ((debug & level)) printk(args); } while (0)
@@ -26,6 +30,7 @@ MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported
#define deb_reg(args...) dprintk(0x02,args)
#define deb_ts(args...) dprintk(0x04,args)
#define deb_irq(args...) dprintk(0x08,args)
+#define deb_chk(args...) dprintk(0x10,args)
static int debug = 0;
module_param(debug, int, 0644);
@@ -56,6 +61,10 @@ struct flexcop_pci {
spinlock_t irq_lock;
+ unsigned long last_irq;
+
+ struct work_struct irq_check_work;
+
struct flexcop_device *fc_dev;
};
@@ -88,18 +97,55 @@ static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_regi
return 0;
}
+static void flexcop_pci_irq_check_work(void *data)
+{
+ struct flexcop_pci *fc_pci = data;
+ struct flexcop_device *fc = fc_pci->fc_dev;
+
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714);
+
+ flexcop_dump_reg(fc_pci->fc_dev,dma1_000,4);
+
+ if (v.sram_dest_reg_714.net_ovflow_error)
+ deb_chk("sram net_ovflow_error\n");
+ if (v.sram_dest_reg_714.media_ovflow_error)
+ deb_chk("sram media_ovflow_error\n");
+ if (v.sram_dest_reg_714.cai_ovflow_error)
+ deb_chk("sram cai_ovflow_error\n");
+ if (v.sram_dest_reg_714.cai_ovflow_error)
+ deb_chk("sram cai_ovflow_error\n");
+
+ schedule_delayed_work(&fc_pci->irq_check_work,
+ msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
+}
+
/* When PID filtering is turned on, we use the timer IRQ, because small amounts
* of data need to be passed to the user space instantly as well. When PID
* filtering is turned off, we use the page-change-IRQ */
-static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t flexcop_pci_isr(int irq, void *dev_id, struct pt_regs *regs)
{
struct flexcop_pci *fc_pci = dev_id;
struct flexcop_device *fc = fc_pci->fc_dev;
- flexcop_ibi_value v = fc->read_ibi_reg(fc,irq_20c);
+ flexcop_ibi_value v;
irqreturn_t ret = IRQ_HANDLED;
spin_lock_irq(&fc_pci->irq_lock);
+ v = fc->read_ibi_reg(fc,irq_20c);
+
+ /* errors */
+ if (v.irq_20c.Data_receiver_error)
+ deb_chk("data receiver error\n");
+ if (v.irq_20c.Continuity_error_flag)
+ deb_chk("Contunuity error flag is set\n");
+ if (v.irq_20c.LLC_SNAP_FLAG_set)
+ deb_chk("LLC_SNAP_FLAG_set is set\n");
+ if (v.irq_20c.Transport_Error)
+ deb_chk("Transport error\n");
+
+ if ((fc_pci->count % 1000) == 0)
+ deb_chk("%d valid irq took place so far\n",fc_pci->count);
+
if (v.irq_20c.DMA1_IRQ_Status == 1) {
if (fc_pci->active_dma1_addr == 0)
flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr0,fc_pci->dma[0].size / 188);
@@ -115,8 +161,9 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs)
fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2;
u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0;
- deb_irq("irq: %08x cur_addr: %08x: cur_pos: %08x, last_cur_pos: %08x ",
- v.raw,cur_addr,cur_pos,fc_pci->last_dma1_cur_pos);
+ deb_irq("%u irq: %08x cur_addr: %08x: cur_pos: %08x, last_cur_pos: %08x ",
+ jiffies_to_usecs(jiffies - fc_pci->last_irq),v.raw,cur_addr,cur_pos,fc_pci->last_dma1_cur_pos);
+ fc_pci->last_irq = jiffies;
/* buffer end was reached, restarted from the beginning
* pass the data from last_cur_pos to the buffer end to the demux
@@ -127,7 +174,6 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs)
fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos,
(fc_pci->dma[0].size*2) - fc_pci->last_dma1_cur_pos);
fc_pci->last_dma1_cur_pos = 0;
- fc_pci->count = 0;
}
if (cur_pos > fc_pci->last_dma1_cur_pos) {
@@ -139,16 +185,14 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs)
deb_irq("\n");
fc_pci->last_dma1_cur_pos = cur_pos;
- } else
+ fc_pci->count++;
+ } else {
+ deb_irq("isr for flexcop called, apparently without reason (%08x)\n",v.raw);
ret = IRQ_NONE;
+ }
spin_unlock_irq(&fc_pci->irq_lock);
-/* packet count would be ideal for hw filtering, but it isn't working. Either
- * the data book is wrong, or I'm unable to read it correctly */
-
-/* if (v.irq_20c.DMA1_Size_IRQ_Status == 1) { packet counter */
-
return ret;
}
@@ -156,30 +200,35 @@ static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff)
{
struct flexcop_pci *fc_pci = fc->bus_specific;
if (onoff) {
- flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1);
- flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1);
- flexcop_dma_config_timer(fc,FC_DMA_1,1);
+ flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1);
+ flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2);
- if (fc_pci->fc_dev->pid_filtering) {
- fc_pci->last_dma1_cur_pos = 0;
- flexcop_dma_control_timer_irq(fc,FC_DMA_1,1);
- } else {
- fc_pci->active_dma1_addr = 0;
- flexcop_dma_control_size_irq(fc,FC_DMA_1,1);
- }
+ flexcop_dma_config_timer(fc,FC_DMA_1,0);
-/* flexcop_dma_config_packet_count(fc,FC_DMA_1,0xc0);
- flexcop_dma_control_packet_irq(fc,FC_DMA_1,1); */
+ flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,1);
+ deb_irq("DMA xfer enabled\n");
- deb_irq("irqs enabled\n");
+ fc_pci->last_dma1_cur_pos = 0;
+ flexcop_dma_control_timer_irq(fc,FC_DMA_1,1);
+ deb_irq("IRQ enabled\n");
+
+// fc_pci->active_dma1_addr = 0;
+// flexcop_dma_control_size_irq(fc,FC_DMA_1,1);
+
+ if (irq_chk_intv > 0)
+ schedule_delayed_work(&fc_pci->irq_check_work,
+ msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
} else {
- if (fc_pci->fc_dev->pid_filtering)
- flexcop_dma_control_timer_irq(fc,FC_DMA_1,0);
- else
- flexcop_dma_control_size_irq(fc,FC_DMA_1,0);
+ if (irq_chk_intv > 0)
+ cancel_delayed_work(&fc_pci->irq_check_work);
+
+ flexcop_dma_control_timer_irq(fc,FC_DMA_1,0);
+ deb_irq("IRQ disabled\n");
-// flexcop_dma_control_packet_irq(fc,FC_DMA_1,0);
- deb_irq("irqs disabled\n");
+// flexcop_dma_control_size_irq(fc,FC_DMA_1,0);
+
+ flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,0);
+ deb_irq("DMA xfer disabled\n");
}
return 0;
@@ -198,6 +247,7 @@ static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci)
flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
fc_pci->init_state |= FC_PCI_DMA_INIT;
+
goto success;
dma1_free:
flexcop_dma_free(&fc_pci->dma[0]);
@@ -244,7 +294,7 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci)
pci_set_drvdata(fc_pci->pdev, fc_pci);
- if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_irq,
+ if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr,
SA_SHIRQ, DRIVER_NAME, fc_pci)) != 0)
goto err_pci_iounmap;
@@ -324,6 +374,8 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
if ((ret = flexcop_pci_dma_init(fc_pci)) != 0)
goto err_fc_exit;
+ INIT_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work, fc_pci);
+
goto success;
err_fc_exit:
flexcop_device_exit(fc);
@@ -350,17 +402,17 @@ static void flexcop_pci_remove(struct pci_dev *pdev)
static struct pci_device_id flexcop_pci_tbl[] = {
{ PCI_DEVICE(0x13d0, 0x2103) },
-/* { PCI_DEVICE(0x13d0, 0x2200) }, PCI FlexCopIII ? */
+/* { PCI_DEVICE(0x13d0, 0x2200) }, ? */
{ },
};
MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl);
static struct pci_driver flexcop_pci_driver = {
- .name = "Technisat/B2C2 FlexCop II/IIb/III PCI",
+ .name = "b2c2_flexcop_pci",
.id_table = flexcop_pci_tbl,
- .probe = flexcop_pci_probe,
- .remove = flexcop_pci_remove,
+ .probe = flexcop_pci_probe,
+ .remove = flexcop_pci_remove,
};
static int __init flexcop_pci_module_init(void)
diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h
index 75b50f21afe..4ae1eb5bfe9 100644
--- a/drivers/media/dvb/b2c2/flexcop-reg.h
+++ b/drivers/media/dvb/b2c2/flexcop-reg.h
@@ -36,555 +36,21 @@ typedef enum {
extern const char *flexcop_device_names[];
/* FlexCop IBI Registers */
+#if defined(__LITTLE_ENDIAN)
+ #include "flexcop_ibi_value_le.h"
+#elif defined(__BIG_ENDIAN)
+ #include "flexcop_ibi_value_be.h"
+#else
+ #error no endian defined
+#endif
-/* flexcop_ibi_reg - a huge union representing the register structure */
-typedef union {
- u32 raw;
-
-/* DMA 0x000 to 0x01c
- * DMA1 0x000 to 0x00c
- * DMA2 0x010 to 0x01c
- */
- struct {
- u32 dma_0start : 1; /* set: data will be delivered to dma1_address0 */
- u32 dma_0No_update : 1; /* set: dma1_cur_address will be updated, unset: no update */
- u32 dma_address0 :30; /* physical/virtual host memory address0 DMA */
- } dma_0x0;
-
- struct {
- u32 DMA_maxpackets : 8; /* (remapped) PCI DMA1 Packet Count Interrupt. This variable
- is able to be read and written while bit(1) of register
- 0x00c (remap_enable) is set. This variable represents
- the number of packets that will be transmitted to the PCI
- host using PCI DMA1 before an interrupt to the PCI is
- asserted. This functionality may be enabled using bit(20)
- of register 0x208. N=0 disables the IRQ. */
- u32 dma_addr_size :24; /* size of memory buffer in DWORDs (bytesize / 4) for DMA */
- } dma_0x4_remap;
-
- struct {
- u32 dma1timer : 7; /* reading PCI DMA1 timer ... when remap_enable is 0 */
- u32 unused : 1;
- u32 dma_addr_size :24;
- } dma_0x4_read;
-
- struct {
- u32 unused : 1;
- u32 dmatimer : 7; /* writing PCI DMA1 timer ... when remap_enable is 0 */
- u32 dma_addr_size :24;
- } dma_0x4_write;
-
- struct {
- u32 unused : 2;
- u32 dma_cur_addr :30; /* current physical host memory address pointer for DMA */
- } dma_0x8;
-
- struct {
- u32 dma_1start : 1; /* set: data will be delivered to dma_address1, when dma_address0 is full */
- u32 remap_enable : 1; /* remap enable for 0x0x4(7:0) */
- u32 dma_address1 :30; /* Physical/virtual address 1 on DMA */
- } dma_0xc;
-
-/* Two-wire Serial Master and Clock 0x100-0x110 */
- struct {
-// u32 slave_transmitter : 1; /* ???*/
- u32 chipaddr : 7; /* two-line serial address of the target slave */
- u32 reserved1 : 1;
- u32 baseaddr : 8; /* address of the location of the read/write operation */
- u32 data1_reg : 8; /* first byte in two-line serial read/write operation */
- u32 working_start : 1; /* when doing a write operation this indicator is 0 when ready
- * set to 1 when doing a write operation */
- u32 twoWS_rw : 1; /* read/write indicator (1 = read, 0 write) */
- u32 total_bytes : 2; /* number of data bytes in each two-line serial transaction (0 = 1 byte, 11 = 4byte)*/
- u32 twoWS_port_reg : 2; /* port selection: 01 - Front End/Demod, 10 - EEPROM, 11 - Tuner */
- u32 no_base_addr_ack_error : 1; /* writing: write-req: frame is produced w/o baseaddr, read-req: read-cycles w/o
- * preceding address assignment write frame
- * ACK_ERROR = 1 when no ACK from slave in the last transaction */
- u32 st_done : 1; /* indicator for transaction is done */
- } tw_sm_c_100;
-
- struct {
- u32 data2_reg : 8; /* 2nd data byte */
- u32 data3_reg : 8; /* 3rd data byte */
- u32 data4_reg : 8; /* 4th data byte */
- u32 exlicit_stops : 1; /* when set, transactions are produced w/o trailing STOP flag, then send isolated STOP flags */
- u32 force_stop : 1; /* isolated stop flag */
- u32 unused : 6;
- } tw_sm_c_104;
-
-/* Clock. The register allows the FCIII to convert an incoming Master clock
- * (MCLK) signal into a lower frequency clock through the use of a LowCounter
- * (TLO) and a High- Counter (THI). The time counts for THI and TLO are
- * measured in MCLK; each count represents 4 MCLK input clock cycles.
- *
- * The default output for port #1 is set for Front End Demod communication. (0x108)
- * The default output for port #2 is set for EEPROM communication. (0x10c)
- * The default output for port #3 is set for Tuner communication. (0x110)
- */
- struct {
- u32 thi1 : 6; /* Thi for port #1 (def: 100110b; 38) */
- u32 reserved1 : 2;
- u32 tlo1 : 5; /* Tlo for port #1 (def: 11100b; 28) */
- u32 reserved2 :19;
- } tw_sm_c_108;
-
- struct {
- u32 thi1 : 6; /* Thi for port #2 (def: 111001b; 57) */
- u32 reserved1 : 2;
- u32 tlo1 : 5; /* Tlo for port #2 (def: 11100b; 28) */
- u32 reserved2 :19;
- } tw_sm_c_10c;
-
- struct {
- u32 thi1 : 6; /* Thi for port #3 (def: 111001b; 57) */
- u32 reserved1 : 2;
- u32 tlo1 : 5; /* Tlo for port #3 (def: 11100b; 28) */
- u32 reserved2 :19;
- } tw_sm_c_110;
-
-/* LNB Switch Frequency 0x200
- * Clock that creates the LNB switch tone. The default is set to have a fixed
- * low output (not oscillating) to the LNB_CTL line.
- */
- struct {
- u32 LNB_CTLHighCount_sig :15; /* It is the number of pre-scaled clock cycles that will be low. */
- u32 LNB_CTLLowCount_sig :15; /* For example, to obtain a 22KHz output given a 45 Mhz Master
- Clock signal (MCLK), set PreScalar=01 and LowCounter value to 0x1ff. */
- u32 LNB_CTLPrescaler_sig : 2; /* pre-scaler divides MCLK: 00 (no division), 01 by 2, 10 by 4, 11 by 12 */
- } lnb_switch_freq_200;
-
-/* ACPI, Peripheral Reset, LNB Polarity
- * ACPI power conservation mode, LNB polarity selection (low or high voltage),
- * and peripheral reset.
- */
- struct {
- u32 ACPI1_sig : 1; /* turn of the power of tuner and LNB, not implemented in FCIII */
- u32 ACPI3_sig : 1; /* turn of power of the complete satelite receiver board (except FCIII) */
- u32 LNB_L_H_sig : 1; /* low or high voltage for LNB. (0 = low, 1 = high) */
- u32 Per_reset_sig : 1; /* misc. init reset (default: 1), to reset set to low and back to high */
- u32 reserved :20;
- u32 Rev_N_sig_revision_hi : 4;/* 0xc in case of FCIII */
- u32 Rev_N_sig_reserved1 : 2;
- u32 Rev_N_sig_caps : 1; /* if 1, FCIII has 32 PID- and MAC-filters and is capable of IP multicast */
- u32 Rev_N_sig_reserved2 : 1;
- } misc_204;
-
-/* Control and Status 0x208 to 0x21c */
-/* Gross enable and disable control */
- struct {
- u32 Stream1_filter_sig : 1; /* Stream1 PID filtering */
- u32 Stream2_filter_sig : 1; /* Stream2 PID filtering */
- u32 PCR_filter_sig : 1; /* PCR PID filter */
- u32 PMT_filter_sig : 1; /* PMT PID filter */
-
- u32 EMM_filter_sig : 1; /* EMM PID filter */
- u32 ECM_filter_sig : 1; /* ECM PID filter */
- u32 Null_filter_sig : 1; /* Filters null packets, PID=0x1fff. */
- u32 Mask_filter_sig : 1; /* mask PID filter */
-
- u32 WAN_Enable_sig : 1; /* WAN output line through V8 memory space is activated. */
- u32 WAN_CA_Enable_sig : 1; /* not in FCIII */
- u32 CA_Enable_sig : 1; /* not in FCIII */
- u32 SMC_Enable_sig : 1; /* CI stream data (CAI) goes directly to the smart card intf (opposed IBI 0x600 or SC-cmd buf). */
-
- u32 Per_CA_Enable_sig : 1; /* not in FCIII */
- u32 Multi2_Enable_sig : 1; /* ? */
- u32 MAC_filter_Mode_sig : 1; /* (MAC_filter_enable) Globally enables MAC filters for Net PID filteres. */
- u32 Rcv_Data_sig : 1; /* PID filtering module enable. When this bit is a one, the PID filter will
- examine and process packets according to all other (individual) PID
- filtering controls. If it a zero, no packet processing of any kind will
- take place. All data from the tuner will be thrown away. */
-
- u32 DMA1_IRQ_Enable_sig : 1; /* When set, a DWORD counter is enabled on PCI DMA1 that asserts the PCI
- * interrupt after the specified count for filling the buffer. */
- u32 DMA1_Timer_Enable_sig : 1; /* When set, a timer is enabled on PCI DMA1 that asserts the PCI interrupt
- after a specified amount of time. */
- u32 DMA2_IRQ_Enable_sig : 1; /* same as DMA1_IRQ_Enable_sig but for DMA2 */
- u32 DMA2_Timer_Enable_sig : 1; /* same as DMA1_Timer_Enable_sig but for DMA2 */
-
- u32 DMA1_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA1 that asserts the PCI interrupt. */
- u32 DMA2_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA2 that asserts the PCI interrupt. */
- u32 Mailbox_from_V8_Enable_sig: 1; /* When set, writes to the mailbox register produce an interrupt to the
- PCI host to indicate that mailbox data is available. */
-
- u32 unused : 9;
- } ctrl_208;
-
-/* General status. When a PCI interrupt occurs, this register is read to
- * discover the reason for the interrupt.
- */
- struct {
- u32 DMA1_IRQ_Status : 1; /* When set(1) the DMA1 counter had generated an IRQ. Read Only. */
- u32 DMA1_Timer_Status : 1; /* When set(1) the DMA1 timer had generated an IRQ. Read Only. */
- u32 DMA2_IRQ_Status : 1; /* When set(1) the DMA2 counter had generated an IRQ. Read Only. */
- u32 DMA2_Timer_Status : 1; /* When set(1) the DMA2 timer had generated an IRQ. Read Only. */
- u32 DMA1_Size_IRQ_Status : 1; /* (Read only). This register is read after an interrupt to */
- u32 DMA2_Size_IRQ_Status : 1; /* find out why we had an IRQ. Reading this register will clear this bit. Packet count*/
- u32 Mailbox_from_V8_Status_sig: 1; /* Same as above. Reading this register will clear this bit. */
- u32 Data_receiver_error : 1; /* 1 indicate an error in the receiver Front End (Tuner module) */
- u32 Continuity_error_flag : 1; /* 1 indicates a continuity error in the TS stream. */
- u32 LLC_SNAP_FLAG_set : 1; /* 1 indicates that the LCC_SNAP_FLAG was set. */
- u32 Transport_Error : 1; /* When set indicates that an unexpected packet was received. */
- u32 reserved :21;
- } irq_20c;
-
-
-/* Software reset register */
- struct {
- u32 reset_blocks : 8; /* Enabled when Block_reset_enable = 0xB2 and 0x208 bits 15:8 = 0x00.
- Each bit location represents a 0x100 block of registers. Writing
- a one in a bit location resets that block of registers and the logic
- that it controls. */
- u32 Block_reset_enable : 8; /* This variable is set to 0xB2 when the register is written. */
- u32 Special_controls :16; /* Asserts Reset_V8 => 0xC258; Turns on pci encryption => 0xC25A;
- Turns off pci encryption => 0xC259 Note: pci_encryption default
- at power-up is ON. */
- } sw_reset_210;
-
- struct {
- u32 vuart_oe_sig : 1; /* When clear, the V8 processor has sole control of the serial UART
- (RS-232 Smart Card interface). When set, the IBI interface
- defined by register 0x600 controls the serial UART. */
- u32 v2WS_oe_sig : 1; /* When clear, the V8 processor has direct control of the Two-line
- Serial Master EEPROM target. When set, the Two-line Serial Master
- EEPROM target interface is controlled by IBI register 0x100. */
- u32 halt_V8_sig : 1; /* When set, contiguous wait states are applied to the V8-space
- bus masters. Once this signal is cleared, normal V8-space
- operations resume. */
- u32 section_pkg_enable_sig: 1; /* When set, this signal enables the front end translation circuitry
- to process section packed transport streams. */
- u32 s2p_sel_sig : 1; /* Serial to parallel conversion. When set, polarized transport data
- within the FlexCop3 front end circuitry is converted from a serial
- stream into parallel data before downstream processing otherwise
- interprets the data. */
- u32 unused1 : 3;
- u32 polarity_PS_CLK_sig: 1; /* This signal is used to invert the input polarity of the tranport
- stream CLOCK signal before any processing occurs on the transport
- stream within FlexCop3. */
- u32 polarity_PS_VALID_sig: 1; /* This signal is used to invert the input polarity of the tranport
- stream VALID signal before any processing occurs on the transport
- stream within FlexCop3. */
- u32 polarity_PS_SYNC_sig: 1; /* This signal is used to invert the input polarity of the tranport
- stream SYNC signal before any processing occurs on the transport
- stream within FlexCop3. */
- u32 polarity_PS_ERR_sig: 1; /* This signal is used to invert the input polarity of the tranport
- stream ERROR signal before any processing occurs on the transport
- stream within FlexCop3. */
- u32 unused2 :20;
- } misc_214;
-
-/* Mailbox from V8 to host */
- struct {
- u32 Mailbox_from_V8 :32; /* When this register is written by either the V8 processor or by an
- end host, an interrupt is generated to the PCI host to indicate
- that mailbox data is available. Reading register 20c will clear
- the IRQ. */
- } mbox_v8_to_host_218;
-
-/* Mailbox from host to v8 Mailbox_to_V8
- * Mailbox_to_V8 mailbox storage register
- * used to send messages from PCI to V8. Writing to this register will send an
- * IRQ to the V8. Then it can read the data from here. Reading this register
- * will clear the IRQ. If the V8 is halted and bit 31 of this register is set,
- * then this register is used instead as a direct interface to access the
- * V8space memory.
- */
- struct {
- u32 sysramaccess_data : 8; /* Data byte written or read from the specified address in V8 SysRAM. */
- u32 sysramaccess_addr :15; /* 15 bit address used to access V8 Sys-RAM. */
- u32 unused : 7;
- u32 sysramaccess_write: 1; /* Write flag used to latch data into the V8 SysRAM. */
- u32 sysramaccess_busmuster: 1; /* Setting this bit when the V8 is halted at 0x214 Bit(2) allows
- this IBI register interface to directly drive the V8-space memory. */
- } mbox_host_to_v8_21c;
-
-
-/* PIDs, Translation Bit, SMC Filter Select 0x300 to 0x31c */
- struct {
- u32 Stream1_PID :13; /* Primary use is receiving Net data, so these 13 bits normally
- hold the PID value for the desired network stream. */
- u32 Stream1_trans : 1; /* When set, Net translation will take place for Net data ferried in TS packets. */
- u32 MAC_Multicast_filter : 1; /* When clear, multicast MAC filtering is not allowed for Stream1 and PID_n filters. */
- u32 debug_flag_pid_saved : 1;
- u32 Stream2_PID :13; /* 13 bits for Stream 2 PID filter value. General use. */
- u32 Stream2_trans : 1; /* When set Tables/CAI translation will take place for the data ferried in
- Stream2_PID TS packets. */
- u32 debug_flag_write_status00 : 1;
- u32 debug_fifo_problem : 1;
- } pid_filter_300;
-
- struct {
- u32 PCR_PID :13; /* PCR stream PID filter value. Primary use is Program Clock Reference stream filtering. */
- u32 PCR_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
- u32 debug_overrun3 : 1;
- u32 debug_overrun2 : 1;
- u32 PMT_PID :13; /* stream PID filter value. Primary use is Program Management Table segment filtering. */
- u32 PMT_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
- u32 reserved : 2;
- } pid_filter_304;
-
- struct {
- u32 EMM_PID :13; /* EMM PID filter value. Primary use is Entitlement Management Messaging for
- conditional access-related data. */
- u32 EMM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
- u32 EMM_filter_4 : 1; /* When set will pass only EMM data possessing the same ID code as the
- first four bytes (32 bits) of the end-user s 6-byte Smart Card ID number Select */
- u32 EMM_filter_6 : 1; /* When set will pass only EMM data possessing the same 6-byte code as the end-users
- complete 6-byte Smart Card ID number. */
- u32 ECM_PID :13; /* ECM PID filter value. Primary use is Entitlement Control Messaging for conditional
- access-related data. */
- u32 ECM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
- u32 reserved : 2;
- } pid_filter_308;
-
- struct {
- u32 Group_PID :13; /* PID value for group filtering. */
- u32 Group_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
- u32 unused1 : 2;
- u32 Group_mask :13; /* Mask value used in logical "and" equation that defines group filtering */
- u32 unused2 : 3;
- } pid_filter_30c_ext_ind_0_7;
-
- struct {
- u32 net_master_read :17;
- u32 unused :15;
- } pid_filter_30c_ext_ind_1;
-
- struct {
- u32 net_master_write :17;
- u32 unused :15;
- } pid_filter_30c_ext_ind_2;
-
- struct {
- u32 next_net_master_write :17;
- u32 unused :15;
- } pid_filter_30c_ext_ind_3;
-
- struct {
- u32 unused1 : 1;
- u32 state_write :10;
- u32 reserved1 : 6; /* default: 000100 */
- u32 stack_read :10;
- u32 reserved2 : 5; /* default: 00100 */
- } pid_filter_30c_ext_ind_4;
-
- struct {
- u32 stack_cnt :10;
- u32 unused :22;
- } pid_filter_30c_ext_ind_5;
-
- struct {
- u32 pid_fsm_save_reg0 : 2;
- u32 pid_fsm_save_reg1 : 2;
- u32 pid_fsm_save_reg2 : 2;
- u32 pid_fsm_save_reg3 : 2;
- u32 pid_fsm_save_reg4 : 2;
- u32 pid_fsm_save_reg300 : 2;
- u32 write_status1 : 2;
- u32 write_status4 : 2;
- u32 data_size_reg :12;
- u32 unused : 4;
- } pid_filter_30c_ext_ind_6;
-
- struct {
- u32 index_reg : 5; /* (Index pointer) Points at an internal PIDn register. A binary code
- representing one of 32 internal PIDn registers as well as its
- corresponding internal MAC_lown register. */
- u32 extra_index_reg : 3; /* This vector is used to select between sets of debug signals routed to register 0x30c. */
- u32 AB_select : 1; /* Used in conjunction with 0x31c. read/write to the MAC_highA or MAC_highB register
- 0=MAC_highB register, 1=MAC_highA */
- u32 pass_alltables : 1; /* 1=Net packets are not filtered against the Network Table ID found in register 0x400.
- All types of networks (DVB, ATSC, ISDB) are passed. */
- u32 unused :22;
- } index_reg_310;
-
- struct {
- u32 PID :13; /* PID value */
- u32 PID_trans : 1; /* translation will take place for packets filtered */
- u32 PID_enable_bit : 1; /* When set this PID filter is enabled */
- u32 reserved :17;
- } pid_n_reg_314;
-
- struct {
- u32 A4_byte : 8;
- u32 A5_byte : 8;
- u32 A6_byte : 8;
- u32 Enable_bit : 1; /* enabled (1) or disabled (1) */
- u32 HighAB_bit : 1; /* use MAC_highA (1) or MAC_highB (0) as MSB */
- u32 reserved : 6;
- } mac_low_reg_318;
-
- struct {
- u32 A1_byte : 8;
- u32 A2_byte : 8;
- u32 A3_byte : 8;
- u32 reserved : 8;
- } mac_high_reg_31c;
-
-/* Table, SMCID,MACDestination Filters 0x400 to 0x41c */
- struct {
- u32 reserved :16;
#define fc_data_Tag_ID_DVB 0x3e
#define fc_data_Tag_ID_ATSC 0x3f
#define fc_data_Tag_ID_IDSB 0x8b
- u32 data_Tag_ID :16;
- } data_tag_400;
-
- struct {
- u32 Card_IDbyte6 : 8;
- u32 Card_IDbyte5 : 8;
- u32 Card_IDbyte4 : 8;
- u32 Card_IDbyte3 : 8;
- } card_id_408;
-
- struct {
- u32 Card_IDbyte2 : 8;
- u32 Card_IDbyte1 : 8;
- } card_id_40c;
-
- /* holding the unique mac address of the receiver which houses the FlexCopIII */
- struct {
- u32 MAC1 : 8;
- u32 MAC2 : 8;
- u32 MAC3 : 8;
- u32 MAC6 : 8;
- } mac_address_418;
-
- struct {
- u32 MAC7 : 8;
- u32 MAC8 : 8;
- u32 reserved : 16;
- } mac_address_41c;
-
- struct {
- u32 transmitter_data_byte : 8;
- u32 ReceiveDataReady : 1;
- u32 ReceiveByteFrameError: 1;
- u32 txbuffempty : 1;
- u32 reserved :21;
- } ci_600;
-
- struct {
- u32 pi_d : 8;
- u32 pi_ha :20;
- u32 pi_rw : 1;
- u32 pi_component_reg : 3;
- } pi_604;
-
- struct {
- u32 serialReset : 1;
- u32 oncecycle_read : 1;
- u32 Timer_Read_req : 1;
- u32 Timer_Load_req : 1;
- u32 timer_data : 7;
- u32 unused : 1; /* ??? not mentioned in data book */
- u32 Timer_addr : 5;
- u32 reserved : 3;
- u32 pcmcia_a_mod_pwr_n : 1;
- u32 pcmcia_b_mod_pwr_n : 1;
- u32 config_Done_stat : 1;
- u32 config_Init_stat : 1;
- u32 config_Prog_n : 1;
- u32 config_wr_n : 1;
- u32 config_cs_n : 1;
- u32 config_cclk : 1;
- u32 pi_CiMax_IRQ_n : 1;
- u32 pi_timeout_status : 1;
- u32 pi_wait_n : 1;
- u32 pi_busy_n : 1;
- } pi_608;
- struct {
- u32 PID :13;
- u32 key_enable : 1;
#define fc_key_code_default 0x1
#define fc_key_code_even 0x2
#define fc_key_code_odd 0x3
- u32 key_code : 2;
- u32 key_array_col : 3;
- u32 key_array_row : 5;
- u32 dvb_en : 1; /* 0=TS bypasses the Descrambler */
- u32 rw_flag : 1;
- u32 reserved : 6;
- } dvb_reg_60c;
-
-/* SRAM and Output Destination 0x700 to 0x714 */
- struct {
- u32 sram_addr :15;
- u32 sram_rw : 1; /* 0=write, 1=read */
- u32 sram_data : 8;
- u32 sc_xfer_bit : 1;
- u32 reserved1 : 3;
- u32 oe_pin_reg : 1;
- u32 ce_pin_reg : 1;
- u32 reserved2 : 1;
- u32 start_sram_ibi : 1;
- } sram_ctrl_reg_700;
-
- struct {
- u32 net_addr_read :16;
- u32 net_addr_write :16;
- } net_buf_reg_704;
-
- struct {
- u32 cai_read :11;
- u32 reserved1 : 5;
- u32 cai_write :11;
- u32 reserved2 : 6;
- u32 cai_cnt : 4;
- } cai_buf_reg_708;
-
- struct {
- u32 cao_read :11;
- u32 reserved1 : 5;
- u32 cap_write :11;
- u32 reserved2 : 6;
- u32 cao_cnt : 4;
- } cao_buf_reg_70c;
-
- struct {
- u32 media_read :11;
- u32 reserved1 : 5;
- u32 media_write :11;
- u32 reserved2 : 6;
- u32 media_cnt : 4;
- } media_buf_reg_710;
-
- struct {
- u32 NET_Dest : 2;
- u32 CAI_Dest : 2;
- u32 CAO_Dest : 2;
- u32 MEDIA_Dest : 2;
- u32 net_ovflow_error : 1;
- u32 media_ovflow_error : 1;
- u32 cai_ovflow_error : 1;
- u32 cao_ovflow_error : 1;
- u32 ctrl_usb_wan : 1;
- u32 ctrl_sramdma : 1;
- u32 ctrl_maximumfill : 1;
- u32 reserved :17;
- } sram_dest_reg_714;
-
- struct {
- u32 net_cnt :12;
- u32 reserved1 : 4;
- u32 net_addr_read : 1;
- u32 reserved2 : 3;
- u32 net_addr_write : 1;
- u32 reserved3 :11;
- } net_buf_reg_718;
-
- struct {
- u32 wan_speed_sig : 2;
- u32 reserved1 : 6;
- u32 wan_wait_state : 8;
- u32 sram_chip : 2;
- u32 sram_memmap : 2;
- u32 reserved2 : 4;
- u32 wan_pkt_frame : 4;
- u32 reserved3 : 4;
- } wan_ctrl_reg_71c;
-} flexcop_ibi_value;
extern flexcop_ibi_value ibi_zero;
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c
index 0113449abd1..0a78ba3737a 100644
--- a/drivers/media/dvb/b2c2/flexcop-usb.c
+++ b/drivers/media/dvb/b2c2/flexcop-usb.c
@@ -545,7 +545,7 @@ static struct usb_device_id flexcop_usb_table [] = {
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver flexcop_usb_driver = {
.owner = THIS_MODULE,
- .name = "Technisat/B2C2 FlexCop II/IIb/III USB",
+ .name = "b2c2_flexcop_usb",
.probe = flexcop_usb_probe,
.disconnect = flexcop_usb_disconnect,
.id_table = flexcop_usb_table,
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
index 8b5d14dd36e..12873d43540 100644
--- a/drivers/media/dvb/b2c2/flexcop.c
+++ b/drivers/media/dvb/b2c2/flexcop.c
@@ -46,7 +46,7 @@
int b2c2_flexcop_debug;
module_param_named(debug, b2c2_flexcop_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram (|-able))." DEBSTATUS);
+MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram,32=reg (|-able))." DEBSTATUS);
#undef DEBSTATUS
/* global zero for ibi values */
@@ -173,9 +173,20 @@ static void flexcop_reset(struct flexcop_device *fc)
fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
v210.raw = 0;
- v210.sw_reset_210.reset_blocks = 0xff;
+ v210.sw_reset_210.reset_block_000 = 1;
+ v210.sw_reset_210.reset_block_100 = 1;
+ v210.sw_reset_210.reset_block_200 = 1;
+ v210.sw_reset_210.reset_block_300 = 1;
+ v210.sw_reset_210.reset_block_400 = 1;
+ v210.sw_reset_210.reset_block_500 = 1;
+ v210.sw_reset_210.reset_block_600 = 1;
+ v210.sw_reset_210.reset_block_700 = 1;
v210.sw_reset_210.Block_reset_enable = 0xb2;
+
+ v210.sw_reset_210.Special_controls = 0xc259;
+
fc->write_ibi_reg(fc,sw_reset_210,v210);
+ msleep(1);
/* reset the periphical devices */
@@ -186,6 +197,25 @@ static void flexcop_reset(struct flexcop_device *fc)
fc->write_ibi_reg(fc,misc_204,v204);
}
+void flexcop_reset_block_300(struct flexcop_device *fc)
+{
+ flexcop_ibi_value v208_save = fc->read_ibi_reg(fc,ctrl_208),
+ v210 = fc->read_ibi_reg(fc,sw_reset_210);
+
+ deb_rdump("208: %08x, 210: %08x\n",v208_save.raw,v210.raw);
+
+ fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
+
+ v210.sw_reset_210.reset_block_300 = 1;
+ v210.sw_reset_210.Block_reset_enable = 0xb2;
+
+ fc->write_ibi_reg(fc,sw_reset_210,v210);
+ msleep(1);
+
+ fc->write_ibi_reg(fc,ctrl_208,v208_save);
+}
+EXPORT_SYMBOL(flexcop_reset_block_300);
+
struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
{
void *bus;
diff --git a/drivers/media/dvb/b2c2/flexcop.h b/drivers/media/dvb/b2c2/flexcop.h
index caa343a97bd..0cebe1d92e0 100644
--- a/drivers/media/dvb/b2c2/flexcop.h
+++ b/drivers/media/dvb/b2c2/flexcop.h
@@ -26,5 +26,6 @@ extern int b2c2_flexcop_debug;
#define deb_i2c(args...) dprintk(0x04,args)
#define deb_ts(args...) dprintk(0x08,args)
#define deb_sram(args...) dprintk(0x10,args)
+#define deb_rdump(args...) dprintk(0x20,args)
#endif
diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h
new file mode 100644
index 00000000000..ed9a6756b19
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h
@@ -0,0 +1,458 @@
+/* This file is part of linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * register descriptions
+ *
+ * see flexcop.c for copyright information.
+ */
+
+/* This file is automatically generated, do not edit things here. */
+#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
+#define __FLEXCOP_IBI_VALUE_INCLUDED__
+
+typedef union {
+ u32 raw;
+
+ struct {
+ u32 dma_address0 :30;
+ u32 dma_0No_update : 1;
+ u32 dma_0start : 1;
+ } dma_0x0;
+
+ struct {
+ u32 dma_addr_size :24;
+ u32 DMA_maxpackets : 8;
+ } dma_0x4_remap;
+
+ struct {
+ u32 dma_addr_size :24;
+ u32 unused : 1;
+ u32 dma1timer : 7;
+ } dma_0x4_read;
+
+ struct {
+ u32 dma_addr_size :24;
+ u32 dmatimer : 7;
+ u32 unused : 1;
+ } dma_0x4_write;
+
+ struct {
+ u32 dma_cur_addr :30;
+ u32 unused : 2;
+ } dma_0x8;
+
+ struct {
+ u32 dma_address1 :30;
+ u32 remap_enable : 1;
+ u32 dma_1start : 1;
+ } dma_0xc;
+
+ struct {
+ u32 st_done : 1;
+ u32 no_base_addr_ack_error : 1;
+ u32 twoWS_port_reg : 2;
+ u32 total_bytes : 2;
+ u32 twoWS_rw : 1;
+ u32 working_start : 1;
+ u32 data1_reg : 8;
+ u32 baseaddr : 8;
+ u32 reserved1 : 1;
+ u32 chipaddr : 7;
+ } tw_sm_c_100;
+
+ struct {
+ u32 unused : 6;
+ u32 force_stop : 1;
+ u32 exlicit_stops : 1;
+ u32 data4_reg : 8;
+ u32 data3_reg : 8;
+ u32 data2_reg : 8;
+ } tw_sm_c_104;
+
+ struct {
+ u32 reserved2 :19;
+ u32 tlo1 : 5;
+ u32 reserved1 : 2;
+ u32 thi1 : 6;
+ } tw_sm_c_108;
+
+ struct {
+ u32 reserved2 :19;
+ u32 tlo1 : 5;
+ u32 reserved1 : 2;
+ u32 thi1 : 6;
+ } tw_sm_c_10c;
+
+ struct {
+ u32 reserved2 :19;
+ u32 tlo1 : 5;
+ u32 reserved1 : 2;
+ u32 thi1 : 6;
+ } tw_sm_c_110;
+
+ struct {
+ u32 LNB_CTLPrescaler_sig : 2;
+ u32 LNB_CTLLowCount_sig :15;
+ u32 LNB_CTLHighCount_sig :15;
+ } lnb_switch_freq_200;
+
+ struct {
+ u32 Rev_N_sig_reserved2 : 1;
+ u32 Rev_N_sig_caps : 1;
+ u32 Rev_N_sig_reserved1 : 2;
+ u32 Rev_N_sig_revision_hi : 4;
+ u32 reserved :20;
+ u32 Per_reset_sig : 1;
+ u32 LNB_L_H_sig : 1;
+ u32 ACPI3_sig : 1;
+ u32 ACPI1_sig : 1;
+ } misc_204;
+
+ struct {
+ u32 unused : 9;
+ u32 Mailbox_from_V8_Enable_sig : 1;
+ u32 DMA2_Size_IRQ_Enable_sig : 1;
+ u32 DMA1_Size_IRQ_Enable_sig : 1;
+ u32 DMA2_Timer_Enable_sig : 1;
+ u32 DMA2_IRQ_Enable_sig : 1;
+ u32 DMA1_Timer_Enable_sig : 1;
+ u32 DMA1_IRQ_Enable_sig : 1;
+ u32 Rcv_Data_sig : 1;
+ u32 MAC_filter_Mode_sig : 1;
+ u32 Multi2_Enable_sig : 1;
+ u32 Per_CA_Enable_sig : 1;
+ u32 SMC_Enable_sig : 1;
+ u32 CA_Enable_sig : 1;
+ u32 WAN_CA_Enable_sig : 1;
+ u32 WAN_Enable_sig : 1;
+ u32 Mask_filter_sig : 1;
+ u32 Null_filter_sig : 1;
+ u32 ECM_filter_sig : 1;
+ u32 EMM_filter_sig : 1;
+ u32 PMT_filter_sig : 1;
+ u32 PCR_filter_sig : 1;
+ u32 Stream2_filter_sig : 1;
+ u32 Stream1_filter_sig : 1;
+ } ctrl_208;
+
+ struct {
+ u32 reserved :21;
+ u32 Transport_Error : 1;
+ u32 LLC_SNAP_FLAG_set : 1;
+ u32 Continuity_error_flag : 1;
+ u32 Data_receiver_error : 1;
+ u32 Mailbox_from_V8_Status_sig : 1;
+ u32 DMA2_Size_IRQ_Status : 1;
+ u32 DMA1_Size_IRQ_Status : 1;
+ u32 DMA2_Timer_Status : 1;
+ u32 DMA2_IRQ_Status : 1;
+ u32 DMA1_Timer_Status : 1;
+ u32 DMA1_IRQ_Status : 1;
+ } irq_20c;
+
+ struct {
+ u32 Special_controls :16;
+ u32 Block_reset_enable : 8;
+ u32 reset_block_700 : 1;
+ u32 reset_block_600 : 1;
+ u32 reset_block_500 : 1;
+ u32 reset_block_400 : 1;
+ u32 reset_block_300 : 1;
+ u32 reset_block_200 : 1;
+ u32 reset_block_100 : 1;
+ u32 reset_block_000 : 1;
+ } sw_reset_210;
+
+ struct {
+ u32 unused2 :20;
+ u32 polarity_PS_ERR_sig : 1;
+ u32 polarity_PS_SYNC_sig : 1;
+ u32 polarity_PS_VALID_sig : 1;
+ u32 polarity_PS_CLK_sig : 1;
+ u32 unused1 : 3;
+ u32 s2p_sel_sig : 1;
+ u32 section_pkg_enable_sig : 1;
+ u32 halt_V8_sig : 1;
+ u32 v2WS_oe_sig : 1;
+ u32 vuart_oe_sig : 1;
+ } misc_214;
+
+ struct {
+ u32 Mailbox_from_V8 :32;
+ } mbox_v8_to_host_218;
+
+ struct {
+ u32 sysramaccess_busmuster : 1;
+ u32 sysramaccess_write : 1;
+ u32 unused : 7;
+ u32 sysramaccess_addr :15;
+ u32 sysramaccess_data : 8;
+ } mbox_host_to_v8_21c;
+
+ struct {
+ u32 debug_fifo_problem : 1;
+ u32 debug_flag_write_status00 : 1;
+ u32 Stream2_trans : 1;
+ u32 Stream2_PID :13;
+ u32 debug_flag_pid_saved : 1;
+ u32 MAC_Multicast_filter : 1;
+ u32 Stream1_trans : 1;
+ u32 Stream1_PID :13;
+ } pid_filter_300;
+
+ struct {
+ u32 reserved : 2;
+ u32 PMT_trans : 1;
+ u32 PMT_PID :13;
+ u32 debug_overrun2 : 1;
+ u32 debug_overrun3 : 1;
+ u32 PCR_trans : 1;
+ u32 PCR_PID :13;
+ } pid_filter_304;
+
+ struct {
+ u32 reserved : 2;
+ u32 ECM_trans : 1;
+ u32 ECM_PID :13;
+ u32 EMM_filter_6 : 1;
+ u32 EMM_filter_4 : 1;
+ u32 EMM_trans : 1;
+ u32 EMM_PID :13;
+ } pid_filter_308;
+
+ struct {
+ u32 unused2 : 3;
+ u32 Group_mask :13;
+ u32 unused1 : 2;
+ u32 Group_trans : 1;
+ u32 Group_PID :13;
+ } pid_filter_30c_ext_ind_0_7;
+
+ struct {
+ u32 unused :15;
+ u32 net_master_read :17;
+ } pid_filter_30c_ext_ind_1;
+
+ struct {
+ u32 unused :15;
+ u32 net_master_write :17;
+ } pid_filter_30c_ext_ind_2;
+
+ struct {
+ u32 unused :15;
+ u32 next_net_master_write :17;
+ } pid_filter_30c_ext_ind_3;
+
+ struct {
+ u32 reserved2 : 5;
+ u32 stack_read :10;
+ u32 reserved1 : 6;
+ u32 state_write :10;
+ u32 unused1 : 1;
+ } pid_filter_30c_ext_ind_4;
+
+ struct {
+ u32 unused :22;
+ u32 stack_cnt :10;
+ } pid_filter_30c_ext_ind_5;
+
+ struct {
+ u32 unused : 4;
+ u32 data_size_reg :12;
+ u32 write_status4 : 2;
+ u32 write_status1 : 2;
+ u32 pid_fsm_save_reg300 : 2;
+ u32 pid_fsm_save_reg4 : 2;
+ u32 pid_fsm_save_reg3 : 2;
+ u32 pid_fsm_save_reg2 : 2;
+ u32 pid_fsm_save_reg1 : 2;
+ u32 pid_fsm_save_reg0 : 2;
+ } pid_filter_30c_ext_ind_6;
+
+ struct {
+ u32 unused :22;
+ u32 pass_alltables : 1;
+ u32 AB_select : 1;
+ u32 extra_index_reg : 3;
+ u32 index_reg : 5;
+ } index_reg_310;
+
+ struct {
+ u32 reserved :17;
+ u32 PID_enable_bit : 1;
+ u32 PID_trans : 1;
+ u32 PID :13;
+ } pid_n_reg_314;
+
+ struct {
+ u32 reserved : 6;
+ u32 HighAB_bit : 1;
+ u32 Enable_bit : 1;
+ u32 A6_byte : 8;
+ u32 A5_byte : 8;
+ u32 A4_byte : 8;
+ } mac_low_reg_318;
+
+ struct {
+ u32 reserved : 8;
+ u32 A3_byte : 8;
+ u32 A2_byte : 8;
+ u32 A1_byte : 8;
+ } mac_high_reg_31c;
+
+ struct {
+ u32 data_Tag_ID :16;
+ u32 reserved :16;
+ } data_tag_400;
+
+ struct {
+ u32 Card_IDbyte3 : 8;
+ u32 Card_IDbyte4 : 8;
+ u32 Card_IDbyte5 : 8;
+ u32 Card_IDbyte6 : 8;
+ } card_id_408;
+
+ struct {
+ u32 Card_IDbyte1 : 8;
+ u32 Card_IDbyte2 : 8;
+ } card_id_40c;
+
+ struct {
+ u32 MAC6 : 8;
+ u32 MAC3 : 8;
+ u32 MAC2 : 8;
+ u32 MAC1 : 8;
+ } mac_address_418;
+
+ struct {
+ u32 reserved :16;
+ u32 MAC8 : 8;
+ u32 MAC7 : 8;
+ } mac_address_41c;
+
+ struct {
+ u32 reserved :21;
+ u32 txbuffempty : 1;
+ u32 ReceiveByteFrameError : 1;
+ u32 ReceiveDataReady : 1;
+ u32 transmitter_data_byte : 8;
+ } ci_600;
+
+ struct {
+ u32 pi_component_reg : 3;
+ u32 pi_rw : 1;
+ u32 pi_ha :20;
+ u32 pi_d : 8;
+ } pi_604;
+
+ struct {
+ u32 pi_busy_n : 1;
+ u32 pi_wait_n : 1;
+ u32 pi_timeout_status : 1;
+ u32 pi_CiMax_IRQ_n : 1;
+ u32 config_cclk : 1;
+ u32 config_cs_n : 1;
+ u32 config_wr_n : 1;
+ u32 config_Prog_n : 1;
+ u32 config_Init_stat : 1;
+ u32 config_Done_stat : 1;
+ u32 pcmcia_b_mod_pwr_n : 1;
+ u32 pcmcia_a_mod_pwr_n : 1;
+ u32 reserved : 3;
+ u32 Timer_addr : 5;
+ u32 unused : 1;
+ u32 timer_data : 7;
+ u32 Timer_Load_req : 1;
+ u32 Timer_Read_req : 1;
+ u32 oncecycle_read : 1;
+ u32 serialReset : 1;
+ } pi_608;
+
+ struct {
+ u32 reserved : 6;
+ u32 rw_flag : 1;
+ u32 dvb_en : 1;
+ u32 key_array_row : 5;
+ u32 key_array_col : 3;
+ u32 key_code : 2;
+ u32 key_enable : 1;
+ u32 PID :13;
+ } dvb_reg_60c;
+
+ struct {
+ u32 start_sram_ibi : 1;
+ u32 reserved2 : 1;
+ u32 ce_pin_reg : 1;
+ u32 oe_pin_reg : 1;
+ u32 reserved1 : 3;
+ u32 sc_xfer_bit : 1;
+ u32 sram_data : 8;
+ u32 sram_rw : 1;
+ u32 sram_addr :15;
+ } sram_ctrl_reg_700;
+
+ struct {
+ u32 net_addr_write :16;
+ u32 net_addr_read :16;
+ } net_buf_reg_704;
+
+ struct {
+ u32 cai_cnt : 4;
+ u32 reserved2 : 6;
+ u32 cai_write :11;
+ u32 reserved1 : 5;
+ u32 cai_read :11;
+ } cai_buf_reg_708;
+
+ struct {
+ u32 cao_cnt : 4;
+ u32 reserved2 : 6;
+ u32 cap_write :11;
+ u32 reserved1 : 5;
+ u32 cao_read :11;
+ } cao_buf_reg_70c;
+
+ struct {
+ u32 media_cnt : 4;
+ u32 reserved2 : 6;
+ u32 media_write :11;
+ u32 reserved1 : 5;
+ u32 media_read :11;
+ } media_buf_reg_710;
+
+ struct {
+ u32 reserved :17;
+ u32 ctrl_maximumfill : 1;
+ u32 ctrl_sramdma : 1;
+ u32 ctrl_usb_wan : 1;
+ u32 cao_ovflow_error : 1;
+ u32 cai_ovflow_error : 1;
+ u32 media_ovflow_error : 1;
+ u32 net_ovflow_error : 1;
+ u32 MEDIA_Dest : 2;
+ u32 CAO_Dest : 2;
+ u32 CAI_Dest : 2;
+ u32 NET_Dest : 2;
+ } sram_dest_reg_714;
+
+ struct {
+ u32 reserved3 :11;
+ u32 net_addr_write : 1;
+ u32 reserved2 : 3;
+ u32 net_addr_read : 1;
+ u32 reserved1 : 4;
+ u32 net_cnt :12;
+ } net_buf_reg_718;
+
+ struct {
+ u32 reserved3 : 4;
+ u32 wan_pkt_frame : 4;
+ u32 reserved2 : 4;
+ u32 sram_memmap : 2;
+ u32 sram_chip : 2;
+ u32 wan_wait_state : 8;
+ u32 reserved1 : 6;
+ u32 wan_speed_sig : 2;
+ } wan_ctrl_reg_71c;
+} flexcop_ibi_value;
+
+#endif
diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h
new file mode 100644
index 00000000000..49f2315b6e5
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h
@@ -0,0 +1,458 @@
+/* This file is part of linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * register descriptions
+ *
+ * see flexcop.c for copyright information.
+ */
+
+/* This file is automatically generated, do not edit things here. */
+#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
+#define __FLEXCOP_IBI_VALUE_INCLUDED__
+
+typedef union {
+ u32 raw;
+
+ struct {
+ u32 dma_0start : 1;
+ u32 dma_0No_update : 1;
+ u32 dma_address0 :30;
+ } dma_0x0;
+
+ struct {
+ u32 DMA_maxpackets : 8;
+ u32 dma_addr_size :24;
+ } dma_0x4_remap;
+
+ struct {
+ u32 dma1timer : 7;
+ u32 unused : 1;
+ u32 dma_addr_size :24;
+ } dma_0x4_read;
+
+ struct {
+ u32 unused : 1;
+ u32 dmatimer : 7;
+ u32 dma_addr_size :24;
+ } dma_0x4_write;
+
+ struct {
+ u32 unused : 2;
+ u32 dma_cur_addr :30;
+ } dma_0x8;
+
+ struct {
+ u32 dma_1start : 1;
+ u32 remap_enable : 1;
+ u32 dma_address1 :30;
+ } dma_0xc;
+
+ struct {
+ u32 chipaddr : 7;
+ u32 reserved1 : 1;
+ u32 baseaddr : 8;
+ u32 data1_reg : 8;
+ u32 working_start : 1;
+ u32 twoWS_rw : 1;
+ u32 total_bytes : 2;
+ u32 twoWS_port_reg : 2;
+ u32 no_base_addr_ack_error : 1;
+ u32 st_done : 1;
+ } tw_sm_c_100;
+
+ struct {
+ u32 data2_reg : 8;
+ u32 data3_reg : 8;
+ u32 data4_reg : 8;
+ u32 exlicit_stops : 1;
+ u32 force_stop : 1;
+ u32 unused : 6;
+ } tw_sm_c_104;
+
+ struct {
+ u32 thi1 : 6;
+ u32 reserved1 : 2;
+ u32 tlo1 : 5;
+ u32 reserved2 :19;
+ } tw_sm_c_108;
+
+ struct {
+ u32 thi1 : 6;
+ u32 reserved1 : 2;
+ u32 tlo1 : 5;
+ u32 reserved2 :19;
+ } tw_sm_c_10c;
+
+ struct {
+ u32 thi1 : 6;
+ u32 reserved1 : 2;
+ u32 tlo1 : 5;
+ u32 reserved2 :19;
+ } tw_sm_c_110;
+
+ struct {
+ u32 LNB_CTLHighCount_sig :15;
+ u32 LNB_CTLLowCount_sig :15;
+ u32 LNB_CTLPrescaler_sig : 2;
+ } lnb_switch_freq_200;
+
+ struct {
+ u32 ACPI1_sig : 1;
+ u32 ACPI3_sig : 1;
+ u32 LNB_L_H_sig : 1;
+ u32 Per_reset_sig : 1;
+ u32 reserved :20;
+ u32 Rev_N_sig_revision_hi : 4;
+ u32 Rev_N_sig_reserved1 : 2;
+ u32 Rev_N_sig_caps : 1;
+ u32 Rev_N_sig_reserved2 : 1;
+ } misc_204;
+
+ struct {
+ u32 Stream1_filter_sig : 1;
+ u32 Stream2_filter_sig : 1;
+ u32 PCR_filter_sig : 1;
+ u32 PMT_filter_sig : 1;
+ u32 EMM_filter_sig : 1;
+ u32 ECM_filter_sig : 1;
+ u32 Null_filter_sig : 1;
+ u32 Mask_filter_sig : 1;
+ u32 WAN_Enable_sig : 1;
+ u32 WAN_CA_Enable_sig : 1;
+ u32 CA_Enable_sig : 1;
+ u32 SMC_Enable_sig : 1;
+ u32 Per_CA_Enable_sig : 1;
+ u32 Multi2_Enable_sig : 1;
+ u32 MAC_filter_Mode_sig : 1;
+ u32 Rcv_Data_sig : 1;
+ u32 DMA1_IRQ_Enable_sig : 1;
+ u32 DMA1_Timer_Enable_sig : 1;
+ u32 DMA2_IRQ_Enable_sig : 1;
+ u32 DMA2_Timer_Enable_sig : 1;
+ u32 DMA1_Size_IRQ_Enable_sig : 1;
+ u32 DMA2_Size_IRQ_Enable_sig : 1;
+ u32 Mailbox_from_V8_Enable_sig : 1;
+ u32 unused : 9;
+ } ctrl_208;
+
+ struct {
+ u32 DMA1_IRQ_Status : 1;
+ u32 DMA1_Timer_Status : 1;
+ u32 DMA2_IRQ_Status : 1;
+ u32 DMA2_Timer_Status : 1;
+ u32 DMA1_Size_IRQ_Status : 1;
+ u32 DMA2_Size_IRQ_Status : 1;
+ u32 Mailbox_from_V8_Status_sig : 1;
+ u32 Data_receiver_error : 1;
+ u32 Continuity_error_flag : 1;
+ u32 LLC_SNAP_FLAG_set : 1;
+ u32 Transport_Error : 1;
+ u32 reserved :21;
+ } irq_20c;
+
+ struct {
+ u32 reset_block_000 : 1;
+ u32 reset_block_100 : 1;
+ u32 reset_block_200 : 1;
+ u32 reset_block_300 : 1;
+ u32 reset_block_400 : 1;
+ u32 reset_block_500 : 1;
+ u32 reset_block_600 : 1;
+ u32 reset_block_700 : 1;
+ u32 Block_reset_enable : 8;
+ u32 Special_controls :16;
+ } sw_reset_210;
+
+ struct {
+ u32 vuart_oe_sig : 1;
+ u32 v2WS_oe_sig : 1;
+ u32 halt_V8_sig : 1;
+ u32 section_pkg_enable_sig : 1;
+ u32 s2p_sel_sig : 1;
+ u32 unused1 : 3;
+ u32 polarity_PS_CLK_sig : 1;
+ u32 polarity_PS_VALID_sig : 1;
+ u32 polarity_PS_SYNC_sig : 1;
+ u32 polarity_PS_ERR_sig : 1;
+ u32 unused2 :20;
+ } misc_214;
+
+ struct {
+ u32 Mailbox_from_V8 :32;
+ } mbox_v8_to_host_218;
+
+ struct {
+ u32 sysramaccess_data : 8;
+ u32 sysramaccess_addr :15;
+ u32 unused : 7;
+ u32 sysramaccess_write : 1;
+ u32 sysramaccess_busmuster : 1;
+ } mbox_host_to_v8_21c;
+
+ struct {
+ u32 Stream1_PID :13;
+ u32 Stream1_trans : 1;
+ u32 MAC_Multicast_filter : 1;
+ u32 debug_flag_pid_saved : 1;
+ u32 Stream2_PID :13;
+ u32 Stream2_trans : 1;
+ u32 debug_flag_write_status00 : 1;
+ u32 debug_fifo_problem : 1;
+ } pid_filter_300;
+
+ struct {
+ u32 PCR_PID :13;
+ u32 PCR_trans : 1;
+ u32 debug_overrun3 : 1;
+ u32 debug_overrun2 : 1;
+ u32 PMT_PID :13;
+ u32 PMT_trans : 1;
+ u32 reserved : 2;
+ } pid_filter_304;
+
+ struct {
+ u32 EMM_PID :13;
+ u32 EMM_trans : 1;
+ u32 EMM_filter_4 : 1;
+ u32 EMM_filter_6 : 1;
+ u32 ECM_PID :13;
+ u32 ECM_trans : 1;
+ u32 reserved : 2;
+ } pid_filter_308;
+
+ struct {
+ u32 Group_PID :13;
+ u32 Group_trans : 1;
+ u32 unused1 : 2;
+ u32 Group_mask :13;
+ u32 unused2 : 3;
+ } pid_filter_30c_ext_ind_0_7;
+
+ struct {
+ u32 net_master_read :17;
+ u32 unused :15;
+ } pid_filter_30c_ext_ind_1;
+
+ struct {
+ u32 net_master_write :17;
+ u32 unused :15;
+ } pid_filter_30c_ext_ind_2;
+
+ struct {
+ u32 next_net_master_write :17;
+ u32 unused :15;
+ } pid_filter_30c_ext_ind_3;
+
+ struct {
+ u32 unused1 : 1;
+ u32 state_write :10;
+ u32 reserved1 : 6;
+ u32 stack_read :10;
+ u32 reserved2 : 5;
+ } pid_filter_30c_ext_ind_4;
+
+ struct {
+ u32 stack_cnt :10;
+ u32 unused :22;
+ } pid_filter_30c_ext_ind_5;
+
+ struct {
+ u32 pid_fsm_save_reg0 : 2;
+ u32 pid_fsm_save_reg1 : 2;
+ u32 pid_fsm_save_reg2 : 2;
+ u32 pid_fsm_save_reg3 : 2;
+ u32 pid_fsm_save_reg4 : 2;
+ u32 pid_fsm_save_reg300 : 2;
+ u32 write_status1 : 2;
+ u32 write_status4 : 2;
+ u32 data_size_reg :12;
+ u32 unused : 4;
+ } pid_filter_30c_ext_ind_6;
+
+ struct {
+ u32 index_reg : 5;
+ u32 extra_index_reg : 3;
+ u32 AB_select : 1;
+ u32 pass_alltables : 1;
+ u32 unused :22;
+ } index_reg_310;
+
+ struct {
+ u32 PID :13;
+ u32 PID_trans : 1;
+ u32 PID_enable_bit : 1;
+ u32 reserved :17;
+ } pid_n_reg_314;
+
+ struct {
+ u32 A4_byte : 8;
+ u32 A5_byte : 8;
+ u32 A6_byte : 8;
+ u32 Enable_bit : 1;
+ u32 HighAB_bit : 1;
+ u32 reserved : 6;
+ } mac_low_reg_318;
+
+ struct {
+ u32 A1_byte : 8;
+ u32 A2_byte : 8;
+ u32 A3_byte : 8;
+ u32 reserved : 8;
+ } mac_high_reg_31c;
+
+ struct {
+ u32 reserved :16;
+ u32 data_Tag_ID :16;
+ } data_tag_400;
+
+ struct {
+ u32 Card_IDbyte6 : 8;
+ u32 Card_IDbyte5 : 8;
+ u32 Card_IDbyte4 : 8;
+ u32 Card_IDbyte3 : 8;
+ } card_id_408;
+
+ struct {
+ u32 Card_IDbyte2 : 8;
+ u32 Card_IDbyte1 : 8;
+ } card_id_40c;
+
+ struct {
+ u32 MAC1 : 8;
+ u32 MAC2 : 8;
+ u32 MAC3 : 8;
+ u32 MAC6 : 8;
+ } mac_address_418;
+
+ struct {
+ u32 MAC7 : 8;
+ u32 MAC8 : 8;
+ u32 reserved :16;
+ } mac_address_41c;
+
+ struct {
+ u32 transmitter_data_byte : 8;
+ u32 ReceiveDataReady : 1;
+ u32 ReceiveByteFrameError : 1;
+ u32 txbuffempty : 1;
+ u32 reserved :21;
+ } ci_600;
+
+ struct {
+ u32 pi_d : 8;
+ u32 pi_ha :20;
+ u32 pi_rw : 1;
+ u32 pi_component_reg : 3;
+ } pi_604;
+
+ struct {
+ u32 serialReset : 1;
+ u32 oncecycle_read : 1;
+ u32 Timer_Read_req : 1;
+ u32 Timer_Load_req : 1;
+ u32 timer_data : 7;
+ u32 unused : 1;
+ u32 Timer_addr : 5;
+ u32 reserved : 3;
+ u32 pcmcia_a_mod_pwr_n : 1;
+ u32 pcmcia_b_mod_pwr_n : 1;
+ u32 config_Done_stat : 1;
+ u32 config_Init_stat : 1;
+ u32 config_Prog_n : 1;
+ u32 config_wr_n : 1;
+ u32 config_cs_n : 1;
+ u32 config_cclk : 1;
+ u32 pi_CiMax_IRQ_n : 1;
+ u32 pi_timeout_status : 1;
+ u32 pi_wait_n : 1;
+ u32 pi_busy_n : 1;
+ } pi_608;
+
+ struct {
+ u32 PID :13;
+ u32 key_enable : 1;
+ u32 key_code : 2;
+ u32 key_array_col : 3;
+ u32 key_array_row : 5;
+ u32 dvb_en : 1;
+ u32 rw_flag : 1;
+ u32 reserved : 6;
+ } dvb_reg_60c;
+
+ struct {
+ u32 sram_addr :15;
+ u32 sram_rw : 1;
+ u32 sram_data : 8;
+ u32 sc_xfer_bit : 1;
+ u32 reserved1 : 3;
+ u32 oe_pin_reg : 1;
+ u32 ce_pin_reg : 1;
+ u32 reserved2 : 1;
+ u32 start_sram_ibi : 1;
+ } sram_ctrl_reg_700;
+
+ struct {
+ u32 net_addr_read :16;
+ u32 net_addr_write :16;
+ } net_buf_reg_704;
+
+ struct {
+ u32 cai_read :11;
+ u32 reserved1 : 5;
+ u32 cai_write :11;
+ u32 reserved2 : 6;
+ u32 cai_cnt : 4;
+ } cai_buf_reg_708;
+
+ struct {
+ u32 cao_read :11;
+ u32 reserved1 : 5;
+ u32 cap_write :11;
+ u32 reserved2 : 6;
+ u32 cao_cnt : 4;
+ } cao_buf_reg_70c;
+
+ struct {
+ u32 media_read :11;
+ u32 reserved1 : 5;
+ u32 media_write :11;
+ u32 reserved2 : 6;
+ u32 media_cnt : 4;
+ } media_buf_reg_710;
+
+ struct {
+ u32 NET_Dest : 2;
+ u32 CAI_Dest : 2;
+ u32 CAO_Dest : 2;
+ u32 MEDIA_Dest : 2;
+ u32 net_ovflow_error : 1;
+ u32 media_ovflow_error : 1;
+ u32 cai_ovflow_error : 1;
+ u32 cao_ovflow_error : 1;
+ u32 ctrl_usb_wan : 1;
+ u32 ctrl_sramdma : 1;
+ u32 ctrl_maximumfill : 1;
+ u32 reserved :17;
+ } sram_dest_reg_714;
+
+ struct {
+ u32 net_cnt :12;
+ u32 reserved1 : 4;
+ u32 net_addr_read : 1;
+ u32 reserved2 : 3;
+ u32 net_addr_write : 1;
+ u32 reserved3 :11;
+ } net_buf_reg_718;
+
+ struct {
+ u32 wan_speed_sig : 2;
+ u32 reserved1 : 6;
+ u32 wan_wait_state : 8;
+ u32 sram_chip : 2;
+ u32 sram_memmap : 2;
+ u32 reserved2 : 4;
+ u32 wan_pkt_frame : 4;
+ u32 reserved3 : 4;
+ } wan_ctrl_reg_71c;
+} flexcop_ibi_value;
+
+#endif
diff --git a/drivers/media/dvb/b2c2/skystar2.c b/drivers/media/dvb/b2c2/skystar2.c
deleted file mode 100644
index acbc4c34f72..00000000000
--- a/drivers/media/dvb/b2c2/skystar2.c
+++ /dev/null
@@ -1,2644 +0,0 @@
-/*
- * skystar2.c - driver for the Technisat SkyStar2 PCI DVB card
- * based on the FlexCopII by B2C2,Inc.
- *
- * Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
- *
- * FIX: DISEQC Tone Burst in flexcop_diseqc_ioctl()
- * FIX: FULL soft DiSEqC for skystar2 (FlexCopII rev 130) VP310 equipped
- * Vincenzo Di Massa, hawk.it at tiscalinet.it
- *
- * Converted to Linux coding style
- * Misc reorganization, polishing, restyling
- * Roberto Ragusa, skystar2-c5b8 at robertoragusa dot it
- *
- * Added hardware filtering support,
- * Niklas Peinecke, peinecke at gdv.uni-hannover.de
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This 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 Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/version.h>
-
-#include <asm/io.h>
-
-#include "dvb_frontend.h"
-
-#include <linux/dvb/frontend.h>
-#include <linux/dvb/dmx.h>
-#include "dvb_demux.h"
-#include "dmxdev.h"
-#include "dvb_filter.h"
-#include "dvbdev.h"
-#include "demux.h"
-#include "dvb_net.h"
-#include "stv0299.h"
-#include "mt352.h"
-#include "mt312.h"
-#include "nxt2002.h"
-
-static int debug;
-static int enable_hw_filters = 2;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Set debugging level (0 = default, 1 = most messages, 2 = all messages).");
-module_param(enable_hw_filters, int, 0444);
-MODULE_PARM_DESC(enable_hw_filters, "enable hardware filters: supported values: 0 (none), 1, 2");
-
-#define dprintk(x...) do { if (debug>=1) printk(x); } while (0)
-#define ddprintk(x...) do { if (debug>=2) printk(x); } while (0)
-
-#define SIZE_OF_BUF_DMA1 0x3ac00
-#define SIZE_OF_BUF_DMA2 0x758
-
-#define MAX_N_HW_FILTERS (6+32)
-#define N_PID_SLOTS 256
-
-struct dmaq {
- u32 bus_addr;
- u32 head;
- u32 tail;
- u32 buffer_size;
- u8 *buffer;
-};
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
-#define __iomem
-#endif
-
-struct adapter {
- struct pci_dev *pdev;
-
- u8 card_revision;
- u32 b2c2_revision;
- u32 pid_filter_max;
- u32 mac_filter_max;
- u32 irq;
- void __iomem *io_mem;
- unsigned long io_port;
- u8 mac_addr[8];
- u32 dw_sram_type;
-
- struct dvb_adapter dvb_adapter;
- struct dvb_demux demux;
- struct dmxdev dmxdev;
- struct dmx_frontend hw_frontend;
- struct dmx_frontend mem_frontend;
- struct i2c_adapter i2c_adap;
- struct dvb_net dvbnet;
-
- struct semaphore i2c_sem;
-
- struct dmaq dmaq1;
- struct dmaq dmaq2;
-
- u32 dma_ctrl;
- u32 dma_status;
-
- int capturing;
-
- spinlock_t lock;
-
- int useable_hw_filters;
- u16 hw_pids[MAX_N_HW_FILTERS];
- u16 pid_list[N_PID_SLOTS];
- int pid_rc[N_PID_SLOTS]; // ref counters for the pids
- int pid_count;
- int whole_bandwidth_count;
- u32 mac_filter;
-
- struct dvb_frontend* fe;
- int (*fe_sleep)(struct dvb_frontend* fe);
-};
-
-#define write_reg_dw(adapter,reg,value) writel(value, adapter->io_mem + reg)
-#define read_reg_dw(adapter,reg) readl(adapter->io_mem + reg)
-
-static void write_reg_bitfield(struct adapter *adapter, u32 reg, u32 zeromask, u32 orvalue)
-{
- u32 tmp;
-
- tmp = read_reg_dw(adapter, reg);
- tmp = (tmp & ~zeromask) | orvalue;
- write_reg_dw(adapter, reg, tmp);
-}
-
-/* i2c functions */
-static int i2c_main_write_for_flex2(struct adapter *adapter, u32 command, u8 *buf, int retries)
-{
- int i;
- u32 value;
-
- write_reg_dw(adapter, 0x100, 0);
- write_reg_dw(adapter, 0x100, command);
-
- for (i = 0; i < retries; i++) {
- value = read_reg_dw(adapter, 0x100);
-
- if ((value & 0x40000000) == 0) {
- if ((value & 0x81000000) == 0x80000000) {
- if (buf != 0)
- *buf = (value >> 0x10) & 0xff;
-
- return 1;
- }
- } else {
- write_reg_dw(adapter, 0x100, 0);
- write_reg_dw(adapter, 0x100, command);
- }
- }
-
- return 0;
-}
-
-/* device = 0x10000000 for tuner, 0x20000000 for eeprom */
-static void i2c_main_setup(u32 device, u32 chip_addr, u8 op, u8 addr, u32 value, u32 len, u32 *command)
-{
- *command = device | ((len - 1) << 26) | (value << 16) | (addr << 8) | chip_addr;
-
- if (op != 0)
- *command = *command | 0x03000000;
- else
- *command = *command | 0x01000000;
-}
-
-static int flex_i2c_read4(struct adapter *adapter, u32 device, u32 chip_addr, u16 addr, u8 *buf, u8 len)
-{
- u32 command;
- u32 value;
-
- int result, i;
-
- i2c_main_setup(device, chip_addr, 1, addr, 0, len, &command);
-
- result = i2c_main_write_for_flex2(adapter, command, buf, 100000);
-
- if ((result & 0xff) != 0) {
- if (len > 1) {
- value = read_reg_dw(adapter, 0x104);
-
- for (i = 1; i < len; i++) {
- buf[i] = value & 0xff;
- value = value >> 8;
- }
- }
- }
-
- return result;
-}
-
-static int flex_i2c_write4(struct adapter *adapter, u32 device, u32 chip_addr, u32 addr, u8 *buf, u8 len)
-{
- u32 command;
- u32 value;
- int i;
-
- if (len > 1) {
- value = 0;
-
- for (i = len; i > 1; i--) {
- value = value << 8;
- value = value | buf[i - 1];
- }
-
- write_reg_dw(adapter, 0x104, value);
- }
-
- i2c_main_setup(device, chip_addr, 0, addr, buf[0], len, &command);
-
- return i2c_main_write_for_flex2(adapter, command, NULL, 100000);
-}
-
-static void fixchipaddr(u32 device, u32 bus, u32 addr, u32 *ret)
-{
- if (device == 0x20000000)
- *ret = bus | ((addr >> 8) & 3);
- else
- *ret = bus;
-}
-
-static u32 flex_i2c_read(struct adapter *adapter, u32 device, u32 bus, u32 addr, u8 *buf, u32 len)
-{
- u32 chipaddr;
- u32 bytes_to_transfer;
- u8 *start;
-
- ddprintk("%s:\n", __FUNCTION__);
-
- start = buf;
-
- while (len != 0) {
- bytes_to_transfer = len;
-
- if (bytes_to_transfer > 4)
- bytes_to_transfer = 4;
-
- fixchipaddr(device, bus, addr, &chipaddr);
-
- if (flex_i2c_read4(adapter, device, chipaddr, addr, buf, bytes_to_transfer) == 0)
- return buf - start;
-
- buf = buf + bytes_to_transfer;
- addr = addr + bytes_to_transfer;
- len = len - bytes_to_transfer;
- };
-
- return buf - start;
-}
-
-static u32 flex_i2c_write(struct adapter *adapter, u32 device, u32 bus, u32 addr, u8 *buf, u32 len)
-{
- u32 chipaddr;
- u32 bytes_to_transfer;
- u8 *start;
-
- ddprintk("%s:\n", __FUNCTION__);
-
- start = buf;
-
- while (len != 0) {
- bytes_to_transfer = len;
-
- if (bytes_to_transfer > 4)
- bytes_to_transfer = 4;
-
- fixchipaddr(device, bus, addr, &chipaddr);
-
- if (flex_i2c_write4(adapter, device, chipaddr, addr, buf, bytes_to_transfer) == 0)
- return buf - start;
-
- buf = buf + bytes_to_transfer;
- addr = addr + bytes_to_transfer;
- len = len - bytes_to_transfer;
- }
-
- return buf - start;
-}
-
-static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msgs, int num)
-{
- struct adapter *tmp = i2c_get_adapdata(adapter);
- int i, ret = 0;
-
- if (down_interruptible(&tmp->i2c_sem))
- return -ERESTARTSYS;
-
- ddprintk("%s: %d messages to transfer\n", __FUNCTION__, num);
-
- for (i = 0; i < num; i++) {
- ddprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i,
- msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len);
- }
-
- // read command
- if ((num == 2) && (msgs[0].flags == 0) && (msgs[1].flags == I2C_M_RD) && (msgs[0].buf != NULL) && (msgs[1].buf != NULL)) {
-
- ret = flex_i2c_read(tmp, 0x10000000, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len);
-
- up(&tmp->i2c_sem);
-
- if (ret != msgs[1].len) {
- dprintk("%s: read error !\n", __FUNCTION__);
-
- for (i = 0; i < 2; i++) {
- dprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i,
- msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len);
- }
-
- return -EREMOTEIO;
- }
-
- return num;
- }
- // write command
- for (i = 0; i < num; i++) {
-
- if ((msgs[i].flags != 0) || (msgs[i].buf == NULL) || (msgs[i].len < 2))
- return -EINVAL;
-
- ret = flex_i2c_write(tmp, 0x10000000, msgs[i].addr, msgs[i].buf[0], &msgs[i].buf[1], msgs[i].len - 1);
-
- up(&tmp->i2c_sem);
-
- if (ret != msgs[0].len - 1) {
- dprintk("%s: write error %i !\n", __FUNCTION__, ret);
-
- dprintk("message %d: flags=0x%x, addr=0x%x, buf[0]=0x%x, len=%d \n", i,
- msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len);
-
- return -EREMOTEIO;
- }
-
- return num;
- }
-
- printk("%s: unknown command format !\n", __FUNCTION__);
-
- return -EINVAL;
-}
-
-/* SRAM (Skystar2 rev2.3 has one "ISSI IS61LV256" chip on board,
- but it seems that FlexCopII can work with more than one chip) */
-static void sram_set_net_dest(struct adapter *adapter, u8 dest)
-{
- u32 tmp;
-
- udelay(1000);
-
- tmp = (read_reg_dw(adapter, 0x714) & 0xfffffffc) | (dest & 3);
-
- udelay(1000);
-
- write_reg_dw(adapter, 0x714, tmp);
- write_reg_dw(adapter, 0x714, tmp);
-
- udelay(1000);
-
- /* return value is never used? */
-/* return tmp; */
-}
-
-static void sram_set_cai_dest(struct adapter *adapter, u8 dest)
-{
- u32 tmp;
-
- udelay(1000);
-
- tmp = (read_reg_dw(adapter, 0x714) & 0xfffffff3) | ((dest & 3) << 2);
-
- udelay(1000);
- udelay(1000);
-
- write_reg_dw(adapter, 0x714, tmp);
- write_reg_dw(adapter, 0x714, tmp);
-
- udelay(1000);
-
- /* return value is never used? */
-/* return tmp; */
-}
-
-static void sram_set_cao_dest(struct adapter *adapter, u8 dest)
-{
- u32 tmp;
-
- udelay(1000);
-
- tmp = (read_reg_dw(adapter, 0x714) & 0xffffffcf) | ((dest & 3) << 4);
-
- udelay(1000);
- udelay(1000);
-
- write_reg_dw(adapter, 0x714, tmp);
- write_reg_dw(adapter, 0x714, tmp);
-
- udelay(1000);
-
- /* return value is never used? */
-/* return tmp; */
-}
-
-static void sram_set_media_dest(struct adapter *adapter, u8 dest)
-{
- u32 tmp;
-
- udelay(1000);
-
- tmp = (read_reg_dw(adapter, 0x714) & 0xffffff3f) | ((dest & 3) << 6);
-
- udelay(1000);
- udelay(1000);
-
- write_reg_dw(adapter, 0x714, tmp);
- write_reg_dw(adapter, 0x714, tmp);
-
- udelay(1000);
-
- /* return value is never used? */
-/* return tmp; */
-}
-
-/* SRAM memory is accessed through a buffer register in the FlexCop
- chip (0x700). This register has the following structure:
- bits 0-14 : address
- bit 15 : read/write flag
- bits 16-23 : 8-bit word to write
- bits 24-27 : = 4
- bits 28-29 : memory bank selector
- bit 31 : busy flag
-*/
-static void flex_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
-{
- int i, retries;
- u32 command;
-
- for (i = 0; i < len; i++) {
- command = bank | addr | 0x04000000 | (*buf << 0x10);
-
- retries = 2;
-
- while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
- mdelay(1);
- retries--;
- };
-
- if (retries == 0)
- printk("%s: SRAM timeout\n", __FUNCTION__);
-
- write_reg_dw(adapter, 0x700, command);
-
- buf++;
- addr++;
- }
-}
-
-static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
-{
- int i, retries;
- u32 command, value;
-
- for (i = 0; i < len; i++) {
- command = bank | addr | 0x04008000;
-
- retries = 10000;
-
- while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
- mdelay(1);
- retries--;
- };
-
- if (retries == 0)
- printk("%s: SRAM timeout\n", __FUNCTION__);
-
- write_reg_dw(adapter, 0x700, command);
-
- retries = 10000;
-
- while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
- mdelay(1);
- retries--;
- };
-
- if (retries == 0)
- printk("%s: SRAM timeout\n", __FUNCTION__);
-
- value = read_reg_dw(adapter, 0x700) >> 0x10;
-
- *buf = (value & 0xff);
-
- addr++;
- buf++;
- }
-}
-
-static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
-{
- u32 bank;
-
- bank = 0;
-
- if (adapter->dw_sram_type == 0x20000) {
- bank = (addr & 0x18000) << 0x0d;
- }
-
- if (adapter->dw_sram_type == 0x00000) {
- if ((addr >> 0x0f) == 0)
- bank = 0x20000000;
- else
- bank = 0x10000000;
- }
-
- flex_sram_write(adapter, bank, addr & 0x7fff, buf, len);
-}
-
-static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
-{
- u32 bank;
-
- bank = 0;
-
- if (adapter->dw_sram_type == 0x20000) {
- bank = (addr & 0x18000) << 0x0d;
- }
-
- if (adapter->dw_sram_type == 0x00000) {
- if ((addr >> 0x0f) == 0)
- bank = 0x20000000;
- else
- bank = 0x10000000;
- }
-
- flex_sram_read(adapter, bank, addr & 0x7fff, buf, len);
-}
-
-static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
-{
- u32 length;
-
- while (len != 0) {
- length = len;
-
- // check if the address range belongs to the same
- // 32K memory chip. If not, the data is read from
- // one chip at a time.
- if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
- length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
- }
-
- sram_read_chunk(adapter, addr, buf, length);
-
- addr = addr + length;
- buf = buf + length;
- len = len - length;
- }
-}
-
-static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
-{
- u32 length;
-
- while (len != 0) {
- length = len;
-
- // check if the address range belongs to the same
- // 32K memory chip. If not, the data is written to
- // one chip at a time.
- if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
- length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
- }
-
- sram_write_chunk(adapter, addr, buf, length);
-
- addr = addr + length;
- buf = buf + length;
- len = len - length;
- }
-}
-
-static void sram_set_size(struct adapter *adapter, u32 mask)
-{
- write_reg_dw(adapter, 0x71c, (mask | (~0x30000 & read_reg_dw(adapter, 0x71c))));
-}
-
-static void sram_init(struct adapter *adapter)
-{
- u32 tmp;
-
- tmp = read_reg_dw(adapter, 0x71c);
-
- write_reg_dw(adapter, 0x71c, 1);
-
- if (read_reg_dw(adapter, 0x71c) != 0) {
- write_reg_dw(adapter, 0x71c, tmp);
-
- adapter->dw_sram_type = tmp & 0x30000;
-
- ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type);
-
- } else {
-
- adapter->dw_sram_type = 0x10000;
-
- ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type);
- }
-
- /* return value is never used? */
-/* return adapter->dw_sram_type; */
-}
-
-static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
-{
- u8 tmp1, tmp2;
-
- dprintk("%s: mask = %x, addr = %x\n", __FUNCTION__, mask, addr);
-
- sram_set_size(adapter, mask);
- sram_init(adapter);
-
- tmp2 = 0xa5;
- tmp1 = 0x4f;
-
- sram_write(adapter, addr, &tmp2, 1);
- sram_write(adapter, addr + 4, &tmp1, 1);
-
- tmp2 = 0;
-
- mdelay(20);
-
- sram_read(adapter, addr, &tmp2, 1);
- sram_read(adapter, addr, &tmp2, 1);
-
- dprintk("%s: wrote 0xa5, read 0x%2x\n", __FUNCTION__, tmp2);
-
- if (tmp2 != 0xa5)
- return 0;
-
- tmp2 = 0x5a;
- tmp1 = 0xf4;
-
- sram_write(adapter, addr, &tmp2, 1);
- sram_write(adapter, addr + 4, &tmp1, 1);
-
- tmp2 = 0;
-
- mdelay(20);
-
- sram_read(adapter, addr, &tmp2, 1);
- sram_read(adapter, addr, &tmp2, 1);
-
- dprintk("%s: wrote 0x5a, read 0x%2x\n", __FUNCTION__, tmp2);
-
- if (tmp2 != 0x5a)
- return 0;
-
- return 1;
-}
-
-static u32 sram_length(struct adapter *adapter)
-{
- if (adapter->dw_sram_type == 0x10000)
- return 32768; // 32K
- if (adapter->dw_sram_type == 0x00000)
- return 65536; // 64K
- if (adapter->dw_sram_type == 0x20000)
- return 131072; // 128K
-
- return 32768; // 32K
-}
-
-/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory.
- - for 128K there are 4x32K chips at bank 0,1,2,3.
- - for 64K there are 2x32K chips at bank 1,2.
- - for 32K there is one 32K chip at bank 0.
-
- FlexCop works only with one bank at a time. The bank is selected
- by bits 28-29 of the 0x700 register.
-
- bank 0 covers addresses 0x00000-0x07fff
- bank 1 covers addresses 0x08000-0x0ffff
- bank 2 covers addresses 0x10000-0x17fff
- bank 3 covers addresses 0x18000-0x1ffff
-*/
-static int sram_detect_for_flex2(struct adapter *adapter)
-{
- u32 tmp, tmp2, tmp3;
-
- dprintk("%s:\n", __FUNCTION__);
-
- tmp = read_reg_dw(adapter, 0x208);
- write_reg_dw(adapter, 0x208, 0);
-
- tmp2 = read_reg_dw(adapter, 0x71c);
-
- dprintk("%s: tmp2 = %x\n", __FUNCTION__, tmp2);
-
- write_reg_dw(adapter, 0x71c, 1);
-
- tmp3 = read_reg_dw(adapter, 0x71c);
-
- dprintk("%s: tmp3 = %x\n", __FUNCTION__, tmp3);
-
- write_reg_dw(adapter, 0x71c, tmp2);
-
- // check for internal SRAM ???
- tmp3--;
- if (tmp3 != 0) {
- sram_set_size(adapter, 0x10000);
- sram_init(adapter);
- write_reg_dw(adapter, 0x208, tmp);
-
- dprintk("%s: sram size = 32K\n", __FUNCTION__);
-
- return 32;
- }
-
- if (sram_test_location(adapter, 0x20000, 0x18000) != 0) {
- sram_set_size(adapter, 0x20000);
- sram_init(adapter);
- write_reg_dw(adapter, 0x208, tmp);
-
- dprintk("%s: sram size = 128K\n", __FUNCTION__);
-
- return 128;
- }
-
- if (sram_test_location(adapter, 0x00000, 0x10000) != 0) {
- sram_set_size(adapter, 0x00000);
- sram_init(adapter);
- write_reg_dw(adapter, 0x208, tmp);
-
- dprintk("%s: sram size = 64K\n", __FUNCTION__);
-
- return 64;
- }
-
- if (sram_test_location(adapter, 0x10000, 0x00000) != 0) {
- sram_set_size(adapter, 0x10000);
- sram_init(adapter);
- write_reg_dw(adapter, 0x208, tmp);
-
- dprintk("%s: sram size = 32K\n", __FUNCTION__);
-
- return 32;
- }
-
- sram_set_size(adapter, 0x10000);
- sram_init(adapter);
- write_reg_dw(adapter, 0x208, tmp);
-
- dprintk("%s: SRAM detection failed. Set to 32K \n", __FUNCTION__);
-
- return 0;
-}
-
-static void sll_detect_sram_size(struct adapter *adapter)
-{
- sram_detect_for_flex2(adapter);
-}
-
-/* EEPROM (Skystar2 has one "24LC08B" chip on board) */
-/*
-static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len)
-{
- return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len);
-}
-*/
-
-static int eeprom_read(struct adapter *adapter, u16 addr, u8 *buf, u16 len)
-{
- return flex_i2c_read(adapter, 0x20000000, 0x50, addr, buf, len);
-}
-
-static u8 calc_lrc(u8 *buf, int len)
-{
- int i;
- u8 sum;
-
- sum = 0;
-
- for (i = 0; i < len; i++)
- sum = sum ^ buf[i];
-
- return sum;
-}
-
-static int eeprom_lrc_read(struct adapter *adapter, u32 addr, u32 len, u8 *buf, int retries)
-{
- int i;
-
- for (i = 0; i < retries; i++) {
- if (eeprom_read(adapter, addr, buf, len) == len) {
- if (calc_lrc(buf, len - 1) == buf[len - 1])
- return 1;
- }
- }
-
- return 0;
-}
-
-/*
-static int eeprom_lrc_write(struct adapter *adapter, u32 addr, u32 len, u8 *wbuf, u8 *rbuf, int retries)
-{
- int i;
-
- for (i = 0; i < retries; i++) {
- if (eeprom_write(adapter, addr, wbuf, len) == len) {
- if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1)
- return 1;
- }
- }
-
- return 0;
-}
-*/
-
-
-/* These functions could be used to unlock SkyStar2 cards. */
-
-/*
-static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len)
-{
- u8 rbuf[20];
- u8 wbuf[20];
-
- if (len != 16)
- return 0;
-
- memcpy(wbuf, key, len);
-
- wbuf[16] = 0;
- wbuf[17] = 0;
- wbuf[18] = 0;
- wbuf[19] = calc_lrc(wbuf, 19);
-
- return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4);
-}
-
-static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len)
-{
- u8 buf[20];
-
- if (len != 16)
- return 0;
-
- if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0)
- return 0;
-
- memcpy(key, buf, len);
-
- return 1;
-}
-*/
-
-static int eeprom_get_mac_addr(struct adapter *adapter, char type, u8 *mac)
-{
- u8 tmp[8];
-
- if (eeprom_lrc_read(adapter, 0x3f8, 8, tmp, 4) != 0) {
- if (type != 0) {
- mac[0] = tmp[0];
- mac[1] = tmp[1];
- mac[2] = tmp[2];
- mac[3] = 0xfe;
- mac[4] = 0xff;
- mac[5] = tmp[3];
- mac[6] = tmp[4];
- mac[7] = tmp[5];
-
- } else {
-
- mac[0] = tmp[0];
- mac[1] = tmp[1];
- mac[2] = tmp[2];
- mac[3] = tmp[3];
- mac[4] = tmp[4];
- mac[5] = tmp[5];
- }
-
- return 1;
-
- } else {
-
- if (type == 0) {
- memset(mac, 0, 6);
-
- } else {
-
- memset(mac, 0, 8);
- }
-
- return 0;
- }
-}
-
-/*
-static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac)
-{
- u8 tmp[8];
-
- if (type != 0) {
- tmp[0] = mac[0];
- tmp[1] = mac[1];
- tmp[2] = mac[2];
- tmp[3] = mac[5];
- tmp[4] = mac[6];
- tmp[5] = mac[7];
-
- } else {
-
- tmp[0] = mac[0];
- tmp[1] = mac[1];
- tmp[2] = mac[2];
- tmp[3] = mac[3];
- tmp[4] = mac[4];
- tmp[5] = mac[5];
- }
-
- tmp[6] = 0;
- tmp[7] = calc_lrc(tmp, 7);
-
- if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8)
- return 1;
-
- return 0;
-}
-*/
-
-/* PID filter */
-
-/* every flexcop has 6 "lower" hw PID filters */
-/* these are enabled by setting bits 0-5 of 0x208 */
-/* for the 32 additional filters we have to select one */
-/* of them through 0x310 and modify through 0x314 */
-/* op: 0=disable, 1=enable */
-static void filter_enable_hw_filter(struct adapter *adapter, int id, u8 op)
-{
- dprintk("%s: id=%d op=%d\n", __FUNCTION__, id, op);
- if (id <= 5) {
- u32 mask = (0x00000001 << id);
- write_reg_bitfield(adapter, 0x208, mask, op ? mask : 0);
- } else {
- /* select */
- write_reg_bitfield(adapter, 0x310, 0x1f, (id - 6) & 0x1f);
- /* modify */
- write_reg_bitfield(adapter, 0x314, 0x00006000, op ? 0x00004000 : 0);
- }
-}
-
-/* this sets the PID that should pass the specified filter */
-static void pid_set_hw_pid(struct adapter *adapter, int id, u16 pid)
-{
- dprintk("%s: id=%d pid=%d\n", __FUNCTION__, id, pid);
- if (id <= 5) {
- u32 adr = 0x300 + ((id & 6) << 1);
- int shift = (id & 1) ? 16 : 0;
- dprintk("%s: id=%d addr=%x %c pid=%d\n", __FUNCTION__, id, adr, (id & 1) ? 'h' : 'l', pid);
- write_reg_bitfield(adapter, adr, (0x7fff) << shift, (pid & 0x1fff) << shift);
- } else {
- /* select */
- write_reg_bitfield(adapter, 0x310, 0x1f, (id - 6) & 0x1f);
- /* modify */
- write_reg_bitfield(adapter, 0x314, 0x1fff, pid & 0x1fff);
- }
-}
-
-
-/*
-static void filter_enable_null_filter(struct adapter *adapter, u32 op)
-{
- dprintk("%s: op=%x\n", __FUNCTION__, op);
-
- write_reg_bitfield(adapter, 0x208, 0x00000040, op?0x00000040:0);
-}
-*/
-
-static void filter_enable_mask_filter(struct adapter *adapter, u32 op)
-{
- dprintk("%s: op=%x\n", __FUNCTION__, op);
-
- write_reg_bitfield(adapter, 0x208, 0x00000080, op ? 0x00000080 : 0);
-}
-
-
-static void ctrl_enable_mac(struct adapter *adapter, u32 op)
-{
- write_reg_bitfield(adapter, 0x208, 0x00004000, op ? 0x00004000 : 0);
-}
-
-static int ca_set_mac_dst_addr_filter(struct adapter *adapter, u8 *mac)
-{
- u32 tmp1, tmp2;
-
- tmp1 = (mac[3] << 0x18) | (mac[2] << 0x10) | (mac[1] << 0x08) | mac[0];
- tmp2 = (mac[5] << 0x08) | mac[4];
-
- write_reg_dw(adapter, 0x418, tmp1);
- write_reg_dw(adapter, 0x41c, tmp2);
-
- return 0;
-}
-
-/*
-static void set_ignore_mac_filter(struct adapter *adapter, u8 op)
-{
- if (op != 0) {
- write_reg_bitfield(adapter, 0x208, 0x00004000, 0);
- adapter->mac_filter = 1;
- } else {
- if (adapter->mac_filter != 0) {
- adapter->mac_filter = 0;
- write_reg_bitfield(adapter, 0x208, 0x00004000, 0x00004000);
- }
- }
-}
-*/
-
-/*
-static void check_null_filter_enable(struct adapter *adapter)
-{
- filter_enable_null_filter(adapter, 1);
- filter_enable_mask_filter(adapter, 1);
-}
-*/
-
-static void pid_set_group_pid(struct adapter *adapter, u16 pid)
-{
- u32 value;
-
- dprintk("%s: pid=%x\n", __FUNCTION__, pid);
- value = (pid & 0x3fff) | (read_reg_dw(adapter, 0x30c) & 0xffff0000);
- write_reg_dw(adapter, 0x30c, value);
-}
-
-static void pid_set_group_mask(struct adapter *adapter, u16 pid)
-{
- u32 value;
-
- dprintk("%s: pid=%x\n", __FUNCTION__, pid);
- value = ((pid & 0x3fff) << 0x10) | (read_reg_dw(adapter, 0x30c) & 0xffff);
- write_reg_dw(adapter, 0x30c, value);
-}
-
-/*
-static int pid_get_group_pid(struct adapter *adapter)
-{
- return read_reg_dw(adapter, 0x30c) & 0x00001fff;
-}
-
-static int pid_get_group_mask(struct adapter *adapter)
-{
- return (read_reg_dw(adapter, 0x30c) >> 0x10)& 0x00001fff;
-}
-*/
-
-/*
-static void reset_hardware_pid_filter(struct adapter *adapter)
-{
- pid_set_stream1_pid(adapter, 0x1fff);
-
- pid_set_stream2_pid(adapter, 0x1fff);
- filter_enable_stream2_filter(adapter, 0);
-
- pid_set_pcr_pid(adapter, 0x1fff);
- filter_enable_pcr_filter(adapter, 0);
-
- pid_set_pmt_pid(adapter, 0x1fff);
- filter_enable_pmt_filter(adapter, 0);
-
- pid_set_ecm_pid(adapter, 0x1fff);
- filter_enable_ecm_filter(adapter, 0);
-
- pid_set_emm_pid(adapter, 0x1fff);
- filter_enable_emm_filter(adapter, 0);
-}
-*/
-
-static void init_pids(struct adapter *adapter)
-{
- int i;
-
- adapter->pid_count = 0;
- adapter->whole_bandwidth_count = 0;
- for (i = 0; i < adapter->useable_hw_filters; i++) {
- dprintk("%s: setting filter %d to 0x1fff\n", __FUNCTION__, i);
- adapter->hw_pids[i] = 0x1fff;
- pid_set_hw_pid(adapter, i, 0x1fff);
-}
-
- pid_set_group_pid(adapter, 0);
- pid_set_group_mask(adapter, 0x1fe0);
-}
-
-static void open_whole_bandwidth(struct adapter *adapter)
-{
- dprintk("%s:\n", __FUNCTION__);
- pid_set_group_pid(adapter, 0);
- pid_set_group_mask(adapter, 0);
-/*
- filter_enable_mask_filter(adapter, 1);
-*/
-}
-
-static void close_whole_bandwidth(struct adapter *adapter)
-{
- dprintk("%s:\n", __FUNCTION__);
- pid_set_group_pid(adapter, 0);
- pid_set_group_mask(adapter, 0x1fe0);
-/*
- filter_enable_mask_filter(adapter, 1);
-*/
-}
-
-static void whole_bandwidth_inc(struct adapter *adapter)
-{
- if (adapter->whole_bandwidth_count++ == 0)
- open_whole_bandwidth(adapter);
-}
-
-static void whole_bandwidth_dec(struct adapter *adapter)
-{
- if (--adapter->whole_bandwidth_count <= 0)
- close_whole_bandwidth(adapter);
-}
-
-/* The specified PID has to be let through the
- hw filters.
- We try to allocate an hardware filter and open whole
- bandwidth when allocation is impossible.
- All pids<=0x1f pass through the group filter.
- Returns 1 on success, -1 on error */
-static int add_hw_pid(struct adapter *adapter, u16 pid)
-{
- int i;
-
- dprintk("%s: pid=%d\n", __FUNCTION__, pid);
-
- if (pid <= 0x1f)
- return 1;
-
- /* we can't use a filter for 0x2000, so no search */
- if (pid != 0x2000) {
- /* find an unused hardware filter */
- for (i = 0; i < adapter->useable_hw_filters; i++) {
- dprintk("%s: pid=%d searching slot=%d\n", __FUNCTION__, pid, i);
- if (adapter->hw_pids[i] == 0x1fff) {
- dprintk("%s: pid=%d slot=%d\n", __FUNCTION__, pid, i);
- adapter->hw_pids[i] = pid;
- pid_set_hw_pid(adapter, i, pid);
- filter_enable_hw_filter(adapter, i, 1);
- return 1;
- }
- }
- }
- /* if we have not used a filter, this pid depends on whole bandwidth */
- dprintk("%s: pid=%d whole_bandwidth\n", __FUNCTION__, pid);
- whole_bandwidth_inc(adapter);
- return 1;
- }
-
-/* returns -1 if the pid was not present in the filters */
-static int remove_hw_pid(struct adapter *adapter, u16 pid)
-{
- int i;
-
- dprintk("%s: pid=%d\n", __FUNCTION__, pid);
-
- if (pid <= 0x1f)
- return 1;
-
- /* we can't use a filter for 0x2000, so no search */
- if (pid != 0x2000) {
- for (i = 0; i < adapter->useable_hw_filters; i++) {
- dprintk("%s: pid=%d searching slot=%d\n", __FUNCTION__, pid, i);
- if (adapter->hw_pids[i] == pid) { // find the pid slot
- dprintk("%s: pid=%d slot=%d\n", __FUNCTION__, pid, i);
- adapter->hw_pids[i] = 0x1fff;
- pid_set_hw_pid(adapter, i, 0x1fff);
- filter_enable_hw_filter(adapter, i, 0);
- return 1;
- }
- }
- }
- /* if we have not used a filter, this pid depended on whole bandwith */
- dprintk("%s: pid=%d whole_bandwidth\n", __FUNCTION__, pid);
- whole_bandwidth_dec(adapter);
- return 1;
- }
-
-/* Adds a PID to the filters.
- Adding a pid more than once is possible, we keep reference counts.
- Whole stream available through pid==0x2000.
- Returns 1 on success, -1 on error */
-static int add_pid(struct adapter *adapter, u16 pid)
-{
- int i;
-
- dprintk("%s: pid=%d\n", __FUNCTION__, pid);
-
- if (pid > 0x1ffe && pid != 0x2000)
- return -1;
-
- // check if the pid is already present
- for (i = 0; i < adapter->pid_count; i++)
- if (adapter->pid_list[i] == pid) {
- adapter->pid_rc[i]++; // increment ref counter
- return 1;
- }
-
- if (adapter->pid_count == N_PID_SLOTS)
- return -1; // no more pids can be added
- adapter->pid_list[adapter->pid_count] = pid; // register pid
- adapter->pid_rc[adapter->pid_count] = 1;
- adapter->pid_count++;
- // hardware setting
- add_hw_pid(adapter, pid);
-
- return 1;
- }
-
-/* Removes a PID from the filters. */
-static int remove_pid(struct adapter *adapter, u16 pid)
-{
- int i;
-
- dprintk("%s: pid=%d\n", __FUNCTION__, pid);
-
- if (pid > 0x1ffe && pid != 0x2000)
- return -1;
-
- // check if the pid is present (it must be!)
- for (i = 0; i < adapter->pid_count; i++) {
- if (adapter->pid_list[i] == pid) {
- adapter->pid_rc[i]--;
- if (adapter->pid_rc[i] <= 0) {
- // remove from the list
- adapter->pid_count--;
- adapter->pid_list[i]=adapter->pid_list[adapter->pid_count];
- adapter->pid_rc[i] = adapter->pid_rc[adapter->pid_count];
- // hardware setting
- remove_hw_pid(adapter, pid);
- }
- return 1;
- }
- }
-
- return -1;
-}
-
-
-/* dma & irq */
-static void ctrl_enable_smc(struct adapter *adapter, u32 op)
-{
- write_reg_bitfield(adapter, 0x208, 0x00000800, op ? 0x00000800 : 0);
-}
-
-static void dma_enable_disable_irq(struct adapter *adapter, u32 flag1, u32 flag2, u32 flag3)
-{
- adapter->dma_ctrl = adapter->dma_ctrl & 0x000f0000;
-
- if (flag1 == 0) {
- if (flag2 == 0)
- adapter->dma_ctrl = adapter->dma_ctrl & ~0x00010000;
- else
- adapter->dma_ctrl = adapter->dma_ctrl | 0x00010000;
-
- if (flag3 == 0)
- adapter->dma_ctrl = adapter->dma_ctrl & ~0x00020000;
- else
- adapter->dma_ctrl = adapter->dma_ctrl | 0x00020000;
-
- } else {
-
- if (flag2 == 0)
- adapter->dma_ctrl = adapter->dma_ctrl & ~0x00040000;
- else
- adapter->dma_ctrl = adapter->dma_ctrl | 0x00040000;
-
- if (flag3 == 0)
- adapter->dma_ctrl = adapter->dma_ctrl & ~0x00080000;
- else
- adapter->dma_ctrl = adapter->dma_ctrl | 0x00080000;
- }
-}
-
-static void irq_dma_enable_disable_irq(struct adapter *adapter, u32 op)
-{
- u32 value;
-
- value = read_reg_dw(adapter, 0x208) & 0xfff0ffff;
-
- if (op != 0)
- value = value | (adapter->dma_ctrl & 0x000f0000);
-
- write_reg_dw(adapter, 0x208, value);
-}
-
-/* FlexCopII has 2 dma channels. DMA1 is used to transfer TS data to
- system memory.
-
- The DMA1 buffer is divided in 2 subbuffers of equal size.
- FlexCopII will transfer TS data to one subbuffer, signal an interrupt
- when the subbuffer is full and continue fillig the second subbuffer.
-
- For DMA1:
- subbuffer size in 32-bit words is stored in the first 24 bits of
- register 0x004. The last 8 bits of register 0x004 contain the number
- of subbuffers.
-
- the first 30 bits of register 0x000 contain the address of the first
- subbuffer. The last 2 bits contain 0, when dma1 is disabled and 1,
- when dma1 is enabled.
-
- the first 30 bits of register 0x00c contain the address of the second
- subbuffer. the last 2 bits contain 1.
-
- register 0x008 will contain the address of the subbuffer that was filled
- with TS data, when FlexCopII will generate an interrupt.
-
- For DMA2:
- subbuffer size in 32-bit words is stored in the first 24 bits of
- register 0x014. The last 8 bits of register 0x014 contain the number
- of subbuffers.
-
- the first 30 bits of register 0x010 contain the address of the first
- subbuffer. The last 2 bits contain 0, when dma1 is disabled and 1,
- when dma1 is enabled.
-
- the first 30 bits of register 0x01c contain the address of the second
- subbuffer. the last 2 bits contain 1.
-
- register 0x018 contains the address of the subbuffer that was filled
- with TS data, when FlexCopII generates an interrupt.
-*/
-static int dma_init_dma(struct adapter *adapter, u32 dma_channel)
-{
- u32 subbuffers, subbufsize, subbuf0, subbuf1;
-
- if (dma_channel == 0) {
- dprintk("%s: Initializing DMA1 channel\n", __FUNCTION__);
-
- subbuffers = 2;
-
- subbufsize = (((adapter->dmaq1.buffer_size / 2) / 4) << 8) | subbuffers;
-
- subbuf0 = adapter->dmaq1.bus_addr & 0xfffffffc;
-
- subbuf1 = ((adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) & 0xfffffffc) | 1;
-
- dprintk("%s: first subbuffer address = 0x%x\n", __FUNCTION__, subbuf0);
- udelay(1000);
- write_reg_dw(adapter, 0x000, subbuf0);
-
- dprintk("%s: subbuffer size = 0x%x\n", __FUNCTION__, (subbufsize >> 8) * 4);
- udelay(1000);
- write_reg_dw(adapter, 0x004, subbufsize);
-
- dprintk("%s: second subbuffer address = 0x%x\n", __FUNCTION__, subbuf1);
- udelay(1000);
- write_reg_dw(adapter, 0x00c, subbuf1);
-
- dprintk("%s: counter = 0x%x\n", __FUNCTION__, adapter->dmaq1.bus_addr & 0xfffffffc);
- write_reg_dw(adapter, 0x008, adapter->dmaq1.bus_addr & 0xfffffffc);
- udelay(1000);
-
- dma_enable_disable_irq(adapter, 0, 1, subbuffers ? 1 : 0);
-
- irq_dma_enable_disable_irq(adapter, 1);
-
- sram_set_media_dest(adapter, 1);
- sram_set_net_dest(adapter, 1);
- sram_set_cai_dest(adapter, 2);
- sram_set_cao_dest(adapter, 2);
- }
-
- if (dma_channel == 1) {
- dprintk("%s: Initializing DMA2 channel\n", __FUNCTION__);
-
- subbuffers = 2;
-
- subbufsize = (((adapter->dmaq2.buffer_size / 2) / 4) << 8) | subbuffers;
-
- subbuf0 = adapter->dmaq2.bus_addr & 0xfffffffc;
-
- subbuf1 = ((adapter->dmaq2.bus_addr + adapter->dmaq2.buffer_size / 2) & 0xfffffffc) | 1;
-
- dprintk("%s: first subbuffer address = 0x%x\n", __FUNCTION__, subbuf0);
- udelay(1000);
- write_reg_dw(adapter, 0x010, subbuf0);
-
- dprintk("%s: subbuffer size = 0x%x\n", __FUNCTION__, (subbufsize >> 8) * 4);
- udelay(1000);
- write_reg_dw(adapter, 0x014, subbufsize);
-
- dprintk("%s: second buffer address = 0x%x\n", __FUNCTION__, subbuf1);
- udelay(1000);
- write_reg_dw(adapter, 0x01c, subbuf1);
-
- sram_set_cai_dest(adapter, 2);
- }
-
- return 0;
-}
-
-static void ctrl_enable_receive_data(struct adapter *adapter, u32 op)
-{
- if (op == 0) {
- write_reg_bitfield(adapter, 0x208, 0x00008000, 0);
- adapter->dma_status = adapter->dma_status & ~0x00000004;
- } else {
- write_reg_bitfield(adapter, 0x208, 0x00008000, 0x00008000);
- adapter->dma_status = adapter->dma_status | 0x00000004;
- }
-}
-
-/* bit 0 of dma_mask is set to 1 if dma1 channel has to be enabled/disabled
- bit 1 of dma_mask is set to 1 if dma2 channel has to be enabled/disabled
-*/
-static void dma_start_stop(struct adapter *adapter, u32 dma_mask, int start_stop)
-{
- u32 dma_enable, dma1_enable, dma2_enable;
-
- dprintk("%s: dma_mask=%x\n", __FUNCTION__, dma_mask);
-
- if (start_stop == 1) {
- dprintk("%s: starting dma\n", __FUNCTION__);
-
- dma1_enable = 0;
- dma2_enable = 0;
-
- if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) == 0) && (adapter->dmaq1.bus_addr != 0)) {
- adapter->dma_status = adapter->dma_status | 1;
- dma1_enable = 1;
- }
-
- if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) == 0) && (adapter->dmaq2.bus_addr != 0)) {
- adapter->dma_status = adapter->dma_status | 2;
- dma2_enable = 1;
- }
- // enable dma1 and dma2
- if ((dma1_enable == 1) && (dma2_enable == 1)) {
- write_reg_dw(adapter, 0x000, adapter->dmaq1.bus_addr | 1);
- write_reg_dw(adapter, 0x00c, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1);
- write_reg_dw(adapter, 0x010, adapter->dmaq2.bus_addr | 1);
-
- ctrl_enable_receive_data(adapter, 1);
-
- return;
- }
- // enable dma1
- if ((dma1_enable == 1) && (dma2_enable == 0)) {
- write_reg_dw(adapter, 0x000, adapter->dmaq1.bus_addr | 1);
- write_reg_dw(adapter, 0x00c, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1);
-
- ctrl_enable_receive_data(adapter, 1);
-
- return;
- }
- // enable dma2
- if ((dma1_enable == 0) && (dma2_enable == 1)) {
- write_reg_dw(adapter, 0x010, adapter->dmaq2.bus_addr | 1);
-
- ctrl_enable_receive_data(adapter, 1);
-
- return;
- }
- // start dma
- if ((dma1_enable == 0) && (dma2_enable == 0)) {
- ctrl_enable_receive_data(adapter, 1);
-
- return;
- }
-
- } else {
-
- dprintk("%s: stopping dma\n", __FUNCTION__);
-
- dma_enable = adapter->dma_status & 0x00000003;
-
- if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) != 0)) {
- dma_enable = dma_enable & 0xfffffffe;
- }
-
- if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) != 0)) {
- dma_enable = dma_enable & 0xfffffffd;
- }
- //stop dma
- if ((dma_enable == 0) && ((adapter->dma_status & 4) != 0)) {
- ctrl_enable_receive_data(adapter, 0);
-
- udelay(3000);
- }
- //disable dma1
- if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) != 0) && (adapter->dmaq1.bus_addr != 0)) {
- write_reg_dw(adapter, 0x000, adapter->dmaq1.bus_addr);
- write_reg_dw(adapter, 0x00c, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1);
-
- adapter->dma_status = adapter->dma_status & ~0x00000001;
- }
- //disable dma2
- if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) != 0) && (adapter->dmaq2.bus_addr != 0)) {
- write_reg_dw(adapter, 0x010, adapter->dmaq2.bus_addr);
-
- adapter->dma_status = adapter->dma_status & ~0x00000002;
- }
- }
-}
-
-static void open_stream(struct adapter *adapter, u16 pid)
-{
- u32 dma_mask;
-
- ++adapter->capturing;
-
- filter_enable_mask_filter(adapter, 1);
-
- add_pid(adapter, pid);
-
- dprintk("%s: adapter->dma_status=%x\n", __FUNCTION__, adapter->dma_status);
-
- if ((adapter->dma_status & 7) != 7) {
- dma_mask = 0;
-
- if (((adapter->dma_status & 0x10000000) != 0) && ((adapter->dma_status & 1) == 0)) {
- dma_mask = dma_mask | 1;
-
- adapter->dmaq1.head = 0;
- adapter->dmaq1.tail = 0;
-
- memset(adapter->dmaq1.buffer, 0, adapter->dmaq1.buffer_size);
- }
-
- if (((adapter->dma_status & 0x20000000) != 0) && ((adapter->dma_status & 2) == 0)) {
- dma_mask = dma_mask | 2;
-
- adapter->dmaq2.head = 0;
- adapter->dmaq2.tail = 0;
- }
-
- if (dma_mask != 0) {
- irq_dma_enable_disable_irq(adapter, 1);
-
- dma_start_stop(adapter, dma_mask, 1);
- }
- }
-}
-
-static void close_stream(struct adapter *adapter, u16 pid)
-{
- if (adapter->capturing > 0)
- --adapter->capturing;
-
- dprintk("%s: dma_status=%x\n", __FUNCTION__, adapter->dma_status);
-
- if (adapter->capturing == 0) {
- u32 dma_mask = 0;
-
- if ((adapter->dma_status & 1) != 0)
- dma_mask = dma_mask | 0x00000001;
- if ((adapter->dma_status & 2) != 0)
- dma_mask = dma_mask | 0x00000002;
-
- if (dma_mask != 0) {
- dma_start_stop(adapter, dma_mask, 0);
- }
- }
- remove_pid(adapter, pid);
-}
-
-static void interrupt_service_dma1(struct adapter *adapter)
-{
- struct dvb_demux *dvbdmx = &adapter->demux;
-
- int n_cur_dma_counter;
- u32 n_num_bytes_parsed;
- u32 n_num_new_bytes_transferred;
- u32 dw_default_packet_size = 188;
- u8 gb_tmp_buffer[188];
- u8 *pb_dma_buf_cur_pos;
-
- n_cur_dma_counter = readl(adapter->io_mem + 0x008) - adapter->dmaq1.bus_addr;
- n_cur_dma_counter = (n_cur_dma_counter / dw_default_packet_size) * dw_default_packet_size;
-
- if ((n_cur_dma_counter < 0) || (n_cur_dma_counter > adapter->dmaq1.buffer_size)) {
- dprintk("%s: dma counter outside dma buffer\n", __FUNCTION__);
- return;
- }
-
- adapter->dmaq1.head = n_cur_dma_counter;
-
- if (adapter->dmaq1.tail <= n_cur_dma_counter) {
- n_num_new_bytes_transferred = n_cur_dma_counter - adapter->dmaq1.tail;
-
- } else {
-
- n_num_new_bytes_transferred = (adapter->dmaq1.buffer_size - adapter->dmaq1.tail) + n_cur_dma_counter;
- }
-
- ddprintk("%s: n_cur_dma_counter = %d\n", __FUNCTION__, n_cur_dma_counter);
- ddprintk("%s: dmaq1.tail = %d\n", __FUNCTION__, adapter->dmaq1.tail);
- ddprintk("%s: bytes_transferred = %d\n", __FUNCTION__, n_num_new_bytes_transferred);
-
- if (n_num_new_bytes_transferred < dw_default_packet_size)
- return;
-
- n_num_bytes_parsed = 0;
-
- while (n_num_bytes_parsed < n_num_new_bytes_transferred) {
- pb_dma_buf_cur_pos = adapter->dmaq1.buffer + adapter->dmaq1.tail;
-
- if (adapter->dmaq1.buffer + adapter->dmaq1.buffer_size < adapter->dmaq1.buffer + adapter->dmaq1.tail + 188) {
- memcpy(gb_tmp_buffer, adapter->dmaq1.buffer + adapter->dmaq1.tail,
- adapter->dmaq1.buffer_size - adapter->dmaq1.tail);
- memcpy(gb_tmp_buffer + (adapter->dmaq1.buffer_size - adapter->dmaq1.tail), adapter->dmaq1.buffer,
- (188 - (adapter->dmaq1.buffer_size - adapter->dmaq1.tail)));
-
- pb_dma_buf_cur_pos = gb_tmp_buffer;
- }
-
- if (adapter->capturing != 0) {
- dvb_dmx_swfilter_packets(dvbdmx, pb_dma_buf_cur_pos, dw_default_packet_size / 188);
- }
-
- n_num_bytes_parsed = n_num_bytes_parsed + dw_default_packet_size;
-
- adapter->dmaq1.tail = adapter->dmaq1.tail + dw_default_packet_size;
-
- if (adapter->dmaq1.tail >= adapter->dmaq1.buffer_size)
- adapter->dmaq1.tail = adapter->dmaq1.tail - adapter->dmaq1.buffer_size;
- };
-}
-
-static void interrupt_service_dma2(struct adapter *adapter)
-{
- printk("%s:\n", __FUNCTION__);
-}
-
-static irqreturn_t isr(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct adapter *tmp = dev_id;
-
- u32 value;
-
- ddprintk("%s:\n", __FUNCTION__);
-
- spin_lock_irq(&tmp->lock);
-
- if (0 == ((value = read_reg_dw(tmp, 0x20c)) & 0x0f)) {
- spin_unlock_irq(&tmp->lock);
- return IRQ_NONE;
- }
-
- while (value != 0) {
- if ((value & 0x03) != 0)
- interrupt_service_dma1(tmp);
- if ((value & 0x0c) != 0)
- interrupt_service_dma2(tmp);
- value = read_reg_dw(tmp, 0x20c) & 0x0f;
- }
-
- spin_unlock_irq(&tmp->lock);
- return IRQ_HANDLED;
-}
-
-static int init_dma_queue_one(struct adapter *adapter, struct dmaq *dmaq,
- int size, int dmaq_offset)
-{
- struct pci_dev *pdev = adapter->pdev;
- dma_addr_t dma_addr;
-
- dmaq->head = 0;
- dmaq->tail = 0;
-
- dmaq->buffer = pci_alloc_consistent(pdev, size + 0x80, &dma_addr);
- if (!dmaq->buffer)
- return -ENOMEM;
-
- dmaq->bus_addr = dma_addr;
- dmaq->buffer_size = size;
-
- dma_init_dma(adapter, dmaq_offset);
-
- ddprintk("%s: allocated dma buffer at 0x%p, length=%d\n",
- __FUNCTION__, dmaq->buffer, size);
-
- return 0;
- }
-
-static int init_dma_queue(struct adapter *adapter)
-{
- struct {
- struct dmaq *dmaq;
- u32 dma_status;
- int size;
- } dmaq_desc[] = {
- { &adapter->dmaq1, 0x10000000, SIZE_OF_BUF_DMA1 },
- { &adapter->dmaq2, 0x20000000, SIZE_OF_BUF_DMA2 }
- }, *p = dmaq_desc;
- int i;
-
- for (i = 0; i < 2; i++, p++) {
- if (init_dma_queue_one(adapter, p->dmaq, p->size, i) < 0)
- adapter->dma_status &= ~p->dma_status;
- else
- adapter->dma_status |= p->dma_status;
- }
- return (adapter->dma_status & 0x30000000) ? 0 : -ENOMEM;
-}
-
-static void free_dma_queue_one(struct adapter *adapter, struct dmaq *dmaq)
-{
- if (dmaq->buffer) {
- pci_free_consistent(adapter->pdev, dmaq->buffer_size + 0x80,
- dmaq->buffer, dmaq->bus_addr);
- memset(dmaq, 0, sizeof(*dmaq));
- }
-}
-
-static void free_dma_queue(struct adapter *adapter)
-{
- struct dmaq *dmaq[] = {
- &adapter->dmaq1,
- &adapter->dmaq2,
- NULL
- }, **p;
-
- for (p = dmaq; *p; p++)
- free_dma_queue_one(adapter, *p);
- }
-
-static void release_adapter(struct adapter *adapter)
-{
- struct pci_dev *pdev = adapter->pdev;
-
- iounmap(adapter->io_mem);
- pci_disable_device(pdev);
- pci_release_region(pdev, 0);
- pci_release_region(pdev, 1);
-}
-
-static void free_adapter_object(struct adapter *adapter)
-{
- dprintk("%s:\n", __FUNCTION__);
-
- close_stream(adapter, 0);
- free_irq(adapter->irq, adapter);
- free_dma_queue(adapter);
- release_adapter(adapter);
- kfree(adapter);
-}
-
-static struct pci_driver skystar2_pci_driver;
-
-static int claim_adapter(struct adapter *adapter)
-{
- struct pci_dev *pdev = adapter->pdev;
- u16 var;
- int ret;
-
- ret = pci_request_region(pdev, 1, skystar2_pci_driver.name);
- if (ret < 0)
- goto out;
-
- ret = pci_request_region(pdev, 0, skystar2_pci_driver.name);
- if (ret < 0)
- goto err_pci_release_1;
-
- pci_read_config_byte(pdev, PCI_CLASS_REVISION, &adapter->card_revision);
-
- dprintk("%s: card revision %x \n", __FUNCTION__, adapter->card_revision);
-
- ret = pci_enable_device(pdev);
- if (ret < 0)
- goto err_pci_release_0;
-
- pci_read_config_word(pdev, 4, &var);
-
- if ((var & 4) == 0)
- pci_set_master(pdev);
-
- adapter->io_port = pdev->resource[1].start;
-
- adapter->io_mem = ioremap(pdev->resource[0].start, 0x800);
-
- if (!adapter->io_mem) {
- dprintk("%s: can not map io memory\n", __FUNCTION__);
- ret = -EIO;
- goto err_pci_disable;
- }
-
- dprintk("%s: io memory maped at %p\n", __FUNCTION__, adapter->io_mem);
-
- ret = 1;
-out:
- return ret;
-
-err_pci_disable:
- pci_disable_device(pdev);
-err_pci_release_0:
- pci_release_region(pdev, 0);
-err_pci_release_1:
- pci_release_region(pdev, 1);
- goto out;
-}
-
-/*
-static int sll_reset_flexcop(struct adapter *adapter)
-{
- write_reg_dw(adapter, 0x208, 0);
- write_reg_dw(adapter, 0x210, 0xb2ff);
-
- return 0;
-}
-*/
-
-static void decide_how_many_hw_filters(struct adapter *adapter)
-{
- int hw_filters;
- int mod_option_hw_filters;
-
- // FlexCop IIb & III have 6+32 hw filters
- // FlexCop II has 6 hw filters, every other should have at least 6
- switch (adapter->b2c2_revision) {
- case 0x82: /* II */
- hw_filters = 6;
- break;
- case 0xc3: /* IIB */
- hw_filters = 6 + 32;
- break;
- case 0xc0: /* III */
- hw_filters = 6 + 32;
- break;
- default:
- hw_filters = 6;
- break;
- }
- printk("%s: the chip has %i hardware filters", __FILE__, hw_filters);
-
- mod_option_hw_filters = 0;
- if (enable_hw_filters >= 1)
- mod_option_hw_filters += 6;
- if (enable_hw_filters >= 2)
- mod_option_hw_filters += 32;
-
- if (mod_option_hw_filters >= hw_filters) {
- adapter->useable_hw_filters = hw_filters;
- } else {
- adapter->useable_hw_filters = mod_option_hw_filters;
- printk(", but only %d will be used because of module option", mod_option_hw_filters);
- }
- printk("\n");
- dprintk("%s: useable_hardware_filters set to %i\n", __FILE__, adapter->useable_hw_filters);
-}
-
-static int driver_initialize(struct pci_dev *pdev)
-{
- struct adapter *adapter;
- u32 tmp;
- int ret = -ENOMEM;
-
- adapter = kmalloc(sizeof(struct adapter), GFP_KERNEL);
- if (!adapter) {
- dprintk("%s: out of memory!\n", __FUNCTION__);
- goto out;
- }
-
- memset(adapter, 0, sizeof(struct adapter));
-
- pci_set_drvdata(pdev,adapter);
-
- adapter->pdev = pdev;
- adapter->irq = pdev->irq;
-
- ret = claim_adapter(adapter);
- if (ret < 0)
- goto err_kfree;
-
- irq_dma_enable_disable_irq(adapter, 0);
-
- ret = request_irq(pdev->irq, isr, 0x4000000, "Skystar2", adapter);
- if (ret < 0) {
- dprintk("%s: unable to allocate irq=%d !\n", __FUNCTION__, pdev->irq);
- goto err_release_adapter;
- }
-
- read_reg_dw(adapter, 0x208);
- write_reg_dw(adapter, 0x208, 0);
- write_reg_dw(adapter, 0x210, 0xb2ff);
- write_reg_dw(adapter, 0x208, 0x40);
-
- ret = init_dma_queue(adapter);
- if (ret < 0)
- goto err_free_irq;
-
- adapter->b2c2_revision = (read_reg_dw(adapter, 0x204) >> 0x18);
-
- switch (adapter->b2c2_revision) {
- case 0x82:
- printk("%s: FlexCopII(rev.130) chip found\n", __FILE__);
- break;
- case 0xc3:
- printk("%s: FlexCopIIB(rev.195) chip found\n", __FILE__);
- break;
- case 0xc0:
- printk("%s: FlexCopIII(rev.192) chip found\n", __FILE__);
- break;
- default:
- printk("%s: The revision of the FlexCop chip on your card is %d\n", __FILE__, adapter->b2c2_revision);
- printk("%s: This driver works only with FlexCopII(rev.130), FlexCopIIB(rev.195) and FlexCopIII(rev.192).\n", __FILE__);
- ret = -ENODEV;
- goto err_free_dma_queue;
- }
-
- decide_how_many_hw_filters(adapter);
-
- init_pids(adapter);
-
- tmp = read_reg_dw(adapter, 0x204);
-
- write_reg_dw(adapter, 0x204, 0);
- mdelay(20);
-
- write_reg_dw(adapter, 0x204, tmp);
- mdelay(10);
-
- tmp = read_reg_dw(adapter, 0x308);
- write_reg_dw(adapter, 0x308, 0x4000 | tmp);
-
- adapter->dw_sram_type = 0x10000;
-
- sll_detect_sram_size(adapter);
-
- dprintk("%s sram length = %d, sram type= %x\n", __FUNCTION__, sram_length(adapter), adapter->dw_sram_type);
-
- sram_set_media_dest(adapter, 1);
- sram_set_net_dest(adapter, 1);
-
- ctrl_enable_smc(adapter, 0);
-
- sram_set_cai_dest(adapter, 2);
- sram_set_cao_dest(adapter, 2);
-
- dma_enable_disable_irq(adapter, 1, 0, 0);
-
- if (eeprom_get_mac_addr(adapter, 0, adapter->mac_addr) != 0) {
- printk("%s MAC address = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n", __FUNCTION__, adapter->mac_addr[0],
- adapter->mac_addr[1], adapter->mac_addr[2], adapter->mac_addr[3], adapter->mac_addr[4], adapter->mac_addr[5],
- adapter->mac_addr[6], adapter->mac_addr[7]
- );
-
- ca_set_mac_dst_addr_filter(adapter, adapter->mac_addr);
- ctrl_enable_mac(adapter, 1);
- }
-
- spin_lock_init(&adapter->lock);
-
-out:
- return ret;
-
-err_free_dma_queue:
- free_dma_queue(adapter);
-err_free_irq:
- free_irq(pdev->irq, adapter);
-err_release_adapter:
- release_adapter(adapter);
-err_kfree:
- pci_set_drvdata(pdev, NULL);
- kfree(adapter);
- goto out;
-}
-
-static void driver_halt(struct pci_dev *pdev)
-{
- struct adapter *adapter = pci_get_drvdata(pdev);
-
- irq_dma_enable_disable_irq(adapter, 0);
-
- ctrl_enable_receive_data(adapter, 0);
-
- free_adapter_object(adapter);
-
- pci_set_drvdata(pdev, NULL);
-}
-
-static int dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
- struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
- struct adapter *adapter = (struct adapter *) dvbdmx->priv;
-
- dprintk("%s: PID=%d, type=%d\n", __FUNCTION__, dvbdmxfeed->pid, dvbdmxfeed->type);
-
- open_stream(adapter, dvbdmxfeed->pid);
-
- return 0;
-}
-
-static int dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
- struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
- struct adapter *adapter = (struct adapter *) dvbdmx->priv;
-
- dprintk("%s: PID=%d, type=%d\n", __FUNCTION__, dvbdmxfeed->pid, dvbdmxfeed->type);
-
- close_stream(adapter, dvbdmxfeed->pid);
-
- return 0;
-}
-
-/* lnb control */
-static void set_tuner_tone(struct adapter *adapter, u8 tone)
-{
- u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc };
- u16 ax;
-
- dprintk("%s: %u\n", __FUNCTION__, tone);
-
- switch (tone) {
- case 1:
- ax = wz_half_period_for_45_mhz[0];
- break;
- case 2:
- ax = wz_half_period_for_45_mhz[1];
- break;
- case 3:
- ax = wz_half_period_for_45_mhz[2];
- break;
- case 4:
- ax = wz_half_period_for_45_mhz[3];
- break;
-
- default:
- ax = 0;
- }
-
- if (ax != 0) {
- write_reg_dw(adapter, 0x200, ((ax << 0x0f) + (ax & 0x7fff)) | 0x40000000);
-
- } else {
-
- write_reg_dw(adapter, 0x200, 0x40ff8000);
- }
-}
-
-static void set_tuner_polarity(struct adapter *adapter, u8 polarity)
-{
- u32 var;
-
- dprintk("%s : polarity = %u \n", __FUNCTION__, polarity);
-
- var = read_reg_dw(adapter, 0x204);
-
- if (polarity == 0) {
- dprintk("%s: LNB power off\n", __FUNCTION__);
- var = var | 1;
- };
-
- if (polarity == 1) {
- var = var & ~1;
- var = var & ~4;
- };
-
- if (polarity == 2) {
- var = var & ~1;
- var = var | 4;
- }
-
- write_reg_dw(adapter, 0x204, var);
-}
-
-static void diseqc_send_bit(struct adapter *adapter, int data)
-{
- set_tuner_tone(adapter, 1);
- udelay(data ? 500 : 1000);
- set_tuner_tone(adapter, 0);
- udelay(data ? 1000 : 500);
-}
-
-
-static void diseqc_send_byte(struct adapter *adapter, int data)
- {
- int i, par = 1, d;
-
- for (i = 7; i >= 0; i--) {
- d = (data >> i) & 1;
- par ^= d;
- diseqc_send_bit(adapter, d);
- }
-
- diseqc_send_bit(adapter, par);
- }
-
-
-static int send_diseqc_msg(struct adapter *adapter, int len, u8 *msg, unsigned long burst)
-{
- int i;
-
- set_tuner_tone(adapter, 0);
- mdelay(16);
-
- for (i = 0; i < len; i++)
- diseqc_send_byte(adapter, msg[i]);
-
- mdelay(16);
-
- if (burst != -1) {
- if (burst)
- diseqc_send_byte(adapter, 0xff);
- else {
- set_tuner_tone(adapter, 1);
- udelay(12500);
- set_tuner_tone(adapter, 0);
- }
- msleep(20);
- }
-
- return 0;
-}
-
-static int flexcop_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
- struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
- switch(tone) {
- case SEC_TONE_ON:
- set_tuner_tone(adapter, 1);
- break;
- case SEC_TONE_OFF:
- set_tuner_tone(adapter, 0);
- break;
- default:
- return -EINVAL;
- };
-
- return 0;
-}
-
-static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
- {
- struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
- send_diseqc_msg(adapter, cmd->msg_len, cmd->msg, 0);
-
- return 0;
- }
-
-static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
-{
- struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
- send_diseqc_msg(adapter, 0, NULL, minicmd);
-
- return 0;
-}
-
-static int flexcop_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
- {
- struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
- dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__);
-
- switch (voltage) {
- case SEC_VOLTAGE_13:
- dprintk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13);
- set_tuner_polarity(adapter, 1);
- return 0;
-
- case SEC_VOLTAGE_18:
- dprintk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18);
- set_tuner_polarity(adapter, 2);
- return 0;
-
- default:
- return -EINVAL;
- }
- }
-
-static int flexcop_sleep(struct dvb_frontend* fe)
- {
- struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
- dprintk("%s: FE_SLEEP\n", __FUNCTION__);
- set_tuner_polarity(adapter, 0);
-
- if (adapter->fe_sleep) return adapter->fe_sleep(fe);
- return 0;
- }
-
-static u32 flexcop_i2c_func(struct i2c_adapter *adapter)
- {
- printk("flexcop_i2c_func\n");
-
- return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm flexcop_algo = {
- .name = "flexcop i2c algorithm",
- .id = I2C_ALGO_BIT,
- .master_xfer = master_xfer,
- .functionality = flexcop_i2c_func,
-};
-
-
-
-
-static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
-{
- u8 aclk = 0;
- u8 bclk = 0;
-
- if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
- else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
- else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
- else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
- else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
- else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
-
- stv0299_writereg (fe, 0x13, aclk);
- stv0299_writereg (fe, 0x14, bclk);
- stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
- stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
- stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
-
- return 0;
-}
-
-static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
-{
- u8 buf[4];
- u32 div;
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
- struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
- div = params->frequency / 125;
-
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = div & 0xff;
- buf[2] = 0x84; // 0xC4
- buf[3] = 0x08;
-
- if (params->frequency < 1500000) buf[3] |= 0x10;
-
- if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO;
- return 0;
-}
-
-static u8 samsung_tbmu24112_inittab[] = {
- 0x01, 0x15,
- 0x02, 0x30,
- 0x03, 0x00,
- 0x04, 0x7D,
- 0x05, 0x35,
- 0x06, 0x02,
- 0x07, 0x00,
- 0x08, 0xC3,
- 0x0C, 0x00,
- 0x0D, 0x81,
- 0x0E, 0x23,
- 0x0F, 0x12,
- 0x10, 0x7E,
- 0x11, 0x84,
- 0x12, 0xB9,
- 0x13, 0x88,
- 0x14, 0x89,
- 0x15, 0xC9,
- 0x16, 0x00,
- 0x17, 0x5C,
- 0x18, 0x00,
- 0x19, 0x00,
- 0x1A, 0x00,
- 0x1C, 0x00,
- 0x1D, 0x00,
- 0x1E, 0x00,
- 0x1F, 0x3A,
- 0x20, 0x2E,
- 0x21, 0x80,
- 0x22, 0xFF,
- 0x23, 0xC1,
- 0x28, 0x00,
- 0x29, 0x1E,
- 0x2A, 0x14,
- 0x2B, 0x0F,
- 0x2C, 0x09,
- 0x2D, 0x05,
- 0x31, 0x1F,
- 0x32, 0x19,
- 0x33, 0xFE,
- 0x34, 0x93,
- 0xff, 0xff,
- };
-
-static struct stv0299_config samsung_tbmu24112_config = {
- .demod_address = 0x68,
- .inittab = samsung_tbmu24112_inittab,
- .mclk = 88000000UL,
- .invert = 0,
- .enhanced_tuning = 0,
- .skip_reinit = 0,
- .lock_output = STV0229_LOCKOUTPUT_LK,
- .volt13_op0_op1 = STV0299_VOLT13_OP1,
- .min_delay_ms = 100,
- .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
- .pll_set = samsung_tbmu24112_pll_set,
-};
-
-
-
-static int nxt2002_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
-{
- struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
- return request_firmware(fw, name, &adapter->pdev->dev);
-}
-
-
-static struct nxt2002_config samsung_tbmv_config = {
- .demod_address = 0x0A,
- .request_firmware = nxt2002_request_firmware,
-};
-
-static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
-{
- static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d };
- static u8 mt352_reset [] = { 0x50, 0x80 };
- static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
- static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
- static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
-
- mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
- udelay(2000);
- mt352_write(fe, mt352_reset, sizeof(mt352_reset));
- mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-
- mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
- mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
-
- return 0;
-}
-
-static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
-{
- u32 div;
- unsigned char bs = 0;
-
- #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
- div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
-
- if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
- if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
- if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
-
- pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address
- pllbuf[1] = div >> 8;
- pllbuf[2] = div & 0xff;
- pllbuf[3] = 0xcc;
- pllbuf[4] = bs;
-
- return 0;
-}
-
-static struct mt352_config samsung_tdtc9251dh0_config = {
-
- .demod_address = 0x0f,
- .demod_init = samsung_tdtc9251dh0_demod_init,
- .pll_set = samsung_tdtc9251dh0_pll_set,
-};
-
-static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
-{
- u8 buf[4];
- u32 div;
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
- struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
- div = (params->frequency + (125/2)) / 125;
-
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = (div >> 0) & 0xff;
- buf[2] = 0x84 | ((div >> 10) & 0x60);
- buf[3] = 0x80;
-
- if (params->frequency < 1550000)
- buf[3] |= 0x02;
-
- if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO;
- return 0;
-}
-
-static struct mt312_config skystar23_samsung_tbdu18132_config = {
-
- .demod_address = 0x0e,
- .pll_set = skystar23_samsung_tbdu18132_pll_set,
-};
-
-
-
-
-static void frontend_init(struct adapter *skystar2)
-{
- switch(skystar2->pdev->device) {
- case 0x2103: // Technisat Skystar2 OR Technisat Airstar2 (DVB-T or ATSC)
-
- // Attempt to load the Nextwave nxt2002 for ATSC support
- skystar2->fe = nxt2002_attach(&samsung_tbmv_config, &skystar2->i2c_adap);
- if (skystar2->fe != NULL) {
- skystar2->fe_sleep = skystar2->fe->ops->sleep;
- skystar2->fe->ops->sleep = flexcop_sleep;
- break;
- }
-
- // try the skystar2 v2.6 first (stv0299/Samsung tbmu24112(sl1935))
- skystar2->fe = stv0299_attach(&samsung_tbmu24112_config, &skystar2->i2c_adap);
- if (skystar2->fe != NULL) {
- skystar2->fe->ops->set_voltage = flexcop_set_voltage;
- skystar2->fe_sleep = skystar2->fe->ops->sleep;
- skystar2->fe->ops->sleep = flexcop_sleep;
- break;
-}
-
- // try the airstar2 (mt352/Samsung tdtc9251dh0(??))
- skystar2->fe = mt352_attach(&samsung_tdtc9251dh0_config, &skystar2->i2c_adap);
- if (skystar2->fe != NULL) {
- skystar2->fe->ops->info.frequency_min = 474000000;
- skystar2->fe->ops->info.frequency_max = 858000000;
- break;
- }
-
- // try the skystar2 v2.3 (vp310/Samsung tbdu18132(tsa5059))
- skystar2->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &skystar2->i2c_adap);
- if (skystar2->fe != NULL) {
- skystar2->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
- skystar2->fe->ops->diseqc_send_burst = flexcop_diseqc_send_burst;
- skystar2->fe->ops->set_tone = flexcop_set_tone;
- skystar2->fe->ops->set_voltage = flexcop_set_voltage;
- skystar2->fe_sleep = skystar2->fe->ops->sleep;
- skystar2->fe->ops->sleep = flexcop_sleep;
- break;
- }
- break;
- }
-
- if (skystar2->fe == NULL) {
- printk("skystar2: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
- skystar2->pdev->vendor,
- skystar2->pdev->device,
- skystar2->pdev->subsystem_vendor,
- skystar2->pdev->subsystem_device);
- } else {
- if (dvb_register_frontend(&skystar2->dvb_adapter, skystar2->fe)) {
- printk("skystar2: Frontend registration failed!\n");
- if (skystar2->fe->ops->release)
- skystar2->fe->ops->release(skystar2->fe);
- skystar2->fe = NULL;
- }
- }
-}
-
-
-static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- struct adapter *adapter;
- struct dvb_adapter *dvb_adapter;
- struct dvb_demux *dvbdemux;
- struct dmx_demux *dmx;
- int ret = -ENODEV;
-
- if (!pdev)
- goto out;
-
- ret = driver_initialize(pdev);
- if (ret < 0)
- goto out;
-
- adapter = pci_get_drvdata(pdev);
- dvb_adapter = &adapter->dvb_adapter;
-
- ret = dvb_register_adapter(dvb_adapter, skystar2_pci_driver.name,
- THIS_MODULE);
- if (ret < 0) {
- printk("%s: Error registering DVB adapter\n", __FUNCTION__);
- goto err_halt;
- }
-
- dvb_adapter->priv = adapter;
-
-
- init_MUTEX(&adapter->i2c_sem);
-
-
- memset(&adapter->i2c_adap, 0, sizeof(struct i2c_adapter));
- strcpy(adapter->i2c_adap.name, "SkyStar2");
-
- i2c_set_adapdata(&adapter->i2c_adap, adapter);
-
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
- adapter->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
-#else
- adapter->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
-#endif
- adapter->i2c_adap.algo = &flexcop_algo;
- adapter->i2c_adap.algo_data = NULL;
- adapter->i2c_adap.id = I2C_ALGO_BIT;
-
- ret = i2c_add_adapter(&adapter->i2c_adap);
- if (ret < 0)
- goto err_dvb_unregister;
-
- dvbdemux = &adapter->demux;
-
- dvbdemux->priv = adapter;
- dvbdemux->filternum = N_PID_SLOTS;
- dvbdemux->feednum = N_PID_SLOTS;
- dvbdemux->start_feed = dvb_start_feed;
- dvbdemux->stop_feed = dvb_stop_feed;
- dvbdemux->write_to_decoder = NULL;
- dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
-
- ret = dvb_dmx_init(&adapter->demux);
- if (ret < 0)
- goto err_i2c_del;
-
- dmx = &dvbdemux->dmx;
-
- adapter->hw_frontend.source = DMX_FRONTEND_0;
- adapter->dmxdev.filternum = N_PID_SLOTS;
- adapter->dmxdev.demux = dmx;
- adapter->dmxdev.capabilities = 0;
-
- ret = dvb_dmxdev_init(&adapter->dmxdev, &adapter->dvb_adapter);
- if (ret < 0)
- goto err_dmx_release;
-
- ret = dmx->add_frontend(dmx, &adapter->hw_frontend);
- if (ret < 0)
- goto err_dmxdev_release;
-
- adapter->mem_frontend.source = DMX_MEMORY_FE;
-
- ret = dmx->add_frontend(dmx, &adapter->mem_frontend);
- if (ret < 0)
- goto err_remove_hw_frontend;
-
- ret = dmx->connect_frontend(dmx, &adapter->hw_frontend);
- if (ret < 0)
- goto err_remove_mem_frontend;
-
- dvb_net_init(&adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx);
-
- frontend_init(adapter);
-out:
- return ret;
-
-err_remove_mem_frontend:
- dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->mem_frontend);
-err_remove_hw_frontend:
- dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->hw_frontend);
-err_dmxdev_release:
- dvb_dmxdev_release(&adapter->dmxdev);
-err_dmx_release:
- dvb_dmx_release(&adapter->demux);
-err_i2c_del:
- i2c_del_adapter(&adapter->i2c_adap);
-err_dvb_unregister:
- dvb_unregister_adapter(&adapter->dvb_adapter);
-err_halt:
- driver_halt(pdev);
- goto out;
-}
-
-static void skystar2_remove(struct pci_dev *pdev)
-{
- struct adapter *adapter = pci_get_drvdata(pdev);
- struct dvb_demux *dvbdemux;
- struct dmx_demux *dmx;
-
- if (!adapter)
- return;
-
- dvb_net_release(&adapter->dvbnet);
- dvbdemux = &adapter->demux;
- dmx = &dvbdemux->dmx;
-
- dmx->close(dmx);
- dmx->remove_frontend(dmx, &adapter->hw_frontend);
- dmx->remove_frontend(dmx, &adapter->mem_frontend);
-
- dvb_dmxdev_release(&adapter->dmxdev);
- dvb_dmx_release(dvbdemux);
-
- if (adapter->fe != NULL)
- dvb_unregister_frontend(adapter->fe);
-
- dvb_unregister_adapter(&adapter->dvb_adapter);
-
- i2c_del_adapter(&adapter->i2c_adap);
-
- driver_halt(pdev);
- }
-
-static struct pci_device_id skystar2_pci_tbl[] = {
- {0x000013d0, 0x00002103, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000},
-/* {0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, UNDEFINED HARDWARE - mail linuxtv.org list */ //FCIII
- {0,},
-};
-
-MODULE_DEVICE_TABLE(pci, skystar2_pci_tbl);
-
-static struct pci_driver skystar2_pci_driver = {
- .name = "SkyStar2",
- .id_table = skystar2_pci_tbl,
- .probe = skystar2_probe,
- .remove = skystar2_remove,
-};
-
-static int skystar2_init(void)
-{
- return pci_register_driver(&skystar2_pci_driver);
-}
-
-static void skystar2_cleanup(void)
-{
- pci_unregister_driver(&skystar2_pci_driver);
-}
-
-module_init(skystar2_init);
-module_exit(skystar2_cleanup);
-
-MODULE_DESCRIPTION("Technisat SkyStar2 DVB PCI Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 1339912c308..9bd12832e3d 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -258,10 +258,10 @@ int write_dst(struct dst_state *state, u8 *data, u8 len)
if (debug && (verbose > 4)) {
u8 i;
if (verbose > 4) {
- dprintk("%s writing", __FUNCTION__);
+ dprintk("%s writing [ ", __FUNCTION__);
for (i = 0; i < len; i++)
- dprintk(" %02x", data[i]);
- dprintk("\n");
+ dprintk("%02x ", data[i]);
+ dprintk("]\n");
}
}
for (cnt = 0; cnt < 2; cnt++) {
@@ -320,10 +320,29 @@ int read_dst(struct dst_state *state, u8 * ret, u8 len)
}
EXPORT_SYMBOL(read_dst);
-static int dst_set_freq(struct dst_state *state, u32 freq)
+static int dst_set_polarization(struct dst_state *state)
{
- u8 *val;
+ switch (state->voltage) {
+ case SEC_VOLTAGE_13: // vertical
+ printk("%s: Polarization=[Vertical]\n", __FUNCTION__);
+ state->tx_tuna[8] &= ~0x40; //1
+ break;
+
+ case SEC_VOLTAGE_18: // horizontal
+ printk("%s: Polarization=[Horizontal]\n", __FUNCTION__);
+ state->tx_tuna[8] |= 0x40; // 0
+ break;
+
+ case SEC_VOLTAGE_OFF:
+
+ break;
+ }
+
+ return 0;
+}
+static int dst_set_freq(struct dst_state *state, u32 freq)
+{
state->frequency = freq;
if (debug > 4)
dprintk("%s: set Frequency %u\n", __FUNCTION__, freq);
@@ -332,46 +351,30 @@ static int dst_set_freq(struct dst_state *state, u32 freq)
freq = freq / 1000;
if (freq < 950 || freq > 2150)
return -EINVAL;
- val = &state->tx_tuna[0];
- val[2] = (freq >> 8) & 0x7f;
- val[3] = (u8) freq;
- val[4] = 1;
- val[8] &= ~4;
- if (freq < 1531)
- val[8] |= 4;
+
+ state->tx_tuna[2] = (freq >> 8);
+ state->tx_tuna[3] = (u8) freq;
+ state->tx_tuna[4] = 0x01;
+ state->tx_tuna[8] &= ~0x04;
+ if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
+ if (freq < 1531)
+ state->tx_tuna[8] |= 0x04;
+ }
+
} else if (state->dst_type == DST_TYPE_IS_TERR) {
freq = freq / 1000;
if (freq < 137000 || freq > 858000)
return -EINVAL;
- val = &state->tx_tuna[0];
- val[2] = (freq >> 16) & 0xff;
- val[3] = (freq >> 8) & 0xff;
- val[4] = (u8) freq;
- val[5] = 0;
- switch (state->bandwidth) {
- case BANDWIDTH_6_MHZ:
- val[6] = 6;
- break;
- case BANDWIDTH_7_MHZ:
- case BANDWIDTH_AUTO:
- val[6] = 7;
- break;
+ state->tx_tuna[2] = (freq >> 16) & 0xff;
+ state->tx_tuna[3] = (freq >> 8) & 0xff;
+ state->tx_tuna[4] = (u8) freq;
- case BANDWIDTH_8_MHZ:
- val[6] = 8;
- break;
- }
-
- val[7] = 0;
- val[8] = 0;
} else if (state->dst_type == DST_TYPE_IS_CABLE) {
- /* guess till will get one */
- freq = freq / 1000;
- val = &state->tx_tuna[0];
- val[2] = (freq >> 16) & 0xff;
- val[3] = (freq >> 8) & 0xff;
- val[4] = (u8) freq;
+ state->tx_tuna[2] = (freq >> 16) & 0xff;
+ state->tx_tuna[3] = (freq >> 8) & 0xff;
+ state->tx_tuna[4] = (u8) freq;
+
} else
return -EINVAL;
return 0;
@@ -379,51 +382,58 @@ static int dst_set_freq(struct dst_state *state, u32 freq)
static int dst_set_bandwidth(struct dst_state* state, fe_bandwidth_t bandwidth)
{
- u8 *val;
-
state->bandwidth = bandwidth;
if (state->dst_type != DST_TYPE_IS_TERR)
return 0;
- val = &state->tx_tuna[0];
switch (bandwidth) {
- case BANDWIDTH_6_MHZ:
- val[6] = 6;
- break;
+ case BANDWIDTH_6_MHZ:
+ if (state->dst_hw_cap & DST_TYPE_HAS_CA)
+ state->tx_tuna[7] = 0x06;
+ else {
+ state->tx_tuna[6] = 0x06;
+ state->tx_tuna[7] = 0x00;
+ }
+ break;
- case BANDWIDTH_7_MHZ:
- val[6] = 7;
- break;
+ case BANDWIDTH_7_MHZ:
+ if (state->dst_hw_cap & DST_TYPE_HAS_CA)
+ state->tx_tuna[7] = 0x07;
+ else {
+ state->tx_tuna[6] = 0x07;
+ state->tx_tuna[7] = 0x00;
+ }
+ break;
- case BANDWIDTH_8_MHZ:
- val[6] = 8;
- break;
+ case BANDWIDTH_8_MHZ:
+ if (state->dst_hw_cap & DST_TYPE_HAS_CA)
+ state->tx_tuna[7] = 0x08;
+ else {
+ state->tx_tuna[6] = 0x08;
+ state->tx_tuna[7] = 0x00;
+ }
+ break;
- default:
- return -EINVAL;
+ default:
+ return -EINVAL;
}
return 0;
}
static int dst_set_inversion(struct dst_state* state, fe_spectral_inversion_t inversion)
{
- u8 *val;
-
state->inversion = inversion;
-
- val = &state->tx_tuna[0];
-
- val[8] &= ~0x80;
-
switch (inversion) {
- case INVERSION_OFF:
- break;
- case INVERSION_ON:
- val[8] |= 0x80;
- break;
- default:
- return -EINVAL;
+ case INVERSION_OFF: // Inversion = Normal
+ state->tx_tuna[8] &= ~0x80;
+ break;
+
+ case INVERSION_ON:
+ state->tx_tuna[8] |= 0x80;
+ break;
+ default:
+ return -EINVAL;
}
return 0;
}
@@ -478,6 +488,52 @@ static int dst_set_symbolrate(struct dst_state* state, u32 srate)
return 0;
}
+
+static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation)
+{
+ if (state->dst_type != DST_TYPE_IS_CABLE)
+ return 0;
+
+ state->modulation = modulation;
+ switch (modulation) {
+ case QAM_16:
+ state->tx_tuna[8] = 0x10;
+ break;
+
+ case QAM_32:
+ state->tx_tuna[8] = 0x20;
+ break;
+
+ case QAM_64:
+ state->tx_tuna[8] = 0x40;
+ break;
+
+ case QAM_128:
+ state->tx_tuna[8] = 0x80;
+ break;
+
+ case QAM_256:
+ state->tx_tuna[8] = 0x00;
+ break;
+
+ case QPSK:
+ case QAM_AUTO:
+ case VSB_8:
+ case VSB_16:
+ default:
+ return -EINVAL;
+
+ }
+
+ return 0;
+}
+
+static fe_modulation_t dst_get_modulation(struct dst_state *state)
+{
+ return state->modulation;
+}
+
+
u8 dst_check_sum(u8 * buf, u32 len)
{
u32 i;
@@ -577,7 +633,7 @@ struct dst_types dst_tlist[] = {
.device_id = "200103A",
.offset = 0,
.dst_type = DST_TYPE_IS_SAT,
- .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
+ .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS,
.dst_feature = 0
}, /* obsolete */
@@ -626,7 +682,7 @@ struct dst_types dst_tlist[] = {
.device_id = "DSTMCI",
.offset = 1,
.dst_type = DST_TYPE_IS_SAT,
- .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD,
+ .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT,
.dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4
| DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC
},
@@ -872,7 +928,7 @@ static int dst_get_signal(struct dst_state* state)
{
int retval;
u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb };
-
+ printk("%s: Getting Signal strength and other parameters !!!!!!!!\n", __FUNCTION__);
if ((state->diseq_flags & ATTEMPT_TUNE) == 0) {
state->decode_lock = state->decode_strength = state->decode_snr = 0;
return 0;
@@ -954,15 +1010,8 @@ static int dst_get_tuna(struct dst_state* state)
state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3];
state->decode_lock = 1;
- /*
- dst->decode_n1 = (dst->rx_tuna[4] << 8) +
- (dst->rx_tuna[5]);
-
- dst->decode_n2 = (dst->rx_tuna[8] << 8) +
- (dst->rx_tuna[7]);
- */
state->diseq_flags |= HAS_LOCK;
- /* dst->cur_jiff = jiffies; */
+
return 1;
}
@@ -1098,7 +1147,11 @@ static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
switch (tone) {
case SEC_TONE_OFF:
- state->tx_tuna[2] = 0xff;
+ if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+ state->tx_tuna[2] = 0x00;
+ else
+ state->tx_tuna[2] = 0xff;
+
break;
case SEC_TONE_ON:
@@ -1145,7 +1198,8 @@ static int dst_init(struct dvb_frontend* fe)
static u8 ini_tvci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
static u8 ini_cabfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
static u8 ini_cabci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
- state->inversion = INVERSION_ON;
+// state->inversion = INVERSION_ON;
+ state->inversion = INVERSION_OFF;
state->voltage = SEC_VOLTAGE_13;
state->tone = SEC_TONE_OFF;
state->symbol_rate = 29473000;
@@ -1174,7 +1228,7 @@ static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status)
*status = 0;
if (state->diseq_flags & HAS_LOCK) {
- dst_get_signal(state);
+// dst_get_signal(state); // don't require(?) to ask MCU
if (state->decode_lock)
*status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI;
}
@@ -1208,20 +1262,25 @@ static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet
dst_set_freq(state, p->frequency);
if (verbose > 4)
- dprintk("Set Frequency = [%d]\n", p->frequency);
+ dprintk("Set Frequency=[%d]\n", p->frequency);
- dst_set_inversion(state, p->inversion);
+// dst_set_inversion(state, p->inversion);
if (state->dst_type == DST_TYPE_IS_SAT) {
+ if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+ dst_set_inversion(state, p->inversion);
+
dst_set_fec(state, p->u.qpsk.fec_inner);
dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+ dst_set_polarization(state);
if (verbose > 4)
- dprintk("Set Symbolrate = [%d]\n", p->u.qpsk.symbol_rate);
+ dprintk("Set Symbolrate=[%d]\n", p->u.qpsk.symbol_rate);
} else if (state->dst_type == DST_TYPE_IS_TERR) {
dst_set_bandwidth(state, p->u.ofdm.bandwidth);
} else if (state->dst_type == DST_TYPE_IS_CABLE) {
dst_set_fec(state, p->u.qam.fec_inner);
dst_set_symbolrate(state, p->u.qam.symbol_rate);
+ dst_set_modulation(state, p->u.qam.modulation);
}
dst_write_tuna(fe);
@@ -1233,8 +1292,11 @@ static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet
struct dst_state* state = fe->demodulator_priv;
p->frequency = state->decode_freq;
- p->inversion = state->inversion;
+// p->inversion = state->inversion;
if (state->dst_type == DST_TYPE_IS_SAT) {
+ if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+ p->inversion = state->inversion;
+
p->u.qpsk.symbol_rate = state->symbol_rate;
p->u.qpsk.fec_inner = dst_get_fec(state);
} else if (state->dst_type == DST_TYPE_IS_TERR) {
@@ -1242,7 +1304,8 @@ static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet
} else if (state->dst_type == DST_TYPE_IS_CABLE) {
p->u.qam.symbol_rate = state->symbol_rate;
p->u.qam.fec_inner = dst_get_fec(state);
- p->u.qam.modulation = QAM_AUTO;
+// p->u.qam.modulation = QAM_AUTO;
+ p->u.qam.modulation = dst_get_modulation(state);
}
return 0;
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index d781504cc2f..bfaacd5fc20 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -32,7 +32,7 @@
#include "dst_ca.h"
#include "dst_common.h"
-static unsigned int verbose = 1;
+static unsigned int verbose = 5;
module_param(verbose, int, 0644);
MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
@@ -295,34 +295,28 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message,
return 0;
}
-static int handle_en50221_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
+static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length)
{
if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) {
hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */
hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */
}
else {
+ hw_buffer->msg[0] = (length & 0xff) + 7;
+ hw_buffer->msg[1] = 0x40;
hw_buffer->msg[2] = 0x03;
hw_buffer->msg[3] = 0x00;
+ hw_buffer->msg[4] = 0x03;
+ hw_buffer->msg[5] = length & 0xff;
+ hw_buffer->msg[6] = 0x00;
}
return 0;
}
-static int debug_8820_buffer(struct ca_msg *hw_buffer)
-{
- unsigned int i;
-
- dprintk("%s:Debug=[", __FUNCTION__);
- for (i = 0; i < (hw_buffer->msg[0] + 1); i++)
- dprintk(" %02x", hw_buffer->msg[i]);
- dprintk("]\n");
-
- return 0;
-}
-static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 reply)
+static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply)
{
- if ((dst_put_ci(state, hw_buffer->msg, (hw_buffer->length + 1), hw_buffer->msg, reply)) < 0) {
+ if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) {
dprintk("%s: DST-CI Command failed.\n", __FUNCTION__);
dprintk("%s: Resetting DST.\n", __FUNCTION__);
rdc_reset_state(state);
@@ -334,234 +328,141 @@ static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 r
return 0;
}
-
-static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
+u32 asn_1_decode(u8 *asn_1_array)
{
- u32 hw_offset, buf_offset, i, k;
- u32 program_info_length = 0, es_info_length = 0, length = 0, words = 0;
- u8 found_prog_ca_desc = 0, found_stream_ca_desc = 0, error_condition = 0, hw_buffer_length = 0;
-
- if (verbose > 3)
- dprintk("%s, p_ca_message length %d (0x%x)\n", __FUNCTION__,p_ca_message->length,p_ca_message->length );
-
- handle_en50221_tag(state, p_ca_message, hw_buffer); /* EN50221 tag */
-
- /* Handle the length field (variable) */
- if (!(p_ca_message->msg[3] & 0x80)) { /* Length = 1 */
- length = p_ca_message->msg[3] & 0x7f;
- words = 0; /* domi's suggestion */
- }
- else { /* Length = words */
- words = p_ca_message->msg[3] & 0x7f;
- for (i = 0; i < words; i++) {
- length = length << 8;
- length = length | p_ca_message->msg[4 + i];
+ u8 length_field = 0, word_count = 0, count = 0;
+ u32 length = 0;
+
+ length_field = asn_1_array[0];
+ dprintk("%s: Length field=[%02x]\n", __FUNCTION__, length_field);
+ if (length_field < 0x80) {
+ length = length_field & 0x7f;
+ dprintk("%s: Length=[%02x]\n", __FUNCTION__, length);
+ } else {
+ word_count = length_field & 0x7f;
+ for (count = 0; count < word_count; count++) {
+ length = (length | asn_1_array[count + 1]) << 8;
+ dprintk("%s: Length=[%04x]\n", __FUNCTION__, length);
}
}
- if (verbose > 4) {
- dprintk("%s:Length=[%d (0x%x)], Words=[%d]\n", __FUNCTION__, length,length, words);
-
- /* Debug Input string */
- for (i = 0; i < length; i++)
- dprintk(" %02x", p_ca_message->msg[i]);
- dprintk("]\n");
- }
-
- hw_offset = 7;
- buf_offset = words + 4;
-
- /* Program Header */
- if (verbose > 4)
- dprintk("\n%s:Program Header=[", __FUNCTION__);
- for (i = 0; i < 6; i++) {
- hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];
- if (verbose > 4)
- dprintk(" %02x", p_ca_message->msg[buf_offset]);
- hw_offset++, buf_offset++, hw_buffer_length++;
- }
- if (verbose > 4)
- dprintk("]\n");
+ return length;
+}
- program_info_length = 0;
- program_info_length = (((program_info_length | p_ca_message->msg[words + 8]) & 0x0f) << 8) | p_ca_message->msg[words + 9];
- if (verbose > 4)
- dprintk("%s:Program info Length=[%d][%02x], hw_offset=[%d], buf_offset=[%d] \n",
- __FUNCTION__, program_info_length, program_info_length, hw_offset, buf_offset);
+static int init_buffer(u8 *buffer, u32 length)
+{
+ u32 i;
+ for (i = 0; i < length; i++)
+ buffer[i] = 0;
- if (program_info_length && (program_info_length < 256)) { /* If program_info_length */
- hw_buffer->msg[11] = hw_buffer->msg[11] & 0x0f; /* req only 4 bits */
- hw_buffer->msg[12] = hw_buffer->msg[12] + 1; /* increment! ASIC bug! */
+ return 0;
+}
- if (p_ca_message->msg[buf_offset + 1] == 0x09) { /* Check CA descriptor */
- found_prog_ca_desc = 1;
- if (verbose > 4)
- dprintk("%s: Found CA descriptor @ Program level\n", __FUNCTION__);
- }
+static int debug_string(u8 *msg, u32 length, u32 offset)
+{
+ u32 i;
- if (found_prog_ca_desc) { /* Command only if CA descriptor */
- hw_buffer->msg[13] = p_ca_message->msg[buf_offset]; /* CA PMT command ID */
- hw_offset++, buf_offset++, hw_buffer_length++;
- }
+ dprintk(" String=[ ");
+ for (i = offset; i < length; i++)
+ dprintk("%02x ", msg[i]);
+ dprintk("]\n");
- /* Program descriptors */
- if (verbose > 4) {
- dprintk("%s:**********>buf_offset=[%d], hw_offset=[%d]\n", __FUNCTION__, buf_offset, hw_offset);
- dprintk("%s:Program descriptors=[", __FUNCTION__);
- }
- while (program_info_length && !error_condition) { /* Copy prog descriptors */
- if (program_info_length > p_ca_message->length) { /* Error situation */
- dprintk ("%s:\"WARNING\" Length error, line=[%d], prog_info_length=[%d]\n",
- __FUNCTION__, __LINE__, program_info_length);
- dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__);
- error_condition = 1;
- break;
- }
+ return 0;
+}
- hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];
- dprintk(" %02x", p_ca_message->msg[buf_offset]);
- hw_offset++, buf_offset++, hw_buffer_length++, program_info_length--;
- }
- if (verbose > 4) {
- dprintk("]\n");
- dprintk("%s:**********>buf_offset=[%d], hw_offset=[%d]\n", __FUNCTION__, buf_offset, hw_offset);
- }
- if (found_prog_ca_desc) {
- if (!reply) {
- hw_buffer->msg[13] = 0x01; /* OK descrambling */
- if (verbose > 1)
- dprintk("CA PMT Command = OK Descrambling\n");
- }
- else {
- hw_buffer->msg[13] = 0x02; /* Ok MMI */
- if (verbose > 1)
- dprintk("CA PMT Command = Ok MMI\n");
- }
- if (query) {
- hw_buffer->msg[13] = 0x03; /* Query */
- if (verbose > 1)
- dprintk("CA PMT Command = CA PMT query\n");
- }
- }
- }
- else {
- hw_buffer->msg[11] = hw_buffer->msg[11] & 0xf0; /* Don't write to ASIC */
- hw_buffer->msg[12] = hw_buffer->msg[12] = 0x00;
+static int copy_string(u8 *destination, u8 *source, u32 dest_offset, u32 source_offset, u32 length)
+{
+ u32 i;
+ dprintk("%s: Copying [", __FUNCTION__);
+ for (i = 0; i < length; i++) {
+ destination[i + dest_offset] = source[i + source_offset];
+ dprintk(" %02x", source[i + source_offset]);
}
- if (verbose > 4)
- dprintk("%s:**********>p_ca_message->length=[%d], buf_offset=[%d], hw_offset=[%d]\n",
- __FUNCTION__, p_ca_message->length, buf_offset, hw_offset);
-
- while ((buf_offset < p_ca_message->length) && !error_condition) {
- /* Bail out in case of an indefinite loop */
- if ((es_info_length > p_ca_message->length) || (buf_offset > p_ca_message->length)) {
- dprintk("%s:\"WARNING\" Length error, line=[%d], prog_info_length=[%d], buf_offset=[%d]\n",
- __FUNCTION__, __LINE__, program_info_length, buf_offset);
-
- dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__);
- error_condition = 1;
- break;
- }
-
- /* Stream Header */
-
- for (k = 0; k < 5; k++) {
- hw_buffer->msg[hw_offset + k] = p_ca_message->msg[buf_offset + k];
- }
+ dprintk("]\n");
- es_info_length = 0;
- es_info_length = (es_info_length | (p_ca_message->msg[buf_offset + 3] & 0x0f)) << 8 | p_ca_message->msg[buf_offset + 4];
+ return i;
+}
- if (verbose > 4) {
- dprintk("\n%s:----->Stream header=[%02x %02x %02x %02x %02x]\n", __FUNCTION__,
- p_ca_message->msg[buf_offset + 0], p_ca_message->msg[buf_offset + 1],
- p_ca_message->msg[buf_offset + 2], p_ca_message->msg[buf_offset + 3],
- p_ca_message->msg[buf_offset + 4]);
+static int modify_4_bits(u8 *message, u32 pos)
+{
+ message[pos] &= 0x0f;
- dprintk("%s:----->Stream type=[%02x], es length=[%d (0x%x)], Chars=[%02x] [%02x], buf_offset=[%d]\n", __FUNCTION__,
- p_ca_message->msg[buf_offset + 0], es_info_length, es_info_length,
- p_ca_message->msg[buf_offset + 3], p_ca_message->msg[buf_offset + 4], buf_offset);
- }
+ return 0;
+}
- hw_buffer->msg[hw_offset + 3] &= 0x0f; /* req only 4 bits */
- if (found_prog_ca_desc) {
- hw_buffer->msg[hw_offset + 3] = 0x00;
- hw_buffer->msg[hw_offset + 4] = 0x00;
- }
- hw_offset += 5, buf_offset += 5, hw_buffer_length += 5;
+static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
+{
+ u32 length = 0, count = 0;
+ u8 asn_1_words, program_header_length;
+ u16 program_info_length = 0, es_info_length = 0;
+ u32 hw_offset = 0, buf_offset = 0, i;
+ u8 dst_tag_length;
- /* Check for CA descriptor */
- if (p_ca_message->msg[buf_offset + 1] == 0x09) {
- if (verbose > 4)
- dprintk("%s:Found CA descriptor @ Stream level\n", __FUNCTION__);
- found_stream_ca_desc = 1;
- }
+ length = asn_1_decode(&p_ca_message->msg[3]);
+ dprintk("%s: CA Message length=[%d]\n", __FUNCTION__, length);
+ dprintk("%s: ASN.1 ", __FUNCTION__);
+ debug_string(&p_ca_message->msg[4], length, 0); // length does not include tag and length
- /* ES descriptors */
-
- if (es_info_length && !error_condition && !found_prog_ca_desc && found_stream_ca_desc) {
-// if (!ca_pmt_done) {
- hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset]; /* CA PMT cmd(es) */
- if (verbose > 4)
- printk("%s:----->CA PMT Command ID=[%02x]\n", __FUNCTION__, p_ca_message->msg[buf_offset]);
-// hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--, ca_pmt_done = 1;
- hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--;
-// }
- if (verbose > 4)
- dprintk("%s:----->ES descriptors=[", __FUNCTION__);
-
- while (es_info_length && !error_condition) { /* ES descriptors */
- if ((es_info_length > p_ca_message->length) || (buf_offset > p_ca_message->length)) {
- if (verbose > 4) {
- dprintk("%s:\"WARNING\" ES Length error, line=[%d], es_info_length=[%d], buf_offset=[%d]\n",
- __FUNCTION__, __LINE__, es_info_length, buf_offset);
-
- dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__);
- }
- error_condition = 1;
- break;
- }
+ init_buffer(hw_buffer->msg, length);
+ handle_dst_tag(state, p_ca_message, hw_buffer, length);
- hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];
- if (verbose > 3)
- dprintk("%02x ", hw_buffer->msg[hw_offset]);
- hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--;
- }
- found_stream_ca_desc = 0; /* unset for new streams */
- dprintk("]\n");
+ hw_offset = 7;
+ asn_1_words = 1; // just a hack to test, should compute this one
+ buf_offset = 3;
+ program_header_length = 6;
+ dst_tag_length = 7;
+
+// debug_twinhan_ca_params(state, p_ca_message, hw_buffer, reply, query, length, hw_offset, buf_offset);
+// dprintk("%s: Program Header(BUF)", __FUNCTION__);
+// debug_string(&p_ca_message->msg[4], program_header_length, 0);
+// dprintk("%s: Copying Program header\n", __FUNCTION__);
+ copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, (buf_offset + asn_1_words), program_header_length);
+ buf_offset += program_header_length, hw_offset += program_header_length;
+ modify_4_bits(hw_buffer->msg, (hw_offset - 2));
+ if (state->type_flags & DST_TYPE_HAS_INC_COUNT) { // workaround
+ dprintk("%s: Probably an ASIC bug !!!\n", __FUNCTION__);
+ debug_string(hw_buffer->msg, (hw_offset + program_header_length), 0);
+ hw_buffer->msg[hw_offset - 1] += 1;
+ }
+
+// dprintk("%s: Program Header(HW), Count=[%d]", __FUNCTION__, count);
+// debug_string(hw_buffer->msg, hw_offset, 0);
+
+ program_info_length = ((program_info_length | (p_ca_message->msg[buf_offset - 1] & 0x0f)) << 8) | p_ca_message->msg[buf_offset];
+ dprintk("%s: Program info length=[%02x]\n", __FUNCTION__, program_info_length);
+ if (program_info_length) {
+ count = copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, (buf_offset + 1), (program_info_length + 1) ); // copy next elem, not current
+ buf_offset += count, hw_offset += count;
+// dprintk("%s: Program level ", __FUNCTION__);
+// debug_string(hw_buffer->msg, hw_offset, 0);
+ }
+
+ buf_offset += 1;// hw_offset += 1;
+ for (i = buf_offset; i < length; i++) {
+// dprintk("%s: Stream Header ", __FUNCTION__);
+ count = copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, buf_offset, 5);
+ modify_4_bits(hw_buffer->msg, (hw_offset + 3));
+
+ hw_offset += 5, buf_offset += 5, i += 4;
+// debug_string(hw_buffer->msg, hw_offset, (hw_offset - 5));
+ es_info_length = ((es_info_length | (p_ca_message->msg[buf_offset - 1] & 0x0f)) << 8) | p_ca_message->msg[buf_offset];
+ dprintk("%s: ES info length=[%02x]\n", __FUNCTION__, es_info_length);
+ if (es_info_length) {
+ // copy descriptors @ STREAM level
+ dprintk("%s: Descriptors @ STREAM level...!!! \n", __FUNCTION__);
}
- }
-
- /* MCU Magic words */
-
- hw_buffer_length += 7;
- hw_buffer->msg[0] = hw_buffer_length;
- hw_buffer->msg[1] = 64;
- hw_buffer->msg[4] = 3;
- hw_buffer->msg[5] = hw_buffer->msg[0] - 7;
- hw_buffer->msg[6] = 0;
-
- /* Fix length */
- hw_buffer->length = hw_buffer->msg[0];
-
- put_checksum(&hw_buffer->msg[0], hw_buffer->msg[0]);
- /* Do the actual write */
- if (verbose > 4) {
- dprintk("%s:======================DEBUGGING================================\n", __FUNCTION__);
- dprintk("%s: Actual Length=[%d]\n", __FUNCTION__, hw_buffer_length);
}
- /* Only for debugging! */
- if (verbose > 2)
- debug_8820_buffer(hw_buffer);
- if (verbose > 3)
- dprintk("%s: Reply = [%d]\n", __FUNCTION__, reply);
- write_to_8820(state, hw_buffer, reply);
+ hw_buffer->msg[length + dst_tag_length] = dst_check_sum(hw_buffer->msg, (length + dst_tag_length));
+// dprintk("%s: Total length=[%d], Checksum=[%02x]\n", __FUNCTION__, (length + dst_tag_length), hw_buffer->msg[length + dst_tag_length]);
+ debug_string(hw_buffer->msg, (length + dst_tag_length + 1), 0); // dst tags also
+ write_to_8820(state, hw_buffer, (length + dst_tag_length + 1), reply); // checksum
return 0;
}
+
/* Board supports CA PMT reply ? */
static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
{
@@ -605,7 +506,7 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
struct ca_msg *hw_buffer;
if ((hw_buffer = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
- printk("%s: Memory allocation failure\n", __FUNCTION__);
+ dprintk("%s: Memory allocation failure\n", __FUNCTION__);
return -ENOMEM;
}
if (verbose > 3)
@@ -630,8 +531,10 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
switch (command) {
case CA_PMT:
if (verbose > 3)
+// dprintk("Command = SEND_CA_PMT\n");
dprintk("Command = SEND_CA_PMT\n");
- if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) {
+// if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) {
+ if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started
dprintk("%s: -->CA_PMT Failed !\n", __FUNCTION__);
return -1;
}
@@ -664,7 +567,7 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
return -1;
}
if (verbose > 3)
- printk("%s: -->CA_APP_INFO_ENQUIRY Success !\n", __FUNCTION__);
+ dprintk("%s: -->CA_APP_INFO_ENQUIRY Success !\n", __FUNCTION__);
break;
}
@@ -681,17 +584,17 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
struct ca_msg *p_ca_message;
if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
- printk("%s: Memory allocation failure\n", __FUNCTION__);
+ dprintk("%s: Memory allocation failure\n", __FUNCTION__);
return -ENOMEM;
}
if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) {
- printk("%s: Memory allocation failure\n", __FUNCTION__);
+ dprintk("%s: Memory allocation failure\n", __FUNCTION__);
return -ENOMEM;
}
if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) {
- printk("%s: Memory allocation failure\n", __FUNCTION__);
+ dprintk("%s: Memory allocation failure\n", __FUNCTION__);
return -ENOMEM;
}
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
index 0b3da29245f..ef532a6acea 100644
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ b/drivers/media/dvb/bt8xx/dst_common.h
@@ -47,6 +47,8 @@
#define DST_TYPE_HAS_FW_2 16
#define DST_TYPE_HAS_FW_3 32
#define DST_TYPE_HAS_FW_BUILD 64
+#define DST_TYPE_HAS_OBS_REGS 128
+#define DST_TYPE_HAS_INC_COUNT 256
/* Card capability list */
@@ -110,6 +112,7 @@ struct dst_state {
u32 dst_hw_cap;
u8 dst_fw_version;
fe_sec_mini_cmd_t minicmd;
+ fe_modulation_t modulation;
u8 messages[256];
};
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index 96c57fde95a..7d8b3cad350 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -699,6 +699,8 @@ static void cinergyt2_query_rc (void *data)
for (n=0; len>0 && n<(len/sizeof(rc_events[0])); n++) {
int i;
+/* dprintk(1,"rc_events[%d].value = %x, type=%x\n",n,le32_to_cpu(rc_events[n].value),rc_events[n].type);*/
+
if (rc_events[n].type == CINERGYT2_RC_EVENT_TYPE_NEC &&
rc_events[n].value == ~0)
{
@@ -714,7 +716,7 @@ static void cinergyt2_query_rc (void *data)
cinergyt2->rc_input_event = KEY_MAX;
for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i+=3) {
if (rc_keys[i+0] == rc_events[n].type &&
- rc_keys[i+1] == rc_events[n].value)
+ rc_keys[i+1] == le32_to_cpu(rc_events[n].value))
{
cinergyt2->rc_input_event = rc_keys[i+2];
break;
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index c225de7ffd8..68050cd527c 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -42,12 +42,6 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
#define dprintk if (debug) printk
-static inline struct dmxdev_filter *
-dvb_dmxdev_file_to_filter(struct file *file)
-{
- return (struct dmxdev_filter *) file->private_data;
-}
-
static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer)
{
buffer->data=NULL;
@@ -669,8 +663,10 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
ret = filter->feed.ts->start_filtering(filter->feed.ts);
- if (ret < 0)
+ if (ret < 0) {
+ dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed);
return ret;
+ }
break;
}
@@ -842,7 +838,7 @@ static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
static ssize_t
dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
- struct dmxdev_filter *dmxdevfilter=dvb_dmxdev_file_to_filter(file);
+ struct dmxdev_filter *dmxdevfilter= file->private_data;
int ret=0;
if (down_interruptible(&dmxdevfilter->mutex))
@@ -863,7 +859,7 @@ dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg)
{
- struct dmxdev_filter *dmxdevfilter=dvb_dmxdev_file_to_filter(file);
+ struct dmxdev_filter *dmxdevfilter = file->private_data;
struct dmxdev *dmxdev=dmxdevfilter->dev;
unsigned long arg=(unsigned long) parg;
int ret=0;
@@ -960,7 +956,7 @@ static int dvb_demux_ioctl(struct inode *inode, struct file *file,
static unsigned int dvb_demux_poll (struct file *file, poll_table *wait)
{
- struct dmxdev_filter *dmxdevfilter = dvb_dmxdev_file_to_filter(file);
+ struct dmxdev_filter *dmxdevfilter = file->private_data;
unsigned int mask = 0;
if (!dmxdevfilter)
@@ -985,7 +981,7 @@ static unsigned int dvb_demux_poll (struct file *file, poll_table *wait)
static int dvb_demux_release(struct inode *inode, struct file *file)
{
- struct dmxdev_filter *dmxdevfilter = dvb_dmxdev_file_to_filter(file);
+ struct dmxdev_filter *dmxdevfilter = file->private_data;
struct dmxdev *dmxdev = dmxdevfilter->dev;
return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
@@ -1109,7 +1105,6 @@ dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE);
dmxdev->dvr[i].dev=dmxdev;
dmxdev->dvr[i].buffer.data=NULL;
- dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE);
dvb_dmxdev_dvr_state_set(&dmxdev->dvr[i], DMXDEV_STATE_FREE);
}
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index f11daae91cd..a8bc84240b5 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -42,6 +42,8 @@
#include "dvb_frontend.h"
#include "dvbdev.h"
+// #define DEBUG_LOCKLOSS 1
+
static int dvb_frontend_debug;
static int dvb_shutdown_timeout = 5;
static int dvb_force_auto_inversion;
@@ -113,6 +115,7 @@ struct dvb_frontend_private {
int exit;
int wakeup;
fe_status_t status;
+ fe_sec_tone_mode_t tone;
};
@@ -434,9 +437,26 @@ static int dvb_frontend_thread(void *data)
/* we're tuned, and the lock is still good... */
if (s & FE_HAS_LOCK)
continue;
- else {
- /* if we _WERE_ tuned, but now don't have a lock,
- * need to zigzag */
+ else { /* if we _WERE_ tuned, but now don't have a lock */
+#ifdef DEBUG_LOCKLOSS
+ /* first of all try setting the tone again if it was on - this
+ * sometimes works around problems with noisy power supplies */
+ if (fe->ops->set_tone && (fepriv->tone == SEC_TONE_ON)) {
+ fe->ops->set_tone(fe, fepriv->tone);
+ mdelay(100);
+ s = 0;
+ fe->ops->read_status(fe, &s);
+ if (s & FE_HAS_LOCK) {
+ printk("DVB%i: Lock was lost, but regained by setting "
+ "the tone. This may indicate your power supply "
+ "is noisy/slightly incompatable with this DVB-S "
+ "adapter\n", fe->dvb->num);
+ fepriv->state = FESTATE_TUNED;
+ continue;
+ }
+ }
+#endif
+ /* some other reason for losing the lock - start zigzagging */
fepriv->state = FESTATE_ZIGZAG_FAST;
fepriv->started_auto_step = fepriv->auto_step;
check_wrapped = 0;
@@ -626,11 +646,21 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
break;
}
- case FE_READ_STATUS:
+ case FE_READ_STATUS: {
+ fe_status_t* status = parg;
+
+ /* if retune was requested but hasn't occured yet, prevent
+ * that user get signal state from previous tuning */
+ if(fepriv->state == FESTATE_RETUNE) {
+ err=0;
+ *status = 0;
+ break;
+ }
+
if (fe->ops->read_status)
- err = fe->ops->read_status(fe, (fe_status_t*) parg);
+ err = fe->ops->read_status(fe, status);
break;
-
+ }
case FE_READ_BER:
if (fe->ops->read_ber)
err = fe->ops->read_ber(fe, (__u32*) parg);
@@ -681,6 +711,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
+ fepriv->tone = (fe_sec_tone_mode_t) parg;
}
break;
@@ -883,6 +914,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
init_MUTEX (&fepriv->events.sem);
fe->dvb = dvb;
fepriv->inversion = INVERSION_OFF;
+ fepriv->tone = SEC_TONE_OFF;
printk ("DVB: registering frontend %i (%s)...\n",
fe->dvb->num,
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index d2b02179279..9c2c1d1136b 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -40,28 +40,6 @@
#include "dvbdev.h"
-/* FIXME: Move to i2c-id.h */
-#define I2C_DRIVERID_DVBFE_SP8870 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_CX22700 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_AT76C651 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_CX24110 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_CX22702 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_DIB3000MB I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_DST I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_DUMMY I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_L64781 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_MT312 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_MT352 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_NXT6000 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_SP887X I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_STV0299 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_TDA1004X I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_TDA8083 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_VES1820 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_VES1X93 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_TDA80XX I2C_DRIVERID_EXP2
-
-
struct dvb_frontend_tune_settings {
int min_delay_ms;
int step_size;
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 8aa32f6e447..612e5b087b1 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -3,30 +3,35 @@ config DVB_USB
depends on DVB_CORE && USB
select FW_LOADER
help
- By enabling this you will be able to choose the various USB 1.1 and
- USB2.0 DVB devices.
+ By enabling this you will be able to choose the various supported
+ USB1.1 and USB2.0 DVB devices.
Almost every USB device needs a firmware, please look into
- <file:Documentation/dvb/README.dvb-usb>
+ <file:Documentation/dvb/README.dvb-usb>.
- Say Y if you own an USB DVB device.
+ For a complete list of supported USB devices see the LinuxTV DVB Wiki:
+ <http://www.linuxtv.org/wiki/index.php/DVB_USB>
+
+ Say Y if you own a USB DVB device.
config DVB_USB_DEBUG
bool "Enable extended debug support for all DVB-USB devices"
depends on DVB_USB
help
- Say Y if you want to enable debuging. See modinfo dvb-usb (and the
+ Say Y if you want to enable debugging. See modinfo dvb-usb (and the
appropriate drivers) for debug levels.
config DVB_USB_A800
tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)"
depends on DVB_USB
+ select DVB_DIB3000MC
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_DIB3000MB
help
Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
@@ -52,6 +57,7 @@ config DVB_USB_DIBUSB_MB
config DVB_USB_DIBUSB_MC
tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
depends on DVB_USB
+ select DVB_DIB3000MC
help
Support for 2.0 DVB-T receivers based on reference designs made by
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
@@ -66,12 +72,23 @@ config DVB_USB_DIBUSB_MC
config DVB_USB_UMT_010
tristate "HanfTek UMT-010 DVB-T USB2.0 support"
depends on DVB_USB
+ select DVB_DIB3000MC
help
Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
+config DVB_USB_CXUSB
+ tristate "Medion MD95700 hybrid USB2.0 (Conexant) support"
+ depends on DVB_USB
+ select DVB_CX22702
+ help
+ Say Y here to support the Medion MD95700 hybrid USB2.0 device. Currently
+ only the DVB-T part is supported.
+
config DVB_USB_DIGITV
tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
depends on DVB_USB
+ select DVB_NXT6000
+ select DVB_MT352
help
Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver.
@@ -87,13 +104,16 @@ config DVB_USB_VP7045
config DVB_USB_NOVA_T_USB2
tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
depends on DVB_USB
+ select DVB_DIB3000MC
help
Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
config DVB_USB_DTT200U
- tristate "Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 support"
+ tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)"
depends on DVB_USB
help
- Say Y here to support the Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver.
+ Say Y here to support the WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver.
The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan).
+
+ The WT-220U and its clones are pen-sized.
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index d65b50f9abb..746d87ed6f3 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -27,4 +27,7 @@ obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o
dvb-usb-digitv-objs = digitv.o
obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
+dvb-usb-cxusb-objs = cxusb.o
+obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o
+
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c
index a3542935604..f2fcc2f1f84 100644
--- a/drivers/media/dvb/dvb-usb/a800.c
+++ b/drivers/media/dvb/dvb-usb/a800.c
@@ -61,6 +61,12 @@ static struct dvb_usb_rc_key a800_rc_keys[] = {
{ 0x02, 0x00, KEY_LAST }, /* >>| / BLUE */
{ 0x02, 0x04, KEY_EPG }, /* EPG */
{ 0x02, 0x15, KEY_MENU }, /* MENU */
+
+ { 0x03, 0x03, KEY_CHANNELUP }, /* CH UP */
+ { 0x03, 0x02, KEY_CHANNELDOWN }, /* CH DOWN */
+ { 0x03, 0x01, KEY_FIRST }, /* |<< / GREEN */
+ { 0x03, 0x00, KEY_LAST }, /* >>| / BLUE */
+
};
int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
@@ -68,7 +74,7 @@ int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
u8 key[5];
if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0),
0x04, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, key, 5,
- 2*HZ) != 5)
+ 2000) != 5)
return -ENODEV;
/* call the universal NEC remote processor, to find out the key's state and event */
@@ -143,7 +149,7 @@ static struct dvb_usb_properties a800_properties = {
static struct usb_driver a800_driver = {
.owner = THIS_MODULE,
- .name = "AVerMedia AverTV DVB-T USB 2.0 (A800)",
+ .name = "dvb_usb_a800",
.probe = a800_probe,
.disconnect = dvb_usb_device_exit,
.id_table = a800_table,
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
new file mode 100644
index 00000000000..c3e1b661aae
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -0,0 +1,295 @@
+/* DVB USB compliant linux driver for Conexant USB reference design.
+ *
+ * The Conexant reference design I saw on their website was only for analogue
+ * capturing (using the cx25842). The box I took to write this driver (reverse
+ * engineered) is the one labeled Medion MD95700. In addition to the cx25842
+ * for analogue capturing it also has a cx22702 DVB-T demodulator on the main
+ * board. Besides it has a atiremote (X10) and a USB2.0 hub onboard.
+ *
+ * Maybe it is a little bit premature to call this driver cxusb, but I assume
+ * the USB protocol is identical or at least inherited from the reference
+ * design, so it can be reused for the "analogue-only" device (if it will
+ * appear at all).
+ *
+ * TODO: check if the cx25840-driver (from ivtv) can be used for the analogue
+ * part
+ *
+ * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "cxusb.h"
+
+#include "cx22702.h"
+
+/* debug */
+int dvb_usb_cxusb_debug;
+module_param_named(debug,dvb_usb_cxusb_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+static int cxusb_ctrl_msg(struct dvb_usb_device *d,
+ u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+ int wo = (rbuf == NULL || rlen == 0); /* write-only */
+ u8 sndbuf[1+wlen];
+ memset(sndbuf,0,1+wlen);
+
+ sndbuf[0] = cmd;
+ memcpy(&sndbuf[1],wbuf,wlen);
+ if (wo)
+ dvb_usb_generic_write(d,sndbuf,1+wlen);
+ else
+ dvb_usb_generic_rw(d,sndbuf,1+wlen,rbuf,rlen,0);
+
+ return 0;
+}
+
+/* I2C */
+static void cxusb_set_i2c_path(struct dvb_usb_device *d, enum cxusb_i2c_pathes path)
+{
+ struct cxusb_state *st = d->priv;
+ u8 o[2],i;
+
+ if (path == st->cur_i2c_path)
+ return;
+
+ o[0] = IOCTL_SET_I2C_PATH;
+ switch (path) {
+ case PATH_CX22702:
+ o[1] = 0;
+ break;
+ case PATH_TUNER_OTHER:
+ o[1] = 1;
+ break;
+ default:
+ err("unkown i2c path");
+ return;
+ }
+ cxusb_ctrl_msg(d,CMD_IOCTL,o,2,&i,1);
+
+ if (i != 0x01)
+ deb_info("i2c_path setting failed.\n");
+
+ st->cur_i2c_path = path;
+}
+
+static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int i;
+
+ if (down_interruptible(&d->i2c_sem) < 0)
+ return -EAGAIN;
+
+ if (num > 2)
+ warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+ for (i = 0; i < num; i++) {
+
+ switch (msg[i].addr) {
+ case 0x63:
+ cxusb_set_i2c_path(d,PATH_CX22702);
+ break;
+ default:
+ cxusb_set_i2c_path(d,PATH_TUNER_OTHER);
+ break;
+ }
+
+ /* read request */
+ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+ u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len];
+ obuf[0] = msg[i].len;
+ obuf[1] = msg[i+1].len;
+ obuf[2] = msg[i].addr;
+ memcpy(&obuf[3],msg[i].buf,msg[i].len);
+
+ if (cxusb_ctrl_msg(d, CMD_I2C_READ,
+ obuf, 3+msg[i].len,
+ ibuf, 1+msg[i+1].len) < 0)
+ break;
+
+ if (ibuf[0] != 0x08)
+ deb_info("i2c read could have been failed\n");
+
+ memcpy(msg[i+1].buf,&ibuf[1],msg[i+1].len);
+
+ i++;
+ } else { /* write */
+ u8 obuf[2+msg[i].len], ibuf;
+ obuf[0] = msg[i].addr;
+ obuf[1] = msg[i].len;
+ memcpy(&obuf[2],msg[i].buf,msg[i].len);
+
+ if (cxusb_ctrl_msg(d,CMD_I2C_WRITE, obuf, 2+msg[i].len, &ibuf,1) < 0)
+ break;
+ if (ibuf != 0x08)
+ deb_info("i2c write could have been failed\n");
+ }
+ }
+
+ up(&d->i2c_sem);
+ return i;
+}
+
+static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm cxusb_i2c_algo = {
+ .name = "Conexant USB I2C algorithm",
+ .id = I2C_ALGO_BIT,
+ .master_xfer = cxusb_i2c_xfer,
+ .functionality = cxusb_i2c_func,
+};
+
+static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ return 0;
+}
+
+static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ u8 buf[2] = { 0x03, 0x00 };
+ if (onoff)
+ cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0);
+ else
+ cxusb_ctrl_msg(d,0x37, NULL, 0, NULL, 0);
+
+ return 0;
+}
+
+struct cx22702_config cxusb_cx22702_config = {
+ .demod_address = 0x63,
+
+ .output_mode = CX22702_PARALLEL_OUTPUT,
+
+ .pll_init = dvb_usb_pll_init_i2c,
+ .pll_set = dvb_usb_pll_set_i2c,
+};
+
+/* Callbacks for DVB USB */
+static int cxusb_tuner_attach(struct dvb_usb_device *d)
+{
+ u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
+ d->pll_addr = 0x61;
+ memcpy(d->pll_init,bpll,4);
+ d->pll_desc = &dvb_pll_fmd1216me;
+ return 0;
+}
+
+static int cxusb_frontend_attach(struct dvb_usb_device *d)
+{
+ u8 buf[2] = { 0x03, 0x00 };
+ u8 b = 0;
+
+ if (usb_set_interface(d->udev,0,0) < 0)
+ err("set interface to alts=0 failed");
+
+ cxusb_ctrl_msg(d,0xde,&b,0,NULL,0);
+ cxusb_set_i2c_path(d,PATH_TUNER_OTHER);
+ cxusb_ctrl_msg(d,CMD_POWER_OFF, NULL, 0, &b, 1);
+
+ if (usb_set_interface(d->udev,0,6) < 0)
+ err("set interface failed");
+
+ cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0);
+ cxusb_set_i2c_path(d,PATH_CX22702);
+ cxusb_ctrl_msg(d,CMD_POWER_ON, NULL, 0, &b, 1);
+
+ if ((d->fe = cx22702_attach(&cxusb_cx22702_config, &d->i2c_adap)) != NULL)
+ return 0;
+
+ return -EIO;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_properties cxusb_properties;
+
+static int cxusb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return dvb_usb_device_init(intf,&cxusb_properties,THIS_MODULE);
+}
+
+static struct usb_device_id cxusb_table [] = {
+ { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
+ {} /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, cxusb_table);
+
+static struct dvb_usb_properties cxusb_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_FX2,
+
+ .size_of_priv = sizeof(struct cxusb_state),
+
+ .streaming_ctrl = cxusb_streaming_ctrl,
+ .power_ctrl = cxusb_power_ctrl,
+ .frontend_attach = cxusb_frontend_attach,
+ .tuner_attach = cxusb_tuner_attach,
+
+ .i2c_algo = &cxusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_ISOC,
+ .count = 5,
+ .endpoint = 0x02,
+ .u = {
+ .isoc = {
+ .framesperurb = 32,
+ .framesize = 940,
+ .interval = 5,
+ }
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { "Medion MD95700 (MDUSBTV-HYBRID)",
+ { NULL },
+ { &cxusb_table[0], NULL },
+ },
+ }
+};
+
+static struct usb_driver cxusb_driver = {
+ .owner = THIS_MODULE,
+ .name = "dvb_usb_cxusb",
+ .probe = cxusb_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = cxusb_table,
+};
+
+/* module stuff */
+static int __init cxusb_module_init(void)
+{
+ int result;
+ if ((result = usb_register(&cxusb_driver))) {
+ err("usb_register failed. Error number %d",result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit cxusb_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&cxusb_driver);
+}
+
+module_init (cxusb_module_init);
+module_exit (cxusb_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design");
+MODULE_VERSION("1.0-alpha");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h
new file mode 100644
index 00000000000..1d79016e319
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/cxusb.h
@@ -0,0 +1,30 @@
+#ifndef _DVB_USB_CXUSB_H_
+#define _DVB_USB_CXUSB_H_
+
+#define DVB_USB_LOG_PREFIX "digitv"
+#include "dvb-usb.h"
+
+extern int dvb_usb_cxusb_debug;
+#define deb_info(args...) dprintk(dvb_usb_cxusb_debug,0x01,args)
+
+/* usb commands - some of it are guesses, don't have a reference yet */
+#define CMD_I2C_WRITE 0x08
+#define CMD_I2C_READ 0x09
+
+#define CMD_IOCTL 0x0e
+#define IOCTL_SET_I2C_PATH 0x02
+
+#define CMD_POWER_OFF 0x50
+#define CMD_POWER_ON 0x51
+
+enum cxusb_i2c_pathes {
+ PATH_UNDEF = 0x00,
+ PATH_CX22702 = 0x01,
+ PATH_TUNER_OTHER = 0x02,
+};
+
+struct cxusb_state {
+ enum cxusb_i2c_pathes cur_i2c_path;
+};
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index a0ffbb59fa1..828b5182e16 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -31,10 +31,17 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_device *d)
return 0;
}
-/* some of the dibusb 1.1 device aren't equipped with the default tuner
+static int dibusb_thomson_tuner_attach(struct dvb_usb_device *d)
+{
+ d->pll_addr = 0x61;
+ d->pll_desc = &dvb_pll_tua6010xs;
+ return 0;
+}
+
+/* Some of the Artec 1.1 device aren't equipped with the default tuner
* (Thomson Cable), but with a Panasonic ENV77H11D5. This function figures
* this out. */
-static int dibusb_dib3000mb_tuner_attach (struct dvb_usb_device *d)
+static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d)
{
u8 b[2] = { 0,0 }, b2[1];
int ret = 0;
@@ -59,8 +66,7 @@ static int dibusb_dib3000mb_tuner_attach (struct dvb_usb_device *d)
if (b2[0] == 0xfe) {
info("this device has the Thomson Cable onboard. Which is default.");
- d->pll_addr = 0x61;
- d->pll_desc = &dvb_pll_tua6010xs;
+ dibusb_thomson_tuner_attach(d);
} else {
u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
info("this device has the Panasonic ENV77H11D5 onboard.");
@@ -90,8 +96,8 @@ static int dibusb_probe(struct usb_interface *intf,
/* do not change the order of the ID table */
static struct usb_device_id dibusb_dib3000mb_table [] = {
-/* 00 */ { USB_DEVICE(USB_VID_AVERMEDIA_UNK, USB_PID_AVERMEDIA_DVBT_USB_COLD)},
-/* 01 */ { USB_DEVICE(USB_VID_AVERMEDIA_UNK, USB_PID_AVERMEDIA_DVBT_USB_WARM)},
+/* 00 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_COLD)},
+/* 01 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_WARM)},
/* 02 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) },
/* 03 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_WARM) },
/* 04 */ { USB_DEVICE(USB_VID_COMPRO_UNK, USB_PID_COMPRO_DVBU2000_UNK_COLD) },
@@ -114,7 +120,17 @@ static struct usb_device_id dibusb_dib3000mb_table [] = {
/* 21 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
/* 22 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
/* 23 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_COLD) },
+
+/* device ID with default DIBUSB2_0-firmware and with the hacked firmware */
/* 24 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) },
+/* 25 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_COLD) },
+/* 26 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_WARM) },
+
+// #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+
+#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+/* 27 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
+#endif
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table);
@@ -134,7 +150,7 @@ static struct dvb_usb_properties dibusb1_1_properties = {
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
.power_ctrl = dibusb_power_ctrl,
.frontend_attach = dibusb_dib3000mb_frontend_attach,
- .tuner_attach = dibusb_dib3000mb_tuner_attach,
+ .tuner_attach = dibusb_tuner_probe_and_attach,
.rc_interval = DEFAULT_RC_INTERVAL,
.rc_key_map = dibusb_rc_keys,
@@ -156,7 +172,7 @@ static struct dvb_usb_properties dibusb1_1_properties = {
}
},
- .num_device_descs = 8,
+ .num_device_descs = 9,
.devices = {
{ "AVerMedia AverTV DVBT USB1.1",
{ &dibusb_dib3000mb_table[0], NULL },
@@ -190,11 +206,17 @@ static struct dvb_usb_properties dibusb1_1_properties = {
{ &dibusb_dib3000mb_table[19], NULL },
{ &dibusb_dib3000mb_table[20], NULL },
},
+ { "VideoWalker DVB-T USB",
+ { &dibusb_dib3000mb_table[25], NULL },
+ { &dibusb_dib3000mb_table[26], NULL },
+ },
}
};
static struct dvb_usb_properties dibusb1_1_an2235_properties = {
.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+ .pid_filter_count = 16,
+
.usb_ctrl = CYPRESS_AN2235,
.firmware = "dvb-usb-dibusb-an2235-01.fw",
@@ -206,7 +228,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
.power_ctrl = dibusb_power_ctrl,
.frontend_attach = dibusb_dib3000mb_frontend_attach,
- .tuner_attach = dibusb_dib3000mb_tuner_attach,
+ .tuner_attach = dibusb_tuner_probe_and_attach,
.rc_interval = DEFAULT_RC_INTERVAL,
.rc_key_map = dibusb_rc_keys,
@@ -228,20 +250,32 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
}
},
+#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+ .num_device_descs = 2,
+#else
.num_device_descs = 1,
+#endif
.devices = {
{ "Artec T1 USB1.1 TVBOX with AN2235",
{ &dibusb_dib3000mb_table[20], NULL },
{ &dibusb_dib3000mb_table[21], NULL },
},
+#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+ { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
+ { &dibusb_dib3000mb_table[27], NULL },
+ { NULL },
+ },
+#endif
}
};
static struct dvb_usb_properties dibusb2_0b_properties = {
.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+ .pid_filter_count = 32,
+
.usb_ctrl = CYPRESS_FX2,
- .firmware = "dvb-usb-adstech-usb2-01.fw",
+ .firmware = "dvb-usb-adstech-usb2-02.fw",
.size_of_priv = sizeof(struct dibusb_state),
@@ -250,7 +284,7 @@ static struct dvb_usb_properties dibusb2_0b_properties = {
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
.power_ctrl = dibusb2_0_power_ctrl,
.frontend_attach = dibusb_dib3000mb_frontend_attach,
- .tuner_attach = dibusb_dib3000mb_tuner_attach,
+ .tuner_attach = dibusb_thomson_tuner_attach,
.rc_interval = DEFAULT_RC_INTERVAL,
.rc_key_map = dibusb_rc_keys,
@@ -272,18 +306,18 @@ static struct dvb_usb_properties dibusb2_0b_properties = {
}
},
- .num_device_descs = 2,
+ .num_device_descs = 1,
.devices = {
{ "KWorld/ADSTech Instant DVB-T USB 2.0",
{ &dibusb_dib3000mb_table[23], NULL },
- { &dibusb_dib3000mb_table[24], NULL }, /* device ID with default DIBUSB2_0-firmware */
+ { &dibusb_dib3000mb_table[24], NULL },
},
}
};
static struct usb_driver dibusb_driver = {
.owner = THIS_MODULE,
- .name = "DiBcom based USB DVB-T devices (DiB3000M-B based)",
+ .name = "dvb_usb_dibusb_mb",
.probe = dibusb_probe,
.disconnect = dvb_usb_device_exit,
.id_table = dibusb_dib3000mb_table,
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c
index aad8ed3fe00..e9dac430f37 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mc.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c
@@ -83,7 +83,7 @@ static struct dvb_usb_properties dibusb_mc_properties = {
static struct usb_driver dibusb_mc_driver = {
.owner = THIS_MODULE,
- .name = "DiBcom based USB2.0 DVB-T (DiB3000M-C/P based) devices",
+ .name = "dvb_usb_dibusb_mc",
.probe = dibusb_mc_probe,
.disconnect = dvb_usb_device_exit,
.id_table = dibusb_dib3000mc_table,
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index 5acf3fde952..9a676afc1d6 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -1,10 +1,9 @@
/* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0
* receiver
*
- * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) and
- * Allan Third (allan.third@cs.man.ac.uk)
+ * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
*
- * partly based on the SDK published by Nebula Electronics (TODO do we want this line ?)
+ * partly based on the SDK published by Nebula Electronics
*
* This 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
@@ -38,7 +37,7 @@ static int digitv_ctrl_msg(struct dvb_usb_device *d,
dvb_usb_generic_write(d,sndbuf,7);
} else {
dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7,10);
- memcpy(&rbuf,&rcvbuf[3],rlen);
+ memcpy(rbuf,&rcvbuf[3],rlen);
}
return 0;
}
@@ -95,41 +94,20 @@ static int digitv_identify_state (struct usb_device *udev, struct
static int digitv_mt352_demod_init(struct dvb_frontend *fe)
{
- static u8 mt352_clock_config[] = { 0x89, 0x38, 0x2d };
- static u8 mt352_reset[] = { 0x50, 0x80 };
- static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 };
-
- static u8 mt352_agc_cfg[] = { 0x68, 0xa0 };
- static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0xa0 };
- static u8 mt352_acq_ctl[] = { 0x53, 0x50 };
- static u8 mt352_agc_target[] = { 0x67, 0x20 };
-
- static u8 mt352_rs_err_per[] = { 0x7c, 0x00, 0x01 };
- static u8 mt352_snr_select[] = { 0x79, 0x00, 0x20 };
-
- static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x05 };
+ static u8 reset_buf[] = { 0x89, 0x38, 0x8a, 0x2d, 0x50, 0x80 };
+ static u8 init_buf[] = { 0x68, 0xa0, 0x8e, 0x40, 0x53, 0x50,
+ 0x67, 0x20, 0x7d, 0x01, 0x7c, 0x00, 0x7a, 0x00,
+ 0x79, 0x20, 0x57, 0x05, 0x56, 0x31, 0x88, 0x0f,
+ 0x75, 0x32 };
+ int i;
- static u8 mt352_scan_ctl[] = { 0x88, 0x0f };
- static u8 mt352_capt_range[] = { 0x75, 0x32 };
+ for (i = 0; i < ARRAY_SIZE(reset_buf); i += 2)
+ mt352_write(fe, &reset_buf[i], 2);
- mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
- mt352_write(fe, mt352_reset, sizeof(mt352_reset));
msleep(1);
- mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio));
-
- mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
- mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
- mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl));
- mt352_write(fe, mt352_agc_target, sizeof(mt352_agc_target));
-
-
- mt352_write(fe, mt352_rs_err_per, sizeof(mt352_rs_err_per));
- mt352_write(fe, mt352_snr_select, sizeof(mt352_snr_select));
- mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1));
-
- mt352_write(fe, mt352_scan_ctl, sizeof(mt352_scan_ctl));
- mt352_write(fe, mt352_capt_range, sizeof(mt352_capt_range));
+ for (i = 0; i < ARRAY_SIZE(init_buf); i += 2)
+ mt352_write(fe, &init_buf[i], 2);
return 0;
}
@@ -137,7 +115,7 @@ static int digitv_mt352_demod_init(struct dvb_frontend *fe)
static struct mt352_config digitv_mt352_config = {
.demod_address = 0x0, /* ignored by the digitv anyway */
.demod_init = digitv_mt352_demod_init,
- .pll_set = NULL, /* TODO */
+ .pll_set = dvb_usb_pll_set,
};
static struct nxt6000_config digitv_nxt6000_config = {
@@ -150,9 +128,9 @@ static struct nxt6000_config digitv_nxt6000_config = {
static int digitv_frontend_attach(struct dvb_usb_device *d)
{
- if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) == NULL)
+ if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL)
return 0;
- if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) == NULL) {
+ if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) {
warn("nxt6000 support is not done yet, in fact you are one of the first "
"person who wants to use this device in Linux. Please report to "
@@ -163,6 +141,13 @@ static int digitv_frontend_attach(struct dvb_usb_device *d)
return -EIO;
}
+static int digitv_tuner_attach(struct dvb_usb_device *d)
+{
+ d->pll_addr = 0x60;
+ d->pll_desc = &dvb_pll_tded4;
+ return 0;
+}
+
static struct dvb_usb_rc_key digitv_rc_keys[] = {
{ 0x00, 0x16, KEY_POWER }, /* dummy key */
};
@@ -184,7 +169,6 @@ int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
return 0;
}
-
/* DVB USB Driver stuff */
static struct dvb_usb_properties digitv_properties;
@@ -208,13 +192,8 @@ static struct dvb_usb_properties digitv_properties = {
.size_of_priv = 0,
- .streaming_ctrl = NULL,
- .pid_filter = NULL,
- .pid_filter_ctrl = NULL,
- .power_ctrl = NULL,
.frontend_attach = digitv_frontend_attach,
- .tuner_attach = NULL, // digitv_tuner_attach,
- .read_mac_address = NULL,
+ .tuner_attach = digitv_tuner_attach,
.rc_interval = 1000,
.rc_key_map = digitv_rc_keys,
@@ -238,7 +217,7 @@ static struct dvb_usb_properties digitv_properties = {
}
},
- .num_device_descs = 2,
+ .num_device_descs = 1,
.devices = {
{ "Nebula Electronics uDigiTV DVB-T USB2.0)",
{ &digitv_table[0], NULL },
@@ -249,7 +228,7 @@ static struct dvb_usb_properties digitv_properties = {
static struct usb_driver digitv_driver = {
.owner = THIS_MODULE,
- .name = "Nebula Electronics uDigiTV DVB-T USB2.0 device",
+ .name = "dvb_usb_digitv",
.probe = digitv_probe,
.disconnect = dvb_usb_device_exit,
.id_table = digitv_table,
diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c
index d17d768038c..b032523b07b 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c
@@ -1,5 +1,5 @@
-/* Frontend part of the Linux driver for the Yakumo/Hama/Typhoon DVB-T
- * USB2.0 receiver.
+/* Frontend part of the Linux driver for the WideView/ Yakumo/ Hama/
+ * Typhoon/ Yuan DVB-T USB2.0 receiver.
*
* Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
*
@@ -14,61 +14,58 @@
struct dtt200u_fe_state {
struct dvb_usb_device *d;
+ fe_status_t stat;
+
struct dvb_frontend_parameters fep;
struct dvb_frontend frontend;
};
-#define moan(which,what) info("unexpected value in '%s' for cmd '%02x' - please report to linux-dvb@linuxtv.org",which,what)
-
static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
- u8 bw = GET_TUNE_STAT;
- u8 br[3] = { 0 };
-// u8 bdeb[5] = { 0 };
+ u8 st = GET_TUNE_STATUS, b[3];
+
+ dvb_usb_generic_rw(state->d,&st,1,b,3,0);
- dvb_usb_generic_rw(state->d,&bw,1,br,3,0);
- switch (br[0]) {
+ switch (b[0]) {
case 0x01:
- *stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+ *stat = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
break;
- case 0x00:
- *stat = 0;
+ case 0x00: /* pending */
+ *stat = FE_TIMEDOUT; /* during set_frontend */
break;
default:
- moan("br[0]",GET_TUNE_STAT);
+ case 0x02: /* failed */
+ *stat = 0;
break;
}
-
-// bw[0] = 0x88;
-// dvb_usb_generic_rw(state->d,bw,1,bdeb,5,0);
-
-// deb_info("%02x: %02x %02x %02x %02x %02x\n",bw[0],bdeb[0],bdeb[1],bdeb[2],bdeb[3],bdeb[4]);
-
return 0;
}
+
static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
- u8 bw = GET_BER;
- *ber = 0;
- dvb_usb_generic_rw(state->d,&bw,1,(u8*) ber,3,0);
+ u8 bw = GET_VIT_ERR_CNT,b[3];
+ dvb_usb_generic_rw(state->d,&bw,1,b,3,0);
+ *ber = (b[0] << 16) | (b[1] << 8) | b[2];
return 0;
}
static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
- u8 bw = GET_UNK;
- *unc = 0;
- dvb_usb_generic_rw(state->d,&bw,1,(u8*) unc,3,0);
+ u8 bw = GET_RS_UNCOR_BLK_CNT,b[2];
+
+ dvb_usb_generic_rw(state->d,&bw,1,b,2,0);
+ *unc = (b[0] << 8) | b[1];
return 0;
}
static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
- u8 bw = GET_SIG_STRENGTH, b;
+ u8 bw = GET_AGC, b;
dvb_usb_generic_rw(state->d,&bw,1,&b,1,0);
*strength = (b << 8) | b;
return 0;
@@ -86,7 +83,7 @@ static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
static int dtt200u_fe_init(struct dvb_frontend* fe)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
- u8 b = RESET_DEMOD;
+ u8 b = SET_INIT;
return dvb_usb_generic_write(state->d,&b,1);
}
@@ -98,8 +95,8 @@ static int dtt200u_fe_sleep(struct dvb_frontend* fe)
static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
{
tune->min_delay_ms = 1500;
- tune->step_size = 166667;
- tune->max_drift = 166667 * 2;
+ tune->step_size = 0;
+ tune->max_drift = 0;
return 0;
}
@@ -107,27 +104,32 @@ static int dtt200u_fe_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
+ int i;
+ fe_status_t st;
u16 freq = fep->frequency / 250000;
- u8 bw,bwbuf[2] = { SET_BANDWIDTH, 0 }, freqbuf[3] = { SET_FREQUENCY, 0, 0 };
+ u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 };
switch (fep->u.ofdm.bandwidth) {
- case BANDWIDTH_8_MHZ: bw = 8; break;
- case BANDWIDTH_7_MHZ: bw = 7; break;
- case BANDWIDTH_6_MHZ: bw = 6; break;
+ case BANDWIDTH_8_MHZ: bwbuf[1] = 8; break;
+ case BANDWIDTH_7_MHZ: bwbuf[1] = 7; break;
+ case BANDWIDTH_6_MHZ: bwbuf[1] = 6; break;
case BANDWIDTH_AUTO: return -EOPNOTSUPP;
default:
return -EINVAL;
}
- deb_info("set_frontend\n");
- bwbuf[1] = bw;
dvb_usb_generic_write(state->d,bwbuf,2);
freqbuf[1] = freq & 0xff;
freqbuf[2] = (freq >> 8) & 0xff;
dvb_usb_generic_write(state->d,freqbuf,3);
- memcpy(&state->fep,fep,sizeof(struct dvb_frontend_parameters));
+ for (i = 0; i < 30; i++) {
+ msleep(20);
+ dtt200u_fe_read_status(fe, &st);
+ if (st & FE_TIMEDOUT)
+ continue;
+ }
return 0;
}
@@ -174,7 +176,7 @@ success:
static struct dvb_frontend_ops dtt200u_fe_ops = {
.info = {
- .name = "DTT200U (Yakumo/Typhoon/Hama) DVB-T",
+ .name = "WideView USB DVB-T",
.type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
index fb2b5a2da13..47dba6e4596 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -1,8 +1,10 @@
-/* DVB USB library compliant Linux driver for the Yakumo/Hama/Typhoon DVB-T
- * USB2.0 receiver.
+/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/
+ * Typhoon/ Yuan DVB-T USB2.0 receiver.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
+ * Thanks to Steve Chang from WideView for providing support for the WT-220U.
+ *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
@@ -16,14 +18,24 @@ int dvb_usb_dtt200u_debug;
module_param_named(debug,dvb_usb_dtt200u_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB_DEBUG_STATUS);
+static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ u8 b = SET_INIT;
+
+ if (onoff)
+ dvb_usb_generic_write(d,&b,2);
+
+ return 0;
+}
+
static int dtt200u_streaming_ctrl(struct dvb_usb_device *d, int onoff)
{
- u8 b_streaming[2] = { SET_TS_CTRL, onoff };
+ u8 b_streaming[2] = { SET_STREAMING, onoff };
u8 b_rst_pid = RESET_PID_FILTER;
dvb_usb_generic_write(d,b_streaming,2);
- if (!onoff)
+ if (onoff == 0)
dvb_usb_generic_write(d,&b_rst_pid,1);
return 0;
}
@@ -36,7 +48,7 @@ static int dtt200u_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int
b_pid[0] = SET_PID_FILTER;
b_pid[1] = index;
b_pid[2] = pid & 0xff;
- b_pid[3] = (pid >> 8) & 0xff;
+ b_pid[3] = (pid >> 8) & 0x1f;
return dvb_usb_generic_write(d,b_pid,4);
}
@@ -54,9 +66,9 @@ static struct dvb_usb_rc_key dtt200u_rc_keys[] = {
{ 0x80, 0x08, KEY_5 },
{ 0x80, 0x09, KEY_6 },
{ 0x80, 0x0a, KEY_7 },
- { 0x00, 0x0c, KEY_ZOOM },
+ { 0x80, 0x0c, KEY_ZOOM },
{ 0x80, 0x0d, KEY_0 },
- { 0x00, 0x0e, KEY_SELECT },
+ { 0x80, 0x0e, KEY_SELECT },
{ 0x80, 0x12, KEY_POWER },
{ 0x80, 0x1a, KEY_CHANNELUP },
{ 0x80, 0x1b, KEY_8 },
@@ -66,7 +78,7 @@ static struct dvb_usb_rc_key dtt200u_rc_keys[] = {
static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
- u8 key[5],cmd = GET_RC_KEY;
+ u8 key[5],cmd = GET_RC_CODE;
dvb_usb_generic_rw(d,&cmd,1,key,5,0);
dvb_usb_nec_rc_key_to_event(d,key,event,state);
if (key[0] != 0)
@@ -81,32 +93,41 @@ static int dtt200u_frontend_attach(struct dvb_usb_device *d)
}
static struct dvb_usb_properties dtt200u_properties;
+static struct dvb_usb_properties wt220u_properties;
static int dtt200u_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- return dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE);
+ if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE) == 0 ||
+ dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE) == 0)
+ return 0;
+
+ return -ENODEV;
}
static struct usb_device_id dtt200u_usb_table [] = {
- { USB_DEVICE(USB_VID_AVERMEDIA_UNK, USB_PID_DTT200U_COLD) },
- { USB_DEVICE(USB_VID_AVERMEDIA_UNK, USB_PID_DTT200U_WARM) },
+// { USB_DEVICE(0x04b4,0x8613) },
+ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) },
+ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) },
+ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD) },
+ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) },
{ 0 },
};
MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
static struct dvb_usb_properties dtt200u_properties = {
.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
- .pid_filter_count = 255, /* It is a guess, but there are at least 10 */
+ .pid_filter_count = 15,
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-dtt200u-01.fw",
+ .power_ctrl = dtt200u_power_ctrl,
.streaming_ctrl = dtt200u_streaming_ctrl,
.pid_filter = dtt200u_pid_filter,
.frontend_attach = dtt200u_frontend_attach,
- .rc_interval = 200,
+ .rc_interval = 300,
.rc_key_map = dtt200u_rc_keys,
.rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
.rc_query = dtt200u_rc_query,
@@ -127,18 +148,59 @@ static struct dvb_usb_properties dtt200u_properties = {
.num_device_descs = 1,
.devices = {
- { .name = "Yakumo/Hama/Typhoon DVB-T USB2.0)",
- .cold_ids = { &dtt200u_usb_table[0], &dtt200u_usb_table[2] },
+ { .name = "WideView/Yuan/Yakumo/Hama/Typhoon DVB-T USB2.0 (WT-200U)",
+ .cold_ids = { &dtt200u_usb_table[0], NULL },
.warm_ids = { &dtt200u_usb_table[1], NULL },
},
{ 0 },
}
};
+static struct dvb_usb_properties wt220u_properties = {
+ .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
+ .pid_filter_count = 15,
+
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-wt220u-01.fw",
+
+ .power_ctrl = dtt200u_power_ctrl,
+ .streaming_ctrl = dtt200u_streaming_ctrl,
+ .pid_filter = dtt200u_pid_filter,
+ .frontend_attach = dtt200u_frontend_attach,
+
+ .rc_interval = 300,
+ .rc_key_map = dtt200u_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
+ .rc_query = dtt200u_rc_query,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { .name = "WideView WT-220U PenType Receiver (and clones)",
+ .cold_ids = { &dtt200u_usb_table[2], NULL },
+ .warm_ids = { &dtt200u_usb_table[3], NULL },
+ },
+ { 0 },
+ }
+};
+
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver dtt200u_usb_driver = {
.owner = THIS_MODULE,
- .name = "Yakumo/Hama/Typhoon DVB-T USB2.0",
+ .name = "dvb_usb_dtt200u",
.probe = dtt200u_usb_probe,
.disconnect = dvb_usb_device_exit,
.id_table = dtt200u_usb_table,
@@ -166,6 +228,6 @@ module_init(dtt200u_usb_module_init);
module_exit(dtt200u_usb_module_exit);
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("Driver for the Yakumo/Hama/Typhoon DVB-T USB2.0 device");
+MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon DVB-T USB2.0 devices");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.h b/drivers/media/dvb/dvb-usb/dtt200u.h
index ed414207151..6f1f3042e21 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.h
+++ b/drivers/media/dvb/dvb-usb/dtt200u.h
@@ -1,5 +1,5 @@
-/* Common header file of Linux driver for the Yakumo/Hama/Typhoon DVB-T
- * USB2.0 receiver.
+/* Common header file of Linux driver for the WideView/ Yakumo/ Hama/
+ * Typhoon/ Yuan DVB-T USB2.0 receiver.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
@@ -22,44 +22,34 @@ extern int dvb_usb_dtt200u_debug;
/* guessed protocol description (reverse engineered):
* read
* 00 - USB type 0x02 for usb2.0, 0x01 for usb1.1
- * 81 - <TS_LOCK> <current frequency divided by 250000>
- * 82 - crash - do not touch
- * 83 - crash - do not touch
- * 84 - remote control
- * 85 - crash - do not touch (OK, stop testing here)
* 88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
- * 89 - noise-to-signal
- * 8a - unkown 1 byte - signal_strength
- * 8c - ber ???
- * 8d - ber
- * 8e - unc
*/
-#define GET_SPEED 0x00
-#define GET_TUNE_STAT 0x81
-#define GET_RC_KEY 0x84
-#define GET_STATUS 0x88
-#define GET_SNR 0x89
-#define GET_SIG_STRENGTH 0x8a
-#define GET_UNK 0x8c
-#define GET_BER 0x8d
-#define GET_UNC 0x8e
+#define GET_SPEED 0x00
+#define GET_TUNE_STATUS 0x81
+#define GET_RC_CODE 0x84
+#define GET_CONFIGURATION 0x88
+#define GET_AGC 0x89
+#define GET_SNR 0x8a
+#define GET_VIT_ERR_CNT 0x8c
+#define GET_RS_ERR_CNT 0x8d
+#define GET_RS_UNCOR_BLK_CNT 0x8e
/* write
- * 01 - reset the demod
+ * 01 - init
* 02 - frequency (divided by 250000)
* 03 - bandwidth
* 04 - pid table (index pid(7:0) pid(12:8))
* 05 - reset the pid table
- * 08 - demod transfer enabled or not (FX2 transfer is enabled by default)
+ * 08 - transfer switch
*/
-#define RESET_DEMOD 0x01
-#define SET_FREQUENCY 0x02
+#define SET_INIT 0x01
+#define SET_RF_FREQ 0x02
#define SET_BANDWIDTH 0x03
#define SET_PID_FILTER 0x04
#define RESET_PID_FILTER 0x05
-#define SET_TS_CTRL 0x08
+#define SET_STREAMING 0x08
extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h
index 67e0d73fbce..7300489d3e2 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-common.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-common.h
@@ -12,14 +12,16 @@
#include "dvb-usb.h"
extern int dvb_usb_debug;
+extern int dvb_usb_disable_rc_polling;
#define deb_info(args...) dprintk(dvb_usb_debug,0x01,args)
#define deb_xfer(args...) dprintk(dvb_usb_debug,0x02,args)
-#define deb_pll(args...) dprintk(dvb_usb_debug,0x04,args)
+#define deb_pll(args...) dprintk(dvb_usb_debug,0x04,args)
#define deb_ts(args...) dprintk(dvb_usb_debug,0x08,args)
#define deb_err(args...) dprintk(dvb_usb_debug,0x10,args)
#define deb_rc(args...) dprintk(dvb_usb_debug,0x20,args)
#define deb_fw(args...) dprintk(dvb_usb_debug,0x40,args)
+#define deb_mem(args...) dprintk(dvb_usb_debug,0x80,args)
/* commonly used methods */
extern int usb_cypress_load_firmware(struct usb_device *, const char *, int);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index bcb34191868..794d513a848 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -12,7 +12,7 @@
/* Vendor IDs */
#define USB_VID_ADSTECH 0x06e1
#define USB_VID_ANCHOR 0x0547
-#define USB_VID_AVERMEDIA_UNK 0x14aa
+#define USB_VID_WIDEVIEW 0x14aa
#define USB_VID_AVERMEDIA 0x07ca
#define USB_VID_COMPRO 0x185b
#define USB_VID_COMPRO_UNK 0x145f
@@ -24,6 +24,8 @@
#define USB_VID_HANFTEK 0x15f4
#define USB_VID_HAUPPAUGE 0x2040
#define USB_VID_HYPER_PALTEK 0x1025
+#define USB_VID_KYE 0x0458
+#define USB_VID_MEDION 0x1660
#define USB_VID_VISIONPLUS 0x13d3
#define USB_VID_TWINHAN 0x1822
#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
@@ -70,6 +72,8 @@
#define USB_PID_HANFTEK_UMT_010_WARM 0x0015
#define USB_PID_DTT200U_COLD 0x0201
#define USB_PID_DTT200U_WARM 0x0301
+#define USB_PID_WT220U_COLD 0x0222
+#define USB_PID_WT220U_WARM 0x0221
#define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300
#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301
#define USB_PID_NEBULA_DIGITV 0x0201
@@ -78,6 +82,8 @@
#define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820
#define USB_PID_DVICO_BLUEBIRD_LGZ201_1 0xdb01
#define USB_PID_DVICO_BLUEBIRD_TH7579_2 0xdb11
-
+#define USB_PID_MEDION_MD95700 0x0932
+#define USB_PID_KYE_DVB_T_COLD 0x701e
+#define USB_PID_KYE_DVB_T_WARM 0x701f
#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
index 3aadec974cf..c3b3ae4f3ec 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
@@ -18,6 +18,10 @@ int dvb_usb_debug;
module_param_named(debug,dvb_usb_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." DVB_USB_DEBUG_STATUS);
+int dvb_usb_disable_rc_polling;
+module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644);
+MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0).");
+
/* general initialization functions */
int dvb_usb_exit(struct dvb_usb_device *d)
{
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 9f1e23f82ba..fc7800f1743 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -21,6 +21,10 @@ static void dvb_usb_read_remote_control(void *data)
/* TODO: need a lock here. We can simply skip checking for the remote control
if we're busy. */
+ /* when the parameter has been set to 1 via sysfs while the driver was running */
+ if (dvb_usb_disable_rc_polling)
+ return;
+
if (d->props.rc_query(d,&event,&state)) {
err("error while querying for an remote control event.");
goto schedule;
@@ -35,7 +39,7 @@ static void dvb_usb_read_remote_control(void *data)
d->last_event = event;
case REMOTE_KEY_REPEAT:
deb_rc("key repeated\n");
- input_event(&d->rc_input_dev, EV_KEY, event, 1);
+ input_event(&d->rc_input_dev, EV_KEY, d->last_event, 1);
input_event(&d->rc_input_dev, EV_KEY, d->last_event, 0);
input_sync(&d->rc_input_dev);
break;
@@ -85,7 +89,9 @@ schedule:
int dvb_usb_remote_init(struct dvb_usb_device *d)
{
int i;
- if (d->props.rc_key_map == NULL)
+ if (d->props.rc_key_map == NULL ||
+ d->props.rc_query == NULL ||
+ dvb_usb_disable_rc_polling)
return 0;
/* Initialise the remote-control structures.*/
@@ -154,12 +160,12 @@ int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
break;
}
/* See if we can match the raw key code. */
- for (i = 0; i < sizeof(keymap)/sizeof(struct dvb_usb_rc_key); i++)
+ for (i = 0; i < d->props.rc_key_map_size; i++)
if (keymap[i].custom == keybuf[1] &&
keymap[i].data == keybuf[3]) {
*event = keymap[i].event;
*state = REMOTE_KEY_PRESSED;
- break;
+ return 0;
}
deb_err("key mapping failed - no appropriate key found in keymapping\n");
break;
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
index 83d476fb410..f5799a4c228 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
@@ -24,11 +24,12 @@ int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
if ((ret = down_interruptible(&d->usb_sem)))
return ret;
+ deb_xfer(">>> ");
debug_dump(wbuf,wlen,deb_xfer);
ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev,
d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen,
- 2*HZ);
+ 2000);
if (ret)
err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
@@ -42,12 +43,14 @@ int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev,
d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen,
- 2*HZ);
+ 2000);
if (ret)
err("recv bulk message failed: %d",ret);
- else
+ else {
+ deb_xfer("<<< ");
debug_dump(rbuf,actlen,deb_xfer);
+ }
}
up(&d->usb_sem);
@@ -61,12 +64,19 @@ int dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len)
}
EXPORT_SYMBOL(dvb_usb_generic_write);
-static void dvb_usb_bulk_urb_complete(struct urb *urb, struct pt_regs *ptregs)
+
+/* URB stuff for streaming */
+static void dvb_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
{
struct dvb_usb_device *d = urb->context;
+ int ptype = usb_pipetype(urb->pipe);
+ int i;
+ u8 *b;
- deb_ts("bulk urb completed. feedcount: %d, status: %d, length: %d\n",d->feedcount,urb->status,
- urb->actual_length);
+ deb_ts("'%s' urb completed. feedcount: %d, status: %d, length: %d/%d, pack_num: %d, errors: %d\n",
+ ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", d->feedcount,
+ urb->status,urb->actual_length,urb->transfer_buffer_length,
+ urb->number_of_packets,urb->error_count);
switch (urb->status) {
case 0: /* success */
@@ -81,11 +91,33 @@ static void dvb_usb_bulk_urb_complete(struct urb *urb, struct pt_regs *ptregs)
break;
}
- if (d->feedcount > 0 && urb->actual_length > 0) {
- if (d->state & DVB_USB_STATE_DVB)
- dvb_dmx_swfilter(&d->demux, (u8*) urb->transfer_buffer,urb->actual_length);
- } else
- deb_ts("URB dropped because of feedcount.\n");
+ if (d->feedcount > 0) {
+ if (d->state & DVB_USB_STATE_DVB) {
+ switch (ptype) {
+ case PIPE_ISOCHRONOUS:
+ b = (u8 *) urb->transfer_buffer;
+ for (i = 0; i < urb->number_of_packets; i++) {
+ if (urb->iso_frame_desc[i].status != 0)
+ deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status);
+ else if (urb->iso_frame_desc[i].actual_length > 0) {
+ dvb_dmx_swfilter(&d->demux,b + urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].actual_length);
+ }
+ urb->iso_frame_desc[i].status = 0;
+ urb->iso_frame_desc[i].actual_length = 0;
+ }
+ debug_dump(b,20,deb_ts);
+ break;
+ case PIPE_BULK:
+ if (urb->actual_length > 0)
+ dvb_dmx_swfilter(&d->demux, (u8 *) urb->transfer_buffer,urb->actual_length);
+ break;
+ default:
+ err("unkown endpoint type in completition handler.");
+ return;
+ }
+ }
+ }
usb_submit_urb(urb,GFP_ATOMIC);
}
@@ -94,7 +126,7 @@ int dvb_usb_urb_kill(struct dvb_usb_device *d)
{
int i;
for (i = 0; i < d->urbs_submitted; i++) {
- deb_info("killing URB no. %d.\n",i);
+ deb_ts("killing URB no. %d.\n",i);
/* stop the URB */
usb_kill_urb(d->urb_list[i]);
@@ -107,9 +139,9 @@ int dvb_usb_urb_submit(struct dvb_usb_device *d)
{
int i,ret;
for (i = 0; i < d->urbs_initialized; i++) {
- deb_info("submitting URB no. %d\n",i);
+ deb_ts("submitting URB no. %d\n",i);
if ((ret = usb_submit_urb(d->urb_list[i],GFP_ATOMIC))) {
- err("could not submit URB no. %d - get them all back\n",i);
+ err("could not submit URB no. %d - get them all back",i);
dvb_usb_urb_kill(d);
return ret;
}
@@ -118,32 +150,78 @@ int dvb_usb_urb_submit(struct dvb_usb_device *d)
return 0;
}
-static int dvb_usb_bulk_urb_init(struct dvb_usb_device *d)
+static int dvb_usb_free_stream_buffers(struct dvb_usb_device *d)
{
- int i,bufsize = d->props.urb.count * d->props.urb.u.bulk.buffersize;
+ if (d->state & DVB_USB_STATE_URB_BUF) {
+ while (d->buf_num) {
+ d->buf_num--;
+ deb_mem("freeing buffer %d\n",d->buf_num);
+ usb_buffer_free(d->udev, d->buf_size,
+ d->buf_list[d->buf_num], d->dma_addr[d->buf_num]);
+ }
+ kfree(d->buf_list);
+ kfree(d->dma_addr);
+ }
+
+ d->state &= ~DVB_USB_STATE_URB_BUF;
- deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize);
- /* allocate the actual buffer for the URBs */
- if ((d->buffer = usb_buffer_alloc(d->udev, bufsize, SLAB_ATOMIC, &d->dma_handle)) == NULL) {
- deb_info("not enough memory for urb-buffer allocation.\n");
+ return 0;
+}
+
+static int dvb_usb_allocate_stream_buffers(struct dvb_usb_device *d, int num, unsigned long size)
+{
+ d->buf_num = 0;
+ d->buf_size = size;
+
+ deb_mem("all in all I will use %lu bytes for streaming\n",num*size);
+
+ if ((d->buf_list = kmalloc(num*sizeof(u8 *), GFP_ATOMIC)) == NULL)
+ return -ENOMEM;
+
+ if ((d->dma_addr = kmalloc(num*sizeof(dma_addr_t), GFP_ATOMIC)) == NULL) {
+ kfree(d->buf_list);
return -ENOMEM;
}
- deb_info("allocation successful\n");
- memset(d->buffer,0,bufsize);
+ memset(d->buf_list,0,num*sizeof(u8 *));
+ memset(d->dma_addr,0,num*sizeof(dma_addr_t));
d->state |= DVB_USB_STATE_URB_BUF;
+ for (d->buf_num = 0; d->buf_num < num; d->buf_num++) {
+ deb_mem("allocating buffer %d\n",d->buf_num);
+ if (( d->buf_list[d->buf_num] =
+ usb_buffer_alloc(d->udev, size, SLAB_ATOMIC,
+ &d->dma_addr[d->buf_num]) ) == NULL) {
+ deb_mem("not enough memory for urb-buffer allocation.\n");
+ dvb_usb_free_stream_buffers(d);
+ return -ENOMEM;
+ }
+ deb_mem("buffer %d: %p (dma: %d)\n",d->buf_num,d->buf_list[d->buf_num],d->dma_addr[d->buf_num]);
+ memset(d->buf_list[d->buf_num],0,size);
+ }
+ deb_mem("allocation successful\n");
+
+ return 0;
+}
+
+static int dvb_usb_bulk_urb_init(struct dvb_usb_device *d)
+{
+ int i;
+
+ if ((i = dvb_usb_allocate_stream_buffers(d,d->props.urb.count,
+ d->props.urb.u.bulk.buffersize)) < 0)
+ return i;
+
/* allocate the URBs */
for (i = 0; i < d->props.urb.count; i++) {
- if (!(d->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) {
+ if ((d->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC)) == NULL)
return -ENOMEM;
- }
usb_fill_bulk_urb( d->urb_list[i], d->udev,
usb_rcvbulkpipe(d->udev,d->props.urb.endpoint),
- &d->buffer[i*d->props.urb.u.bulk.buffersize],
+ d->buf_list[i],
d->props.urb.u.bulk.buffersize,
- dvb_usb_bulk_urb_complete, d);
+ dvb_usb_urb_complete, d);
d->urb_list[i]->transfer_flags = 0;
d->urbs_initialized++;
@@ -151,6 +229,47 @@ static int dvb_usb_bulk_urb_init(struct dvb_usb_device *d)
return 0;
}
+static int dvb_usb_isoc_urb_init(struct dvb_usb_device *d)
+{
+ int i,j;
+
+ if ((i = dvb_usb_allocate_stream_buffers(d,d->props.urb.count,
+ d->props.urb.u.isoc.framesize*d->props.urb.u.isoc.framesperurb)) < 0)
+ return i;
+
+ /* allocate the URBs */
+ for (i = 0; i < d->props.urb.count; i++) {
+ struct urb *urb;
+ int frame_offset = 0;
+ if ((d->urb_list[i] =
+ usb_alloc_urb(d->props.urb.u.isoc.framesperurb,GFP_ATOMIC)) == NULL)
+ return -ENOMEM;
+
+ urb = d->urb_list[i];
+
+ urb->dev = d->udev;
+ urb->context = d;
+ urb->complete = dvb_usb_urb_complete;
+ urb->pipe = usb_rcvisocpipe(d->udev,d->props.urb.endpoint);
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+ urb->interval = d->props.urb.u.isoc.interval;
+ urb->number_of_packets = d->props.urb.u.isoc.framesperurb;
+ urb->transfer_buffer_length = d->buf_size;
+ urb->transfer_buffer = d->buf_list[i];
+ urb->transfer_dma = d->dma_addr[i];
+
+ for (j = 0; j < d->props.urb.u.isoc.framesperurb; j++) {
+ urb->iso_frame_desc[j].offset = frame_offset;
+ urb->iso_frame_desc[j].length = d->props.urb.u.isoc.framesize;
+ frame_offset += d->props.urb.u.isoc.framesize;
+ }
+
+ d->urbs_initialized++;
+ }
+ return 0;
+
+}
+
int dvb_usb_urb_init(struct dvb_usb_device *d)
{
/*
@@ -174,8 +293,7 @@ int dvb_usb_urb_init(struct dvb_usb_device *d)
case DVB_USB_BULK:
return dvb_usb_bulk_urb_init(d);
case DVB_USB_ISOC:
- err("isochronous transfer not yet implemented in dvb-usb.");
- return -EINVAL;
+ return dvb_usb_isoc_urb_init(d);
default:
err("unkown URB-type for data transfer.");
return -EINVAL;
@@ -191,7 +309,7 @@ int dvb_usb_urb_exit(struct dvb_usb_device *d)
if (d->state & DVB_USB_STATE_URB_LIST) {
for (i = 0; i < d->urbs_initialized; i++) {
if (d->urb_list[i] != NULL) {
- deb_info("freeing URB no. %d.\n",i);
+ deb_mem("freeing URB no. %d.\n",i);
/* free the URBs */
usb_free_urb(d->urb_list[i]);
}
@@ -202,10 +320,6 @@ int dvb_usb_urb_exit(struct dvb_usb_device *d)
d->state &= ~DVB_USB_STATE_URB_LIST;
}
- if (d->state & DVB_USB_STATE_URB_BUF)
- usb_buffer_free(d->udev, d->props.urb.u.bulk.buffersize * d->props.urb.count,
- d->buffer, d->dma_handle);
-
- d->state &= ~DVB_USB_STATE_URB_BUF;
+ dvb_usb_free_stream_buffers(d);
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index abcee1943f6..a80567caf50 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -189,12 +189,13 @@ struct dvb_usb_properties {
struct {
int framesperurb;
int framesize;
+ int interval;
} isoc;
} u;
} urb;
int num_device_descs;
- struct dvb_usb_device_description devices[8];
+ struct dvb_usb_device_description devices[9];
};
@@ -207,19 +208,28 @@ struct dvb_usb_properties {
* @udev: pointer to the device's struct usb_device.
* @urb_list: array of dynamically allocated struct urb for the MPEG2-TS-
* streaming.
- * @buffer: buffer used to streaming.
- * @dma_handle: dma_addr_t for buffer.
+ *
+ * @buf_num: number of buffer allocated.
+ * @buf_size: size of each buffer in buf_list.
+ * @buf_list: array containing all allocate buffers for streaming.
+ * @dma_addr: list of dma_addr_t for each buffer in buf_list.
+ *
* @urbs_initialized: number of URBs initialized.
* @urbs_submitted: number of URBs submitted.
+ *
* @feedcount: number of reqested feeds (used for streaming-activation)
* @pid_filtering: is hardware pid_filtering used or not.
+ *
* @usb_sem: semaphore of USB control messages (reading needs two messages)
* @i2c_sem: semaphore for i2c-transfers
+ *
* @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
* @pll_addr: I2C address of the tuner for programming
* @pll_init: array containing the initialization buffer
* @pll_desc: pointer to the appropriate struct dvb_pll_desc
- * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod
+ *
+ * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board
+ *
* @dvb_adap: device's dvb_adapter.
* @dmxdev: device's dmxdev.
* @demux: device's software demuxer.
@@ -253,8 +263,12 @@ struct dvb_usb_device {
/* usb */
struct usb_device *udev;
struct urb **urb_list;
- u8 *buffer;
- dma_addr_t dma_handle;
+
+ int buf_num;
+ unsigned long buf_size;
+ u8 **buf_list;
+ dma_addr_t *dma_addr;
+
int urbs_initialized;
int urbs_submitted;
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
index 9d83781aef9..258a92bfbcc 100644
--- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
@@ -203,7 +203,7 @@ static struct dvb_usb_properties nova_t_properties = {
static struct usb_driver nova_t_driver = {
.owner = THIS_MODULE,
- .name = "Hauppauge WinTV-NOVA-T usb2",
+ .name = "dvb_usb_nova_t_usb2",
.probe = nova_t_probe,
.disconnect = dvb_usb_device_exit,
.id_table = nova_t_table,
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
index aa560422ce7..2112ac3cf5e 100644
--- a/drivers/media/dvb/dvb-usb/umt-010.c
+++ b/drivers/media/dvb/dvb-usb/umt-010.c
@@ -129,7 +129,7 @@ static struct dvb_usb_properties umt_properties = {
static struct usb_driver umt_driver = {
.owner = THIS_MODULE,
- .name = "HanfTek UMT-010 USB2.0 DVB-T devices",
+ .name = "dvb_usb_umt_010",
.probe = umt_probe,
.disconnect = dvb_usb_device_exit,
.id_table = umt_table,
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index 02ecc9a8e3b..5adc5d69ec8 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -44,7 +44,7 @@ int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in,
if (usb_control_msg(d->udev,
usb_sndctrlpipe(d->udev,0),
TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0,
- outbuf, 20, 2*HZ) != 20) {
+ outbuf, 20, 2000) != 20) {
err("USB control message 'out' went wrong.");
ret = -EIO;
goto unlock;
@@ -55,7 +55,7 @@ int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in,
if (usb_control_msg(d->udev,
usb_rcvctrlpipe(d->udev,0),
TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
- inbuf, 12, 2*HZ) != 12) {
+ inbuf, 12, 2000) != 12) {
err("USB control message 'in' went wrong.");
ret = -EIO;
goto unlock;
@@ -94,13 +94,38 @@ static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff)
/* The keymapping struct. Somehow this should be loaded to the driver, but
* currently it is hardcoded. */
static struct dvb_usb_rc_key vp7045_rc_keys[] = {
- /* insert the keys like this. to make the raw keys visible, enable
- * debug=0x04 when loading dvb-usb-vp7045. */
-
- /* these keys are probably wrong. I don't have a working IR-receiver on my
- * vp7045, so I can't test it. Patches are welcome. */
- { 0x00, 0x01, KEY_1 },
- { 0x00, 0x02, KEY_2 },
+ { 0x00, 0x16, KEY_POWER },
+ { 0x00, 0x10, KEY_MUTE },
+ { 0x00, 0x03, KEY_1 },
+ { 0x00, 0x01, KEY_2 },
+ { 0x00, 0x06, KEY_3 },
+ { 0x00, 0x09, KEY_4 },
+ { 0x00, 0x1d, KEY_5 },
+ { 0x00, 0x1f, KEY_6 },
+ { 0x00, 0x0d, KEY_7 },
+ { 0x00, 0x19, KEY_8 },
+ { 0x00, 0x1b, KEY_9 },
+ { 0x00, 0x15, KEY_0 },
+ { 0x00, 0x05, KEY_CHANNELUP },
+ { 0x00, 0x02, KEY_CHANNELDOWN },
+ { 0x00, 0x1e, KEY_VOLUMEUP },
+ { 0x00, 0x0a, KEY_VOLUMEDOWN },
+ { 0x00, 0x11, KEY_RECORD },
+ { 0x00, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
+ { 0x00, 0x14, KEY_PLAY },
+ { 0x00, 0x1a, KEY_STOP },
+ { 0x00, 0x40, KEY_REWIND },
+ { 0x00, 0x12, KEY_FASTFORWARD },
+ { 0x00, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
+ { 0x00, 0x4c, KEY_PAUSE },
+ { 0x00, 0x4d, KEY_SCREEN }, /* Full screen mode. */
+ { 0x00, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
+ { 0x00, 0x0c, KEY_CANCEL }, /* Cancel */
+ { 0x00, 0x1c, KEY_EPG }, /* EPG */
+ { 0x00, 0x00, KEY_TAB }, /* Tab */
+ { 0x00, 0x48, KEY_INFO }, /* Preview */
+ { 0x00, 0x04, KEY_LIST }, /* RecordList */
+ { 0x00, 0x0f, KEY_TEXT } /* Teletext */
};
static int vp7045_rc_query(struct dvb_usb_device *d, u32 *key_buf, int *state)
@@ -230,7 +255,7 @@ static struct dvb_usb_properties vp7045_properties = {
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver vp7045_usb_driver = {
.owner = THIS_MODULE,
- .name = "dvb-usb-vp7045",
+ .name = "dvb_usb_vp7045",
.probe = vp7045_usb_probe,
.disconnect = dvb_usb_device_exit,
.id_table = vp7045_usb_table,
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index b4fddf513eb..d847c62bd83 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -40,6 +40,12 @@ config DVB_VES1X93
help
A DVB-S tuner module. Say Y when you want to support this frontend.
+config DVB_S5H1420
+ tristate "Samsung S5H1420 based"
+ depends on DVB_CORE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
comment "DVB-T (terrestrial) frontends"
depends on DVB_CORE
@@ -181,4 +187,11 @@ config DVB_BCM3510
An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
support this frontend.
+config DVB_LGDT3302
+ tristate "LGDT3302 based (DViCO FusionHDTV3 Gold)"
+ depends on DVB_CORE
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+ to support this frontend.
+
endmenu
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 91d6d3576d3..de5e240cba7 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -29,3 +29,5 @@ obj-$(CONFIG_DVB_NXT2002) += nxt2002.o
obj-$(CONFIG_DVB_OR51211) += or51211.o
obj-$(CONFIG_DVB_OR51132) += or51132.o
obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
+obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
+obj-$(CONFIG_DVB_LGDT3302) += lgdt3302.o
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index f4aa44136c7..9f639297a9f 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -76,7 +76,6 @@ static u8 init_tab [] = {
0x49, 0x56,
0x6b, 0x1e,
0xc8, 0x02,
- 0xf8, 0x02,
0xf9, 0x00,
0xfa, 0x00,
0xfb, 0x00,
@@ -203,7 +202,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
struct cx22702_state* state = fe->demodulator_priv;
/* set PLL */
- cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
+ cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
if (state->config->pll_set) {
state->config->pll_set(fe, p);
} else if (state->config->pll_desc) {
@@ -217,7 +216,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
} else {
BUG();
}
- cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
+ cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
/* set inversion */
cx22702_set_inversion (state, p->inversion);
@@ -256,7 +255,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) & 0xfc );
cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 );
cx22702_writereg(state, 0x00, 0x01); /* Begin aquisition */
- printk("%s: Autodetecting\n",__FUNCTION__);
+ dprintk("%s: Autodetecting\n",__FUNCTION__);
return 0;
}
@@ -347,10 +346,11 @@ static int cx22702_init (struct dvb_frontend* fe)
for (i=0; i<sizeof(init_tab); i+=2)
cx22702_writereg (state, init_tab[i], init_tab[i+1]);
+ cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02);
/* init PLL */
if (state->config->pll_init) {
- cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
+ cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) & 0xfe);
state->config->pll_init(fe);
cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
}
@@ -440,8 +440,10 @@ static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
/* RS Uncorrectable Packet Count then reset */
_ucblocks = cx22702_readreg (state, 0xE3);
- if (state->prevUCBlocks < _ucblocks) *ucblocks = (_ucblocks - state->prevUCBlocks);
- else *ucblocks = state->prevUCBlocks - _ucblocks;
+ if (state->prevUCBlocks < _ucblocks)
+ *ucblocks = (_ucblocks - state->prevUCBlocks);
+ else
+ *ucblocks = state->prevUCBlocks - _ucblocks;
state->prevUCBlocks = _ucblocks;
return 0;
@@ -457,6 +459,12 @@ static int cx22702_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
return cx22702_get_tps (state, &p->u.ofdm);
}
+static int cx22702_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+ tune->min_delay_ms = 1000;
+ return 0;
+}
+
static void cx22702_release(struct dvb_frontend* fe)
{
struct cx22702_state* state = fe->demodulator_priv;
@@ -472,7 +480,8 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
/* allocate memory for the internal state */
state = kmalloc(sizeof(struct cx22702_state), GFP_KERNEL);
- if (state == NULL) goto error;
+ if (state == NULL)
+ goto error;
/* setup the state */
state->config = config;
@@ -481,7 +490,8 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
state->prevUCBlocks = 0;
/* check if the demod is there */
- if (cx22702_readreg(state, 0x1f) != 0x3) goto error;
+ if (cx22702_readreg(state, 0x1f) != 0x3)
+ goto error;
/* create dvb_frontend */
state->frontend.ops = &state->ops;
@@ -514,6 +524,7 @@ static struct dvb_frontend_ops cx22702_ops = {
.set_frontend = cx22702_set_tps,
.get_frontend = cx22702_get_frontend,
+ .get_tune_settings = cx22702_get_tune_settings,
.read_status = cx22702_read_status,
.read_ber = cx22702_read_ber,
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
index 559fdb90666..11f86806756 100644
--- a/drivers/media/dvb/frontends/cx22702.h
+++ b/drivers/media/dvb/frontends/cx22702.h
@@ -35,6 +35,11 @@ struct cx22702_config
/* the demodulator's i2c address */
u8 demod_address;
+ /* serial/parallel output */
+#define CX22702_PARALLEL_OUTPUT 0
+#define CX22702_SERIAL_OUTPUT 1
+ u8 output_mode;
+
/* PLL maintenance */
u8 pll_address;
struct dvb_pll_desc *pll_desc;
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index f73b5f48e23..5afeaa9b43b 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -55,7 +55,7 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
};
EXPORT_SYMBOL(dvb_pll_thomson_dtt7610);
-static void thomson_dtt759x_bw(u8 *buf, int bandwidth)
+static void thomson_dtt759x_bw(u8 *buf, u32 freq, int bandwidth)
{
if (BANDWIDTH_7_MHZ == bandwidth)
buf[3] |= 0x10;
@@ -93,6 +93,32 @@ struct dvb_pll_desc dvb_pll_lg_z201 = {
};
EXPORT_SYMBOL(dvb_pll_lg_z201);
+struct dvb_pll_desc dvb_pll_microtune_4042 = {
+ .name = "Microtune 4042 FI5",
+ .min = 57000000,
+ .max = 858000000,
+ .count = 3,
+ .entries = {
+ { 162000000, 44000000, 62500, 0x8e, 0xa1 },
+ { 457000000, 44000000, 62500, 0x8e, 0x91 },
+ { 999999999, 44000000, 62500, 0x8e, 0x31 },
+ },
+};
+EXPORT_SYMBOL(dvb_pll_microtune_4042);
+
+struct dvb_pll_desc dvb_pll_thomson_dtt7611 = {
+ .name = "Thomson dtt7611",
+ .min = 44000000,
+ .max = 958000000,
+ .count = 3,
+ .entries = {
+ { 157250000, 44000000, 62500, 0x8e, 0x39 },
+ { 454000000, 44000000, 62500, 0x8e, 0x3a },
+ { 999999999, 44000000, 62500, 0x8e, 0x3c },
+ },
+};
+EXPORT_SYMBOL(dvb_pll_thomson_dtt7611);
+
struct dvb_pll_desc dvb_pll_unknown_1 = {
.name = "unknown 1", /* used by dntv live dvb-t */
.min = 174000000,
@@ -146,7 +172,7 @@ EXPORT_SYMBOL(dvb_pll_env57h1xd5);
/* Philips TDA6650/TDA6651
* used in Panasonic ENV77H11D5
*/
-static void tda665x_bw(u8 *buf, int bandwidth)
+static void tda665x_bw(u8 *buf, u32 freq, int bandwidth)
{
if (bandwidth == BANDWIDTH_8_MHZ)
buf[3] |= 0x08;
@@ -178,7 +204,7 @@ EXPORT_SYMBOL(dvb_pll_tda665x);
/* Infineon TUA6034
* used in LG TDTP E102P
*/
-static void tua6034_bw(u8 *buf, int bandwidth)
+static void tua6034_bw(u8 *buf, u32 freq, int bandwidth)
{
if (BANDWIDTH_7_MHZ != bandwidth)
buf[3] |= 0x08;
@@ -198,6 +224,57 @@ struct dvb_pll_desc dvb_pll_tua6034 = {
};
EXPORT_SYMBOL(dvb_pll_tua6034);
+/* Philips FMD1216ME
+ * used in Medion Hybrid PCMCIA card and USB Box
+ */
+static void fmd1216me_bw(u8 *buf, u32 freq, int bandwidth)
+{
+ if (bandwidth == BANDWIDTH_8_MHZ && freq >= 158870000)
+ buf[3] |= 0x08;
+}
+
+struct dvb_pll_desc dvb_pll_fmd1216me = {
+ .name = "Philips FMD1216ME",
+ .min = 50870000,
+ .max = 858000000,
+ .setbw = fmd1216me_bw,
+ .count = 7,
+ .entries = {
+ { 143870000, 36213333, 166667, 0xbc, 0x41 },
+ { 158870000, 36213333, 166667, 0xf4, 0x41 },
+ { 329870000, 36213333, 166667, 0xbc, 0x42 },
+ { 441870000, 36213333, 166667, 0xf4, 0x42 },
+ { 625870000, 36213333, 166667, 0xbc, 0x44 },
+ { 803870000, 36213333, 166667, 0xf4, 0x44 },
+ { 999999999, 36213333, 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)
+{
+ if (bandwidth == BANDWIDTH_8_MHZ)
+ buf[3] |= 0x04;
+}
+
+struct dvb_pll_desc dvb_pll_tded4 = {
+ .name = "ALPS TDED4",
+ .min = 47000000,
+ .max = 863000000,
+ .setbw = tded4_bw,
+ .count = 4,
+ .entries = {
+ { 153000000, 36166667, 166667, 0x85, 0x01 },
+ { 470000000, 36166667, 166667, 0x85, 0x02 },
+ { 823000000, 36166667, 166667, 0x85, 0x08 },
+ { 999999999, 36166667, 166667, 0x85, 0x88 },
+ }
+};
+EXPORT_SYMBOL(dvb_pll_tded4);
+
/* ----------------------------------------------------------- */
/* code */
@@ -231,7 +308,7 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
buf[3] = desc->entries[i].cb2;
if (desc->setbw)
- desc->setbw(buf, bandwidth);
+ desc->setbw(buf, freq, bandwidth);
if (debug)
printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index b796778624b..cb794759d89 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -9,7 +9,7 @@ struct dvb_pll_desc {
char *name;
u32 min;
u32 max;
- void (*setbw)(u8 *buf, int bandwidth);
+ void (*setbw)(u8 *buf, u32 freq, int bandwidth);
int count;
struct {
u32 limit;
@@ -24,12 +24,16 @@ 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_dtt7611;
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_tda665x;
+extern struct dvb_pll_desc dvb_pll_fmd1216me;
+extern struct dvb_pll_desc dvb_pll_tded4;
int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
u32 freq, int bandwidth);
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c
index 031a1ddc7d1..faaad1ae855 100644
--- a/drivers/media/dvb/frontends/l64781.c
+++ b/drivers/media/dvb/frontends/l64781.c
@@ -474,11 +474,12 @@ static int l64781_init(struct dvb_frontend* fe)
return 0;
}
-static int l64781_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+static int l64781_get_tune_settings(struct dvb_frontend* fe,
+ struct dvb_frontend_tune_settings* fesettings)
{
- fesettings->min_delay_ms = 200;
- fesettings->step_size = 166667;
- fesettings->max_drift = 166667*2;
+ fesettings->min_delay_ms = 4000;
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
return 0;
}
diff --git a/drivers/media/dvb/frontends/lgdt3302.c b/drivers/media/dvb/frontends/lgdt3302.c
new file mode 100644
index 00000000000..09c914256e4
--- /dev/null
+++ b/drivers/media/dvb/frontends/lgdt3302.c
@@ -0,0 +1,611 @@
+/*
+ * $Id: lgdt3302.c,v 1.5 2005/07/07 03:47:15 mkrufky Exp $
+ *
+ * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM
+ *
+ * Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net>
+ *
+ * Based on code from Kirk Lapray <kirk_lapray@bigfoot.com>
+ * Copyright (C) 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * NOTES ABOUT THIS DRIVER
+ *
+ * This driver supports DViCO FusionHDTV 3 Gold under Linux.
+ *
+ * TODO:
+ * BER and signal strength always return 0.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/byteorder.h>
+
+#include "dvb_frontend.h"
+#include "dvb-pll.h"
+#include "lgdt3302_priv.h"
+#include "lgdt3302.h"
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"Turn on/off lgdt3302 frontend debugging (default:off).");
+#define dprintk(args...) \
+do { \
+if (debug) printk(KERN_DEBUG "lgdt3302: " args); \
+} while (0)
+
+struct lgdt3302_state
+{
+ struct i2c_adapter* i2c;
+ struct dvb_frontend_ops ops;
+
+ /* Configuration settings */
+ const struct lgdt3302_config* config;
+
+ struct dvb_frontend frontend;
+
+ /* Demodulator private data */
+ fe_modulation_t current_modulation;
+
+ /* Tuner private data */
+ u32 current_frequency;
+};
+
+static int i2c_writebytes (struct lgdt3302_state* state,
+ u8 addr, /* demod_address or pll_address */
+ u8 *buf, /* data bytes to send */
+ int len /* number of bytes to send */ )
+{
+ if (addr == state->config->pll_address) {
+ struct i2c_msg msg =
+ { .addr = addr, .flags = 0, .buf = buf, .len = len };
+ int err;
+
+ if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err);
+ return -EREMOTEIO;
+ }
+ } else {
+ u8 tmp[] = { buf[0], buf[1] };
+ struct i2c_msg msg =
+ { .addr = addr, .flags = 0, .buf = tmp, .len = 2 };
+ int err;
+ int i;
+
+ for (i=1; i<len; i++) {
+ tmp[1] = buf[i];
+ if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err);
+ return -EREMOTEIO;
+ }
+ tmp[0]++;
+ }
+ }
+ return 0;
+}
+static int i2c_readbytes (struct lgdt3302_state* state,
+ u8 addr, /* demod_address or pll_address */
+ u8 *buf, /* holds data bytes read */
+ int len /* number of bytes to read */ )
+{
+ struct i2c_msg msg =
+ { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len };
+ int err;
+
+ if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lgdt3302: %s error (addr %02x, err == %i)\n", __FUNCTION__, addr, err);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+/*
+ * This routine writes the register (reg) to the demod bus
+ * then reads the data returned for (len) bytes.
+ */
+
+static u8 i2c_selectreadbytes (struct lgdt3302_state* state,
+ enum I2C_REG reg, u8* buf, int len)
+{
+ u8 wr [] = { reg };
+ struct i2c_msg msg [] = {
+ { .addr = state->config->demod_address,
+ .flags = 0, .buf = wr, .len = 1 },
+ { .addr = state->config->demod_address,
+ .flags = I2C_M_RD, .buf = buf, .len = len },
+ };
+ int ret;
+ ret = i2c_transfer(state->i2c, msg, 2);
+ if (ret != 2) {
+ printk(KERN_WARNING "lgdt3302: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __FUNCTION__, state->config->demod_address, reg, ret);
+ } else {
+ ret = 0;
+ }
+ return ret;
+}
+
+/* Software reset */
+int lgdt3302_SwReset(struct lgdt3302_state* state)
+{
+ u8 ret;
+ u8 reset[] = {
+ IRQ_MASK,
+ 0x00 /* bit 6 is active low software reset
+ * bits 5-0 are 1 to mask interrupts */
+ };
+
+ ret = i2c_writebytes(state,
+ state->config->demod_address,
+ reset, sizeof(reset));
+ if (ret == 0) {
+ /* spec says reset takes 100 ns why wait */
+ /* mdelay(100); */ /* keep low for 100mS */
+ reset[1] = 0x7f; /* force reset high (inactive)
+ * and unmask interrupts */
+ ret = i2c_writebytes(state,
+ state->config->demod_address,
+ reset, sizeof(reset));
+ }
+ /* Spec does not indicate a need for this either */
+ /*mdelay(5); */ /* wait 5 msec before doing more */
+ return ret;
+}
+
+static int lgdt3302_init(struct dvb_frontend* fe)
+{
+ /* Hardware reset is done using gpio[0] of cx23880x chip.
+ * I'd like to do it here, but don't know how to find chip address.
+ * cx88-cards.c arranges for the reset bit to be inactive (high).
+ * Maybe there needs to be a callable function in cx88-core or
+ * the caller of this function needs to do it. */
+
+ dprintk("%s entered\n", __FUNCTION__);
+ return lgdt3302_SwReset((struct lgdt3302_state*) fe->demodulator_priv);
+}
+
+static int lgdt3302_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ *ber = 0; /* Dummy out for now */
+ return 0;
+}
+
+static int lgdt3302_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
+ u8 buf[2];
+
+ i2c_selectreadbytes(state, PACKET_ERR_COUNTER1, buf, sizeof(buf));
+
+ *ucblocks = (buf[0] << 8) | buf[1];
+ return 0;
+}
+
+static int lgdt3302_set_parameters(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *param)
+{
+ u8 buf[4];
+ struct lgdt3302_state* state =
+ (struct lgdt3302_state*) fe->demodulator_priv;
+
+ /* Use 50MHz parameter values from spec sheet since xtal is 50 */
+ static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 };
+ static u8 vsb_freq_cfg[] = { VSB_CARRIER_FREQ0, 0x00, 0x87, 0x8e, 0x01 };
+ static u8 demux_ctrl_cfg[] = { DEMUX_CONTROL, 0xfb };
+ static u8 agc_rf_cfg[] = { AGC_RF_BANDWIDTH0, 0x40, 0x93, 0x00 };
+ static u8 agc_ctrl_cfg[] = { AGC_FUNC_CTRL2, 0xc6, 0x40 };
+ static u8 agc_delay_cfg[] = { AGC_DELAY0, 0x00, 0x00, 0x00 };
+ static u8 agc_loop_cfg[] = { AGC_LOOP_BANDWIDTH0, 0x08, 0x9a };
+
+ /* Change only if we are actually changing the modulation */
+ if (state->current_modulation != param->u.vsb.modulation) {
+ switch(param->u.vsb.modulation) {
+ case VSB_8:
+ dprintk("%s: VSB_8 MODE\n", __FUNCTION__);
+
+ /* Select VSB mode and serial MPEG interface */
+ top_ctrl_cfg[1] = 0x07;
+ break;
+
+ case QAM_64:
+ dprintk("%s: QAM_64 MODE\n", __FUNCTION__);
+
+ /* Select QAM_64 mode and serial MPEG interface */
+ top_ctrl_cfg[1] = 0x04;
+ break;
+
+ case QAM_256:
+ dprintk("%s: QAM_256 MODE\n", __FUNCTION__);
+
+ /* Select QAM_256 mode and serial MPEG interface */
+ top_ctrl_cfg[1] = 0x05;
+ break;
+ default:
+ printk(KERN_WARNING "lgdt3302: %s: Modulation type(%d) UNSUPPORTED\n", __FUNCTION__, param->u.vsb.modulation);
+ return -1;
+ }
+ /* Initializations common to all modes */
+
+ /* Select the requested mode */
+ i2c_writebytes(state, state->config->demod_address,
+ top_ctrl_cfg, sizeof(top_ctrl_cfg));
+
+ /* Change the value of IFBW[11:0]
+ of AGC IF/RF loop filter bandwidth register */
+ i2c_writebytes(state, state->config->demod_address,
+ agc_rf_cfg, sizeof(agc_rf_cfg));
+
+ /* Change the value of bit 6, 'nINAGCBY' and
+ 'NSSEL[1:0] of ACG function control register 2 */
+ /* Change the value of bit 6 'RFFIX'
+ of AGC function control register 3 */
+ i2c_writebytes(state, state->config->demod_address,
+ agc_ctrl_cfg, sizeof(agc_ctrl_cfg));
+
+ /* Change the TPCLK pin polarity
+ data is valid on falling clock */
+ i2c_writebytes(state, state->config->demod_address,
+ demux_ctrl_cfg, sizeof(demux_ctrl_cfg));
+
+ if (param->u.vsb.modulation == VSB_8) {
+ /* Initialization for VSB modes only */
+ /* Change the value of NCOCTFV[25:0]of carrier
+ recovery center frequency register for VSB */
+ i2c_writebytes(state, state->config->demod_address,
+ vsb_freq_cfg, sizeof(vsb_freq_cfg));
+ } else {
+ /* Initialization for QAM modes only */
+ /* Set the value of 'INLVTHD' register 0x2a/0x2c
+ to value from 'IFACC' register 0x39/0x3b -1 */
+ int value;
+ i2c_selectreadbytes(state, AGC_RFIF_ACC0,
+ &agc_delay_cfg[1], 3);
+ value = ((agc_delay_cfg[1] & 0x0f) << 8) | agc_delay_cfg[3];
+ value = value -1;
+ dprintk("%s IFACC -1 = 0x%03x\n", __FUNCTION__, value);
+ agc_delay_cfg[1] = (value >> 8) & 0x0f;
+ agc_delay_cfg[2] = 0x00;
+ agc_delay_cfg[3] = value & 0xff;
+ i2c_writebytes(state, state->config->demod_address,
+ agc_delay_cfg, sizeof(agc_delay_cfg));
+
+ /* Change the value of IAGCBW[15:8]
+ of inner AGC loop filter bandwith */
+ i2c_writebytes(state, state->config->demod_address,
+ agc_loop_cfg, sizeof(agc_loop_cfg));
+ }
+
+ state->config->set_ts_params(fe, 0);
+ lgdt3302_SwReset(state);
+ state->current_modulation = param->u.vsb.modulation;
+ }
+
+ /* Change only if we are actually changing the channel */
+ if (state->current_frequency != param->frequency) {
+ dvb_pll_configure(state->config->pll_desc, buf,
+ param->frequency, 0);
+ dprintk("%s: tuner bytes: 0x%02x 0x%02x "
+ "0x%02x 0x%02x\n", __FUNCTION__, buf[0],buf[1],buf[2],buf[3]);
+ i2c_writebytes(state, state->config->pll_address ,buf, 4);
+
+ /* Check the status of the tuner pll */
+ i2c_readbytes(state, state->config->pll_address, buf, 1);
+ dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[0]);
+
+ lgdt3302_SwReset(state);
+
+ /* Update current frequency */
+ state->current_frequency = param->frequency;
+ }
+ return 0;
+}
+
+static int lgdt3302_get_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* param)
+{
+ struct lgdt3302_state *state = fe->demodulator_priv;
+ param->frequency = state->current_frequency;
+ return 0;
+}
+
+static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
+ u8 buf[3];
+
+ *status = 0; /* Reset status result */
+
+ /* Check the status of the tuner pll */
+ i2c_readbytes(state, state->config->pll_address, buf, 1);
+ dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[0]);
+ if ((buf[0] & 0xc0) != 0x40)
+ return 0; /* Tuner PLL not locked or not powered on */
+
+ /*
+ * You must set the Mask bits to 1 in the IRQ_MASK in order
+ * to see that status bit in the IRQ_STATUS register.
+ * This is done in SwReset();
+ */
+
+ /* AGC status register */
+ i2c_selectreadbytes(state, AGC_STATUS, buf, 1);
+ dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]);
+ if ((buf[0] & 0x0c) == 0x8){
+ /* Test signal does not exist flag */
+ /* as well as the AGC lock flag. */
+ *status |= FE_HAS_SIGNAL;
+ } else {
+ /* Without a signal all other status bits are meaningless */
+ return 0;
+ }
+
+ /* signal status */
+ i2c_selectreadbytes(state, TOP_CONTROL, buf, sizeof(buf));
+ dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __FUNCTION__, buf[0], buf[1], buf[2]);
+
+#if 0
+ /* Alternative method to check for a signal */
+ /* using the SNR good/bad interrupts. */
+ if ((buf[2] & 0x30) == 0x10)
+ *status |= FE_HAS_SIGNAL;
+#endif
+
+ /* sync status */
+ if ((buf[2] & 0x03) == 0x01) {
+ *status |= FE_HAS_SYNC;
+ }
+
+ /* FEC error status */
+ if ((buf[2] & 0x0c) == 0x08) {
+ *status |= FE_HAS_LOCK;
+ *status |= FE_HAS_VITERBI;
+ }
+
+ /* Carrier Recovery Lock Status Register */
+ i2c_selectreadbytes(state, CARRIER_LOCK, buf, 1);
+ dprintk("%s: CARRIER_LOCK = 0x%02x\n", __FUNCTION__, buf[0]);
+ switch (state->current_modulation) {
+ case QAM_256:
+ case QAM_64:
+ /* Need to undestand why there are 3 lock levels here */
+ if ((buf[0] & 0x07) == 0x07)
+ *status |= FE_HAS_CARRIER;
+ break;
+ case VSB_8:
+ if ((buf[0] & 0x80) == 0x80)
+ *status |= FE_HAS_CARRIER;
+ break;
+ default:
+ printk("KERN_WARNING lgdt3302: %s: Modulation set to unsupported value\n", __FUNCTION__);
+ }
+
+ return 0;
+}
+
+static int lgdt3302_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ /* not directly available. */
+ return 0;
+}
+
+static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+#ifdef SNR_IN_DB
+ /*
+ * Spec sheet shows formula for SNR_EQ = 10 log10(25 * 24**2 / noise)
+ * and SNR_PH = 10 log10(25 * 32**2 / noise) for equalizer and phase tracker
+ * respectively. The following tables are built on these formulas.
+ * The usual definition is SNR = 20 log10(signal/noise)
+ * If the specification is wrong the value retuned is 1/2 the actual SNR in db.
+ *
+ * This table is a an ordered list of noise values computed by the
+ * formula from the spec sheet such that the index into the table
+ * starting at 43 or 45 is the SNR value in db. There are duplicate noise
+ * value entries at the beginning because the SNR varies more than
+ * 1 db for a change of 1 digit in noise at very small values of noise.
+ *
+ * Examples from SNR_EQ table:
+ * noise SNR
+ * 0 43
+ * 1 42
+ * 2 39
+ * 3 37
+ * 4 36
+ * 5 35
+ * 6 34
+ * 7 33
+ * 8 33
+ * 9 32
+ * 10 32
+ * 11 31
+ * 12 31
+ * 13 30
+ */
+
+ static const u32 SNR_EQ[] =
+ { 1, 2, 2, 2, 3, 3, 4, 4, 5, 7,
+ 9, 11, 13, 17, 21, 26, 33, 41, 52, 65,
+ 81, 102, 129, 162, 204, 257, 323, 406, 511, 644,
+ 810, 1020, 1284, 1616, 2035, 2561, 3224, 4059, 5110, 6433,
+ 8098, 10195, 12835, 16158, 20341, 25608, 32238, 40585, 51094, 64323,
+ 80978, 101945, 128341, 161571, 203406, 256073, 0x40000
+ };
+
+ static const u32 SNR_PH[] =
+ { 1, 2, 2, 2, 3, 3, 4, 5, 6, 8,
+ 10, 12, 15, 19, 23, 29, 37, 46, 58, 73,
+ 91, 115, 144, 182, 229, 288, 362, 456, 574, 722,
+ 909, 1144, 1440, 1813, 2282, 2873, 3617, 4553, 5732, 7216,
+ 9084, 11436, 14396, 18124, 22817, 28724, 36161, 45524, 57312, 72151,
+ 90833, 114351, 143960, 181235, 228161, 0x040000
+ };
+
+ static u8 buf[5];/* read data buffer */
+ static u32 noise; /* noise value */
+ static u32 snr_db; /* index into SNR_EQ[] */
+ struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
+
+ /* read both equalizer and pase tracker noise data */
+ i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf));
+
+ if (state->current_modulation == VSB_8) {
+ /* Equalizer Mean-Square Error Register for VSB */
+ noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
+
+ /*
+ * Look up noise value in table.
+ * A better search algorithm could be used...
+ * watch out there are duplicate entries.
+ */
+ for (snr_db = 0; snr_db < sizeof(SNR_EQ); snr_db++) {
+ if (noise < SNR_EQ[snr_db]) {
+ *snr = 43 - snr_db;
+ break;
+ }
+ }
+ } else {
+ /* Phase Tracker Mean-Square Error Register for QAM */
+ noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
+
+ /* Look up noise value in table. */
+ for (snr_db = 0; snr_db < sizeof(SNR_PH); snr_db++) {
+ if (noise < SNR_PH[snr_db]) {
+ *snr = 45 - snr_db;
+ break;
+ }
+ }
+ }
+#else
+ /* Return the raw noise value */
+ static u8 buf[5];/* read data buffer */
+ static u32 noise; /* noise value */
+ struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
+
+ /* read both equalizer and pase tracker noise data */
+ i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf));
+
+ if (state->current_modulation == VSB_8) {
+ /* Equalizer Mean-Square Error Register for VSB */
+ noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
+ } else {
+ /* Phase Tracker Mean-Square Error Register for QAM */
+ noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
+ }
+
+ /* Small values for noise mean signal is better so invert noise */
+ /* Noise is 19 bit value so discard 3 LSB*/
+ *snr = ~noise>>3;
+#endif
+
+ dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr);
+
+ return 0;
+}
+
+static int lgdt3302_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings)
+{
+ /* I have no idea about this - it may not be needed */
+ fe_tune_settings->min_delay_ms = 500;
+ fe_tune_settings->step_size = 0;
+ fe_tune_settings->max_drift = 0;
+ return 0;
+}
+
+static void lgdt3302_release(struct dvb_frontend* fe)
+{
+ struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops lgdt3302_ops;
+
+struct dvb_frontend* lgdt3302_attach(const struct lgdt3302_config* config,
+ struct i2c_adapter* i2c)
+{
+ struct lgdt3302_state* state = NULL;
+ u8 buf[1];
+
+ /* Allocate memory for the internal state */
+ state = (struct lgdt3302_state*) kmalloc(sizeof(struct lgdt3302_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+ memset(state,0,sizeof(*state));
+
+ /* Setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
+ /* Verify communication with demod chip */
+ if (i2c_selectreadbytes(state, 2, buf, 1))
+ goto error;
+
+ state->current_frequency = -1;
+ state->current_modulation = -1;
+
+ /* Create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state)
+ kfree(state);
+ dprintk("%s: ERROR\n",__FUNCTION__);
+ return NULL;
+}
+
+static struct dvb_frontend_ops lgdt3302_ops = {
+ .info = {
+ .name= "LG Electronics LGDT3302 VSB/QAM Frontend",
+ .type = FE_ATSC,
+ .frequency_min= 54000000,
+ .frequency_max= 858000000,
+ .frequency_stepsize= 62500,
+ /* Symbol rate is for all VSB modes need to check QAM */
+ .symbol_rate_min = 10762000,
+ .symbol_rate_max = 10762000,
+ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+ },
+ .init = lgdt3302_init,
+ .set_frontend = lgdt3302_set_parameters,
+ .get_frontend = lgdt3302_get_frontend,
+ .get_tune_settings = lgdt3302_get_tune_settings,
+ .read_status = lgdt3302_read_status,
+ .read_ber = lgdt3302_read_ber,
+ .read_signal_strength = lgdt3302_read_signal_strength,
+ .read_snr = lgdt3302_read_snr,
+ .read_ucblocks = lgdt3302_read_ucblocks,
+ .release = lgdt3302_release,
+};
+
+MODULE_DESCRIPTION("LGDT3302 [DViCO FusionHDTV 3 Gold] (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
+MODULE_AUTHOR("Wilson Michaels");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(lgdt3302_attach);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * compile-command: "make DVB=1"
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/lgdt3302.h b/drivers/media/dvb/frontends/lgdt3302.h
new file mode 100644
index 00000000000..81587a40032
--- /dev/null
+++ b/drivers/media/dvb/frontends/lgdt3302.h
@@ -0,0 +1,49 @@
+/*
+ * $Id: lgdt3302.h,v 1.2 2005/06/28 23:50:48 mkrufky Exp $
+ *
+ * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM
+ *
+ * Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (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 LGDT3302_H
+#define LGDT3302_H
+
+#include <linux/dvb/frontend.h>
+
+struct lgdt3302_config
+{
+ /* The demodulator's i2c address */
+ u8 demod_address;
+ u8 pll_address;
+ struct dvb_pll_desc *pll_desc;
+
+ /* Need to set device param for start_dma */
+ int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+};
+
+extern struct dvb_frontend* lgdt3302_attach(const struct lgdt3302_config* config,
+ struct i2c_adapter* i2c);
+
+#endif /* LGDT3302_H */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/lgdt3302_priv.h b/drivers/media/dvb/frontends/lgdt3302_priv.h
new file mode 100644
index 00000000000..6193fa7a569
--- /dev/null
+++ b/drivers/media/dvb/frontends/lgdt3302_priv.h
@@ -0,0 +1,72 @@
+/*
+ * $Id: lgdt3302_priv.h,v 1.2 2005/06/28 23:50:48 mkrufky Exp $
+ *
+ * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM
+ *
+ * Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (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 _LGDT3302_PRIV_
+#define _LGDT3302_PRIV_
+
+/* i2c control register addresses */
+enum I2C_REG {
+ TOP_CONTROL= 0x00,
+ IRQ_MASK= 0x01,
+ IRQ_STATUS= 0x02,
+ VSB_CARRIER_FREQ0= 0x16,
+ VSB_CARRIER_FREQ1= 0x17,
+ VSB_CARRIER_FREQ2= 0x18,
+ VSB_CARRIER_FREQ3= 0x19,
+ CARRIER_MSEQAM1= 0x1a,
+ CARRIER_MSEQAM2= 0x1b,
+ CARRIER_LOCK= 0x1c,
+ TIMING_RECOVERY= 0x1d,
+ AGC_DELAY0= 0x2a,
+ AGC_DELAY1= 0x2b,
+ AGC_DELAY2= 0x2c,
+ AGC_RF_BANDWIDTH0= 0x2d,
+ AGC_RF_BANDWIDTH1= 0x2e,
+ AGC_RF_BANDWIDTH2= 0x2f,
+ AGC_LOOP_BANDWIDTH0= 0x30,
+ AGC_LOOP_BANDWIDTH1= 0x31,
+ AGC_FUNC_CTRL1= 0x32,
+ AGC_FUNC_CTRL2= 0x33,
+ AGC_FUNC_CTRL3= 0x34,
+ AGC_RFIF_ACC0= 0x39,
+ AGC_RFIF_ACC1= 0x3a,
+ AGC_RFIF_ACC2= 0x3b,
+ AGC_STATUS= 0x3f,
+ SYNC_STATUS_VSB= 0x43,
+ EQPH_ERR0= 0x47,
+ EQ_ERR1= 0x48,
+ EQ_ERR2= 0x49,
+ PH_ERR1= 0x4a,
+ PH_ERR2= 0x4b,
+ DEMUX_CONTROL= 0x66,
+ PACKET_ERR_COUNTER1= 0x6a,
+ PACKET_ERR_COUNTER2= 0x6b,
+};
+
+#endif /* _LGDT3302_PRIV_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
new file mode 100644
index 00000000000..4f396ac8de7
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -0,0 +1,800 @@
+/*
+Driver for Samsung S5H1420 QPSK Demodulator
+
+Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include "dvb_frontend.h"
+#include "s5h1420.h"
+
+
+
+#define TONE_FREQ 22000
+
+struct s5h1420_state {
+ struct i2c_adapter* i2c;
+ struct dvb_frontend_ops ops;
+ const struct s5h1420_config* config;
+ struct dvb_frontend frontend;
+
+ u8 postlocked:1;
+ u32 fclk;
+ u32 tunedfreq;
+ fe_code_rate_t fec_inner;
+ u32 symbol_rate;
+};
+
+static u32 s5h1420_getsymbolrate(struct s5h1420_state* state);
+static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings);
+
+
+static int debug = 0;
+#define dprintk if (debug) printk
+
+static int s5h1420_writereg (struct s5h1420_state* state, u8 reg, u8 data)
+{
+ u8 buf [] = { reg, data };
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+ int err;
+
+ if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+ dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static u8 s5h1420_readreg (struct s5h1420_state* state, u8 reg)
+{
+ int ret;
+ u8 b0 [] = { reg };
+ u8 b1 [] = { 0 };
+ struct i2c_msg msg1 = { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 };
+ struct i2c_msg msg2 = { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 };
+
+ if ((ret = i2c_transfer (state->i2c, &msg1, 1)) != 1)
+ return ret;
+
+ if ((ret = i2c_transfer (state->i2c, &msg2, 1)) != 1)
+ return ret;
+
+ return b1[0];
+}
+
+static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ switch(voltage) {
+ case SEC_VOLTAGE_13:
+ s5h1420_writereg(state, 0x3c, (s5h1420_readreg(state, 0x3c) & 0xfe) | 0x02);
+ break;
+
+ case SEC_VOLTAGE_18:
+ s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) | 0x03);
+ break;
+
+ case SEC_VOLTAGE_OFF:
+ s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) & 0xfd);
+ break;
+ }
+
+ return 0;
+}
+
+static int s5h1420_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ switch(tone) {
+ case SEC_TONE_ON:
+ s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x74) | 0x08);
+ break;
+
+ case SEC_TONE_OFF:
+ s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01);
+ break;
+ }
+
+ return 0;
+}
+
+static int s5h1420_send_master_cmd (struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+ u8 val;
+ int i;
+ unsigned long timeout;
+ int result = 0;
+
+ /* setup for DISEQC */
+ val = s5h1420_readreg(state, 0x3b);
+ s5h1420_writereg(state, 0x3b, 0x02);
+ msleep(15);
+
+ /* write the DISEQC command bytes */
+ for(i=0; i< cmd->msg_len; i++) {
+ s5h1420_writereg(state, 0x3c + i, cmd->msg[i]);
+ }
+
+ /* kick off transmission */
+ s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | ((cmd->msg_len-1) << 4) | 0x08);
+
+ /* wait for transmission to complete */
+ timeout = jiffies + ((100*HZ) / 1000);
+ while(time_before(jiffies, timeout)) {
+ if (s5h1420_readreg(state, 0x3b) & 0x08)
+ break;
+
+ msleep(5);
+ }
+ if (time_after(jiffies, timeout))
+ result = -ETIMEDOUT;
+
+ /* restore original settings */
+ s5h1420_writereg(state, 0x3b, val);
+ msleep(15);
+ return result;
+}
+
+static int s5h1420_recv_slave_reply (struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+ u8 val;
+ int i;
+ int length;
+ unsigned long timeout;
+ int result = 0;
+
+ /* setup for DISEQC recieve */
+ val = s5h1420_readreg(state, 0x3b);
+ s5h1420_writereg(state, 0x3b, 0x82); /* FIXME: guess - do we need to set DIS_RDY(0x08) in receive mode? */
+ msleep(15);
+
+ /* wait for reception to complete */
+ timeout = jiffies + ((reply->timeout*HZ) / 1000);
+ while(time_before(jiffies, timeout)) {
+ if (!(s5h1420_readreg(state, 0x3b) & 0x80)) /* FIXME: do we test DIS_RDY(0x08) or RCV_EN(0x80)? */
+ break;
+
+ msleep(5);
+ }
+ if (time_after(jiffies, timeout)) {
+ result = -ETIMEDOUT;
+ goto exit;
+ }
+
+ /* check error flag - FIXME: not sure what this does - docs do not describe
+ * beyond "error flag for diseqc receive data :( */
+ if (s5h1420_readreg(state, 0x49)) {
+ result = -EIO;
+ goto exit;
+ }
+
+ /* check length */
+ length = (s5h1420_readreg(state, 0x3b) & 0x70) >> 4;
+ if (length > sizeof(reply->msg)) {
+ result = -EOVERFLOW;
+ goto exit;
+ }
+ reply->msg_len = length;
+
+ /* extract data */
+ for(i=0; i< length; i++) {
+ reply->msg[i] = s5h1420_readreg(state, 0x3c + i);
+ }
+
+exit:
+ /* restore original settings */
+ s5h1420_writereg(state, 0x3b, val);
+ msleep(15);
+ return result;
+}
+
+static int s5h1420_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+ u8 val;
+ int result = 0;
+ unsigned long timeout;
+
+ /* setup for tone burst */
+ val = s5h1420_readreg(state, 0x3b);
+ s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x70) | 0x01);
+
+ /* set value for B position if requested */
+ if (minicmd == SEC_MINI_B) {
+ s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x04);
+ }
+ msleep(15);
+
+ /* start transmission */
+ s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x08);
+
+ /* wait for transmission to complete */
+ timeout = jiffies + ((20*HZ) / 1000);
+ while(time_before(jiffies, timeout)) {
+ if (!(s5h1420_readreg(state, 0x3b) & 0x08))
+ break;
+
+ msleep(5);
+ }
+ if (time_after(jiffies, timeout))
+ result = -ETIMEDOUT;
+
+ /* restore original settings */
+ s5h1420_writereg(state, 0x3b, val);
+ msleep(15);
+ return result;
+}
+
+static fe_status_t s5h1420_get_status_bits(struct s5h1420_state* state)
+{
+ u8 val;
+ fe_status_t status = 0;
+
+ val = s5h1420_readreg(state, 0x14);
+ if (val & 0x02)
+ status |= FE_HAS_SIGNAL; // FIXME: not sure if this is right
+ if (val & 0x01)
+ status |= FE_HAS_CARRIER; // FIXME: not sure if this is right
+ val = s5h1420_readreg(state, 0x36);
+ if (val & 0x01)
+ status |= FE_HAS_VITERBI;
+ if (val & 0x20)
+ status |= FE_HAS_SYNC;
+ if (status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI|FE_HAS_SYNC))
+ status |= FE_HAS_LOCK;
+
+ return status;
+}
+
+static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+ u8 val;
+
+ if (status == NULL)
+ return -EINVAL;
+
+ /* determine lock state */
+ *status = s5h1420_get_status_bits(state);
+
+ /* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert the inversion,
+ wait a bit and check again */
+ if (*status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI)) {
+ val = s5h1420_readreg(state, 0x32);
+ if ((val & 0x07) == 0x03) {
+ if (val & 0x08)
+ s5h1420_writereg(state, 0x31, 0x13);
+ else
+ s5h1420_writereg(state, 0x31, 0x1b);
+
+ /* wait a bit then update lock status */
+ mdelay(200);
+ *status = s5h1420_get_status_bits(state);
+ }
+ }
+
+ /* perform post lock setup */
+ if ((*status & FE_HAS_LOCK) && (!state->postlocked)) {
+
+ /* calculate the data rate */
+ u32 tmp = s5h1420_getsymbolrate(state);
+ switch(s5h1420_readreg(state, 0x32) & 0x07) {
+ case 0:
+ tmp = (tmp * 2 * 1) / 2;
+ break;
+
+ case 1:
+ tmp = (tmp * 2 * 2) / 3;
+ break;
+
+ case 2:
+ tmp = (tmp * 2 * 3) / 4;
+ break;
+
+ case 3:
+ tmp = (tmp * 2 * 5) / 6;
+ break;
+
+ case 4:
+ tmp = (tmp * 2 * 6) / 7;
+ break;
+
+ case 5:
+ tmp = (tmp * 2 * 7) / 8;
+ break;
+ }
+ tmp = state->fclk / tmp;
+
+ /* set the MPEG_CLK_INTL for the calculated data rate */
+ if (tmp < 4)
+ val = 0x00;
+ else if (tmp < 8)
+ val = 0x01;
+ else if (tmp < 12)
+ val = 0x02;
+ else if (tmp < 16)
+ val = 0x03;
+ else if (tmp < 24)
+ val = 0x04;
+ else if (tmp < 32)
+ val = 0x05;
+ else
+ val = 0x06;
+ s5h1420_writereg(state, 0x22, val);
+
+ /* DC freeze */
+ s5h1420_writereg(state, 0x1f, s5h1420_readreg(state, 0x1f) | 0x01);
+
+ /* kicker disable + remove DC offset */
+ s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) & 0x6f);
+
+ /* post-lock processing has been done! */
+ state->postlocked = 1;
+ }
+
+ return 0;
+}
+
+static int s5h1420_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ s5h1420_writereg(state, 0x46, 0x1d);
+ mdelay(25);
+ return (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47);
+}
+
+static int s5h1420_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ u8 val = 0xff - s5h1420_readreg(state, 0x15);
+
+ return (int) ((val << 8) | val);
+}
+
+static int s5h1420_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ s5h1420_writereg(state, 0x46, 0x1f);
+ mdelay(25);
+ return (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47);
+}
+
+static void s5h1420_reset(struct s5h1420_state* state)
+{
+ s5h1420_writereg (state, 0x01, 0x08);
+ s5h1420_writereg (state, 0x01, 0x00);
+ udelay(10);
+}
+
+static void s5h1420_setsymbolrate(struct s5h1420_state* state, struct dvb_frontend_parameters *p)
+{
+ u64 val;
+
+ val = (p->u.qpsk.symbol_rate / 1000) * (1<<24);
+ if (p->u.qpsk.symbol_rate <= 21000000) {
+ val *= 2;
+ }
+ do_div(val, (state->fclk / 1000));
+
+ s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0x7f);
+ s5h1420_writereg(state, 0x11, val >> 16);
+ s5h1420_writereg(state, 0x12, val >> 8);
+ s5h1420_writereg(state, 0x13, val & 0xff);
+ s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x80);
+}
+
+static u32 s5h1420_getsymbolrate(struct s5h1420_state* state)
+{
+ u64 val;
+ int sampling = 2;
+
+ if (s5h1420_readreg(state, 0x05) & 0x2)
+ sampling = 1;
+
+ s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08);
+ val = s5h1420_readreg(state, 0x11) << 16;
+ val |= s5h1420_readreg(state, 0x12) << 8;
+ val |= s5h1420_readreg(state, 0x13);
+ s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7);
+
+ val *= (state->fclk / 1000);
+ do_div(val, ((1<<24) * sampling));
+
+ return (u32) (val * 1000);
+}
+
+static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset)
+{
+ int val;
+
+ /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so
+ * divide fclk by 1000000 to get the correct value. */
+ val = -(int) ((freqoffset * (1<<24)) / (state->fclk / 1000000));
+
+ s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0xbf);
+ s5h1420_writereg(state, 0x0e, val >> 16);
+ s5h1420_writereg(state, 0x0f, val >> 8);
+ s5h1420_writereg(state, 0x10, val & 0xff);
+ s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x40);
+}
+
+static int s5h1420_getfreqoffset(struct s5h1420_state* state)
+{
+ int val;
+
+ s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08);
+ val = s5h1420_readreg(state, 0x0e) << 16;
+ val |= s5h1420_readreg(state, 0x0f) << 8;
+ val |= s5h1420_readreg(state, 0x10);
+ s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7);
+
+ if (val & 0x800000)
+ val |= 0xff000000;
+
+ /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so
+ * divide fclk by 1000000 to get the correct value. */
+ val = - ((val * (state->fclk/1000000)) / (1<<24));
+
+ return val;
+}
+
+static void s5h1420_setfec(struct s5h1420_state* state, struct dvb_frontend_parameters *p)
+{
+ if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {
+ s5h1420_writereg(state, 0x31, 0x00);
+ s5h1420_writereg(state, 0x30, 0x3f);
+ } else {
+ switch(p->u.qpsk.fec_inner) {
+ case FEC_1_2:
+ s5h1420_writereg(state, 0x31, 0x10);
+ s5h1420_writereg(state, 0x30, 0x01);
+ break;
+
+ case FEC_2_3:
+ s5h1420_writereg(state, 0x31, 0x11);
+ s5h1420_writereg(state, 0x30, 0x02);
+ break;
+
+ case FEC_3_4:
+ s5h1420_writereg(state, 0x31, 0x12);
+ s5h1420_writereg(state, 0x30, 0x04);
+ break;
+
+ case FEC_5_6:
+ s5h1420_writereg(state, 0x31, 0x13);
+ s5h1420_writereg(state, 0x30, 0x08);
+ break;
+
+ case FEC_6_7:
+ s5h1420_writereg(state, 0x31, 0x14);
+ s5h1420_writereg(state, 0x30, 0x10);
+ break;
+
+ case FEC_7_8:
+ s5h1420_writereg(state, 0x31, 0x15);
+ s5h1420_writereg(state, 0x30, 0x20);
+ break;
+
+ default:
+ return;
+ }
+ }
+}
+
+static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state)
+{
+ switch(s5h1420_readreg(state, 0x32) & 0x07) {
+ case 0:
+ return FEC_1_2;
+
+ case 1:
+ return FEC_2_3;
+
+ case 2:
+ return FEC_3_4;
+
+ case 3:
+ return FEC_5_6;
+
+ case 4:
+ return FEC_6_7;
+
+ case 5:
+ return FEC_7_8;
+ }
+
+ return FEC_NONE;
+}
+
+static void s5h1420_setinversion(struct s5h1420_state* state, struct dvb_frontend_parameters *p)
+{
+ if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {
+ s5h1420_writereg(state, 0x31, 0x00);
+ s5h1420_writereg(state, 0x30, 0x3f);
+ } else {
+ u8 tmp = s5h1420_readreg(state, 0x31) & 0xf7;
+ tmp |= 0x10;
+
+ if (p->inversion == INVERSION_ON)
+ tmp |= 0x80;
+
+ s5h1420_writereg(state, 0x31, tmp);
+ }
+}
+
+static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state)
+{
+ if (s5h1420_readreg(state, 0x32) & 0x08)
+ return INVERSION_ON;
+
+ return INVERSION_OFF;
+}
+
+static int s5h1420_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+ u32 frequency_delta;
+ struct dvb_frontend_tune_settings fesettings;
+
+ /* check if we should do a fast-tune */
+ memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters));
+ s5h1420_get_tune_settings(fe, &fesettings);
+ frequency_delta = p->frequency - state->tunedfreq;
+ if ((frequency_delta > -fesettings.max_drift) && (frequency_delta < fesettings.max_drift) &&
+ (frequency_delta != 0) &&
+ (state->fec_inner == p->u.qpsk.fec_inner) &&
+ (state->symbol_rate == p->u.qpsk.symbol_rate)) {
+
+ s5h1420_setfreqoffset(state, frequency_delta);
+ return 0;
+ }
+
+ /* first of all, software reset */
+ s5h1420_reset(state);
+
+ /* set tuner PLL */
+ if (state->config->pll_set) {
+ s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
+ state->config->pll_set(fe, p, &state->tunedfreq);
+ s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
+ }
+
+ /* set s5h1420 fclk PLL according to desired symbol rate */
+ if (p->u.qpsk.symbol_rate > 28000000) {
+ state->fclk = 88000000;
+ s5h1420_writereg(state, 0x03, 0x50);
+ s5h1420_writereg(state, 0x04, 0x40);
+ s5h1420_writereg(state, 0x05, 0xae);
+ } else if (p->u.qpsk.symbol_rate > 21000000) {
+ state->fclk = 59000000;
+ s5h1420_writereg(state, 0x03, 0x33);
+ s5h1420_writereg(state, 0x04, 0x40);
+ s5h1420_writereg(state, 0x05, 0xae);
+ } else {
+ state->fclk = 88000000;
+ s5h1420_writereg(state, 0x03, 0x50);
+ s5h1420_writereg(state, 0x04, 0x40);
+ s5h1420_writereg(state, 0x05, 0xac);
+ }
+
+ /* set misc registers */
+ s5h1420_writereg(state, 0x02, 0x00);
+ s5h1420_writereg(state, 0x07, 0xb0);
+ s5h1420_writereg(state, 0x0a, 0x67);
+ s5h1420_writereg(state, 0x0b, 0x78);
+ s5h1420_writereg(state, 0x0c, 0x48);
+ s5h1420_writereg(state, 0x0d, 0x6b);
+ s5h1420_writereg(state, 0x2e, 0x8e);
+ s5h1420_writereg(state, 0x35, 0x33);
+ s5h1420_writereg(state, 0x38, 0x01);
+ s5h1420_writereg(state, 0x39, 0x7d);
+ s5h1420_writereg(state, 0x3a, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
+ s5h1420_writereg(state, 0x3c, 0x00);
+ s5h1420_writereg(state, 0x45, 0x61);
+ s5h1420_writereg(state, 0x46, 0x1d);
+
+ /* start QPSK */
+ s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1);
+
+ /* set the frequency offset to adjust for PLL inaccuracy */
+ s5h1420_setfreqoffset(state, p->frequency - state->tunedfreq);
+
+ /* set the reset of the parameters */
+ s5h1420_setsymbolrate(state, p);
+ s5h1420_setinversion(state, p);
+ s5h1420_setfec(state, p);
+
+ state->fec_inner = p->u.qpsk.fec_inner;
+ state->symbol_rate = p->u.qpsk.symbol_rate;
+ state->postlocked = 0;
+ return 0;
+}
+
+static int s5h1420_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state);
+ p->inversion = s5h1420_getinversion(state);
+ p->u.qpsk.symbol_rate = s5h1420_getsymbolrate(state);
+ p->u.qpsk.fec_inner = s5h1420_getfec(state);
+
+ return 0;
+}
+
+static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+ if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) {
+ fesettings->min_delay_ms = 50;
+ fesettings->step_size = 2000;
+ fesettings->max_drift = 8000;
+ } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) {
+ fesettings->min_delay_ms = 100;
+ fesettings->step_size = 1500;
+ fesettings->max_drift = 9000;
+ } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) {
+ fesettings->min_delay_ms = 100;
+ fesettings->step_size = 1000;
+ fesettings->max_drift = 8000;
+ } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) {
+ fesettings->min_delay_ms = 100;
+ fesettings->step_size = 500;
+ fesettings->max_drift = 7000;
+ } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) {
+ fesettings->min_delay_ms = 200;
+ fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+ fesettings->max_drift = 14 * fesettings->step_size;
+ } else {
+ fesettings->min_delay_ms = 200;
+ fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+ fesettings->max_drift = 18 * fesettings->step_size;
+ }
+
+ return 0;
+}
+
+static int s5h1420_init (struct dvb_frontend* fe)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ /* disable power down and do reset */
+ s5h1420_writereg(state, 0x02, 0x10);
+ msleep(10);
+ s5h1420_reset(state);
+
+ /* init PLL */
+ if (state->config->pll_init) {
+ s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
+ state->config->pll_init(fe);
+ s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
+ }
+
+ return 0;
+}
+
+static int s5h1420_sleep(struct dvb_frontend* fe)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ return s5h1420_writereg(state, 0x02, 0x12);
+}
+
+static void s5h1420_release(struct dvb_frontend* fe)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops s5h1420_ops;
+
+struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, struct i2c_adapter* i2c)
+{
+ struct s5h1420_state* state = NULL;
+ u8 identity;
+
+ /* allocate memory for the internal state */
+ state = kmalloc(sizeof(struct s5h1420_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
+ state->postlocked = 0;
+ state->fclk = 88000000;
+ state->tunedfreq = 0;
+ state->fec_inner = FEC_NONE;
+ state->symbol_rate = 0;
+
+ /* check if the demod is there + identify it */
+ identity = s5h1420_readreg(state, 0x00);
+ if (identity != 0x03)
+ goto error;
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops s5h1420_ops = {
+
+ .info = {
+ .name = "Samsung S5H1420 DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 125, /* kHz for QPSK frontends */
+ .frequency_tolerance = 29500,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ /* .symbol_rate_tolerance = ???,*/
+ .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_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK
+ },
+
+ .release = s5h1420_release,
+
+ .init = s5h1420_init,
+ .sleep = s5h1420_sleep,
+
+ .set_frontend = s5h1420_set_frontend,
+ .get_frontend = s5h1420_get_frontend,
+ .get_tune_settings = s5h1420_get_tune_settings,
+
+ .read_status = s5h1420_read_status,
+ .read_ber = s5h1420_read_ber,
+ .read_signal_strength = s5h1420_read_signal_strength,
+ .read_ucblocks = s5h1420_read_ucblocks,
+
+ .diseqc_send_master_cmd = s5h1420_send_master_cmd,
+ .diseqc_recv_slave_reply = s5h1420_recv_slave_reply,
+ .diseqc_send_burst = s5h1420_send_burst,
+ .set_tone = s5h1420_set_tone,
+ .set_voltage = s5h1420_set_voltage,
+};
+
+module_param(debug, int, 0644);
+
+MODULE_DESCRIPTION("Samsung S5H1420 DVB-S Demodulator driver");
+MODULE_AUTHOR("Andrew de Quincey");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(s5h1420_attach);
diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h
new file mode 100644
index 00000000000..b687fc77ceb
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1420.h
@@ -0,0 +1,41 @@
+/*
+ Driver for S5H1420 QPSK Demodulators
+
+ Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (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 S5H1420_H
+#define S5H1420_H
+
+#include <linux/dvb/frontend.h>
+
+struct s5h1420_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout);
+};
+
+extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
+ struct i2c_adapter* i2c);
+
+#endif // S5H1420_H
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
index e681263bf07..928aca052af 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -617,7 +617,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
/* wait for WGAGC lock */
starttime = jiffies;
- timeout = jiffies + (200 * HZ) / 1000;
+ timeout = jiffies + msecs_to_jiffies(2000);
while (time_before(jiffies, timeout)) {
msleep(10);
if (stv0297_readreg(state, 0x43) & 0x08)
@@ -629,7 +629,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
msleep(20);
/* wait for equaliser partial convergence */
- timeout = jiffies + (50 * HZ) / 1000;
+ timeout = jiffies + msecs_to_jiffies(500);
while (time_before(jiffies, timeout)) {
msleep(10);
@@ -642,7 +642,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
}
/* wait for equaliser full convergence */
- timeout = jiffies + (delay * HZ) / 1000;
+ timeout = jiffies + msecs_to_jiffies(delay);
while (time_before(jiffies, timeout)) {
msleep(10);
@@ -659,7 +659,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
stv0297_writereg_mask(state, 0x88, 8, 0);
/* wait for main lock */
- timeout = jiffies + (20 * HZ) / 1000;
+ timeout = jiffies + msecs_to_jiffies(20);
while (time_before(jiffies, timeout)) {
msleep(10);
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index 0beb370792a..ab0c032472c 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -49,10 +49,8 @@ struct tda1004x_state {
/* private demod data */
u8 initialised;
enum tda1004x_demod demod_type;
- u8 fw_version;
};
-
static int debug;
#define dprintk(args...) \
do { \
@@ -122,6 +120,8 @@ static int debug;
#define TDA10046H_GPIO_OUT_SEL 0x41
#define TDA10046H_GPIO_SELECT 0x42
#define TDA10046H_AGC_CONF 0x43
+#define TDA10046H_AGC_THR 0x44
+#define TDA10046H_AGC_RENORM 0x45
#define TDA10046H_AGC_GAINS 0x46
#define TDA10046H_AGC_TUN_MIN 0x47
#define TDA10046H_AGC_TUN_MAX 0x48
@@ -274,14 +274,26 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state,
switch (bandwidth) {
case BANDWIDTH_6_MHZ:
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz));
+ if (state->config->if_freq == TDA10046_FREQ_045) {
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x09);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x4f);
+ }
break;
case BANDWIDTH_7_MHZ:
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz));
+ if (state->config->if_freq == TDA10046_FREQ_045) {
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x79);
+ }
break;
case BANDWIDTH_8_MHZ:
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz));
+ if (state->config->if_freq == TDA10046_FREQ_045) {
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3);
+ }
break;
default:
@@ -315,20 +327,35 @@ static int tda1004x_do_upload(struct tda1004x_state *state,
memcpy(buf + 1, mem + pos, tx_size);
fw_msg.len = tx_size + 1;
if (i2c_transfer(state->i2c, &fw_msg, 1) != 1) {
- printk("tda1004x: Error during firmware upload\n");
+ printk(KERN_ERR "tda1004x: Error during firmware upload\n");
return -EIO;
}
pos += tx_size;
dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, pos);
}
+ // give the DSP a chance to settle 03/10/05 Hac
+ msleep(100);
return 0;
}
-static int tda1004x_check_upload_ok(struct tda1004x_state *state, u8 dspVersion)
+static int tda1004x_check_upload_ok(struct tda1004x_state *state)
{
u8 data1, data2;
+ unsigned long timeout;
+
+ if (state->demod_type == TDA1004X_DEMOD_TDA10046) {
+ timeout = jiffies + 2 * HZ;
+ while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) {
+ if (time_after(jiffies, timeout)) {
+ printk(KERN_ERR "tda1004x: timeout waiting for DSP ready\n");
+ break;
+ }
+ msleep(1);
+ }
+ } else
+ msleep(100);
// check upload was OK
tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP
@@ -336,9 +363,11 @@ static int tda1004x_check_upload_ok(struct tda1004x_state *state, u8 dspVersion)
data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1);
data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2);
- if ((data1 != 0x67) || (data2 != dspVersion))
+ if (data1 != 0x67 || data2 < 0x20 || data2 > 0x2e) {
+ printk(KERN_INFO "tda1004x: found firmware revision %x -- invalid\n", data2);
return -EIO;
-
+ }
+ printk(KERN_INFO "tda1004x: found firmware revision %x -- ok\n", data2);
return 0;
}
@@ -349,14 +378,14 @@ static int tda10045_fwupload(struct dvb_frontend* fe)
const struct firmware *fw;
/* don't re-upload unless necessary */
- if (tda1004x_check_upload_ok(state, 0x2c) == 0)
+ if (tda1004x_check_upload_ok(state) == 0)
return 0;
/* request the firmware, this will block until someone uploads it */
- printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE);
+ printk(KERN_INFO "tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE);
ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
if (ret) {
- printk("tda1004x: no firmware upload (timeout or file not found?)\n");
+ printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
return ret;
}
@@ -370,95 +399,93 @@ static int tda10045_fwupload(struct dvb_frontend* fe)
tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ);
ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN);
+ release_firmware(fw);
if (ret)
return ret;
- printk("tda1004x: firmware upload complete\n");
+ printk(KERN_INFO "tda1004x: firmware upload complete\n");
/* wait for DSP to initialise */
/* DSPREADY doesn't seem to work on the TDA10045H */
msleep(100);
- return tda1004x_check_upload_ok(state, 0x2c);
+ return tda1004x_check_upload_ok(state);
}
-static int tda10046_get_fw_version(struct tda1004x_state *state,
- const struct firmware *fw)
+static void tda10046_init_plls(struct dvb_frontend* fe)
{
- const unsigned char pattern[] = { 0x67, 0x00, 0x50, 0x62, 0x5e, 0x18, 0x67 };
- unsigned int i;
-
- /* area guessed from firmware v20, v21 and v25 */
- for (i = 0x660; i < 0x700; i++) {
- if (!memcmp(&fw->data[i], pattern, sizeof(pattern))) {
- state->fw_version = fw->data[i + sizeof(pattern)];
- printk(KERN_INFO "tda1004x: using firmware v%02x\n",
- state->fw_version);
- return 0;
- }
- }
+ struct tda1004x_state* state = fe->demodulator_priv;
- return -EINVAL;
+ tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
+ tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10
+ if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
+ dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__);
+ tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
+ } else {
+ dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __FUNCTION__);
+ tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3
+ }
+ tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99);
+ switch (state->config->if_freq) {
+ case TDA10046_FREQ_3617:
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
+ break;
+ case TDA10046_FREQ_3613:
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x13);
+ break;
+ case TDA10046_FREQ_045:
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3);
+ break;
+ case TDA10046_FREQ_052:
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x06);
+ break;
+ }
+ tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
}
static int tda10046_fwupload(struct dvb_frontend* fe)
{
struct tda1004x_state* state = fe->demodulator_priv;
- unsigned long timeout;
int ret;
const struct firmware *fw;
/* reset + wake up chip */
- tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0);
+ tda1004x_write_byteI(state, TDA1004X_CONFC4, 0);
tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
- msleep(100);
+ /* let the clocks recover from sleep */
+ msleep(5);
/* don't re-upload unless necessary */
- if (tda1004x_check_upload_ok(state, state->fw_version) == 0)
+ if (tda1004x_check_upload_ok(state) == 0)
return 0;
- /* request the firmware, this will block until someone uploads it */
- printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10046_DEFAULT_FIRMWARE);
- ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
- if (ret) {
- printk("tda1004x: no firmware upload (timeout or file not found?)\n");
- return ret;
- }
-
- if (fw->size < 24478) { /* size of firmware v20, which is the smallest of v20, v21 and v25 */
- printk("tda1004x: firmware file seems to be too small (%d bytes)\n", fw->size);
- return -EINVAL;
- }
-
- ret = tda10046_get_fw_version(state, fw);
- if (ret < 0) {
- printk("tda1004x: unable to find firmware version\n");
- return ret;
- }
-
/* set parameters */
- tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10);
- tda1004x_write_byteI(state, TDA10046H_CONFPLL3, state->config->n_i2c);
- tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99);
- tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
- tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
- tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
-
- ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
- if (ret)
- return ret;
- printk("tda1004x: firmware upload complete\n");
-
- /* wait for DSP to initialise */
- timeout = jiffies + HZ;
- while (!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) {
- if (time_after(jiffies, timeout)) {
- printk("tda1004x: DSP failed to initialised.\n");
- return -EIO;
+ tda10046_init_plls(fe);
+
+ if (state->config->request_firmware != NULL) {
+ /* request the firmware, this will block until someone uploads it */
+ printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
+ ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
+ if (ret) {
+ printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
+ return ret;
}
- msleep(1);
+ tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
+ ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
+ release_firmware(fw);
+ if (ret)
+ return ret;
+ } else {
+ /* boot from firmware eeprom */
+ /* Hac Note: we might need to do some GPIO Magic here */
+ printk(KERN_INFO "tda1004x: booting from eeprom\n");
+ tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4);
+ msleep(300);
}
-
- return tda1004x_check_upload_ok(state, state->fw_version);
+ return tda1004x_check_upload_ok(state);
}
static int tda1004x_encode_fec(int fec)
@@ -560,12 +587,10 @@ static int tda10046_init(struct dvb_frontend* fe)
if (tda10046_fwupload(fe)) {
printk("tda1004x: firmware upload failed\n");
- return -EIO;
+ return -EIO;
}
- tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0); // wake up the chip
-
- // Init the PLL
+ // Init the tuner PLL
if (state->config->pll_init) {
tda1004x_enable_tuner_i2c(state);
state->config->pll_init(fe);
@@ -574,32 +599,44 @@ static int tda10046_init(struct dvb_frontend* fe)
// tda setup
tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
- tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0x40);
- tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
- tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0); // disable pulse killer
- tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10
- tda1004x_write_byteI(state, TDA10046H_CONFPLL3, state->config->n_i2c); // PLL P = N = 0
- tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); // FREQOFFS = 99
- tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); // } PHY2 = -11221
- tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); // }
- tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0); // AGC setup
- tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x60, 0x60); // set AGC polarities
+ tda1004x_write_byteI(state, TDA1004X_AUTO, 7); // select HP stream
+ tda1004x_write_byteI(state, TDA1004X_CONFC1, 8); // disable pulse killer
+
+ tda10046_init_plls(fe);
+ switch (state->config->agc_config) {
+ case TDA10046_AGC_DEFAULT:
+ tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup
+ tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+ break;
+ case TDA10046_AGC_IFO_AUTO_NEG:
+ tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
+ tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+ break;
+ case TDA10046_AGC_IFO_AUTO_POS:
+ tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
+ tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x00); // set AGC polarities
+ break;
+ case TDA10046_AGC_TDA827X:
+ tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup
+ tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold
+ tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x0E); // Gain Renormalize
+ tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+ break;
+ }
+ tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on
tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // }
tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // }
tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff); // }
- tda1004x_write_mask(state, TDA10046H_CVBER_CTRL, 0x30, 0x10); // 10^6 VBER measurement bits
tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1
- tda1004x_write_mask(state, TDA1004X_AUTO, 0x80, 0); // crystal is 50ppm
+ tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits
tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
- tda1004x_write_mask(state, TDA1004X_CONF_TS2, 0x31, 0); // MPEG2 interface config
- tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0x9e, 0); // disable AGC_TUN
+ tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
+ tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
+
tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup
tda1004x_write_byteI(state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config
- tda1004x_write_mask(state, TDA10046H_GPIO_SELECT, 8, 8); // GPIO select
- tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
-
- tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
+ tda1004x_write_byteI(state, TDA10046H_GPIO_SELECT, 8); // GPIO select
state->initialised = 1;
return 0;
@@ -629,9 +666,6 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
state->config->pll_set(fe, fe_params);
tda1004x_disable_tuner_i2c(state);
- if (state->demod_type == TDA1004X_DEMOD_TDA10046)
- tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 4);
-
// Hardcoded to use auto as much as possible on the TDA10045 as it
// is very unreliable if AUTO mode is _not_ used.
if (state->demod_type == TDA1004X_DEMOD_TDA10045) {
@@ -1089,6 +1123,11 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
break;
case TDA1004X_DEMOD_TDA10046:
+ if (state->config->pll_sleep != NULL) {
+ tda1004x_enable_tuner_i2c(state);
+ state->config->pll_sleep(fe);
+ tda1004x_disable_tuner_i2c(state);
+ }
tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
break;
}
@@ -1100,8 +1139,9 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
fesettings->min_delay_ms = 800;
- fesettings->step_size = 166667;
- fesettings->max_drift = 166667*2;
+ /* Drift compensation makes no sense for DVB-T */
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
return 0;
}
@@ -1216,7 +1256,6 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
state->initialised = 0;
state->demod_type = TDA1004X_DEMOD_TDA10046;
- state->fw_version = 0x20; /* dummy default value */
/* check if the demod is there */
if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) {
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
index c8e1d54ff26..8659c52647a 100644
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ b/drivers/media/dvb/frontends/tda1004x.h
@@ -26,6 +26,25 @@
#include <linux/dvb/frontend.h>
#include <linux/firmware.h>
+enum tda10046_xtal {
+ TDA10046_XTAL_4M,
+ TDA10046_XTAL_16M,
+};
+
+enum tda10046_agc {
+ TDA10046_AGC_DEFAULT, /* original configuration */
+ TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */
+ TDA10046_AGC_IFO_AUTO_POS, /* IF AGC only, automatic, positive */
+ TDA10046_AGC_TDA827X, /* IF AGC only, special setup for tda827x */
+};
+
+enum tda10046_if {
+ TDA10046_FREQ_3617, /* original config, 36,166 MHZ */
+ TDA10046_FREQ_3613, /* 36,13 MHZ */
+ TDA10046_FREQ_045, /* low IF, 4.0, 4.5, or 5.0 MHZ */
+ TDA10046_FREQ_052, /* low IF, 5.1667 MHZ for tda9889 */
+};
+
struct tda1004x_config
{
/* the demodulator's i2c address */
@@ -37,14 +56,22 @@ struct tda1004x_config
/* Does the OCLK signal need inverted? */
u8 invert_oclk;
- /* value of N_I2C of the CONF_PLL3 register */
- u8 n_i2c;
+ /* Xtal frequency, 4 or 16MHz*/
+ enum tda10046_xtal xtal_freq;
+
+ /* IF frequency */
+ enum tda10046_if if_freq;
+
+ /* AGC configuration */
+ enum tda10046_agc agc_config;
/* PLL maintenance */
int (*pll_init)(struct dvb_frontend* fe);
+ void (*pll_sleep)(struct dvb_frontend* fe);
int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
/* request firmware for device */
+ /* set this to NULL if the card has a firmware EEPROM */
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
diff --git a/drivers/media/dvb/pluto2/Kconfig b/drivers/media/dvb/pluto2/Kconfig
new file mode 100644
index 00000000000..f02842be0d6
--- /dev/null
+++ b/drivers/media/dvb/pluto2/Kconfig
@@ -0,0 +1,16 @@
+config DVB_PLUTO2
+ tristate "Pluto2 cards"
+ depends on DVB_CORE && PCI
+ select I2C
+ select I2C_ALGOBIT
+ select DVB_TDA1004X
+ help
+ Support for PCI cards based on the Pluto2 FPGA like the Satelco
+ Easywatch Mobile Terrestrial DVB-T Receiver.
+
+ Since these cards have no MPEG decoder onboard, they transmit
+ only compressed MPEG data over the PCI bus, so you need
+ an external software decoder to watch TV on your computer.
+
+ Say Y or M if you own such a device and want to use it.
+
diff --git a/drivers/media/dvb/pluto2/Makefile b/drivers/media/dvb/pluto2/Makefile
new file mode 100644
index 00000000000..86ca84b2be6
--- /dev/null
+++ b/drivers/media/dvb/pluto2/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DVB_PLUTO2) = pluto2.o
+
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
new file mode 100644
index 00000000000..706e0bcb5ed
--- /dev/null
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -0,0 +1,809 @@
+/*
+ * pluto2.c - Satelco Easywatch Mobile Terrestrial Receiver [DVB-T]
+ *
+ * Copyright (C) 2005 Andreas Oberritter <obi@linuxtv.org>
+ *
+ * based on pluto2.c 1.10 - http://instinct-wp8.no-ip.org/pluto/
+ * by Dany Salman <salmandany@yahoo.fr>
+ * Copyright (c) 2004 TDF
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+#include "tda1004x.h"
+
+#define DRIVER_NAME "pluto2"
+
+#define REG_PIDn(n) ((n) << 2) /* PID n pattern registers */
+#define REG_PCAR 0x0020 /* PC address register */
+#define REG_TSCR 0x0024 /* TS ctrl & status */
+#define REG_MISC 0x0028 /* miscellaneous */
+#define REG_MMAC 0x002c /* MSB MAC address */
+#define REG_IMAC 0x0030 /* ISB MAC address */
+#define REG_LMAC 0x0034 /* LSB MAC address */
+#define REG_SPID 0x0038 /* SPI data */
+#define REG_SLCS 0x003c /* serial links ctrl/status */
+
+#define PID0_NOFIL (0x0001 << 16)
+#define PIDn_ENP (0x0001 << 15)
+#define PID0_END (0x0001 << 14)
+#define PID0_AFIL (0x0001 << 13)
+#define PIDn_PID (0x1fff << 0)
+
+#define TSCR_NBPACKETS (0x00ff << 24)
+#define TSCR_DEM (0x0001 << 17)
+#define TSCR_DE (0x0001 << 16)
+#define TSCR_RSTN (0x0001 << 15)
+#define TSCR_MSKO (0x0001 << 14)
+#define TSCR_MSKA (0x0001 << 13)
+#define TSCR_MSKL (0x0001 << 12)
+#define TSCR_OVR (0x0001 << 11)
+#define TSCR_AFUL (0x0001 << 10)
+#define TSCR_LOCK (0x0001 << 9)
+#define TSCR_IACK (0x0001 << 8)
+#define TSCR_ADEF (0x007f << 0)
+
+#define MISC_DVR (0x0fff << 4)
+#define MISC_ALED (0x0001 << 3)
+#define MISC_FRST (0x0001 << 2)
+#define MISC_LED1 (0x0001 << 1)
+#define MISC_LED0 (0x0001 << 0)
+
+#define SPID_SPIDR (0x00ff << 0)
+
+#define SLCS_SCL (0x0001 << 7)
+#define SLCS_SDA (0x0001 << 6)
+#define SLCS_CSN (0x0001 << 2)
+#define SLCS_OVR (0x0001 << 1)
+#define SLCS_SWC (0x0001 << 0)
+
+#define TS_DMA_PACKETS (8)
+#define TS_DMA_BYTES (188 * TS_DMA_PACKETS)
+
+#define I2C_ADDR_TDA10046 0x10
+#define I2C_ADDR_TUA6034 0xc2
+#define NHWFILTERS 8
+
+struct pluto {
+ /* pci */
+ struct pci_dev *pdev;
+ u8 __iomem *io_mem;
+
+ /* dvb */
+ struct dmx_frontend hw_frontend;
+ struct dmx_frontend mem_frontend;
+ struct dmxdev dmxdev;
+ struct dvb_adapter dvb_adapter;
+ struct dvb_demux demux;
+ struct dvb_frontend *fe;
+ struct dvb_net dvbnet;
+ unsigned int full_ts_users;
+ unsigned int users;
+
+ /* i2c */
+ struct i2c_algo_bit_data i2c_bit;
+ struct i2c_adapter i2c_adap;
+ unsigned int i2cbug;
+
+ /* irq */
+ unsigned int overflow;
+
+ /* dma */
+ dma_addr_t dma_addr;
+ u8 dma_buf[TS_DMA_BYTES];
+ u8 dummy[4096];
+};
+
+static inline struct pluto *feed_to_pluto(struct dvb_demux_feed *feed)
+{
+ return container_of(feed->demux, struct pluto, demux);
+}
+
+static inline struct pluto *frontend_to_pluto(struct dvb_frontend *fe)
+{
+ return container_of(fe->dvb, struct pluto, dvb_adapter);
+}
+
+static inline u32 pluto_readreg(struct pluto *pluto, u32 reg)
+{
+ return readl(&pluto->io_mem[reg]);
+}
+
+static inline void pluto_writereg(struct pluto *pluto, u32 reg, u32 val)
+{
+ writel(val, &pluto->io_mem[reg]);
+}
+
+static inline void pluto_rw(struct pluto *pluto, u32 reg, u32 mask, u32 bits)
+{
+ u32 val = readl(&pluto->io_mem[reg]);
+ val &= ~mask;
+ val |= bits;
+ writel(val, &pluto->io_mem[reg]);
+}
+
+static void pluto_setsda(void *data, int state)
+{
+ struct pluto *pluto = data;
+
+ if (state)
+ pluto_rw(pluto, REG_SLCS, SLCS_SDA, SLCS_SDA);
+ else
+ pluto_rw(pluto, REG_SLCS, SLCS_SDA, 0);
+}
+
+static void pluto_setscl(void *data, int state)
+{
+ struct pluto *pluto = data;
+
+ if (state)
+ pluto_rw(pluto, REG_SLCS, SLCS_SCL, SLCS_SCL);
+ else
+ pluto_rw(pluto, REG_SLCS, SLCS_SCL, 0);
+
+ /* try to detect i2c_inb() to workaround hardware bug:
+ * reset SDA to high after SCL has been set to low */
+ if ((state) && (pluto->i2cbug == 0)) {
+ pluto->i2cbug = 1;
+ } else {
+ if ((!state) && (pluto->i2cbug == 1))
+ pluto_setsda(pluto, 1);
+ pluto->i2cbug = 0;
+ }
+}
+
+static int pluto_getsda(void *data)
+{
+ struct pluto *pluto = data;
+
+ return pluto_readreg(pluto, REG_SLCS) & SLCS_SDA;
+}
+
+static int pluto_getscl(void *data)
+{
+ struct pluto *pluto = data;
+
+ return pluto_readreg(pluto, REG_SLCS) & SLCS_SCL;
+}
+
+static void pluto_reset_frontend(struct pluto *pluto, int reenable)
+{
+ u32 val = pluto_readreg(pluto, REG_MISC);
+
+ if (val & MISC_FRST) {
+ val &= ~MISC_FRST;
+ pluto_writereg(pluto, REG_MISC, val);
+ }
+ if (reenable) {
+ val |= MISC_FRST;
+ pluto_writereg(pluto, REG_MISC, val);
+ }
+}
+
+static void pluto_reset_ts(struct pluto *pluto, int reenable)
+{
+ u32 val = pluto_readreg(pluto, REG_TSCR);
+
+ if (val & TSCR_RSTN) {
+ val &= ~TSCR_RSTN;
+ pluto_writereg(pluto, REG_TSCR, val);
+ }
+ if (reenable) {
+ val |= TSCR_RSTN;
+ pluto_writereg(pluto, REG_TSCR, val);
+ }
+}
+
+static void pluto_set_dma_addr(struct pluto *pluto)
+{
+ pluto_writereg(pluto, REG_PCAR, cpu_to_le32(pluto->dma_addr));
+}
+
+static int __devinit pluto_dma_map(struct pluto *pluto)
+{
+ pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf,
+ TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+
+ return pci_dma_mapping_error(pluto->dma_addr);
+}
+
+static void pluto_dma_unmap(struct pluto *pluto)
+{
+ pci_unmap_single(pluto->pdev, pluto->dma_addr,
+ TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+}
+
+static int pluto_start_feed(struct dvb_demux_feed *f)
+{
+ struct pluto *pluto = feed_to_pluto(f);
+
+ /* enable PID filtering */
+ if (pluto->users++ == 0)
+ pluto_rw(pluto, REG_PIDn(0), PID0_AFIL | PID0_NOFIL, 0);
+
+ if ((f->pid < 0x2000) && (f->index < NHWFILTERS))
+ pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, PIDn_ENP | f->pid);
+ else if (pluto->full_ts_users++ == 0)
+ pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, PID0_NOFIL);
+
+ return 0;
+}
+
+static int pluto_stop_feed(struct dvb_demux_feed *f)
+{
+ struct pluto *pluto = feed_to_pluto(f);
+
+ /* disable PID filtering */
+ if (--pluto->users == 0)
+ pluto_rw(pluto, REG_PIDn(0), PID0_AFIL, PID0_AFIL);
+
+ if ((f->pid < 0x2000) && (f->index < NHWFILTERS))
+ pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, 0x1fff);
+ else if (--pluto->full_ts_users == 0)
+ pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, 0);
+
+ return 0;
+}
+
+static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets)
+{
+ /* synchronize the DMA transfer with the CPU
+ * first so that we see updated contents. */
+ pci_dma_sync_single_for_cpu(pluto->pdev, pluto->dma_addr,
+ TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+
+ /* Workaround for broken hardware:
+ * [1] On startup NBPACKETS seems to contain an uninitialized value,
+ * but no packets have been transfered.
+ * [2] Sometimes (actually very often) NBPACKETS stays at zero
+ * although one packet has been transfered.
+ */
+ if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) {
+ unsigned int i = 0, valid;
+ while (pluto->dma_buf[i] == 0x47)
+ i += 188;
+ valid = i / 188;
+ if (nbpackets != valid) {
+ dev_err(&pluto->pdev->dev, "nbpackets=%u valid=%u\n",
+ nbpackets, valid);
+ nbpackets = valid;
+ }
+ }
+
+ dvb_dmx_swfilter_packets(&pluto->demux, pluto->dma_buf, nbpackets);
+
+ /* clear the dma buffer. this is needed to be able to identify
+ * new valid ts packets above */
+ memset(pluto->dma_buf, 0, nbpackets * 188);
+
+ /* reset the dma address */
+ pluto_set_dma_addr(pluto);
+
+ /* sync the buffer and give it back to the card */
+ pci_dma_sync_single_for_device(pluto->pdev, pluto->dma_addr,
+ TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+}
+
+static irqreturn_t pluto_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct pluto *pluto = dev_id;
+ u32 tscr;
+
+ /* check whether an interrupt occured on this device */
+ tscr = pluto_readreg(pluto, REG_TSCR);
+ if (!(tscr & (TSCR_DE | TSCR_OVR)))
+ return IRQ_NONE;
+
+ if (tscr == 0xffffffff) {
+ // FIXME: maybe recover somehow
+ dev_err(&pluto->pdev->dev, "card hung up :(\n");
+ return IRQ_HANDLED;
+ }
+
+ /* dma end interrupt */
+ if (tscr & TSCR_DE) {
+ pluto_dma_end(pluto, (tscr & TSCR_NBPACKETS) >> 24);
+ /* overflow interrupt */
+ if (tscr & TSCR_OVR)
+ pluto->overflow++;
+ if (pluto->overflow) {
+ dev_err(&pluto->pdev->dev, "overflow irq (%d)\n",
+ pluto->overflow);
+ pluto_reset_ts(pluto, 1);
+ pluto->overflow = 0;
+ }
+ } else if (tscr & TSCR_OVR) {
+ pluto->overflow++;
+ }
+
+ /* ACK the interrupt */
+ pluto_writereg(pluto, REG_TSCR, tscr | TSCR_IACK);
+
+ return IRQ_HANDLED;
+}
+
+static void __devinit pluto_enable_irqs(struct pluto *pluto)
+{
+ u32 val = pluto_readreg(pluto, REG_TSCR);
+
+ /* set the number of packets */
+ val &= ~TSCR_ADEF;
+ val |= TS_DMA_PACKETS / 2;
+ /* disable AFUL and LOCK interrupts */
+ val |= (TSCR_MSKA | TSCR_MSKL);
+ /* enable DMA and OVERFLOW interrupts */
+ val &= ~(TSCR_DEM | TSCR_MSKO);
+ /* clear pending interrupts */
+ val |= TSCR_IACK;
+
+ pluto_writereg(pluto, REG_TSCR, val);
+}
+
+static void pluto_disable_irqs(struct pluto *pluto)
+{
+ u32 val = pluto_readreg(pluto, REG_TSCR);
+
+ /* disable all interrupts */
+ val |= (TSCR_DEM | TSCR_MSKO | TSCR_MSKA | TSCR_MSKL);
+ /* clear pending interrupts */
+ val |= TSCR_IACK;
+
+ pluto_writereg(pluto, REG_TSCR, val);
+}
+
+static int __devinit pluto_hw_init(struct pluto *pluto)
+{
+ pluto_reset_frontend(pluto, 1);
+
+ /* set automatic LED control by FPGA */
+ pluto_rw(pluto, REG_MISC, MISC_ALED, MISC_ALED);
+
+ /* set data endianess */
+#ifdef __LITTLE_ENDIAN
+ pluto_rw(pluto, REG_PIDn(0), PID0_END, PID0_END);
+#else
+ pluto_rw(pluto, REG_PIDn(0), PID0_END, 0);
+#endif
+ /* map DMA and set address */
+ pluto_dma_map(pluto);
+ pluto_set_dma_addr(pluto);
+
+ /* enable interrupts */
+ pluto_enable_irqs(pluto);
+
+ /* reset TS logic */
+ pluto_reset_ts(pluto, 1);
+
+ return 0;
+}
+
+static void pluto_hw_exit(struct pluto *pluto)
+{
+ /* disable interrupts */
+ pluto_disable_irqs(pluto);
+
+ pluto_reset_ts(pluto, 0);
+
+ /* LED: disable automatic control, enable yellow, disable green */
+ pluto_rw(pluto, REG_MISC, MISC_ALED | MISC_LED1 | MISC_LED0, MISC_LED1);
+
+ /* unmap DMA */
+ pluto_dma_unmap(pluto);
+
+ pluto_reset_frontend(pluto, 0);
+}
+
+static inline u32 divide(u32 numerator, u32 denominator)
+{
+ if (denominator == 0)
+ return ~0;
+
+ return (numerator + denominator / 2) / denominator;
+}
+
+/* LG Innotek TDTE-E001P (Infineon TUA6034) */
+static int lg_tdtpe001p_pll_set(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct pluto *pluto = frontend_to_pluto(fe);
+ struct i2c_msg msg;
+ int ret;
+ u8 buf[4];
+ u32 div;
+
+ // Fref = 166.667 Hz
+ // Fref * 3 = 500.000 Hz
+ // IF = 36166667
+ // IF / Fref = 217
+ //div = divide(p->frequency + 36166667, 166667);
+ div = divide(p->frequency * 3, 500000) + 217;
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = (div >> 0) & 0xff;
+
+ if (p->frequency < 611000000)
+ buf[2] = 0xb4;
+ else if (p->frequency < 811000000)
+ buf[2] = 0xbc;
+ else
+ buf[2] = 0xf4;
+
+ // VHF: 174-230 MHz
+ // center: 350 MHz
+ // UHF: 470-862 MHz
+ if (p->frequency < 350000000)
+ buf[3] = 0x02;
+ else
+ buf[3] = 0x04;
+
+ if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+ buf[3] |= 0x08;
+
+ if (sizeof(buf) == 6) {
+ buf[4] = buf[2];
+ buf[4] &= ~0x1c;
+ buf[4] |= 0x18;
+
+ buf[5] = (0 << 7) | (2 << 4);
+ }
+
+ msg.addr = I2C_ADDR_TUA6034 >> 1;
+ msg.flags = 0;
+ msg.buf = buf;
+ msg.len = sizeof(buf);
+
+ ret = i2c_transfer(&pluto->i2c_adap, &msg, 1);
+ if (ret < 0)
+ return ret;
+ else if (ret == 0)
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+static int pluto2_request_firmware(struct dvb_frontend *fe,
+ const struct firmware **fw, char *name)
+{
+ struct pluto *pluto = frontend_to_pluto(fe);
+
+ return request_firmware(fw, name, &pluto->pdev->dev);
+}
+
+static struct tda1004x_config pluto2_fe_config __devinitdata = {
+ .demod_address = I2C_ADDR_TDA10046 >> 1,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
+ .pll_set = lg_tdtpe001p_pll_set,
+ .pll_sleep = NULL,
+ .request_firmware = pluto2_request_firmware,
+};
+
+static int __devinit frontend_init(struct pluto *pluto)
+{
+ int ret;
+
+ pluto->fe = tda10046_attach(&pluto2_fe_config, &pluto->i2c_adap);
+ if (!pluto->fe) {
+ dev_err(&pluto->pdev->dev, "could not attach frontend\n");
+ return -ENODEV;
+ }
+
+ ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe);
+ if (ret < 0) {
+ if (pluto->fe->ops->release)
+ pluto->fe->ops->release(pluto->fe);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __devinit pluto_read_rev(struct pluto *pluto)
+{
+ u32 val = pluto_readreg(pluto, REG_MISC) & MISC_DVR;
+ dev_info(&pluto->pdev->dev, "board revision %d.%d\n",
+ (val >> 12) & 0x0f, (val >> 4) & 0xff);
+}
+
+static void __devinit pluto_read_mac(struct pluto *pluto, u8 *mac)
+{
+ u32 val = pluto_readreg(pluto, REG_MMAC);
+ mac[0] = (val >> 8) & 0xff;
+ mac[1] = (val >> 0) & 0xff;
+
+ val = pluto_readreg(pluto, REG_IMAC);
+ mac[2] = (val >> 8) & 0xff;
+ mac[3] = (val >> 0) & 0xff;
+
+ val = pluto_readreg(pluto, REG_LMAC);
+ mac[4] = (val >> 8) & 0xff;
+ mac[5] = (val >> 0) & 0xff;
+
+ dev_info(&pluto->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
+static int __devinit pluto_read_serial(struct pluto *pluto)
+{
+ struct pci_dev *pdev = pluto->pdev;
+ unsigned int i, j;
+ u8 __iomem *cis;
+
+ cis = pci_iomap(pdev, 1, 0);
+ if (!cis)
+ return -EIO;
+
+ dev_info(&pdev->dev, "S/N ");
+
+ for (i = 0xe0; i < 0x100; i += 4) {
+ u32 val = readl(&cis[i]);
+ for (j = 0; j < 32; j += 8) {
+ if ((val & 0xff) == 0xff)
+ goto out;
+ printk("%c", val & 0xff);
+ val >>= 8;
+ }
+ }
+out:
+ printk("\n");
+ pci_iounmap(pdev, cis);
+
+ return 0;
+}
+
+static int __devinit pluto2_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct pluto *pluto;
+ struct dvb_adapter *dvb_adapter;
+ struct dvb_demux *dvbdemux;
+ struct dmx_demux *dmx;
+ int ret = -ENOMEM;
+
+ pluto = kmalloc(sizeof(struct pluto), GFP_KERNEL);
+ if (!pluto)
+ goto out;
+
+ memset(pluto, 0, sizeof(struct pluto));
+ pluto->pdev = pdev;
+
+ ret = pci_enable_device(pdev);
+ if (ret < 0)
+ goto err_kfree;
+
+ /* enable interrupts */
+ pci_write_config_dword(pdev, 0x6c, 0x8000);
+
+ ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (ret < 0)
+ goto err_pci_disable_device;
+
+ pci_set_master(pdev);
+
+ ret = pci_request_regions(pdev, DRIVER_NAME);
+ if (ret < 0)
+ goto err_pci_disable_device;
+
+ pluto->io_mem = pci_iomap(pdev, 0, 0x40);
+ if (!pluto->io_mem) {
+ ret = -EIO;
+ goto err_pci_release_regions;
+ }
+
+ pci_set_drvdata(pdev, pluto);
+
+ ret = request_irq(pdev->irq, pluto_irq, SA_SHIRQ, DRIVER_NAME, pluto);
+ if (ret < 0)
+ goto err_pci_iounmap;
+
+ ret = pluto_hw_init(pluto);
+ if (ret < 0)
+ goto err_free_irq;
+
+ /* i2c */
+ i2c_set_adapdata(&pluto->i2c_adap, pluto);
+ strcpy(pluto->i2c_adap.name, DRIVER_NAME);
+ pluto->i2c_adap.owner = THIS_MODULE;
+ pluto->i2c_adap.id = I2C_ALGO_BIT;
+ pluto->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
+ pluto->i2c_adap.dev.parent = &pdev->dev;
+ pluto->i2c_adap.algo_data = &pluto->i2c_bit;
+ pluto->i2c_bit.data = pluto;
+ pluto->i2c_bit.setsda = pluto_setsda;
+ pluto->i2c_bit.setscl = pluto_setscl;
+ pluto->i2c_bit.getsda = pluto_getsda;
+ pluto->i2c_bit.getscl = pluto_getscl;
+ pluto->i2c_bit.udelay = 10;
+ pluto->i2c_bit.timeout = 10;
+
+ /* Raise SCL and SDA */
+ pluto_setsda(pluto, 1);
+ pluto_setscl(pluto, 1);
+
+ ret = i2c_bit_add_bus(&pluto->i2c_adap);
+ if (ret < 0)
+ goto err_pluto_hw_exit;
+
+ /* dvb */
+ ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE);
+ if (ret < 0)
+ goto err_i2c_bit_del_bus;
+
+ dvb_adapter = &pluto->dvb_adapter;
+
+ pluto_read_rev(pluto);
+ pluto_read_serial(pluto);
+ pluto_read_mac(pluto, dvb_adapter->proposed_mac);
+
+ dvbdemux = &pluto->demux;
+ dvbdemux->filternum = 256;
+ dvbdemux->feednum = 256;
+ dvbdemux->start_feed = pluto_start_feed;
+ dvbdemux->stop_feed = pluto_stop_feed;
+ dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+ DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
+ ret = dvb_dmx_init(dvbdemux);
+ if (ret < 0)
+ goto err_dvb_unregister_adapter;
+
+ dmx = &dvbdemux->dmx;
+
+ pluto->hw_frontend.source = DMX_FRONTEND_0;
+ pluto->mem_frontend.source = DMX_MEMORY_FE;
+ pluto->dmxdev.filternum = NHWFILTERS;
+ pluto->dmxdev.demux = dmx;
+
+ ret = dvb_dmxdev_init(&pluto->dmxdev, dvb_adapter);
+ if (ret < 0)
+ goto err_dvb_dmx_release;
+
+ ret = dmx->add_frontend(dmx, &pluto->hw_frontend);
+ if (ret < 0)
+ goto err_dvb_dmxdev_release;
+
+ ret = dmx->add_frontend(dmx, &pluto->mem_frontend);
+ if (ret < 0)
+ goto err_remove_hw_frontend;
+
+ ret = dmx->connect_frontend(dmx, &pluto->hw_frontend);
+ if (ret < 0)
+ goto err_remove_mem_frontend;
+
+ ret = frontend_init(pluto);
+ if (ret < 0)
+ goto err_disconnect_frontend;
+
+ dvb_net_init(dvb_adapter, &pluto->dvbnet, dmx);
+out:
+ return ret;
+
+err_disconnect_frontend:
+ dmx->disconnect_frontend(dmx);
+err_remove_mem_frontend:
+ dmx->remove_frontend(dmx, &pluto->mem_frontend);
+err_remove_hw_frontend:
+ dmx->remove_frontend(dmx, &pluto->hw_frontend);
+err_dvb_dmxdev_release:
+ dvb_dmxdev_release(&pluto->dmxdev);
+err_dvb_dmx_release:
+ dvb_dmx_release(dvbdemux);
+err_dvb_unregister_adapter:
+ dvb_unregister_adapter(dvb_adapter);
+err_i2c_bit_del_bus:
+ i2c_bit_del_bus(&pluto->i2c_adap);
+err_pluto_hw_exit:
+ pluto_hw_exit(pluto);
+err_free_irq:
+ free_irq(pdev->irq, pluto);
+err_pci_iounmap:
+ pci_iounmap(pdev, pluto->io_mem);
+err_pci_release_regions:
+ pci_release_regions(pdev);
+err_pci_disable_device:
+ pci_disable_device(pdev);
+err_kfree:
+ pci_set_drvdata(pdev, NULL);
+ kfree(pluto);
+ goto out;
+}
+
+static void __devexit pluto2_remove(struct pci_dev *pdev)
+{
+ struct pluto *pluto = pci_get_drvdata(pdev);
+ struct dvb_adapter *dvb_adapter = &pluto->dvb_adapter;
+ struct dvb_demux *dvbdemux = &pluto->demux;
+ struct dmx_demux *dmx = &dvbdemux->dmx;
+
+ dmx->close(dmx);
+ dvb_net_release(&pluto->dvbnet);
+ if (pluto->fe)
+ dvb_unregister_frontend(pluto->fe);
+
+ dmx->disconnect_frontend(dmx);
+ dmx->remove_frontend(dmx, &pluto->mem_frontend);
+ dmx->remove_frontend(dmx, &pluto->hw_frontend);
+ dvb_dmxdev_release(&pluto->dmxdev);
+ dvb_dmx_release(dvbdemux);
+ dvb_unregister_adapter(dvb_adapter);
+ i2c_bit_del_bus(&pluto->i2c_adap);
+ pluto_hw_exit(pluto);
+ free_irq(pdev->irq, pluto);
+ pci_iounmap(pdev, pluto->io_mem);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ kfree(pluto);
+}
+
+#ifndef PCI_VENDOR_ID_SCM
+#define PCI_VENDOR_ID_SCM 0x0432
+#endif
+#ifndef PCI_DEVICE_ID_PLUTO2
+#define PCI_DEVICE_ID_PLUTO2 0x0001
+#endif
+
+static struct pci_device_id pluto2_id_table[] __devinitdata = {
+ {
+ .vendor = PCI_VENDOR_ID_SCM,
+ .device = PCI_DEVICE_ID_PLUTO2,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ }, {
+ /* empty */
+ },
+};
+
+MODULE_DEVICE_TABLE(pci, pluto2_id_table);
+
+static struct pci_driver pluto2_driver = {
+ .name = DRIVER_NAME,
+ .id_table = pluto2_id_table,
+ .probe = pluto2_probe,
+ .remove = __devexit_p(pluto2_remove),
+};
+
+static int __init pluto2_init(void)
+{
+ return pci_register_driver(&pluto2_driver);
+}
+
+static void __exit pluto2_exit(void)
+{
+ pci_unregister_driver(&pluto2_driver);
+}
+
+module_init(pluto2_init);
+module_exit(pluto2_exit);
+
+MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
+MODULE_DESCRIPTION("Pluto2 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 7ffa2c7315b..bf3c011d2cf 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -12,7 +12,7 @@ config DVB_AV7110
select DVB_STV0297
select DVB_L64781
help
- Support for SAA7146 and AV7110 based DVB cards as produced
+ Support for SAA7146 and AV7110 based DVB cards as produced
by Fujitsu-Siemens, Technotrend, Hauppauge and others.
This driver only supports the fullfeatured cards with
@@ -33,7 +33,7 @@ config DVB_AV7110_FIRMWARE
If you want to compile the firmware into the driver you need to say
Y here and provide the correct path of the firmware. You need this
option if you want to compile the whole driver statically into the
- kernel.
+ kernel.
All other people say N.
@@ -66,6 +66,7 @@ config DVB_BUDGET
select DVB_L64781
select DVB_TDA8083
select DVB_TDA10021
+ select DVB_S5H1420
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
@@ -119,9 +120,9 @@ config DVB_BUDGET_PATCH
select DVB_VES1X93
select DVB_TDA8083
help
- Support for Budget Patch (full TS) modification on
+ Support for Budget Patch (full TS) modification on
SAA7146+AV7110 based cards (DVB-S cards). This
- driver doesn't use onboard MPEG2 decoder. The
+ driver doesn't use onboard MPEG2 decoder. The
card is driven in Budget-only mode. Card is
required to have loaded firmware to tune properly.
Firmware can be loaded by insertion and removal of
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 8e33a850e13..e4c6e87f6c5 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -116,13 +116,18 @@ static int av7110_num = 0;
static void init_av7110_av(struct av7110 *av7110)
{
+ int ret;
struct saa7146_dev *dev = av7110->dev;
/* set internal volume control to maximum */
av7110->adac_type = DVB_ADAC_TI;
- av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
+ ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
+ if (ret < 0)
+ printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret);
- av7710_set_video_mode(av7110, vidmode);
+ ret = av7710_set_video_mode(av7110, vidmode);
+ if (ret < 0)
+ printk("dvb-ttpci:cannot set video mode:%d\n",ret);
/* handle different card types */
/* remaining inits according to card and frontend type */
@@ -156,8 +161,12 @@ static void init_av7110_av(struct av7110 *av7110)
if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) {
// switch DVB SCART on
- av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);
- av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1);
+ ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);
+ if (ret < 0)
+ printk("dvb-ttpci:cannot switch on SCART(Main):%d\n",ret);
+ ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1);
+ if (ret < 0)
+ printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret);
if (rgb_on &&
(av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) {
saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16
@@ -165,8 +174,12 @@ static void init_av7110_av(struct av7110 *av7110)
}
}
- av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
- av7110_setup_irc_config(av7110, 0);
+ ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
+ if (ret < 0)
+ printk("dvb-ttpci:cannot set volume :%d\n",ret);
+ ret = av7110_setup_irc_config(av7110, 0);
+ if (ret < 0)
+ printk("dvb-ttpci:cannot setup irc config :%d\n",ret);
}
static void recover_arm(struct av7110 *av7110)
@@ -258,8 +271,9 @@ static int arm_thread(void *data)
*
* If we want to support multiple controls we would have to do much more...
*/
-void av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config)
+int av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config)
{
+ int ret = 0;
static struct av7110 *last;
dprintk(4, "%p\n", av7110);
@@ -270,9 +284,10 @@ void av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config)
last = av7110;
if (av7110) {
- av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config);
+ ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config);
av7110->ir_config = ir_config;
}
+ return ret;
}
static void (*irc_handler)(u32);
@@ -765,13 +780,14 @@ static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
pcrpid, vpid, apid, ttpid, subpid);
}
-void ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
+int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
u16 subpid, u16 pcrpid)
{
+ int ret = 0;
dprintk(4, "%p\n", av7110);
if (down_interruptible(&av7110->pid_mutex))
- return;
+ return -ERESTARTSYS;
if (!(vpid & 0x8000))
av7110->pids[DMX_PES_VIDEO] = vpid;
@@ -786,10 +802,11 @@ void ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
if (av7110->fe_synced) {
pcrpid = av7110->pids[DMX_PES_PCR];
- SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid);
+ ret = SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid);
}
up(&av7110->pid_mutex);
+ return ret;
}
@@ -832,11 +849,13 @@ static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter)
ret = av7110_fw_request(av7110, buf, 20, &handle, 1);
if (ret != 0 || handle >= 32) {
printk("dvb-ttpci: %s error buf %04x %04x %04x %04x "
- "ret %x handle %04x\n",
+ "ret %d handle %04x\n",
__FUNCTION__, buf[0], buf[1], buf[2], buf[3],
ret, handle);
dvbdmxfilter->hw_handle = 0xffff;
- return -1;
+ if (!ret)
+ ret = -1;
+ return ret;
}
av7110->handle2filter[handle] = dvbdmxfilter;
@@ -859,7 +878,7 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
if (handle >= 32) {
printk("%s tried to stop invalid filter %04x, filter type = %x\n",
__FUNCTION__, handle, dvbdmxfilter->type);
- return 0;
+ return -EINVAL;
}
av7110->handle2filter[handle] = NULL;
@@ -873,18 +892,20 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
"resp %04x %04x pid %d\n",
__FUNCTION__, buf[0], buf[1], buf[2], ret,
answ[0], answ[1], dvbdmxfilter->feed->pid);
- ret = -1;
+ if (!ret)
+ ret = -1;
}
return ret;
}
-static void dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
+static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
{
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv;
u16 *pid = dvbdmx->pids, npids[5];
int i;
+ int ret = 0;
dprintk(4, "%p\n", av7110);
@@ -893,36 +914,49 @@ static void dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
npids[i] = (pid[i]&0x8000) ? 0 : pid[i];
if ((i == 2) && npids[i] && (dvbdmxfeed->ts_type & TS_PACKET)) {
npids[i] = 0;
- ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
- StartHWFilter(dvbdmxfeed->filter);
- return;
+ ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
+ if (!ret)
+ ret = StartHWFilter(dvbdmxfeed->filter);
+ return ret;
+ }
+ if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4) {
+ ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
+ if (ret)
+ return ret;
}
- if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4)
- ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
if (dvbdmxfeed->pes_type < 2 && npids[0])
if (av7110->fe_synced)
- av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+ {
+ ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+ if (ret)
+ return ret;
+ }
if ((dvbdmxfeed->ts_type & TS_PACKET)) {
if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000))
- av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed);
+ ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed);
if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000))
- av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed);
+ ret = av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed);
}
+ return ret;
}
-static void dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed)
+static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed)
{
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv;
u16 *pid = dvbdmx->pids, npids[5];
int i;
+ int ret = 0;
+
dprintk(4, "%p\n", av7110);
if (dvbdmxfeed->pes_type <= 1) {
- av7110_av_stop(av7110, dvbdmxfeed->pes_type ? RP_VIDEO : RP_AUDIO);
+ ret = av7110_av_stop(av7110, dvbdmxfeed->pes_type ? RP_VIDEO : RP_AUDIO);
+ if (ret)
+ return ret;
if (!av7110->rec_mode)
dvbdmx->recording = 0;
if (!av7110->playing)
@@ -933,24 +967,27 @@ static void dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed)
switch (i) {
case 2: //teletext
if (dvbdmxfeed->ts_type & TS_PACKET)
- StopHWFilter(dvbdmxfeed->filter);
+ ret = StopHWFilter(dvbdmxfeed->filter);
npids[2] = 0;
break;
case 0:
case 1:
case 4:
if (!pids_off)
- return;
+ return 0;
npids[i] = (pid[i]&0x8000) ? 0 : pid[i];
break;
}
- ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
+ if (!ret)
+ ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
+ return ret;
}
static int av7110_start_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
struct av7110 *av7110 = demux->priv;
+ int ret = 0;
dprintk(4, "%p\n", av7110);
@@ -971,21 +1008,22 @@ static int av7110_start_feed(struct dvb_demux_feed *feed)
!(demux->pids[1] & 0x8000)) {
dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
- av7110_av_start_play(av7110,RP_AV);
- demux->playing = 1;
+ ret = av7110_av_start_play(av7110,RP_AV);
+ if (!ret)
+ demux->playing = 1;
}
break;
default:
- dvb_feed_start_pid(feed);
+ ret = dvb_feed_start_pid(feed);
break;
}
} else if ((feed->ts_type & TS_PACKET) &&
(demux->dmx.frontend->source != DMX_MEMORY_FE)) {
- StartHWFilter(feed->filter);
+ ret = StartHWFilter(feed->filter);
}
}
- if (feed->type == DMX_TYPE_SEC) {
+ else if (feed->type == DMX_TYPE_SEC) {
int i;
for (i = 0; i < demux->filternum; i++) {
@@ -996,12 +1034,15 @@ static int av7110_start_feed(struct dvb_demux_feed *feed)
if (demux->filter[i].filter.parent != &feed->feed.sec)
continue;
demux->filter[i].state = DMX_STATE_GO;
- if (demux->dmx.frontend->source != DMX_MEMORY_FE)
- StartHWFilter(&demux->filter[i]);
+ if (demux->dmx.frontend->source != DMX_MEMORY_FE) {
+ ret = StartHWFilter(&demux->filter[i]);
+ if (ret)
+ break;
+ }
}
}
- return 0;
+ return ret;
}
@@ -1009,7 +1050,7 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
struct av7110 *av7110 = demux->priv;
-
+ int i, rc, ret = 0;
dprintk(4, "%p\n", av7110);
if (feed->type == DMX_TYPE_TS) {
@@ -1022,26 +1063,29 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed)
}
if (feed->ts_type & TS_DECODER &&
feed->pes_type < DMX_TS_PES_OTHER) {
- dvb_feed_stop_pid(feed);
+ ret = dvb_feed_stop_pid(feed);
} else
if ((feed->ts_type & TS_PACKET) &&
(demux->dmx.frontend->source != DMX_MEMORY_FE))
- StopHWFilter(feed->filter);
+ ret = StopHWFilter(feed->filter);
}
- if (feed->type == DMX_TYPE_SEC) {
- int i;
-
- for (i = 0; i<demux->filternum; i++)
+ if (!ret && feed->type == DMX_TYPE_SEC) {
+ for (i = 0; i<demux->filternum; i++) {
if (demux->filter[i].state == DMX_STATE_GO &&
demux->filter[i].filter.parent == &feed->feed.sec) {
demux->filter[i].state = DMX_STATE_READY;
- if (demux->dmx.frontend->source != DMX_MEMORY_FE)
- StopHWFilter(&demux->filter[i]);
+ if (demux->dmx.frontend->source != DMX_MEMORY_FE) {
+ rc = StopHWFilter(&demux->filter[i]);
+ if (!ret)
+ ret = rc;
+ /* keep going, stop as many filters as possible */
+ }
+ }
}
}
- return 0;
+ return ret;
}
@@ -1093,7 +1137,7 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
ret = av7110_fw_request(av7110, &tag, 0, fwstc, 4);
if (ret) {
printk(KERN_ERR "%s: av7110_fw_request error\n", __FUNCTION__);
- return -EIO;
+ return ret;
}
dprintk(2, "fwstc = %04hx %04hx %04hx %04hx\n",
fwstc[0], fwstc[1], fwstc[2], fwstc[3]);
@@ -1119,18 +1163,14 @@ static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
switch (tone) {
case SEC_TONE_ON:
- Set22K(av7110, 1);
- break;
+ return Set22K(av7110, 1);
case SEC_TONE_OFF:
- Set22K(av7110, 0);
- break;
+ return Set22K(av7110, 0);
default:
return -EINVAL;
}
-
- return 0;
}
static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe,
@@ -1138,9 +1178,7 @@ static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe,
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1);
-
- return 0;
+ return av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1);
}
static int av7110_diseqc_send_burst(struct dvb_frontend* fe,
@@ -1148,9 +1186,7 @@ static int av7110_diseqc_send_burst(struct dvb_frontend* fe,
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_diseqc_send(av7110, 0, NULL, minicmd);
-
- return 0;
+ return av7110_diseqc_send(av7110, 0, NULL, minicmd);
}
/* simplified code from budget-core.c */
@@ -1992,76 +2028,85 @@ static struct l64781_config grundig_29504_401_config = {
-static void av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
+static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
{
+ int ret = 0;
int synced = (status & FE_HAS_LOCK) ? 1 : 0;
av7110->fe_status = status;
if (av7110->fe_synced == synced)
- return;
-
- av7110->fe_synced = synced;
+ return 0;
if (av7110->playing)
- return;
+ return 0;
if (down_interruptible(&av7110->pid_mutex))
- return;
+ return -ERESTARTSYS;
- if (av7110->fe_synced) {
- SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO],
+ if (synced) {
+ ret = SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO],
av7110->pids[DMX_PES_AUDIO],
av7110->pids[DMX_PES_TELETEXT], 0,
av7110->pids[DMX_PES_PCR]);
- av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+ if (!ret)
+ ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
} else {
- SetPIDs(av7110, 0, 0, 0, 0, 0);
- av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0);
- av7110_wait_msgstate(av7110, GPMQBusy);
+ ret = SetPIDs(av7110, 0, 0, 0, 0, 0);
+ if (!ret) {
+ ret = av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0);
+ if (!ret)
+ ret = av7110_wait_msgstate(av7110, GPMQBusy);
+ }
}
+ if (!ret)
+ av7110->fe_synced = synced;
+
up(&av7110->pid_mutex);
+ return ret;
}
static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_fe_lock_fix(av7110, 0);
- return av7110->fe_set_frontend(fe, params);
+
+ int ret = av7110_fe_lock_fix(av7110, 0);
+ if (!ret)
+ ret = av7110->fe_set_frontend(fe, params);
+ return ret;
}
static int av7110_fe_init(struct dvb_frontend* fe)
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_fe_lock_fix(av7110, 0);
- return av7110->fe_init(fe);
+ int ret = av7110_fe_lock_fix(av7110, 0);
+ if (!ret)
+ ret = av7110->fe_init(fe);
+ return ret;
}
static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
struct av7110* av7110 = fe->dvb->priv;
- int ret;
/* call the real implementation */
- ret = av7110->fe_read_status(fe, status);
- if (ret)
- return ret;
-
- if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK)) {
- av7110_fe_lock_fix(av7110, *status);
- }
-
- return 0;
+ int ret = av7110->fe_read_status(fe, status);
+ if (!ret)
+ if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK))
+ ret = av7110_fe_lock_fix(av7110, *status);
+ return ret;
}
static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe)
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_fe_lock_fix(av7110, 0);
- return av7110->fe_diseqc_reset_overload(fe);
+ int ret = av7110_fe_lock_fix(av7110, 0);
+ if (!ret)
+ ret = av7110->fe_diseqc_reset_overload(fe);
+ return ret;
}
static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe,
@@ -2069,40 +2114,50 @@ static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe,
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_fe_lock_fix(av7110, 0);
- return av7110->fe_diseqc_send_master_cmd(fe, cmd);
+ int ret = av7110_fe_lock_fix(av7110, 0);
+ if (!ret)
+ ret = av7110->fe_diseqc_send_master_cmd(fe, cmd);
+ return ret;
}
static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_fe_lock_fix(av7110, 0);
- return av7110->fe_diseqc_send_burst(fe, minicmd);
+ int ret = av7110_fe_lock_fix(av7110, 0);
+ if (!ret)
+ ret = av7110->fe_diseqc_send_burst(fe, minicmd);
+ return ret;
}
static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_fe_lock_fix(av7110, 0);
- return av7110->fe_set_tone(fe, tone);
+ int ret = av7110_fe_lock_fix(av7110, 0);
+ if (!ret)
+ ret = av7110->fe_set_tone(fe, tone);
+ return ret;
}
static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_fe_lock_fix(av7110, 0);
- return av7110->fe_set_voltage(fe, voltage);
+ int ret = av7110_fe_lock_fix(av7110, 0);
+ if (!ret)
+ ret = av7110->fe_set_voltage(fe, voltage);
+ return ret;
}
static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned int cmd)
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_fe_lock_fix(av7110, 0);
- return av7110->fe_dishnetwork_send_legacy_command(fe, cmd);
+ int ret = av7110_fe_lock_fix(av7110, 0);
+ if (!ret)
+ ret = av7110->fe_dishnetwork_send_legacy_command(fe, cmd);
+ return ret;
}
static u8 read_pwm(struct av7110* av7110)
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index 4f69b4d0147..508b7739c60 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -119,8 +119,7 @@ struct av7110 {
volatile int bmp_state;
#define BMP_NONE 0
#define BMP_LOADING 1
-#define BMP_LOADINGS 2
-#define BMP_LOADED 3
+#define BMP_LOADED 2
wait_queue_head_t bmpq;
@@ -255,12 +254,12 @@ struct av7110 {
};
-extern void ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
+extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
u16 subpid, u16 pcrpid);
extern void av7110_register_irc_handler(void (*func)(u32));
extern void av7110_unregister_irc_handler(void (*func)(u32));
-extern void av7110_setup_irc_config (struct av7110 *av7110, u32 ir_config);
+extern int av7110_setup_irc_config (struct av7110 *av7110, u32 ir_config);
extern int av7110_ir_init (void);
extern void av7110_ir_exit (void);
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index ccf946125d0..0696a5a4f85 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -121,6 +121,7 @@ static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data)
int av7110_av_start_record(struct av7110 *av7110, int av,
struct dvb_demux_feed *dvbdmxfeed)
{
+ int ret = 0;
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
dprintk(2, "av7110:%p, , dvb_demux_feed:%p\n", av7110, dvbdmxfeed);
@@ -137,7 +138,7 @@ int av7110_av_start_record(struct av7110 *av7110, int av,
dvbdmx->pesfilter[0]->pid,
dvb_filter_pes2ts_cb,
(void *) dvbdmx->pesfilter[0]);
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
break;
case RP_VIDEO:
@@ -145,7 +146,7 @@ int av7110_av_start_record(struct av7110 *av7110, int av,
dvbdmx->pesfilter[1]->pid,
dvb_filter_pes2ts_cb,
(void *) dvbdmx->pesfilter[1]);
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
break;
case RP_AV:
@@ -157,14 +158,15 @@ int av7110_av_start_record(struct av7110 *av7110, int av,
dvbdmx->pesfilter[1]->pid,
dvb_filter_pes2ts_cb,
(void *) dvbdmx->pesfilter[1]);
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0);
break;
}
- return 0;
+ return ret;
}
int av7110_av_start_play(struct av7110 *av7110, int av)
{
+ int ret = 0;
dprintk(2, "av7110:%p, \n", av7110);
if (av7110->rec_mode)
@@ -182,54 +184,57 @@ int av7110_av_start_play(struct av7110 *av7110, int av)
av7110->playing |= av;
switch (av7110->playing) {
case RP_AUDIO:
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
break;
case RP_VIDEO:
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
av7110->sinfo = 0;
break;
case RP_AV:
av7110->sinfo = 0;
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0);
break;
}
- return av7110->playing;
+ if (!ret)
+ ret = av7110->playing;
+ return ret;
}
-void av7110_av_stop(struct av7110 *av7110, int av)
+int av7110_av_stop(struct av7110 *av7110, int av)
{
+ int ret = 0;
dprintk(2, "av7110:%p, \n", av7110);
if (!(av7110->playing & av) && !(av7110->rec_mode & av))
- return;
-
+ return 0;
av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
if (av7110->playing) {
av7110->playing &= ~av;
switch (av7110->playing) {
case RP_AUDIO:
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
break;
case RP_VIDEO:
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
break;
case RP_NONE:
- av7110_set_vidmode(av7110, av7110->vidmode);
+ ret = av7110_set_vidmode(av7110, av7110->vidmode);
break;
}
} else {
av7110->rec_mode &= ~av;
switch (av7110->rec_mode) {
case RP_AUDIO:
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
break;
case RP_VIDEO:
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
break;
case RP_NONE:
break;
}
}
+ return ret;
}
@@ -317,19 +322,22 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
return 0;
}
-void av7110_set_vidmode(struct av7110 *av7110, int mode)
+int av7110_set_vidmode(struct av7110 *av7110, int mode)
{
+ int ret;
dprintk(2, "av7110:%p, \n", av7110);
- av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode);
+ ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode);
- if (!av7110->playing) {
- ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO],
+ if (!ret && !av7110->playing) {
+ ret = ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO],
av7110->pids[DMX_PES_AUDIO],
av7110->pids[DMX_PES_TELETEXT],
0, av7110->pids[DMX_PES_PCR]);
- av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+ if (!ret)
+ ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
}
+ return ret;
}
@@ -340,17 +348,18 @@ static int sw2mode[16] = {
VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL,
};
-static void get_video_format(struct av7110 *av7110, u8 *buf, int count)
+static int get_video_format(struct av7110 *av7110, u8 *buf, int count)
{
int i;
int hsize, vsize;
int sw;
u8 *p;
+ int ret = 0;
dprintk(2, "av7110:%p, \n", av7110);
if (av7110->sinfo)
- return;
+ return 0;
for (i = 7; i < count - 10; i++) {
p = buf + i;
if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3)
@@ -359,11 +368,14 @@ static void get_video_format(struct av7110 *av7110, u8 *buf, int count)
hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4);
vsize = ((p[1] &0x0F) << 8) | (p[2]);
sw = (p[3] & 0x0F);
- av7110_set_vidmode(av7110, sw2mode[sw]);
- dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw);
- av7110->sinfo = 1;
+ ret = av7110_set_vidmode(av7110, sw2mode[sw]);
+ if (!ret) {
+ dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw);
+ av7110->sinfo = 1;
+ }
break;
}
+ return ret;
}
@@ -974,7 +986,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
unsigned long arg = (unsigned long) parg;
int ret = 0;
- dprintk(2, "av7110:%p, \n", av7110);
+ dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd);
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
if ( cmd != VIDEO_GET_STATUS && cmd != VIDEO_GET_EVENT &&
@@ -987,49 +999,57 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
case VIDEO_STOP:
av7110->videostate.play_state = VIDEO_STOPPED;
if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY)
- av7110_av_stop(av7110, RP_VIDEO);
+ ret = av7110_av_stop(av7110, RP_VIDEO);
else
- vidcom(av7110, VIDEO_CMD_STOP,
+ ret = vidcom(av7110, VIDEO_CMD_STOP,
av7110->videostate.video_blank ? 0 : 1);
- av7110->trickmode = TRICK_NONE;
+ if (!ret)
+ av7110->trickmode = TRICK_NONE;
break;
case VIDEO_PLAY:
av7110->trickmode = TRICK_NONE;
if (av7110->videostate.play_state == VIDEO_FREEZED) {
av7110->videostate.play_state = VIDEO_PLAYING;
- vidcom(av7110, VIDEO_CMD_PLAY, 0);
+ ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
+ if (ret)
+ break;
}
if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) {
if (av7110->playing == RP_AV) {
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
+ if (ret)
+ break;
av7110->playing &= ~RP_VIDEO;
}
- av7110_av_start_play(av7110, RP_VIDEO);
- vidcom(av7110, VIDEO_CMD_PLAY, 0);
- } else {
- //av7110_av_stop(av7110, RP_VIDEO);
- vidcom(av7110, VIDEO_CMD_PLAY, 0);
+ ret = av7110_av_start_play(av7110, RP_VIDEO);
}
- av7110->videostate.play_state = VIDEO_PLAYING;
+ if (!ret)
+ ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
+ if (!ret)
+ av7110->videostate.play_state = VIDEO_PLAYING;
break;
case VIDEO_FREEZE:
av7110->videostate.play_state = VIDEO_FREEZED;
if (av7110->playing & RP_VIDEO)
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0);
else
- vidcom(av7110, VIDEO_CMD_FREEZE, 1);
- av7110->trickmode = TRICK_FREEZE;
+ ret = vidcom(av7110, VIDEO_CMD_FREEZE, 1);
+ if (!ret)
+ av7110->trickmode = TRICK_FREEZE;
break;
case VIDEO_CONTINUE:
if (av7110->playing & RP_VIDEO)
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0);
- vidcom(av7110, VIDEO_CMD_PLAY, 0);
- av7110->videostate.play_state = VIDEO_PLAYING;
- av7110->trickmode = TRICK_NONE;
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0);
+ if (!ret)
+ ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
+ if (!ret) {
+ av7110->videostate.play_state = VIDEO_PLAYING;
+ av7110->trickmode = TRICK_NONE;
+ }
break;
case VIDEO_SELECT_SOURCE:
@@ -1045,7 +1065,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
break;
case VIDEO_GET_EVENT:
- ret=dvb_video_get_event(av7110, parg, file->f_flags);
+ ret = dvb_video_get_event(av7110, parg, file->f_flags);
break;
case VIDEO_GET_SIZE:
@@ -1105,25 +1125,32 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
case VIDEO_FAST_FORWARD:
//note: arg is ignored by firmware
if (av7110->playing & RP_VIDEO)
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
- __Scan_I, 2, AV_PES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+ __Scan_I, 2, AV_PES, 0);
else
- vidcom(av7110, VIDEO_CMD_FFWD, arg);
- av7110->trickmode = TRICK_FAST;
- av7110->videostate.play_state = VIDEO_PLAYING;
+ ret = vidcom(av7110, VIDEO_CMD_FFWD, arg);
+ if (!ret) {
+ av7110->trickmode = TRICK_FAST;
+ av7110->videostate.play_state = VIDEO_PLAYING;
+ }
break;
case VIDEO_SLOWMOTION:
if (av7110->playing&RP_VIDEO) {
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
- vidcom(av7110, VIDEO_CMD_SLOW, arg);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
+ if (!ret)
+ ret = vidcom(av7110, VIDEO_CMD_SLOW, arg);
} else {
- vidcom(av7110, VIDEO_CMD_PLAY, 0);
- vidcom(av7110, VIDEO_CMD_STOP, 0);
- vidcom(av7110, VIDEO_CMD_SLOW, arg);
+ ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
+ if (!ret)
+ ret = vidcom(av7110, VIDEO_CMD_STOP, 0);
+ if (!ret)
+ ret = vidcom(av7110, VIDEO_CMD_SLOW, arg);
+ }
+ if (!ret) {
+ av7110->trickmode = TRICK_SLOW;
+ av7110->videostate.play_state = VIDEO_PLAYING;
}
- av7110->trickmode = TRICK_SLOW;
- av7110->videostate.play_state = VIDEO_PLAYING;
break;
case VIDEO_GET_CAPABILITIES:
@@ -1136,18 +1163,21 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
av7110_ipack_reset(&av7110->ipack[1]);
if (av7110->playing == RP_AV) {
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
- __Play, 2, AV_PES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+ __Play, 2, AV_PES, 0);
+ if (ret)
+ break;
if (av7110->trickmode == TRICK_FAST)
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
- __Scan_I, 2, AV_PES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+ __Scan_I, 2, AV_PES, 0);
if (av7110->trickmode == TRICK_SLOW) {
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
- __Slow, 2, 0, 0);
- vidcom(av7110, VIDEO_CMD_SLOW, arg);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+ __Slow, 2, 0, 0);
+ if (!ret)
+ ret = vidcom(av7110, VIDEO_CMD_SLOW, arg);
}
if (av7110->trickmode == TRICK_FREEZE)
- vidcom(av7110, VIDEO_CMD_STOP, 1);
+ ret = vidcom(av7110, VIDEO_CMD_STOP, 1);
}
break;
@@ -1170,7 +1200,7 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
unsigned long arg = (unsigned long) parg;
int ret = 0;
- dprintk(2, "av7110:%p, \n", av7110);
+ dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd);
if (((file->f_flags & O_ACCMODE) == O_RDONLY) &&
(cmd != AUDIO_GET_STATUS))
@@ -1179,28 +1209,32 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case AUDIO_STOP:
if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
- av7110_av_stop(av7110, RP_AUDIO);
+ ret = av7110_av_stop(av7110, RP_AUDIO);
else
- audcom(av7110, AUDIO_CMD_MUTE);
- av7110->audiostate.play_state = AUDIO_STOPPED;
+ ret = audcom(av7110, AUDIO_CMD_MUTE);
+ if (!ret)
+ av7110->audiostate.play_state = AUDIO_STOPPED;
break;
case AUDIO_PLAY:
if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
- av7110_av_start_play(av7110, RP_AUDIO);
- audcom(av7110, AUDIO_CMD_UNMUTE);
- av7110->audiostate.play_state = AUDIO_PLAYING;
+ ret = av7110_av_start_play(av7110, RP_AUDIO);
+ if (!ret)
+ ret = audcom(av7110, AUDIO_CMD_UNMUTE);
+ if (!ret)
+ av7110->audiostate.play_state = AUDIO_PLAYING;
break;
case AUDIO_PAUSE:
- audcom(av7110, AUDIO_CMD_MUTE);
- av7110->audiostate.play_state = AUDIO_PAUSED;
+ ret = audcom(av7110, AUDIO_CMD_MUTE);
+ if (!ret)
+ av7110->audiostate.play_state = AUDIO_PAUSED;
break;
case AUDIO_CONTINUE:
if (av7110->audiostate.play_state == AUDIO_PAUSED) {
av7110->audiostate.play_state = AUDIO_PLAYING;
- audcom(av7110, AUDIO_CMD_MUTE | AUDIO_CMD_PCM16);
+ ret = audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16);
}
break;
@@ -1210,14 +1244,15 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
case AUDIO_SET_MUTE:
{
- audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE);
- av7110->audiostate.mute_state = (int) arg;
+ ret = audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE);
+ if (!ret)
+ av7110->audiostate.mute_state = (int) arg;
break;
}
case AUDIO_SET_AV_SYNC:
av7110->audiostate.AV_sync_state = (int) arg;
- audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF);
+ ret = audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF);
break;
case AUDIO_SET_BYPASS_MODE:
@@ -1229,21 +1264,24 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
switch(av7110->audiostate.channel_select) {
case AUDIO_STEREO:
- audcom(av7110, AUDIO_CMD_STEREO);
- if (av7110->adac_type == DVB_ADAC_CRYSTAL)
- i2c_writereg(av7110, 0x20, 0x02, 0x49);
+ ret = audcom(av7110, AUDIO_CMD_STEREO);
+ if (!ret)
+ if (av7110->adac_type == DVB_ADAC_CRYSTAL)
+ i2c_writereg(av7110, 0x20, 0x02, 0x49);
break;
case AUDIO_MONO_LEFT:
- audcom(av7110, AUDIO_CMD_MONO_L);
- if (av7110->adac_type == DVB_ADAC_CRYSTAL)
- i2c_writereg(av7110, 0x20, 0x02, 0x4a);
+ ret = audcom(av7110, AUDIO_CMD_MONO_L);
+ if (!ret)
+ if (av7110->adac_type == DVB_ADAC_CRYSTAL)
+ i2c_writereg(av7110, 0x20, 0x02, 0x4a);
break;
case AUDIO_MONO_RIGHT:
- audcom(av7110, AUDIO_CMD_MONO_R);
- if (av7110->adac_type == DVB_ADAC_CRYSTAL)
- i2c_writereg(av7110, 0x20, 0x02, 0x45);
+ ret = audcom(av7110, AUDIO_CMD_MONO_R);
+ if (!ret)
+ if (av7110->adac_type == DVB_ADAC_CRYSTAL)
+ i2c_writereg(av7110, 0x20, 0x02, 0x45);
break;
default:
@@ -1264,8 +1302,8 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
av7110_ipack_reset(&av7110->ipack[0]);
if (av7110->playing == RP_AV)
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
- __Play, 2, AV_PES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+ __Play, 2, AV_PES, 0);
break;
case AUDIO_SET_ID:
@@ -1274,7 +1312,7 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
{
struct audio_mixer *amix = (struct audio_mixer *)parg;
- av7110_set_volume(av7110, amix->volume_left, amix->volume_right);
+ ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right);
break;
}
case AUDIO_SET_STREAMTYPE:
diff --git a/drivers/media/dvb/ttpci/av7110_av.h b/drivers/media/dvb/ttpci/av7110_av.h
index cc5e7a7e87c..45dc144b8b4 100644
--- a/drivers/media/dvb/ttpci/av7110_av.h
+++ b/drivers/media/dvb/ttpci/av7110_av.h
@@ -3,14 +3,14 @@
struct av7110;
-extern void av7110_set_vidmode(struct av7110 *av7110, int mode);
+extern int av7110_set_vidmode(struct av7110 *av7110, int mode);
extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len);
extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen);
extern int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len);
extern int av7110_set_volume(struct av7110 *av7110, int volleft, int volright);
-extern void av7110_av_stop(struct av7110 *av7110, int av);
+extern int av7110_av_stop(struct av7110 *av7110, int av);
extern int av7110_av_start_record(struct av7110 *av7110, int av,
struct dvb_demux_feed *dvbdmxfeed);
extern int av7110_av_start_play(struct av7110 *av7110, int av);
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 7fa4a0ebe13..1220826696c 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -137,7 +137,7 @@ static int waitdebi(struct av7110 *av7110, int adr, int state)
return 0;
udelay(5);
}
- return -1;
+ return -ETIMEDOUT;
}
static int load_dram(struct av7110 *av7110, u32 *data, int len)
@@ -155,7 +155,7 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
for (i = 0; i < blocks; i++) {
if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
- return -1;
+ return -ETIMEDOUT;
}
dprintk(4, "writing DRAM block %d\n", i);
mwdebi(av7110, DEBISWAB, bootblock,
@@ -170,7 +170,7 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
if (rest > 0) {
if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
- return -1;
+ return -ETIMEDOUT;
}
if (rest > 4)
mwdebi(av7110, DEBISWAB, bootblock,
@@ -185,13 +185,13 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
}
if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
- return -1;
+ return -ETIMEDOUT;
}
iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, 0, 2);
iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BOOT_COMPLETE) < 0) {
printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
- return -1;
+ return -ETIMEDOUT;
}
return 0;
}
@@ -263,7 +263,7 @@ int av7110_bootarm(struct av7110 *av7110)
if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
"saa7146_wait_for_debi_done() timed out\n");
- return -1;
+ return -ETIMEDOUT;
}
saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
mdelay(1);
@@ -284,7 +284,7 @@ int av7110_bootarm(struct av7110 *av7110)
if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
"saa7146_wait_for_debi_done() timed out after loading DRAM\n");
- return -1;
+ return -ETIMEDOUT;
}
saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
msleep(30); /* the firmware needs some time to initialize */
@@ -308,6 +308,7 @@ int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
{
unsigned long start;
u32 stat;
+ int err;
if (FW_VERSION(av7110->arm_app) <= 0x261c) {
/* not supported by old firmware */
@@ -318,17 +319,17 @@ int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
/* new firmware */
start = jiffies;
for (;;) {
+ err = time_after(jiffies, start + ARM_WAIT_FREE);
if (down_interruptible(&av7110->dcomlock))
return -ERESTARTSYS;
stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
up(&av7110->dcomlock);
- if ((stat & flags) == 0) {
+ if ((stat & flags) == 0)
break;
- }
- if (time_after(jiffies, start + ARM_WAIT_FREE)) {
+ if (err) {
printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
__FUNCTION__, stat & flags);
- return -1;
+ return -ETIMEDOUT;
}
msleep(1);
}
@@ -342,6 +343,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
char *type = NULL;
u16 flags[2] = {0, 0};
u32 stat;
+ int err;
// dprintk(4, "%p\n", av7110);
@@ -351,24 +353,30 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
}
start = jiffies;
- while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
- msleep(1);
- if (time_after(jiffies, start + ARM_WAIT_FREE)) {
+ while (1) {
+ err = time_after(jiffies, start + ARM_WAIT_FREE);
+ if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
+ break;
+ if (err) {
printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
return -ETIMEDOUT;
}
+ msleep(1);
}
wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
#ifndef _NOHANDSHAKE
start = jiffies;
- while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
- msleep(1);
- if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
+ while (1) {
+ err = time_after(jiffies, start + ARM_WAIT_SHAKE);
+ if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
+ break;
+ if (err) {
printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
return -ETIMEDOUT;
}
+ msleep(1);
}
#endif
@@ -401,6 +409,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
/* non-immediate COMMAND type */
start = jiffies;
for (;;) {
+ err = time_after(jiffies, start + ARM_WAIT_FREE);
stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
if (stat & flags[0]) {
printk(KERN_ERR "%s: %s QUEUE overflow\n",
@@ -409,10 +418,10 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
}
if ((stat & flags[1]) == 0)
break;
- if (time_after(jiffies, start + ARM_WAIT_FREE)) {
+ if (err) {
printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
__FUNCTION__, type);
- return -1;
+ return -ETIMEDOUT;
}
msleep(1);
}
@@ -432,13 +441,16 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
#ifdef COM_DEBUG
start = jiffies;
- while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
- msleep(1);
- if (time_after(jiffies, start + ARM_WAIT_FREE)) {
- printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND to complete\n",
- __FUNCTION__);
+ while (1) {
+ err = time_after(jiffies, start + ARM_WAIT_FREE);
+ if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
+ break;
+ if (err) {
+ printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
+ __FUNCTION__, (buf[0] >> 8) & 0xff);
return -ETIMEDOUT;
}
+ msleep(1);
}
stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
@@ -470,7 +482,7 @@ static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
ret = __av7110_send_fw_cmd(av7110, buf, length);
up(&av7110->dcomlock);
- if (ret)
+ if (ret && ret!=-ERESTARTSYS)
printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
__FUNCTION__, ret);
return ret;
@@ -495,7 +507,7 @@ int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
}
ret = av7110_send_fw_cmd(av7110, buf, num + 2);
- if (ret)
+ if (ret && ret != -ERESTARTSYS)
printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
return ret;
}
@@ -518,7 +530,7 @@ int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
}
ret = av7110_send_fw_cmd(av7110, cmd, 18);
- if (ret)
+ if (ret && ret != -ERESTARTSYS)
printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
return ret;
}
@@ -551,26 +563,32 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
}
start = jiffies;
- while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2)) {
-#ifdef _NOHANDSHAKE
- msleep(1);
-#endif
- if (time_after(jiffies, start + ARM_WAIT_FREE)) {
+ while (1) {
+ err = time_after(jiffies, start + ARM_WAIT_FREE);
+ if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
+ break;
+ if (err) {
printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
up(&av7110->dcomlock);
- return -1;
+ return -ETIMEDOUT;
}
+#ifdef _NOHANDSHAKE
+ msleep(1);
+#endif
}
#ifndef _NOHANDSHAKE
start = jiffies;
- while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
- msleep(1);
- if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
+ while (1) {
+ err = time_after(jiffies, start + ARM_WAIT_SHAKE);
+ if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
+ break;
+ if (err) {
printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
up(&av7110->dcomlock);
- return -1;
+ return -ETIMEDOUT;
}
+ msleep(1);
}
#endif
@@ -667,10 +685,10 @@ int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long bu
for (i = 0; i < len; i++)
buf[i + 4] = msg[i];
- if ((ret = av7110_send_fw_cmd(av7110, buf, 18)))
+ ret = av7110_send_fw_cmd(av7110, buf, 18);
+ if (ret && ret!=-ERESTARTSYS)
printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
-
- return 0;
+ return ret;
}
@@ -705,18 +723,22 @@ static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
static int FlushText(struct av7110 *av7110)
{
unsigned long start;
+ int err;
if (down_interruptible(&av7110->dcomlock))
return -ERESTARTSYS;
start = jiffies;
- while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
- msleep(1);
- if (time_after(jiffies, start + ARM_WAIT_OSD)) {
+ while (1) {
+ err = time_after(jiffies, start + ARM_WAIT_OSD);
+ if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
+ break;
+ if (err) {
printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
__FUNCTION__);
up(&av7110->dcomlock);
- return -1;
+ return -ETIMEDOUT;
}
+ msleep(1);
}
up(&av7110->dcomlock);
return 0;
@@ -733,25 +755,31 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
return -ERESTARTSYS;
start = jiffies;
- while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
- msleep(1);
- if (time_after(jiffies, start + ARM_WAIT_OSD)) {
+ while (1) {
+ ret = time_after(jiffies, start + ARM_WAIT_OSD);
+ if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
+ break;
+ if (ret) {
printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
__FUNCTION__);
up(&av7110->dcomlock);
- return -1;
+ return -ETIMEDOUT;
}
+ msleep(1);
}
#ifndef _NOHANDSHAKE
start = jiffies;
- while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2)) {
- msleep(1);
- if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
+ while (1) {
+ ret = time_after(jiffies, start + ARM_WAIT_SHAKE);
+ if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
+ break;
+ if (ret) {
printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
__FUNCTION__);
up(&av7110->dcomlock);
- return -1;
+ return -ETIMEDOUT;
}
+ msleep(1);
}
#endif
for (i = 0; i < length / 2; i++)
@@ -761,7 +789,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
up(&av7110->dcomlock);
- if (ret)
+ if (ret && ret!=-ERESTARTSYS)
printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
return ret;
}
@@ -816,9 +844,25 @@ static osd_raw_window_t bpp2bit[8] = {
OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
};
-static inline int LoadBitmap(struct av7110 *av7110, u16 format,
+static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
+{
+ int ret = wait_event_interruptible_timeout(av7110->bmpq,
+ av7110->bmp_state != BMP_LOADING, 10*HZ);
+ if (ret == -ERESTARTSYS)
+ return ret;
+ if (ret == 0) {
+ printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
+ ret, av7110->bmp_state);
+ av7110->bmp_state = BMP_NONE;
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+static inline int LoadBitmap(struct av7110 *av7110,
u16 dx, u16 dy, int inc, u8 __user * data)
{
+ u16 format;
int bpp;
int i;
int d, delta;
@@ -827,14 +871,7 @@ static inline int LoadBitmap(struct av7110 *av7110, u16 format,
dprintk(4, "%p\n", av7110);
- ret = wait_event_interruptible_timeout(av7110->bmpq, av7110->bmp_state != BMP_LOADING, HZ);
- if (ret == -ERESTARTSYS || ret == 0) {
- printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
- ret, av7110->bmp_state);
- av7110->bmp_state = BMP_NONE;
- return -1;
- }
- BUG_ON (av7110->bmp_state == BMP_LOADING);
+ format = bpp2bit[av7110->osdbpp[av7110->osdwin]];
av7110->bmp_state = BMP_LOADING;
if (format == OSD_BITMAP8) {
@@ -847,18 +884,18 @@ static inline int LoadBitmap(struct av7110 *av7110, u16 format,
bpp=1; delta = 8;
} else {
av7110->bmp_state = BMP_NONE;
- return -1;
+ return -EINVAL;
}
av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
av7110->bmpp = 0;
if (av7110->bmplen > 32768) {
av7110->bmp_state = BMP_NONE;
- return -1;
+ return -EINVAL;
}
for (i = 0; i < dy; i++) {
if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
av7110->bmp_state = BMP_NONE;
- return -1;
+ return -EINVAL;
}
}
if (format != OSD_BITMAP8) {
@@ -873,37 +910,27 @@ static inline int LoadBitmap(struct av7110 *av7110, u16 format,
}
av7110->bmplen += 1024;
dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
- return av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
+ ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
+ if (!ret)
+ ret = WaitUntilBmpLoaded(av7110);
+ return ret;
}
-static int BlitBitmap(struct av7110 *av7110, u16 win, u16 x, u16 y, u16 trans)
+static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y)
{
- int ret;
-
dprintk(4, "%p\n", av7110);
- BUG_ON (av7110->bmp_state == BMP_NONE);
-
- ret = wait_event_interruptible_timeout(av7110->bmpq,
- av7110->bmp_state != BMP_LOADING, 10*HZ);
- if (ret == -ERESTARTSYS || ret == 0) {
- printk("dvb-ttpci: warning: timeout waiting in BlitBitmap: %d, %d\n",
- ret, av7110->bmp_state);
- av7110->bmp_state = BMP_NONE;
- return (ret == 0) ? -ETIMEDOUT : ret;
- }
-
- BUG_ON (av7110->bmp_state != BMP_LOADED);
-
- return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, win, x, y, trans);
+ return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0);
}
static inline int ReleaseBitmap(struct av7110 *av7110)
{
dprintk(4, "%p\n", av7110);
- if (av7110->bmp_state != BMP_LOADED)
+ if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
return -1;
+ if (av7110->bmp_state == BMP_LOADING)
+ dprintk(1,"ReleaseBitmap called while BMP_LOADING\n");
av7110->bmp_state = BMP_NONE;
return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
}
@@ -924,18 +951,22 @@ static u32 RGB2YUV(u16 R, u16 G, u16 B)
return Cr | (Cb << 16) | (Y << 8);
}
-static void OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
+static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
{
+ int ret;
+
u16 ch, cl;
u32 yuv;
yuv = blend ? RGB2YUV(r,g,b) : 0;
cl = (yuv & 0xffff);
ch = ((yuv >> 16) & 0xffff);
- SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
- color, ch, cl);
- SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
- color, ((blend >> 4) & 0x0f));
+ ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
+ color, ch, cl);
+ if (!ret)
+ ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
+ color, ((blend >> 4) & 0x0f));
+ return ret;
}
static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
@@ -968,14 +999,14 @@ static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
{
uint w, h, bpp, bpl, size, lpb, bnum, brest;
int i;
- int rc;
+ int rc,release_rc;
w = x1 - x0 + 1;
h = y1 - y0 + 1;
if (inc <= 0)
inc = w;
if (w <= 0 || w > 720 || h <= 0 || h > 576)
- return -1;
+ return -EINVAL;
bpp = av7110->osdbpp[av7110->osdwin] + 1;
bpl = ((w * bpp + 7) & ~7) / 8;
size = h * bpl;
@@ -983,176 +1014,186 @@ static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
bnum = size / (lpb * bpl);
brest = size - bnum * lpb * bpl;
- for (i = 0; i < bnum; i++) {
- rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
- w, lpb, inc, data);
- if (rc)
- return rc;
- rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + i * lpb, 0);
+ if (av7110->bmp_state == BMP_LOADING) {
+ /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */
+ BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e);
+ rc = WaitUntilBmpLoaded(av7110);
if (rc)
return rc;
- data += lpb * inc;
+ /* just continue. This should work for all fw versions
+ * if bnum==1 && !brest && LoadBitmap was successful
+ */
}
- if (brest) {
- rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
- w, brest / bpl, inc, data);
+
+ rc = 0;
+ for (i = 0; i < bnum; i++) {
+ rc = LoadBitmap(av7110, w, lpb, inc, data);
if (rc)
- return rc;
- rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + bnum * lpb, 0);
+ break;
+ rc = BlitBitmap(av7110, x0, y0 + i * lpb);
if (rc)
- return rc;
+ break;
+ data += lpb * inc;
}
- ReleaseBitmap(av7110);
- return 0;
+ if (!rc && brest) {
+ rc = LoadBitmap(av7110, w, brest / bpl, inc, data);
+ if (!rc)
+ rc = BlitBitmap(av7110, x0, y0 + bnum * lpb);
+ }
+ release_rc = ReleaseBitmap(av7110);
+ if (!rc)
+ rc = release_rc;
+ if (rc)
+ dprintk(1,"returns %d\n",rc);
+ return rc;
}
int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
{
int ret;
- ret = down_interruptible(&av7110->osd_sema);
- if (ret)
+ if (down_interruptible(&av7110->osd_sema))
return -ERESTARTSYS;
- /* stupid, but OSD functions don't provide a return code anyway */
- ret = 0;
-
switch (dc->cmd) {
case OSD_Close:
- DestroyOSDWindow(av7110, av7110->osdwin);
- goto out;
+ ret = DestroyOSDWindow(av7110, av7110->osdwin);
+ break;
case OSD_Open:
av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
- CreateOSDWindow(av7110, av7110->osdwin,
+ ret = CreateOSDWindow(av7110, av7110->osdwin,
bpp2bit[av7110->osdbpp[av7110->osdwin]],
dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
+ if (ret)
+ break;
if (!dc->data) {
- MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
- SetColorBlend(av7110, av7110->osdwin);
+ ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
+ if (ret)
+ break;
+ ret = SetColorBlend(av7110, av7110->osdwin);
}
- goto out;
+ break;
case OSD_Show:
- MoveWindowRel(av7110, av7110->osdwin, 0, 0);
- goto out;
+ ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0);
+ break;
case OSD_Hide:
- HideWindow(av7110, av7110->osdwin);
- goto out;
+ ret = HideWindow(av7110, av7110->osdwin);
+ break;
case OSD_Clear:
- DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
- goto out;
+ ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
+ break;
case OSD_Fill:
- DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
- goto out;
+ ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
+ break;
case OSD_SetColor:
- OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
- goto out;
+ ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
+ break;
case OSD_SetPalette:
- {
- if (FW_VERSION(av7110->arm_app) >= 0x2618) {
+ if (FW_VERSION(av7110->arm_app) >= 0x2618)
ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
- goto out;
- } else {
+ else {
int i, len = dc->x0-dc->color+1;
u8 __user *colors = (u8 __user *)dc->data;
u8 r, g, b, blend;
-
+ ret = 0;
for (i = 0; i<len; i++) {
if (get_user(r, colors + i * 4) ||
get_user(g, colors + i * 4 + 1) ||
get_user(b, colors + i * 4 + 2) ||
get_user(blend, colors + i * 4 + 3)) {
ret = -EFAULT;
- goto out;
+ break;
}
- OSDSetColor(av7110, dc->color + i, r, g, b, blend);
+ ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
+ if (ret)
+ break;
}
}
- ret = 0;
- goto out;
- }
- case OSD_SetTrans:
- goto out;
+ break;
case OSD_SetPixel:
- DrawLine(av7110, av7110->osdwin,
+ ret = DrawLine(av7110, av7110->osdwin,
dc->x0, dc->y0, 0, 0, dc->color);
- goto out;
- case OSD_GetPixel:
- goto out;
+ break;
case OSD_SetRow:
dc->y1 = dc->y0;
/* fall through */
case OSD_SetBlock:
ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
- goto out;
+ break;
case OSD_FillRow:
- DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
+ ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
dc->x1-dc->x0+1, dc->y1, dc->color);
- goto out;
+ break;
case OSD_FillBlock:
- DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
+ ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
- goto out;
+ break;
case OSD_Line:
- DrawLine(av7110, av7110->osdwin,
+ ret = DrawLine(av7110, av7110->osdwin,
dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
- goto out;
- case OSD_Query:
- goto out;
- case OSD_Test:
- goto out;
+ break;
case OSD_Text:
{
char textbuf[240];
if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
ret = -EFAULT;
- goto out;
+ break;
}
textbuf[239] = 0;
if (dc->x1 > 3)
dc->x1 = 3;
- SetFont(av7110, av7110->osdwin, dc->x1,
+ ret = SetFont(av7110, av7110->osdwin, dc->x1,
(u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
- FlushText(av7110);
- WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
- goto out;
+ if (!ret)
+ ret = FlushText(av7110);
+ if (!ret)
+ ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
+ break;
}
case OSD_SetWindow:
- if (dc->x0 < 1 || dc->x0 > 7) {
+ if (dc->x0 < 1 || dc->x0 > 7)
ret = -EINVAL;
- goto out;
+ else {
+ av7110->osdwin = dc->x0;
+ ret = 0;
}
- av7110->osdwin = dc->x0;
- goto out;
+ break;
case OSD_MoveWindow:
- MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
- SetColorBlend(av7110, av7110->osdwin);
- goto out;
+ ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
+ if (!ret)
+ ret = SetColorBlend(av7110, av7110->osdwin);
+ break;
case OSD_OpenRaw:
if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
ret = -EINVAL;
- goto out;
+ break;
}
- if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR) {
+ if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR)
av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
- }
- else {
+ else
av7110->osdbpp[av7110->osdwin] = 0;
- }
- CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
+ ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
+ if (ret)
+ break;
if (!dc->data) {
- MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
- SetColorBlend(av7110, av7110->osdwin);
+ ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
+ if (!ret)
+ ret = SetColorBlend(av7110, av7110->osdwin);
}
- goto out;
+ break;
default:
ret = -EINVAL;
- goto out;
+ break;
}
-out:
up(&av7110->osd_sema);
+ if (ret==-ERESTARTSYS)
+ dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
+ else if (ret)
+ dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret);
+
return ret;
}
diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h
index 52061e17c6d..fedd20f9815 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.h
+++ b/drivers/media/dvb/ttpci/av7110_hw.h
@@ -458,27 +458,27 @@ static inline int SendDAC(struct av7110 *av7110, u8 addr, u8 data)
return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, AudioDAC, 2, addr, data);
}
-static inline void av7710_set_video_mode(struct av7110 *av7110, int mode)
+static inline int av7710_set_video_mode(struct av7110 *av7110, int mode)
{
- av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode);
+ return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode);
}
-static int inline vidcom(struct av7110 *av7110, u32 com, u32 arg)
+static inline int vidcom(struct av7110 *av7110, u32 com, u32 arg)
{
return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_VIDEO_COMMAND, 4,
(com>>16), (com&0xffff),
(arg>>16), (arg&0xffff));
}
-static int inline audcom(struct av7110 *av7110, u32 com)
+static inline int audcom(struct av7110 *av7110, u32 com)
{
return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 2,
(com>>16), (com&0xffff));
}
-static inline void Set22K(struct av7110 *av7110, int state)
+static inline int Set22K(struct av7110 *av7110, int state)
{
- av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0);
+ return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0);
}
diff --git a/drivers/media/dvb/ttpci/av7110_ipack.c b/drivers/media/dvb/ttpci/av7110_ipack.c
index 24664074188..699ef8b5b99 100644
--- a/drivers/media/dvb/ttpci/av7110_ipack.c
+++ b/drivers/media/dvb/ttpci/av7110_ipack.c
@@ -24,7 +24,7 @@ int av7110_ipack_init(struct ipack *p, int size,
void (*func)(u8 *buf, int size, void *priv))
{
if (!(p->buf = vmalloc(size*sizeof(u8)))) {
- printk ("Couldn't allocate memory for ipack\n");
+ printk(KERN_WARNING "Couldn't allocate memory for ipack\n");
return -ENOMEM;
}
p->size = size;
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 6e0f5d307c5..b65f4b0a481 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -570,9 +570,9 @@ static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p
buf[0] = (div >> 8) & 0x7f;
buf[1] = div & 0xff;
- buf[2] = 0x8e;
- buf[3] = (params->frequency < 174500000 ? 0xa1 :
- params->frequency < 454000000 ? 0x92 : 0x34);
+ buf[2] = 0x86;
+ buf[3] = (params->frequency < 150000000 ? 0x01 :
+ params->frequency < 445000000 ? 0x02 : 0x04);
if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
return -EIO;
@@ -695,8 +695,12 @@ static struct tda1004x_config philips_tu1216_config = {
.demod_address = 0x8,
.invert = 1,
.invert_oclk = 1,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
.pll_init = philips_tu1216_pll_init,
.pll_set = philips_tu1216_pll_set,
+ .pll_sleep = NULL,
.request_firmware = philips_tu1216_request_firmware,
};
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index dce11611137..a1267054bc0 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -69,6 +69,7 @@ struct budget_ci {
int slot_status;
struct dvb_ca_en50221 ca;
char ir_dev_name[50];
+ u8 tuner_pll_address; /* used for philips_tdm1316l configs */
};
/* from reading the following remotes:
@@ -723,7 +724,7 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend *fe)
struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
- struct i2c_msg tuner_msg = {.addr = 0x63,.flags = 0,.buf = td1316_init,.len =
+ struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
sizeof(td1316_init) };
// setup PLL configuration
@@ -746,7 +747,7 @@ static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend
{
struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
u8 tuner_buf[4];
- struct i2c_msg tuner_msg = {.addr = 0x63,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) };
+ struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) };
int tuner_frequency = 0;
u8 band, cp, filter;
@@ -838,8 +839,12 @@ static struct tda1004x_config philips_tdm1316l_config = {
.demod_address = 0x8,
.invert = 0,
.invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
.pll_init = philips_tdm1316l_pll_init,
.pll_set = philips_tdm1316l_pll_set,
+ .pll_sleep = NULL,
.request_firmware = philips_tdm1316l_request_firmware,
};
@@ -865,12 +870,22 @@ static void frontend_init(struct budget_ci *budget_ci)
break;
case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
+ budget_ci->tuner_pll_address = 0x63;
budget_ci->budget.dvb_frontend =
tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
break;
}
break;
+
+ case 0x1012: // Hauppauge/TT Nova-T CI budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
+ budget_ci->tuner_pll_address = 0x60;
+ budget_ci->budget.dvb_frontend =
+ tda10046_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+ if (budget_ci->budget.dvb_frontend) {
+ break;
+ }
+ break;
}
if (budget_ci->budget.dvb_frontend == NULL) {
@@ -950,11 +965,13 @@ static struct saa7146_extension budget_extension;
MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
+ MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
{
.vendor = 0,
}
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 083fd44e5f9..9961917e8a7 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -40,6 +40,7 @@
#include "ves1820.h"
#include "l64781.h"
#include "tda8083.h"
+#include "s5h1420.h"
static void Set22K (struct budget *budget, int state)
{
@@ -177,6 +178,62 @@ static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t m
return 0;
}
+static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u8 buf;
+ struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) };
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+
+ switch(voltage) {
+ case SEC_VOLTAGE_13:
+ buf = (buf & 0xf7) | 0x04;
+ break;
+
+ case SEC_VOLTAGE_18:
+ buf = (buf & 0xf7) | 0x0c;
+ break;
+
+ case SEC_VOLTAGE_OFF:
+ buf = buf & 0xf0;
+ break;
+ }
+
+ msg.flags = 0;
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+
+ return 0;
+}
+
+static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, int arg)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u8 buf;
+ struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) };
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+
+ if (arg) {
+ buf = buf | 0x10;
+ } else {
+ buf = buf & 0xef;
+ }
+
+ msg.flags = 0;
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+
+ return 0;
+}
+
+static void lnbp21_init(struct budget* budget)
+{
+ u8 buf = 0x00;
+ struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = &buf, .len = sizeof(buf) };
+
+ i2c_transfer (&budget->i2c_adap, &msg, 1);
+}
+
static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
@@ -395,6 +452,38 @@ static struct tda8083_config grundig_29504_451_config = {
.pll_set = grundig_29504_451_pll_set,
};
+static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u32 div;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = params->frequency / 1000;
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0xc2;
+
+ if (div < 1450)
+ data[3] = 0x00;
+ else if (div < 1850)
+ data[3] = 0x40;
+ else if (div < 2000)
+ data[3] = 0x80;
+ else
+ data[3] = 0xc0;
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+
+ *freqout = div * 1000;
+ return 0;
+}
+
+static struct s5h1420_config s5h1420_config = {
+ .demod_address = 0x53,
+ .pll_set = s5h1420_pll_set,
+};
+
static u8 read_pwm(struct budget* budget)
{
u8 b = 0xff;
@@ -459,6 +548,15 @@ static void frontend_init(struct budget *budget)
break;
}
break;
+
+ case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
+ budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
+ budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+ lnbp21_init(budget);
+ break;
+ }
}
if (budget->dvb_frontend == NULL) {
@@ -532,6 +630,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004),
MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005),
MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
+ MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016),
MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
{
diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig
index 4aa714ab4c2..c6c1d41a2ef 100644
--- a/drivers/media/dvb/ttusb-budget/Kconfig
+++ b/drivers/media/dvb/ttusb-budget/Kconfig
@@ -3,6 +3,7 @@ config DVB_TTUSB_BUDGET
depends on DVB_CORE && USB
select DVB_CX22700
select DVB_TDA1004X
+ select DVB_VES1820
select DVB_TDA8083
select DVB_STV0299
help
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index afa0e7a0e50..2c17a5f5834 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -24,6 +24,7 @@
#include "dmxdev.h"
#include "dvb_demux.h"
#include "dvb_net.h"
+#include "ves1820.h"
#include "cx22700.h"
#include "tda1004x.h"
#include "stv0299.h"
@@ -1367,6 +1368,47 @@ static struct tda8083_config ttusb_novas_grundig_29504_491_config = {
.pll_set = ttusb_novas_grundig_29504_491_pll_set,
};
+static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct ttusb* ttusb = fe->dvb->priv;
+ u32 div;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = (params->frequency + 35937500 + 31250) / 62500;
+
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x85 | ((div >> 10) & 0x60);
+ data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+
+ if (i2c_transfer (&ttusb->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+
+ return 0;
+}
+
+
+static struct ves1820_config alps_tdbe2_config = {
+ .demod_address = 0x09,
+ .xin = 57840000UL,
+ .invert = 1,
+ .selagc = VES1820_SELAGC_SIGNAMPERR,
+ .pll_set = alps_tdbe2_pll_set,
+};
+
+static u8 read_pwm(struct ttusb* ttusb)
+{
+ u8 b = 0xff;
+ u8 pwm;
+ struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
+ { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
+
+ if ((i2c_transfer(&ttusb->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
+ pwm = 0x48;
+
+ return pwm;
+}
static void frontend_init(struct ttusb* ttusb)
@@ -1394,6 +1436,12 @@ static void frontend_init(struct ttusb* ttusb)
break;
+ case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
+ ttusb->fe = ves1820_attach(&alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb));
+ if (ttusb->fe != NULL)
+ break;
+ break;
+
case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??))
// try the ALPS TDMB7 first
ttusb->fe = cx22700_attach(&alps_tdmb7_config, &ttusb->i2c_adap);
@@ -1570,7 +1618,7 @@ static void ttusb_disconnect(struct usb_interface *intf)
static struct usb_device_id ttusb_table[] = {
{USB_DEVICE(0xb48, 0x1003)},
-/* {USB_DEVICE(0xb48, 0x1004)},UNDEFINED HARDWARE - mail linuxtv.org list*/ /* to be confirmed ???? */
+ {USB_DEVICE(0xb48, 0x1004)},
{USB_DEVICE(0xb48, 0x1005)},
{}
};
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 505bdaff5a7..45c9a9a08e4 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -1281,6 +1281,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
if (firmware_size < 60) {
printk("%s: firmware size too small for DSP code (%zu < 60).\n",
__FUNCTION__, firmware_size);
+ release_firmware(fw_entry);
return -1;
}
@@ -1294,6 +1295,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
printk("%s: crc32 check of DSP code failed (calculated "
"0x%08x != 0x%08x in file), file invalid.\n",
__FUNCTION__, crc32_csum, crc32_check);
+ release_firmware(fw_entry);
return -1;
}
memcpy(idstring, &firmware[36], 20);
@@ -1308,15 +1310,19 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL);
- if (result)
+ if (result) {
+ release_firmware(fw_entry);
return result;
+ }
trans_count = 0;
j = 0;
b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL);
- if (b == NULL)
+ if (b == NULL) {
+ release_firmware(fw_entry);
return -ENOMEM;
+ }
for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) {
size = firmware_size - i;
@@ -1345,6 +1351,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL);
+ release_firmware(fw_entry);
kfree(b);
return result;
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
index 1699cc9f6bb..725af3af5b2 100644
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
@@ -157,7 +157,8 @@ struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* conf
/* allocate memory for the internal state */
state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
- if (state == NULL) goto error;
+ if (state == NULL)
+ return NULL;
/* setup the state */
state->config = config;
@@ -167,10 +168,6 @@ struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* conf
state->frontend.ops = &state->ops;
state->frontend.demodulator_priv = state;
return &state->frontend;
-
-error:
- kfree(state);
- return NULL;
}
static struct dvb_frontend_ops ttusbdecfe_dvbs_ops;
@@ -181,7 +178,8 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf
/* allocate memory for the internal state */
state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
- if (state == NULL) goto error;
+ if (state == NULL)
+ return NULL;
/* setup the state */
state->config = config;
@@ -193,10 +191,6 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf
state->frontend.ops = &state->ops;
state->frontend.demodulator_priv = state;
return &state->frontend;
-
-error:
- kfree(state);
- return NULL;
}
static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = {
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 1b70f8b0feb..e771064689e 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -344,6 +344,7 @@ config VIDEO_CX88_DVB
select DVB_MT352
select DVB_OR51132
select DVB_CX22702
+ select DVB_LGDT3302
---help---
This adds support for DVB/ATSC cards based on the
Connexant 2388x chip.
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index b3fb04356b7..b0b47c3cde3 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-cards.c,v 1.76 2005/06/08 01:28:09 mchehab Exp $
+ * $Id: cx88-cards.c,v 1.85 2005/07/04 19:35:05 mkrufky Exp $
*
* device driver for Conexant 2388x based TV cards
* card-specific stuff.
@@ -401,7 +401,7 @@ struct cx88_board cx88_boards[] = {
.dvb = 1,
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
- .name = "DVICO FusionHDTV DVB-T1",
+ .name = "DViCO FusionHDTV DVB-T1",
.tuner_type = TUNER_ABSENT, /* No analog tuner */
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
@@ -445,8 +445,8 @@ struct cx88_board cx88_boards[] = {
.gpio0 = 0x000007f8,
},
},
- [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD] = {
- .name = "DViCO - FusionHDTV 3 Gold",
+ [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q] = {
+ .name = "DViCO FusionHDTV 3 Gold-Q",
.tuner_type = TUNER_MICROTUNE_4042FI5,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
@@ -464,6 +464,9 @@ struct cx88_board cx88_boards[] = {
GPIO[3] selects RF input connector on tuner module
0 - RF connector labeled CABLE
1 - RF connector labeled ANT
+ GPIO[4] selects high RF for QAM256 mode
+ 0 - normal RF
+ 1 - high RF
*/
.input = {{
.type = CX88_VMUX_TELEVISION,
@@ -482,6 +485,7 @@ struct cx88_board cx88_boards[] = {
.vmux = 2,
.gpio0 = 0x0f00,
}},
+ .dvb = 1,
},
[CX88_BOARD_HAUPPAUGE_DVB_T1] = {
.name = "Hauppauge Nova-T DVB-T",
@@ -520,7 +524,7 @@ struct cx88_board cx88_boards[] = {
.blackbird = 1,
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = {
- .name = "DVICO FusionHDTV DVB-T Plus",
+ .name = "DViCO FusionHDTV DVB-T Plus",
.tuner_type = TUNER_ABSENT, /* No analog tuner */
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
@@ -700,21 +704,17 @@ struct cx88_board cx88_boards[] = {
},
},
[CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = {
- .name = "DViCO - FusionHDTV 3 Gold-T",
+ .name = "DViCO FusionHDTV 3 Gold-T",
.tuner_type = TUNER_THOMSON_DTT7611,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- /* See DViCO FusionHDTV 3 Gold for GPIO documentation. */
- .input = {{
+ /* See DViCO FusionHDTV 3 Gold-Q for GPIO documentation. */
+ .input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x0f0d,
},{
- .type = CX88_VMUX_CABLE,
- .vmux = 0,
- .gpio0 = 0x0f05,
- },{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x0f00,
@@ -723,7 +723,36 @@ struct cx88_board cx88_boards[] = {
.vmux = 2,
.gpio0 = 0x0f00,
}},
+ .dvb = 1,
},
+ [CX88_BOARD_ADSTECH_DVB_T_PCI] = {
+ .name = "ADS Tech Instant TV DVB-T PCI",
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x0700,
+ .gpio2 = 0x0101,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x0700,
+ .gpio2 = 0x0101,
+ }},
+ .dvb = 1,
+ },
+ [CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = {
+ .name = "TerraTec Cinergy 1400 DVB-T",
+ .tuner_type = TUNER_ABSENT,
+ .input = {{
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ }},
+ .dvb = 1,
+ },
};
const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
@@ -794,7 +823,7 @@ struct cx88_subid cx88_subids[] = {
},{
.subvendor = 0x18ac,
.subdevice = 0xd810,
- .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD,
+ .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
},{
.subvendor = 0x18ac,
.subdevice = 0xd820,
@@ -843,7 +872,15 @@ struct cx88_subid cx88_subids[] = {
.subvendor = 0x10fc,
.subdevice = 0xd035,
.card = CX88_BOARD_IODATA_GVBCTV7E,
- }
+ },{
+ .subvendor = 0x1421,
+ .subdevice = 0x0334,
+ .card = CX88_BOARD_ADSTECH_DVB_T_PCI,
+ },{
+ .subvendor = 0x153b,
+ .subdevice = 0x1166,
+ .card = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1,
+ },
};
const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index c046a23537d..96cb0ff33bb 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-core.c,v 1.28 2005/06/12 04:19:19 mchehab Exp $
+ * $Id: cx88-core.c,v 1.31 2005/06/22 22:58:04 mchehab Exp $
*
* device driver for Conexant 2388x based TV cards
* driver core
@@ -545,12 +545,14 @@ void cx88_sram_channel_dump(struct cx88_core *core,
core->name,cx_read(ch->cnt2_reg));
}
+/* Used only on cx88-core */
static char *cx88_pci_irqs[32] = {
"vid", "aud", "ts", "vip", "hst", "5", "6", "tm1",
"src_dma", "dst_dma", "risc_rd_err", "risc_wr_err",
"brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err",
"i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1"
};
+/* Used only on cx88-video */
char *cx88_vid_irqs[32] = {
"y_risci1", "u_risci1", "v_risci1", "vbi_risc1",
"y_risci2", "u_risci2", "v_risci2", "vbi_risc2",
@@ -558,6 +560,7 @@ char *cx88_vid_irqs[32] = {
"y_sync", "u_sync", "v_sync", "vbi_sync",
"opc_err", "par_err", "rip_err", "pci_abort",
};
+/* Used only on cx88-mpeg */
char *cx88_mpeg_irqs[32] = {
"ts_risci1", NULL, NULL, NULL,
"ts_risci2", NULL, NULL, NULL,
@@ -1006,21 +1009,7 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
set_tvaudio(core);
// tell i2c chips
-#ifdef V4L2_I2C_CLIENTS
cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
-#else
- {
- struct video_channel c;
- memset(&c,0,sizeof(c));
- c.channel = core->input;
- c.norm = VIDEO_MODE_PAL;
- if ((norm->id & (V4L2_STD_NTSC_M|V4L2_STD_NTSC_M_JP)))
- c.norm = VIDEO_MODE_NTSC;
- if (norm->id & V4L2_STD_SECAM)
- c.norm = VIDEO_MODE_SECAM;
- cx88_call_i2c_clients(core,VIDIOCSCHAN,&c);
- }
-#endif
// done
return 0;
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 1a259c3966c..690477a6791 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-dvb.c,v 1.33 2005/06/12 04:19:19 mchehab Exp $
+ * $Id: cx88-dvb.c,v 1.39 2005/07/02 20:00:46 mkrufky Exp $
*
* device driver for Conexant 2388x based TV cards
* MPEG Transport Stream (DVB) routines
@@ -30,9 +30,10 @@
#include <linux/file.h>
#include <linux/suspend.h>
-/* those two frontends need merging via linuxtv cvs ... */
+/* these three frontends need merging via linuxtv cvs ... */
#define HAVE_CX22702 1
#define HAVE_OR51132 1
+#define HAVE_LGDT3302 1
#include "cx88.h"
#include "dvb-pll.h"
@@ -44,6 +45,9 @@
#if HAVE_OR51132
# include "or51132.h"
#endif
+#if HAVE_LGDT3302
+# include "lgdt3302.h"
+#endif
MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -199,6 +203,32 @@ static struct or51132_config pchdtv_hd3000 = {
};
#endif
+#if HAVE_LGDT3302
+static int lgdt3302_set_ts_param(struct dvb_frontend* fe, int is_punctured)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ if (is_punctured)
+ dev->ts_gen_cntrl |= 0x04;
+ else
+ dev->ts_gen_cntrl &= ~0x04;
+ return 0;
+}
+
+static struct lgdt3302_config fusionhdtv_3_gold_q = {
+ .demod_address = 0x0e,
+ .pll_address = 0x61,
+ .pll_desc = &dvb_pll_microtune_4042,
+ .set_ts_params = lgdt3302_set_ts_param,
+};
+
+static struct lgdt3302_config fusionhdtv_3_gold_t = {
+ .demod_address = 0x0e,
+ .pll_address = 0x61,
+ .pll_desc = &dvb_pll_thomson_dtt7611,
+ .set_ts_params = lgdt3302_set_ts_param,
+};
+#endif
+
static int dvb_register(struct cx8802_dev *dev)
{
/* init struct videobuf_dvb */
@@ -212,6 +242,7 @@ static int dvb_register(struct cx8802_dev *dev)
dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config,
&dev->core->i2c_adap);
break;
+ case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
case CX88_BOARD_CONEXANT_DVB_T1:
dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
&dev->core->i2c_adap);
@@ -231,6 +262,7 @@ static int dvb_register(struct cx8802_dev *dev)
break;
case CX88_BOARD_KWORLD_DVB_T:
case CX88_BOARD_DNTV_LIVE_DVB_T:
+ case CX88_BOARD_ADSTECH_DVB_T_PCI:
dev->core->pll_addr = 0x61;
dev->core->pll_desc = &dvb_pll_unknown_1;
dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config,
@@ -242,6 +274,36 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
break;
#endif
+#if HAVE_LGDT3302
+ case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
+ dev->ts_gen_cntrl = 0x08;
+ {
+ /* Do a hardware reset of chip before using it. */
+ struct cx88_core *core = dev->core;
+
+ cx_clear(MO_GP0_IO, 1);
+ mdelay(100);
+ cx_set(MO_GP0_IO, 9); // ANT connector too FIXME
+ mdelay(200);
+ dev->dvb.frontend = lgdt3302_attach(&fusionhdtv_3_gold_q,
+ &dev->core->i2c_adap);
+ }
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
+ dev->ts_gen_cntrl = 0x08;
+ {
+ /* Do a hardware reset of chip before using it. */
+ struct cx88_core *core = dev->core;
+
+ cx_clear(MO_GP0_IO, 1);
+ mdelay(100);
+ cx_set(MO_GP0_IO, 9); /* ANT connector too FIXME */
+ mdelay(200);
+ dev->dvb.frontend = lgdt3302_attach(&fusionhdtv_3_gold_t,
+ &dev->core->i2c_adap);
+ }
+ break;
+#endif
default:
printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
dev->core->name);
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index e20adefcfc6..b5342234b30 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -1,5 +1,5 @@
/*
- $Id: cx88-i2c.c,v 1.23 2005/06/12 04:19:19 mchehab Exp $
+ $Id: cx88-i2c.c,v 1.24 2005/06/17 18:46:23 mkrufky Exp $
cx88-i2c.c -- all the i2c code is here
@@ -157,6 +157,7 @@ static struct i2c_client cx8800_i2c_client_template = {
};
static char *i2c_devs[128] = {
+ [ 0x1c >> 1 ] = "lgdt3302",
[ 0x86 >> 1 ] = "tda9887/cx22702",
[ 0xa0 >> 1 ] = "eeprom",
[ 0xc0 >> 1 ] = "tuner (analog)",
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index dc0dcf249aa..bdc26e75ab5 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-input.c,v 1.11 2005/05/22 20:57:56 nsh Exp $
+ * $Id: cx88-input.c,v 1.13 2005/06/13 16:07:46 nsh Exp $
*
* Device driver for GPIO attached remote control interfaces
* on Conexant 2388x based TV/DVB cards.
@@ -125,6 +125,86 @@ static IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = {
/* ---------------------------------------------------------------------- */
+/* ADS Tech Instant TV DVB-T PCI Remote */
+static IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE] = {
+ [ 0x5b ] = KEY_POWER,
+ [ 0x5f ] = KEY_MUTE,
+ [ 0x57 ] = KEY_1,
+ [ 0x4f ] = KEY_2,
+ [ 0x53 ] = KEY_3,
+ [ 0x56 ] = KEY_4,
+ [ 0x4e ] = KEY_5,
+ [ 0x5e ] = KEY_6,
+ [ 0x54 ] = KEY_7,
+ [ 0x4c ] = KEY_8,
+ [ 0x5c ] = KEY_9,
+ [ 0x4d ] = KEY_0,
+ [ 0x55 ] = KEY_GOTO,
+ [ 0x5d ] = KEY_SEARCH,
+ [ 0x17 ] = KEY_EPG, // Guide
+ [ 0x1f ] = KEY_MENU,
+ [ 0x0f ] = KEY_UP,
+ [ 0x46 ] = KEY_DOWN,
+ [ 0x16 ] = KEY_LEFT,
+ [ 0x1e ] = KEY_RIGHT,
+ [ 0x0e ] = KEY_SELECT, // Enter
+ [ 0x5a ] = KEY_INFO,
+ [ 0x52 ] = KEY_EXIT,
+ [ 0x59 ] = KEY_PREVIOUS,
+ [ 0x51 ] = KEY_NEXT,
+ [ 0x58 ] = KEY_REWIND,
+ [ 0x50 ] = KEY_FORWARD,
+ [ 0x44 ] = KEY_PLAYPAUSE,
+ [ 0x07 ] = KEY_STOP,
+ [ 0x1b ] = KEY_RECORD,
+ [ 0x13 ] = KEY_TUNER, // Live
+ [ 0x0a ] = KEY_A,
+ [ 0x12 ] = KEY_B,
+ [ 0x03 ] = KEY_PROG1, // 1
+ [ 0x01 ] = KEY_PROG2, // 2
+ [ 0x00 ] = KEY_PROG3, // 3
+ [ 0x06 ] = KEY_DVD,
+ [ 0x48 ] = KEY_AUX, // Photo
+ [ 0x40 ] = KEY_VIDEO,
+ [ 0x19 ] = KEY_AUDIO, // Music
+ [ 0x0b ] = KEY_CHANNELUP,
+ [ 0x08 ] = KEY_CHANNELDOWN,
+ [ 0x15 ] = KEY_VOLUMEUP,
+ [ 0x1c ] = KEY_VOLUMEDOWN,
+};
+
+/* ---------------------------------------------------------------------- */
+
+/* MSI TV@nywhere remote */
+static IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = {
+ [ 0x00 ] = KEY_0, /* '0' */
+ [ 0x01 ] = KEY_1, /* '1' */
+ [ 0x02 ] = KEY_2, /* '2' */
+ [ 0x03 ] = KEY_3, /* '3' */
+ [ 0x04 ] = KEY_4, /* '4' */
+ [ 0x05 ] = KEY_5, /* '5' */
+ [ 0x06 ] = KEY_6, /* '6' */
+ [ 0x07 ] = KEY_7, /* '7' */
+ [ 0x08 ] = KEY_8, /* '8' */
+ [ 0x09 ] = KEY_9, /* '9' */
+ [ 0x0c ] = KEY_MUTE, /* 'Mute' */
+ [ 0x0f ] = KEY_SCREEN, /* 'Full Screen' */
+ [ 0x10 ] = KEY_F, /* 'Funtion' */
+ [ 0x11 ] = KEY_T, /* 'Time shift' */
+ [ 0x12 ] = KEY_POWER, /* 'Power' */
+ [ 0x13 ] = KEY_MEDIA, /* 'MTS' */
+ [ 0x14 ] = KEY_SLOW, /* 'Slow' */
+ [ 0x16 ] = KEY_REWIND, /* 'backward <<' */
+ [ 0x17 ] = KEY_ENTER, /* 'Return' */
+ [ 0x18 ] = KEY_FASTFORWARD, /* 'forward >>' */
+ [ 0x1a ] = KEY_CHANNELUP, /* 'Channel+' */
+ [ 0x1b ] = KEY_VOLUMEUP, /* 'Volume+' */
+ [ 0x1e ] = KEY_CHANNELDOWN, /* 'Channel-' */
+ [ 0x1f ] = KEY_VOLUMEDOWN, /* 'Volume-' */
+};
+
+/* ---------------------------------------------------------------------- */
+
struct cx88_IR {
struct cx88_core *core;
struct input_dev input;
@@ -269,6 +349,20 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir->mask_keyup = 0x80;
ir->polling = 1; // ms
break;
+ case CX88_BOARD_ADSTECH_DVB_T_PCI:
+ ir_codes = ir_codes_adstech_dvb_t_pci;
+ ir->gpio_addr = MO_GP1_IO;
+ ir->mask_keycode = 0xbf;
+ ir->mask_keyup = 0x40;
+ ir->polling = 50; // ms
+ break;
+ case CX88_BOARD_MSI_TVANYWHERE_MASTER:
+ ir_codes = ir_codes_msi_tvanywhere;
+ ir->gpio_addr = MO_GP1_IO;
+ ir->mask_keycode = 0x1f;
+ ir->mask_keyup = 0x40;
+ ir->polling = 1;
+ break;
}
if (NULL == ir_codes) {
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 9ade2ae91e9..85da6dc8d0e 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-mpeg.c,v 1.26 2005/06/03 13:31:51 mchehab Exp $
+ * $Id: cx88-mpeg.c,v 1.30 2005/07/05 19:44:40 mkrufky Exp $
*
* Support for the mpeg transport stream transfers
* PCI function #2 of the cx2388x.
@@ -70,11 +70,16 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
if (cx88_boards[core->board].dvb) {
/* negedge driven & software reset */
- cx_write(TS_GEN_CNTRL, 0x40);
+ cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl);
udelay(100);
cx_write(MO_PINMUX_IO, 0x00);
- cx_write(TS_HW_SOP_CNTRL,47<<16|188<<4|0x00);
- cx_write(TS_SOP_STAT,0x00);
+ cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01);
+ if ((core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q) ||
+ (core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T)) {
+ cx_write(TS_SOP_STAT, 0<<16 | 0<<14 | 1<<13 | 0<<12);
+ } else {
+ cx_write(TS_SOP_STAT,0x00);
+ }
cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl);
udelay(100);
}
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index e4ca7350df1..dc997549b63 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-video.c,v 1.63 2005/06/12 04:19:19 mchehab Exp $
+ * $Id: cx88-video.c,v 1.70 2005/06/20 03:36:00 mkrufky Exp $
*
* device driver for Conexant 2388x based TV cards
* video4linux video interface
@@ -261,7 +261,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
.default_value = 0,
.type = V4L2_CTRL_TYPE_INTEGER,
},
- .off = 0,
+ .off = 128,
.reg = MO_HUE,
.mask = 0x00ff,
.shift = 0,
@@ -1351,9 +1351,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
V4L2_CAP_STREAMING |
V4L2_CAP_VBI_CAPTURE |
#if 0
- V4L2_TUNER_CAP_LOW |
-#endif
-#if 0
V4L2_CAP_VIDEO_OVERLAY |
#endif
0;
@@ -1475,7 +1472,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
}
break;
case 1:
- if (CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD == core->board) {
+ if (CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q == core->board) {
strcpy(a->name,"Line In");
a->capability = V4L2_AUDCAP_STEREO;
return 0;
@@ -1588,11 +1585,11 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
{
struct v4l2_frequency *f = arg;
+ memset(f,0,sizeof(*f));
+
if (UNSET == core->tuner_type)
return -EINVAL;
- if (f->tuner != 0)
- return -EINVAL;
- memset(f,0,sizeof(*f));
+
f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
f->frequency = dev->freq;
return 0;
@@ -1612,11 +1609,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
down(&dev->lock);
dev->freq = f->frequency;
cx88_newstation(core);
-#ifdef V4L2_I2C_CLIENTS
cx88_call_i2c_clients(dev->core,VIDIOC_S_FREQUENCY,f);
-#else
- cx88_call_i2c_clients(dev->core,VIDIOCSFREQ,&dev->freq);
-#endif
up(&dev->lock);
return 0;
}
@@ -1714,11 +1707,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
cap->version = CX88_VERSION_CODE;
- cap->capabilities = V4L2_CAP_TUNER
-#if 0
- | V4L2_TUNER_CAP_LOW
-#endif
- ;
+ cap->capabilities = V4L2_CAP_TUNER;
return 0;
}
case VIDIOC_G_TUNER:
@@ -1730,19 +1719,8 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
memset(t,0,sizeof(*t));
strcpy(t->name, "Radio");
- t->rangelow = (int)(65*16);
- t->rangehigh = (int)(108*16);
-#ifdef V4L2_I2C_CLIENTS
cx88_call_i2c_clients(dev->core,VIDIOC_G_TUNER,t);
-#else
- {
- struct video_tuner vt;
- memset(&vt,0,sizeof(vt));
- cx88_call_i2c_clients(dev,VIDIOCGTUNER,&vt);
- t->signal = vt.signal;
- }
-#endif
return 0;
}
case VIDIOC_ENUMINPUT:
@@ -1775,8 +1753,29 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
*id = 0;
return 0;
}
- case VIDIOC_S_AUDIO:
+ case VIDIOCSTUNER:
+ {
+ struct video_tuner *v = arg;
+
+ if (v->tuner) /* Only tuner 0 */
+ return -EINVAL;
+
+ cx88_call_i2c_clients(dev->core,VIDIOCSTUNER,v);
+ return 0;
+ }
case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *t = arg;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ cx88_call_i2c_clients(dev->core,VIDIOC_S_TUNER,t);
+
+ return 0;
+ }
+
+ case VIDIOC_S_AUDIO:
case VIDIOC_S_INPUT:
case VIDIOC_S_STD:
return 0;
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 867e988a5a9..bc5e038bc0f 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -1,5 +1,5 @@
/*
- * $Id: cx88.h,v 1.62 2005/06/12 04:19:19 mchehab Exp $
+ * $Id: cx88.h,v 1.67 2005/07/01 12:10:07 mkrufky Exp $
*
* v4l2 device driver for cx2388x based TV cards
*
@@ -51,8 +51,6 @@
/* ----------------------------------------------------------- */
/* defines and enums */
-#define V4L2_I2C_CLIENTS 1
-
#define FORMAT_FLAGS_PACKED 0x01
#define FORMAT_FLAGS_PLANAR 0x02
@@ -159,7 +157,7 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_KWORLD_DVB_T 14
#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1 15
#define CX88_BOARD_KWORLD_LTV883 16
-#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD 17
+#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q 17
#define CX88_BOARD_HAUPPAUGE_DVB_T1 18
#define CX88_BOARD_CONEXANT_DVB_T1 19
#define CX88_BOARD_PROVIDEO_PV259 20
@@ -167,10 +165,12 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_PCHDTV_HD3000 22
#define CX88_BOARD_DNTV_LIVE_DVB_T 23
#define CX88_BOARD_HAUPPAUGE_ROSLYN 24
-#define CX88_BOARD_DIGITALLOGIC_MEC 25
+#define CX88_BOARD_DIGITALLOGIC_MEC 25
#define CX88_BOARD_IODATA_GVBCTV7E 26
#define CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO 27
#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T 28
+#define CX88_BOARD_ADSTECH_DVB_T_PCI 29
+#define CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1 30
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 8b623278ccd..ffbe6f4720e 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -1363,19 +1363,7 @@ mpt_suspend(struct pci_dev *pdev, pm_message_t state)
u32 device_state;
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
- switch(state)
- {
- case 1: /* S1 */
- device_state=1; /* D1 */;
- break;
- case 3: /* S3 */
- case 4: /* S4 */
- device_state=3; /* D3 */;
- break;
- default:
- return -EAGAIN /*FIXME*/;
- break;
- }
+ device_state=pci_choose_state(pdev, state);
printk(MYIOC_s_INFO_FMT
"pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
index 5ea89bf0df1..debb8ac5954 100644
--- a/drivers/message/fusion/mptscsih.h
+++ b/drivers/message/fusion/mptscsih.h
@@ -84,7 +84,7 @@
extern void mptscsih_remove(struct pci_dev *);
extern void mptscsih_shutdown(struct pci_dev *);
#ifdef CONFIG_PM
-extern int mptscsih_suspend(struct pci_dev *pdev, u32 state);
+extern int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
extern int mptscsih_resume(struct pci_dev *pdev);
#endif
extern int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func);
diff --git a/drivers/message/i2o/config-osm.c b/drivers/message/i2o/config-osm.c
index d0267609a94..fe2e7afc9ea 100644
--- a/drivers/message/i2o/config-osm.c
+++ b/drivers/message/i2o/config-osm.c
@@ -15,7 +15,9 @@
#include <linux/module.h>
#include <linux/i2o.h>
+#include <linux/dcache.h>
#include <linux/namei.h>
+#include <linux/fs.h>
#include <asm/uaccess.h>
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
index c2655a817e3..ff7c50d1018 100644
--- a/drivers/mtd/maps/pcmciamtd.c
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -18,7 +18,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -800,11 +799,6 @@ static dev_link_t *pcmciamtd_attach(void)
/* Register with Card Services */
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &pcmciamtd_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
DEBUG(2, "Calling RegisterClient");
@@ -850,6 +844,7 @@ static struct pcmcia_driver pcmciamtd_driver = {
.name = "pcmciamtd"
},
.attach = pcmciamtd_attach,
+ .event = pcmciamtd_event,
.detach = pcmciamtd_detach,
.owner = THIS_MODULE,
.id_table = pcmciamtd_ids,
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index f0fc04bd37c..71fd41122c9 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -86,7 +86,6 @@ earlier 3Com products.
#include <linux/ethtool.h>
#include <linux/bitops.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -312,11 +311,6 @@ static dev_link_t *tc574_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &tc574_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -1299,6 +1293,7 @@ static struct pcmcia_driver tc574_driver = {
.name = "3c574_cs",
},
.attach = tc574_attach,
+ .event = tc574_event,
.detach = tc574_detach,
.id_table = tc574_ids,
};
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 8fa1b5f0fb6..d83fdd8c194 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -40,7 +40,6 @@
#include <linux/ioport.h>
#include <linux/bitops.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -226,11 +225,6 @@ static dev_link_t *tc589_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &tc589_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -1074,6 +1068,7 @@ static struct pcmcia_driver tc589_driver = {
.name = "3c589_cs",
},
.attach = tc589_attach,
+ .event = tc589_event,
.detach = tc589_detach,
.id_table = tc589_ids,
};
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 23ce77b1d5b..8bb4e85689e 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -37,7 +37,6 @@
#include <linux/netdevice.h>
#include "../8390.h"
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -181,11 +180,6 @@ static dev_link_t *axnet_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &axnet_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -884,6 +878,7 @@ static struct pcmcia_driver axnet_cs_driver = {
.name = "axnet_cs",
},
.attach = axnet_attach,
+ .event = axnet_event,
.detach = axnet_detach,
.id_table = axnet_ids,
};
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c
index 68d58cc58d3..b9355d9498a 100644
--- a/drivers/net/pcmcia/com20020_cs.c
+++ b/drivers/net/pcmcia/com20020_cs.c
@@ -43,7 +43,6 @@
#include <linux/arcdevice.h>
#include <linux/com20020.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -200,11 +199,6 @@ static dev_link_t *com20020_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &com20020_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -495,6 +489,7 @@ static struct pcmcia_driver com20020_cs_driver = {
.name = "com20020_cs",
},
.attach = com20020_attach,
+ .event = com20020_event,
.detach = com20020_detach,
.id_table = com20020_ids,
};
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 917adbbf0b5..9d8197bb293 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -49,7 +49,6 @@
#include <linux/ioport.h>
#include <linux/crc32.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -288,11 +287,6 @@ static dev_link_t *fmvj18x_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &fmvj18x_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -797,6 +791,7 @@ static struct pcmcia_driver fmvj18x_cs_driver = {
.name = "fmvj18x_cs",
},
.attach = fmvj18x_attach,
+ .event = fmvj18x_event,
.detach = fmvj18x_detach,
.id_table = fmvj18x_ids,
};
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
index cf6d073ea55..b6c140eb979 100644
--- a/drivers/net/pcmcia/ibmtr_cs.c
+++ b/drivers/net/pcmcia/ibmtr_cs.c
@@ -57,7 +57,6 @@
#include <linux/trdevice.h>
#include <linux/ibmtr.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -190,11 +189,6 @@ static dev_link_t *ibmtr_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &ibmtr_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -521,6 +515,7 @@ static struct pcmcia_driver ibmtr_cs_driver = {
.name = "ibmtr_cs",
},
.attach = ibmtr_attach,
+ .event = ibmtr_event,
.detach = ibmtr_detach,
.id_table = ibmtr_ids,
};
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index b86e7253fbf..dbb941004ae 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -146,7 +146,6 @@ Include Files
#include <linux/ioport.h>
#include <linux/bitops.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cisreg.h>
@@ -502,11 +501,6 @@ static dev_link_t *nmclan_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &nmclan_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -1688,6 +1682,7 @@ static struct pcmcia_driver nmclan_cs_driver = {
.name = "nmclan_cs",
},
.attach = nmclan_attach,
+ .event = nmclan_event,
.detach = nmclan_detach,
.id_table = nmclan_ids,
};
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 855a45d062b..e1664aef3df 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -40,7 +40,6 @@
#include <linux/netdevice.h>
#include <../drivers/net/8390.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -276,11 +275,6 @@ static dev_link_t *pcnet_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &pcnet_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -1844,6 +1838,7 @@ static struct pcmcia_driver pcnet_driver = {
.name = "pcnet_cs",
},
.attach = pcnet_attach,
+ .event = pcnet_event,
.detach = pcnet_detach,
.owner = THIS_MODULE,
.id_table = pcnet_ids,
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index bc01c88c670..fbc2f58ff68 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -42,7 +42,6 @@
#include <linux/ethtool.h>
#include <linux/mii.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -370,10 +369,6 @@ static dev_link_t *smc91c92_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &smc91c92_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -2365,6 +2360,7 @@ static struct pcmcia_driver smc91c92_cs_driver = {
.name = "smc91c92_cs",
},
.attach = smc91c92_attach,
+ .event = smc91c92_event,
.detach = smc91c92_detach,
.id_table = smc91c92_ids,
};
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 0cd225e1595..9f33bad174e 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -81,7 +81,6 @@
#include <linux/ioport.h>
#include <linux/bitops.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -619,11 +618,6 @@ xirc2ps_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &xirc2ps_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
if ((err = pcmcia_register_client(&link->handle, &client_reg))) {
@@ -2016,6 +2010,7 @@ static struct pcmcia_driver xirc2ps_cs_driver = {
.name = "xirc2ps_cs",
},
.attach = xirc2ps_attach,
+ .event = xirc2ps_event,
.detach = xirc2ps_detach,
.id_table = xirc2ps_ids,
};
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 3dbb1cb09ed..5cacc7ad9e7 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -3259,7 +3259,7 @@ static void __devexit skge_remove(struct pci_dev *pdev)
}
#ifdef CONFIG_PM
-static int skge_suspend(struct pci_dev *pdev, u32 state)
+static int skge_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct skge_hw *hw = pci_get_drvdata(pdev);
int i, wol = 0;
@@ -3279,7 +3279,7 @@ static int skge_suspend(struct pci_dev *pdev, u32 state)
}
pci_save_state(pdev);
- pci_enable_wake(pdev, state, wol);
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 1f5655655c4..2608e7a3d21 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -3079,7 +3079,9 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
gp->phy_mii.dev = dev;
gp->phy_mii.mdio_read = _phy_read;
gp->phy_mii.mdio_write = _phy_write;
-
+#ifdef CONFIG_PPC_PMAC
+ gp->phy_mii.platform_data = gp->of_node;
+#endif
/* By default, we start with autoneg */
gp->want_autoneg = 1;
diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
index 0fca414d365..d3ddb41d6e5 100644
--- a/drivers/net/sungem_phy.c
+++ b/drivers/net/sungem_phy.c
@@ -32,6 +32,10 @@
#include <linux/ethtool.h>
#include <linux/delay.h>
+#ifdef CONFIG_PPC_PMAC
+#include <asm/prom.h>
+#endif
+
#include "sungem_phy.h"
/* Link modes of the BCM5400 PHY */
@@ -281,10 +285,12 @@ static int bcm5411_suspend(struct mii_phy* phy)
static int bcm5421_init(struct mii_phy* phy)
{
u16 data;
- int rev;
+ unsigned int id;
- rev = phy_read(phy, MII_PHYSID2) & 0x000f;
- if (rev == 0) {
+ id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
+
+ /* Revision 0 of 5421 needs some fixups */
+ if (id == 0x002060e0) {
/* This is borrowed from MacOS
*/
phy_write(phy, 0x18, 0x1007);
@@ -297,21 +303,28 @@ static int bcm5421_init(struct mii_phy* phy)
data = phy_read(phy, 0x15);
phy_write(phy, 0x15, data | 0x0200);
}
-#if 0
- /* This has to be verified before I enable it */
- /* Enable automatic low-power */
- phy_write(phy, 0x1c, 0x9002);
- phy_write(phy, 0x1c, 0xa821);
- phy_write(phy, 0x1c, 0x941d);
-#endif
- return 0;
-}
-static int bcm5421k2_init(struct mii_phy* phy)
-{
- /* Init code borrowed from OF */
- phy_write(phy, 4, 0x01e1);
- phy_write(phy, 9, 0x0300);
+ /* Pick up some init code from OF for K2 version */
+ if ((id & 0xfffffff0) == 0x002062e0) {
+ phy_write(phy, 4, 0x01e1);
+ phy_write(phy, 9, 0x0300);
+ }
+
+ /* Check if we can enable automatic low power */
+#ifdef CONFIG_PPC_PMAC
+ if (phy->platform_data) {
+ struct device_node *np = of_get_parent(phy->platform_data);
+ int can_low_power = 1;
+ if (np == NULL || get_property(np, "no-autolowpower", NULL))
+ can_low_power = 0;
+ if (can_low_power) {
+ /* Enable automatic low-power */
+ phy_write(phy, 0x1c, 0x9002);
+ phy_write(phy, 0x1c, 0xa821);
+ phy_write(phy, 0x1c, 0x941d);
+ }
+ }
+#endif /* CONFIG_PPC_PMAC */
return 0;
}
@@ -762,7 +775,7 @@ static struct mii_phy_def bcm5421_phy_def = {
/* Broadcom BCM 5421 built-in K2 */
static struct mii_phy_ops bcm5421k2_phy_ops = {
- .init = bcm5421k2_init,
+ .init = bcm5421_init,
.suspend = bcm5411_suspend,
.setup_aneg = bcm54xx_setup_aneg,
.setup_forced = bcm54xx_setup_forced,
@@ -779,6 +792,25 @@ static struct mii_phy_def bcm5421k2_phy_def = {
.ops = &bcm5421k2_phy_ops
};
+/* Broadcom BCM 5462 built-in Vesta */
+static struct mii_phy_ops bcm5462V_phy_ops = {
+ .init = bcm5421_init,
+ .suspend = bcm5411_suspend,
+ .setup_aneg = bcm54xx_setup_aneg,
+ .setup_forced = bcm54xx_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = bcm54xx_read_link,
+};
+
+static struct mii_phy_def bcm5462V_phy_def = {
+ .phy_id = 0x002060d0,
+ .phy_id_mask = 0xfffffff0,
+ .name = "BCM5462-Vesta",
+ .features = MII_GBIT_FEATURES,
+ .magic_aneg = 1,
+ .ops = &bcm5462V_phy_ops
+};
+
/* Marvell 88E1101 (Apple seem to deal with 2 different revs,
* I masked out the 8 last bits to get both, but some specs
* would be useful here) --BenH.
@@ -824,6 +856,7 @@ static struct mii_phy_def* mii_phy_table[] = {
&bcm5411_phy_def,
&bcm5421_phy_def,
&bcm5421k2_phy_def,
+ &bcm5462V_phy_def,
&marvell_phy_def,
&genmii_phy_def,
NULL
diff --git a/drivers/net/sungem_phy.h b/drivers/net/sungem_phy.h
index 822cb58174e..430544496c5 100644
--- a/drivers/net/sungem_phy.h
+++ b/drivers/net/sungem_phy.h
@@ -43,9 +43,10 @@ struct mii_phy
int pause;
/* Provided by host chip */
- struct net_device* dev;
+ struct net_device *dev;
int (*mdio_read) (struct net_device *dev, int mii_id, int reg);
void (*mdio_write) (struct net_device *dev, int mii_id, int reg, int val);
+ void *platform_data;
};
/* Pass in a struct mii_phy with dev, mdio_read and mdio_write
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 0b5ca253796..ecfa6f8805c 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -1906,9 +1906,9 @@ typhoon_sleep(struct typhoon *tp, pci_power_t state, u16 events)
*/
netif_carrier_off(tp->dev);
- pci_enable_wake(tp->pdev, pci_choose_state(pdev, state), 1);
+ pci_enable_wake(tp->pdev, state, 1);
pci_disable_device(pdev);
- return pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return pci_set_power_state(pdev, state);
}
static int
@@ -2274,7 +2274,7 @@ typhoon_suspend(struct pci_dev *pdev, pm_message_t state)
goto need_resume;
}
- if(typhoon_sleep(tp, state, tp->wol_events) < 0) {
+ if(typhoon_sleep(tp, pci_choose_state(pdev, state), tp->wol_events) < 0) {
printk(KERN_ERR "%s: unable to put card to sleep\n", dev->name);
goto need_resume;
}
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index f10a9523034..bf25584d68d 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -33,7 +33,6 @@
#include <linux/timer.h>
#include <linux/netdevice.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -210,11 +209,6 @@ static dev_link_t *airo_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &airo_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -574,6 +568,7 @@ static struct pcmcia_driver airo_driver = {
.name = "airo_cs",
},
.attach = airo_attach,
+ .event = airo_event,
.detach = airo_detach,
.id_table = airo_ids,
};
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index 86379d4998a..ff031a3985b 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -43,7 +43,6 @@
#include <linux/moduleparam.h>
#include <linux/device.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -218,11 +217,6 @@ static dev_link_t *atmel_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &atmel_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -668,12 +662,13 @@ static struct pcmcia_device_id atmel_ids[] = {
MODULE_DEVICE_TABLE(pcmcia, atmel_ids);
static struct pcmcia_driver atmel_driver = {
- .owner = THIS_MODULE,
- .drv = {
- .name = "atmel_cs",
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "atmel_cs",
},
- .attach = atmel_attach,
- .detach = atmel_detach,
+ .attach = atmel_attach,
+ .event = atmel_event,
+ .detach = atmel_detach,
.id_table = atmel_ids,
};
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index e12bd75b269..5f507c49907 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -62,7 +62,6 @@
#endif /* WIRELESS_EXT > 12 */
#endif
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -491,11 +490,6 @@ static dev_link_t *netwave_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &netwave_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -1680,6 +1674,7 @@ static struct pcmcia_driver netwave_driver = {
.name = "netwave_cs",
},
.attach = netwave_attach,
+ .event = netwave_event,
.detach = netwave_detach,
.id_table = netwave_ids,
};
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index 597c4586d04..368d2f962f6 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -31,7 +31,6 @@
#include <linux/etherdevice.h>
#include <linux/wireless.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -186,11 +185,6 @@ orinoco_cs_attach(void)
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &orinoco_cs_event;
client_reg.Version = 0x0210; /* FIXME: what does this mean? */
client_reg.event_callback_args.client_data = link;
@@ -664,6 +658,7 @@ static struct pcmcia_driver orinoco_driver = {
.name = DRIVER_NAME,
},
.attach = orinoco_cs_attach,
+ .event = orinoco_cs_event,
.detach = orinoco_cs_detach,
.id_table = orinoco_cs_ids,
};
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 31652af52ea..0e0ba614259 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -46,7 +46,6 @@
#include <linux/skbuff.h>
#include <linux/ethtool.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -393,11 +392,6 @@ static dev_link_t *ray_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &ray_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -2916,6 +2910,7 @@ static struct pcmcia_driver ray_driver = {
.name = "ray_cs",
},
.attach = ray_attach,
+ .event = ray_event,
.detach = ray_detach,
.id_table = ray_ids,
};
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 89532fd9294..f6130a53b79 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -4684,12 +4684,6 @@ wavelan_attach(void)
/* Register with Card Services */
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_REGISTRATION_COMPLETE |
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &wavelan_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -4904,6 +4898,7 @@ static struct pcmcia_driver wavelan_driver = {
.name = "wavelan_cs",
},
.attach = wavelan_attach,
+ .event = wavelan_event,
.detach = wavelan_detach,
.id_table = wavelan_ids,
};
diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h
index ea2ef8dddb9..677ff71883c 100644
--- a/drivers/net/wireless/wavelan_cs.p.h
+++ b/drivers/net/wireless/wavelan_cs.p.h
@@ -452,7 +452,6 @@
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>
-#include <pcmcia/version.h>
/* Wavelan declarations */
#include "i82593.h" /* Definitions for the Intel chip */
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index e3a900482d9..dd902126d01 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -49,7 +49,6 @@
#include <net/iw_handler.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -2005,13 +2004,6 @@ static dev_link_t *wl3501_attach(void)
link->next = wl3501_dev_list;
wl3501_dev_list = link;
client_reg.dev_info = &wl3501_dev_info;
- client_reg.EventMask = CS_EVENT_CARD_INSERTION |
- CS_EVENT_RESET_PHYSICAL |
- CS_EVENT_CARD_RESET |
- CS_EVENT_CARD_REMOVAL |
- CS_EVENT_PM_SUSPEND |
- CS_EVENT_PM_RESUME;
- client_reg.event_handler = wl3501_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -2246,12 +2238,13 @@ static struct pcmcia_device_id wl3501_ids[] = {
MODULE_DEVICE_TABLE(pcmcia, wl3501_ids);
static struct pcmcia_driver wl3501_driver = {
- .owner = THIS_MODULE,
- .drv = {
- .name = "wl3501_cs",
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "wl3501_cs",
},
- .attach = wl3501_attach,
- .detach = wl3501_detach,
+ .attach = wl3501_attach,
+ .event = wl3501_event,
+ .detach = wl3501_detach,
.id_table = wl3501_ids,
};
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
index ff45662c4f7..24e6aacddb7 100644
--- a/drivers/parport/parport_cs.c
+++ b/drivers/parport/parport_cs.c
@@ -48,7 +48,6 @@
#include <linux/parport.h>
#include <linux/parport_pc.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -133,11 +132,6 @@ static dev_link_t *parport_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &parport_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -386,6 +380,7 @@ static struct pcmcia_driver parport_cs_driver = {
.name = "parport_cs",
},
.attach = parport_attach,
+ .event = parport_event,
.detach = parport_detach,
.id_table = parport_ids,
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index 4db69982876..393e0cee91a 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -325,7 +325,7 @@ int pcie_port_device_register(struct pci_dev *dev)
static int suspend_iter(struct device *dev, void *data)
{
struct pcie_port_service_driver *service_driver;
- u32 state = (u32)data;
+ pm_message_t state = * (pm_message_t *) data;
if ((dev->bus == &pcie_port_bus_type) &&
(dev->driver)) {
@@ -336,9 +336,9 @@ static int suspend_iter(struct device *dev, void *data)
return 0;
}
-int pcie_port_device_suspend(struct pci_dev *dev, u32 state)
+int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state)
{
- device_for_each_child(&dev->dev, (void *)state, suspend_iter);
+ device_for_each_child(&dev->dev, &state, suspend_iter);
return 0;
}
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 52ea3459436..6485f75d2fb 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -1,8 +1,5 @@
#
-# PCMCIA bus subsystem configuration
-#
-# Right now the non-CardBus choices are not supported
-# by the integrated kernel driver.
+# PCCARD (PCMCIA/CardBus) bus subsystem configuration
#
menu "PCCARD (PCMCIA/CardBus) support"
@@ -32,7 +29,7 @@ config PCMCIA_DEBUG
The kernel command line options are:
pcmcia_core.pc_debug=N
- ds.pc_debug=N
+ pcmcia.pc_debug=N
sa11xx_core.pc_debug=N
The module option is called pc_debug=N
@@ -73,7 +70,7 @@ config PCMCIA_LOAD_CIS
If unsure, say Y.
config PCMCIA_IOCTL
- bool
+ bool "PCMCIA control ioctl (obsolete)"
depends on PCMCIA
default y
help
@@ -81,9 +78,8 @@ config PCMCIA_IOCTL
subsystem will be built. It is needed by cardmgr and cardctl
(pcmcia-cs) to function properly.
- If you do not use the new pcmciautils package, and have a
- yenta, Cirrus PD6729, i82092, i82365 or tcic compatible bridge,
- you need to say Y here to be able to use 16-bit PCMCIA cards.
+ You should use the new pcmciautils package instead (see
+ <file:Documentation/Changes> for location and details).
If unsure, say Y.
@@ -106,7 +102,8 @@ comment "PC-card bridges"
config YENTA
tristate "CardBus yenta-compatible bridge support"
- depends on CARDBUS
+ depends on PCI
+ select CARDBUS if !EMBEDDED
select PCCARD_NONSTATIC
---help---
This option enables support for CardBus host bridges. Virtually
diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h
index 417bc1500ba..d5122b1ea94 100644
--- a/drivers/pcmcia/au1000_generic.h
+++ b/drivers/pcmcia/au1000_generic.h
@@ -22,7 +22,6 @@
#define __ASM_AU1000_PCMCIA_H
/* include the world */
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c
index df19ce1ea4f..d414a3bb50b 100644
--- a/drivers/pcmcia/au1000_pb1x00.c
+++ b/drivers/pcmcia/au1000_pb1x00.c
@@ -33,7 +33,6 @@
#include <linux/version.h>
#include <linux/types.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c
index 1dfc7765366..f113b69d699 100644
--- a/drivers/pcmcia/au1000_xxs1500.c
+++ b/drivers/pcmcia/au1000_xxs1500.c
@@ -38,7 +38,6 @@
#include <linux/version.h>
#include <linux/types.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index 3ccb5247ec5..1d755e20880 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -31,7 +31,6 @@
#include <asm/io.h>
#define IN_CARD_SERVICES
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index e82859d3227..e39178fc59d 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -33,7 +33,6 @@
#include <asm/irq.h>
#define IN_CARD_SERVICES
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
@@ -216,6 +215,13 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
list_add_tail(&socket->socket_list, &pcmcia_socket_list);
up_write(&pcmcia_socket_list_rwsem);
+#ifndef CONFIG_CARDBUS
+ /*
+ * If we do not support Cardbus, ensure that
+ * the Cardbus socket capability is disabled.
+ */
+ socket->features &= ~SS_CAP_CARDBUS;
+#endif
/* set proper values in socket->dev */
socket->dev.class_data = socket;
@@ -449,11 +455,11 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay)
}
if (status & SS_CARDBUS) {
+ if (!(skt->features & SS_CAP_CARDBUS)) {
+ cs_err(skt, "cardbus cards are not supported.\n");
+ return CS_BAD_TYPE;
+ }
skt->state |= SOCKET_CARDBUS;
-#ifndef CONFIG_CARDBUS
- cs_err(skt, "cardbus cards are not supported.\n");
- return CS_BAD_TYPE;
-#endif
}
/*
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index 0b4c18edfa4..6bbfbd0e02a 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -99,23 +99,11 @@ static inline void cs_socket_put(struct pcmcia_socket *skt)
}
}
-#define CHECK_HANDLE(h) \
- (((h) == NULL) || ((h)->client_magic != CLIENT_MAGIC))
-
#define CHECK_SOCKET(s) \
(((s) >= sockets) || (socket_table[s]->ops == NULL))
-#define SOCKET(h) (h->Socket)
-#define CONFIG(h) (&SOCKET(h)->config[(h)->Function])
-
-#define CHECK_REGION(r) \
- (((r) == NULL) || ((r)->region_magic != REGION_MAGIC))
-
-#define CHECK_ERASEQ(q) \
- (((q) == NULL) || ((q)->eraseq_magic != ERASEQ_MAGIC))
-
-#define EVENT(h, e, p) \
- ((h)->event_handler((e), (p), &(h)->event_callback_args))
+#define SOCKET(h) (h->socket)
+#define CONFIG(h) (&SOCKET(h)->config[(h)->func])
/* In cardbus.c */
int cb_alloc(struct pcmcia_socket *s);
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index d5afd557fe3..3e3c6f12bbe 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -158,17 +158,15 @@ static const lookup_t service_table[] = {
};
-static int pcmcia_report_error(client_handle_t handle, error_info_t *err)
+static int pcmcia_report_error(struct pcmcia_device *p_dev, error_info_t *err)
{
int i;
char *serv;
- if (CHECK_HANDLE(handle))
+ if (!p_dev)
printk(KERN_NOTICE);
- else {
- struct pcmcia_device *p_dev = handle_to_pdev(handle);
+ else
printk(KERN_NOTICE "%s: ", p_dev->dev.bus_id);
- }
for (i = 0; i < ARRAY_SIZE(service_table); i++)
if (service_table[i].key == err->func)
@@ -193,10 +191,10 @@ static int pcmcia_report_error(client_handle_t handle, error_info_t *err)
/*======================================================================*/
-void cs_error(client_handle_t handle, int func, int ret)
+void cs_error(struct pcmcia_device *p_dev, int func, int ret)
{
error_info_t err = { func, ret };
- pcmcia_report_error(handle, &err);
+ pcmcia_report_error(p_dev, &err);
}
EXPORT_SYMBOL(cs_error);
@@ -207,6 +205,10 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
unsigned int i;
u32 hash;
+ if (!p_drv->attach || !p_drv->event || !p_drv->detach)
+ printk(KERN_DEBUG "pcmcia: %s does misses a callback function",
+ p_drv->drv.name);
+
while (did && did->match_flags) {
for (i=0; i<4; i++) {
if (!did->prod_id[i])
@@ -376,7 +378,7 @@ static int pcmcia_device_probe(struct device * dev)
if (p_drv->attach) {
p_dev->instance = p_drv->attach();
- if ((!p_dev->instance) || (p_dev->client.state & CLIENT_UNBOUND)) {
+ if ((!p_dev->instance) || (p_dev->state & CLIENT_UNBOUND)) {
printk(KERN_NOTICE "ds: unable to create instance "
"of '%s'!\n", p_drv->drv.name);
ret = -EINVAL;
@@ -516,10 +518,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);
/* compat */
- p_dev->client.client_magic = CLIENT_MAGIC;
- p_dev->client.Socket = s;
- p_dev->client.Function = function;
- p_dev->client.state = CLIENT_UNBOUND;
+ p_dev->state = CLIENT_UNBOUND;
/* Add to the list in pcmcia_bus_socket */
spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
@@ -573,8 +572,6 @@ static int pcmcia_card_add(struct pcmcia_socket *s)
else
no_funcs = 1;
- /* this doesn't handle multifunction devices on one pcmcia function
- * yet. */
for (i=0; i < no_funcs; i++)
pcmcia_device_add(s, i);
@@ -914,6 +911,7 @@ struct send_event_data {
static int send_event_callback(struct device *dev, void * _data)
{
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+ struct pcmcia_driver *p_drv;
struct send_event_data *data = _data;
/* we get called for all sockets, but may only pass the event
@@ -921,11 +919,16 @@ static int send_event_callback(struct device *dev, void * _data)
if (p_dev->socket != data->skt)
return 0;
- if (p_dev->client.state & (CLIENT_UNBOUND|CLIENT_STALE))
+ p_drv = to_pcmcia_drv(p_dev->dev.driver);
+ if (!p_drv)
return 0;
- if (p_dev->client.EventMask & data->event)
- return EVENT(&p_dev->client, data->event, data->priority);
+ if (p_dev->state & (CLIENT_UNBOUND|CLIENT_STALE))
+ return 0;
+
+ if (p_drv->event)
+ return p_drv->event(data->event, data->priority,
+ &p_dev->event_callback_args);
return 0;
}
@@ -987,11 +990,11 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
-int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
+int pcmcia_register_client(struct pcmcia_device **handle, client_reg_t *req)
{
- client_t *client = NULL;
struct pcmcia_socket *s = NULL;
struct pcmcia_device *p_dev = NULL;
+ struct pcmcia_driver *p_drv = NULL;
/* Look for unbound client with matching dev_info */
down_read(&pcmcia_socket_list_rwsem);
@@ -1006,18 +1009,16 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
continue;
spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
- struct pcmcia_driver *p_drv;
p_dev = pcmcia_get_dev(p_dev);
if (!p_dev)
continue;
- if (!(p_dev->client.state & CLIENT_UNBOUND) ||
+ if (!(p_dev->state & CLIENT_UNBOUND) ||
(!p_dev->dev.driver)) {
pcmcia_put_dev(p_dev);
continue;
}
p_drv = to_pcmcia_drv(p_dev->dev.driver);
if (!strncmp(p_drv->drv.name, (char *)req->dev_info, DEV_NAME_LEN)) {
- client = &p_dev->client;
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
goto found;
}
@@ -1028,26 +1029,20 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
}
found:
up_read(&pcmcia_socket_list_rwsem);
- if (!p_dev || !client)
+ if (!p_dev)
return -ENODEV;
pcmcia_put_socket(s); /* safe, as we already hold a reference from bind_device */
- *handle = client;
- client->state &= ~CLIENT_UNBOUND;
- client->Socket = s;
- client->EventMask = req->EventMask;
- client->event_handler = req->event_handler;
- client->event_callback_args = req->event_callback_args;
- client->event_callback_args.client_handle = client;
+ *handle = p_dev;
+ p_dev->state &= ~CLIENT_UNBOUND;
+ p_dev->event_callback_args = req->event_callback_args;
+ p_dev->event_callback_args.client_handle = p_dev;
- if (s->state & SOCKET_CARDBUS)
- client->state |= CLIENT_CARDBUS;
- if ((!(s->state & SOCKET_CARDBUS)) && (s->functions == 0) &&
- (client->Function != BIND_FN_ALL)) {
+ if (!s->functions) {
cistpl_longlink_mfc_t mfc;
- if (pccard_read_tuple(s, client->Function, CISTPL_LONGLINK_MFC, &mfc)
+ if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC, &mfc)
== CS_SUCCESS)
s->functions = mfc.nfn;
else
@@ -1060,13 +1055,13 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
}
ds_dbg(1, "register_client(): client 0x%p, dev %s\n",
- client, p_dev->dev.bus_id);
- if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE)
- EVENT(client, CS_EVENT_REGISTRATION_COMPLETE, CS_EVENT_PRI_LOW);
+ p_dev, p_dev->dev.bus_id);
if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) {
- if (client->EventMask & CS_EVENT_CARD_INSERTION)
- EVENT(client, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+ if (p_drv->event)
+ p_drv->event(CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW,
+ &p_dev->event_callback_args);
+
}
return CS_SUCCESS;
@@ -1099,7 +1094,7 @@ static int unbind_request(struct pcmcia_socket *s)
}
p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list);
list_del(&p_dev->socket_device_list);
- p_dev->client.state |= CLIENT_STALE;
+ p_dev->state |= CLIENT_STALE;
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
device_unregister(&p_dev->dev);
@@ -1108,31 +1103,25 @@ static int unbind_request(struct pcmcia_socket *s)
return 0;
} /* unbind_request */
-int pcmcia_deregister_client(client_handle_t handle)
+int pcmcia_deregister_client(struct pcmcia_device *p_dev)
{
struct pcmcia_socket *s;
int i;
- struct pcmcia_device *p_dev = handle_to_pdev(handle);
-
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- ds_dbg(1, "deregister_client(%p)\n", handle);
+ s = p_dev->socket;
+ ds_dbg(1, "deregister_client(%p)\n", p_dev);
- if (handle->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
+ if (p_dev->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
goto warn_out;
for (i = 0; i < MAX_WIN; i++)
- if (handle->state & CLIENT_WIN_REQ(i))
+ if (p_dev->state & CLIENT_WIN_REQ(i))
goto warn_out;
- if (handle->state & CLIENT_STALE) {
- handle->client_magic = 0;
- handle->state &= ~CLIENT_STALE;
+ if (p_dev->state & CLIENT_STALE) {
+ p_dev->state &= ~CLIENT_STALE;
pcmcia_put_dev(p_dev);
} else {
- handle->state = CLIENT_UNBOUND;
- handle->event_handler = NULL;
+ p_dev->state = CLIENT_UNBOUND;
}
return CS_SUCCESS;
diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c
index 5ab55ae0ac3..316f8bcc878 100644
--- a/drivers/pcmcia/hd64465_ss.c
+++ b/drivers/pcmcia/hd64465_ss.c
@@ -43,7 +43,6 @@
#include <asm/hd64465/hd64465.h>
#include <asm/hd64465/io.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index d72f9a35c8b..a713015e822 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -53,7 +53,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
@@ -698,14 +697,6 @@ static void __init add_pcic(int ns, int type)
struct i82365_socket *t = &socket[sockets-ns];
base = sockets-ns;
- if (t->ioaddr > 0) {
- if (!request_region(t->ioaddr, 2, "i82365")) {
- printk(KERN_ERR "i82365: IO region conflict at %#lx, not available\n",
- t->ioaddr);
- return;
- }
- }
-
if (base == 0) printk("\n");
printk(KERN_INFO " %s", pcic[type].name);
printk(" ISA-to-PCMCIA at port %#lx ofs 0x%02x",
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
index b1111c6bf06..65f3ee3d4d3 100644
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -29,7 +29,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index c0997c4714f..7b14d7efd68 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -30,7 +30,6 @@
#include <asm/system.h>
#include <asm/addrspace.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
diff --git a/drivers/pcmcia/pcmcia_compat.c b/drivers/pcmcia/pcmcia_compat.c
index 1cc83317e7e..ebb161c4f81 100644
--- a/drivers/pcmcia/pcmcia_compat.c
+++ b/drivers/pcmcia/pcmcia_compat.c
@@ -18,7 +18,6 @@
#include <linux/init.h>
#define IN_CARD_SERVICES
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/bulkmem.h>
@@ -28,64 +27,39 @@
#include "cs_internal.h"
-int pcmcia_get_first_tuple(client_handle_t handle, tuple_t *tuple)
+int pcmcia_get_first_tuple(struct pcmcia_device *p_dev, tuple_t *tuple)
{
- struct pcmcia_socket *s;
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- return pccard_get_first_tuple(s, handle->Function, tuple);
+ return pccard_get_first_tuple(p_dev->socket, p_dev->func, tuple);
}
EXPORT_SYMBOL(pcmcia_get_first_tuple);
-int pcmcia_get_next_tuple(client_handle_t handle, tuple_t *tuple)
+int pcmcia_get_next_tuple(struct pcmcia_device *p_dev, tuple_t *tuple)
{
- struct pcmcia_socket *s;
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- return pccard_get_next_tuple(s, handle->Function, tuple);
+ return pccard_get_next_tuple(p_dev->socket, p_dev->func, tuple);
}
EXPORT_SYMBOL(pcmcia_get_next_tuple);
-int pcmcia_get_tuple_data(client_handle_t handle, tuple_t *tuple)
+int pcmcia_get_tuple_data(struct pcmcia_device *p_dev, tuple_t *tuple)
{
- struct pcmcia_socket *s;
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- return pccard_get_tuple_data(s, tuple);
+ return pccard_get_tuple_data(p_dev->socket, tuple);
}
EXPORT_SYMBOL(pcmcia_get_tuple_data);
-int pcmcia_parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+int pcmcia_parse_tuple(struct pcmcia_device *p_dev, tuple_t *tuple, cisparse_t *parse)
{
return pccard_parse_tuple(tuple, parse);
}
EXPORT_SYMBOL(pcmcia_parse_tuple);
-int pcmcia_validate_cis(client_handle_t handle, cisinfo_t *info)
+int pcmcia_validate_cis(struct pcmcia_device *p_dev, cisinfo_t *info)
{
- struct pcmcia_socket *s;
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- return pccard_validate_cis(s, handle->Function, info);
+ return pccard_validate_cis(p_dev->socket, p_dev->func, info);
}
EXPORT_SYMBOL(pcmcia_validate_cis);
-int pcmcia_reset_card(client_handle_t handle, client_req_t *req)
+int pcmcia_reset_card(struct pcmcia_device *p_dev, client_req_t *req)
{
- struct pcmcia_socket *skt;
-
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- skt = SOCKET(handle);
- if (!skt)
- return CS_BAD_HANDLE;
-
- return pccard_reset_card(skt);
+ return pccard_reset_card(p_dev->socket);
}
EXPORT_SYMBOL(pcmcia_reset_card);
-
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index b883bc151ed..39ba6406fd5 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -31,7 +31,6 @@
#include <linux/workqueue.h>
#define IN_CARD_SERVICES
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -71,29 +70,6 @@ extern int ds_pc_debug;
#define ds_dbg(lvl, fmt, arg...) do { } while (0)
#endif
-static const char *release = "Linux Kernel Card Services";
-
-/** pcmcia_get_card_services_info
- *
- * Return information about this version of Card Services
- */
-static int pcmcia_get_card_services_info(servinfo_t *info)
-{
- unsigned int socket_count = 0;
- struct list_head *tmp;
- info->Signature[0] = 'C';
- info->Signature[1] = 'S';
- down_read(&pcmcia_socket_list_rwsem);
- list_for_each(tmp, &pcmcia_socket_list)
- socket_count++;
- up_read(&pcmcia_socket_list_rwsem);
- info->Count = socket_count;
- info->Revision = CS_RELEASE_CODE;
- info->CSLevel = 0x0210;
- info->VendorString = (char *)release;
- return CS_SUCCESS;
-} /* get_card_services_info */
-
/* backwards-compatible accessing of driver --- by name! */
@@ -591,9 +567,6 @@ static int ds_ioctl(struct inode * inode, struct file * file,
case DS_ADJUST_RESOURCE_INFO:
ret = pcmcia_adjust_resource_info(&buf->adjust);
break;
- case DS_GET_CARD_SERVICES_INFO:
- ret = pcmcia_get_card_services_info(&buf->servinfo);
- break;
case DS_GET_CONFIGURATION_INFO:
if (buf->config.Function &&
(buf->config.Function >= s->functions))
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index c01dc6bf152..184f4f88b2a 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -23,7 +23,6 @@
#include <linux/device.h>
#define IN_CARD_SERVICES
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
@@ -202,14 +201,11 @@ int pccard_access_configuration_register(struct pcmcia_socket *s,
return CS_SUCCESS;
} /* pccard_access_configuration_register */
-int pcmcia_access_configuration_register(client_handle_t handle,
+int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
conf_reg_t *reg)
{
- struct pcmcia_socket *s;
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- return pccard_access_configuration_register(s, handle->Function, reg);
+ return pccard_access_configuration_register(p_dev->socket,
+ p_dev->func, reg);
}
EXPORT_SYMBOL(pcmcia_access_configuration_register);
@@ -271,17 +267,11 @@ int pccard_get_configuration_info(struct pcmcia_socket *s,
return CS_SUCCESS;
} /* pccard_get_configuration_info */
-int pcmcia_get_configuration_info(client_handle_t handle,
+int pcmcia_get_configuration_info(struct pcmcia_device *p_dev,
config_info_t *config)
{
- struct pcmcia_socket *s;
-
- if ((CHECK_HANDLE(handle)) || !config)
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- if (!s)
- return CS_BAD_HANDLE;
- return pccard_get_configuration_info(s, handle->Function, config);
+ return pccard_get_configuration_info(p_dev->socket, p_dev->func,
+ config);
}
EXPORT_SYMBOL(pcmcia_get_configuration_info);
@@ -382,10 +372,8 @@ int pccard_get_status(struct pcmcia_socket *s, unsigned int function,
int pcmcia_get_status(client_handle_t handle, cs_status_t *status)
{
struct pcmcia_socket *s;
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
s = SOCKET(handle);
- return pccard_get_status(s, handle->Function, status);
+ return pccard_get_status(s, handle->func, status);
}
EXPORT_SYMBOL(pcmcia_get_status);
@@ -426,16 +414,14 @@ EXPORT_SYMBOL(pcmcia_map_mem_page);
*
* Modify a locked socket configuration
*/
-int pcmcia_modify_configuration(client_handle_t handle,
+int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
modconf_t *mod)
{
struct pcmcia_socket *s;
config_t *c;
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- c = CONFIG(handle);
+ s = p_dev->socket;
+ c = CONFIG(p_dev);
if (!(s->state & SOCKET_PRESENT))
return CS_NO_CARD;
if (!(c->state & CONFIG_LOCKED))
@@ -472,25 +458,18 @@ int pcmcia_modify_configuration(client_handle_t handle,
EXPORT_SYMBOL(pcmcia_modify_configuration);
-int pcmcia_release_configuration(client_handle_t handle)
+int pcmcia_release_configuration(struct pcmcia_device *p_dev)
{
pccard_io_map io = { 0, 0, 0, 0, 1 };
- struct pcmcia_socket *s;
+ struct pcmcia_socket *s = p_dev->socket;
int i;
- if (CHECK_HANDLE(handle) ||
- !(handle->state & CLIENT_CONFIG_LOCKED))
+ if (!(p_dev->state & CLIENT_CONFIG_LOCKED))
return CS_BAD_HANDLE;
- handle->state &= ~CLIENT_CONFIG_LOCKED;
- s = SOCKET(handle);
-
-#ifdef CONFIG_CARDBUS
- if (handle->state & CLIENT_CARDBUS)
- return CS_SUCCESS;
-#endif
+ p_dev->state &= ~CLIENT_CONFIG_LOCKED;
- if (!(handle->state & CLIENT_STALE)) {
- config_t *c = CONFIG(handle);
+ if (!(p_dev->state & CLIENT_STALE)) {
+ config_t *c = CONFIG(p_dev);
if (--(s->lock_count) == 0) {
s->socket.flags = SS_OUTPUT_ENA; /* Is this correct? */
s->socket.Vpp = 0;
@@ -523,22 +502,16 @@ EXPORT_SYMBOL(pcmcia_release_configuration);
* don't bother checking the port ranges against the current socket
* values.
*/
-int pcmcia_release_io(client_handle_t handle, io_req_t *req)
+int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
{
- struct pcmcia_socket *s;
+ struct pcmcia_socket *s = p_dev->socket;
- if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IO_REQ))
+ if (!(p_dev->state & CLIENT_IO_REQ))
return CS_BAD_HANDLE;
- handle->state &= ~CLIENT_IO_REQ;
- s = SOCKET(handle);
-
-#ifdef CONFIG_CARDBUS
- if (handle->state & CLIENT_CARDBUS)
- return CS_SUCCESS;
-#endif
+ p_dev->state &= ~CLIENT_IO_REQ;
- if (!(handle->state & CLIENT_STALE)) {
- config_t *c = CONFIG(handle);
+ if (!(p_dev->state & CLIENT_STALE)) {
+ config_t *c = CONFIG(p_dev);
if (c->state & CONFIG_LOCKED)
return CS_CONFIGURATION_LOCKED;
if ((c->io.BasePort1 != req->BasePort1) ||
@@ -558,16 +531,15 @@ int pcmcia_release_io(client_handle_t handle, io_req_t *req)
EXPORT_SYMBOL(pcmcia_release_io);
-int pcmcia_release_irq(client_handle_t handle, irq_req_t *req)
+int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)
{
- struct pcmcia_socket *s;
- if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IRQ_REQ))
+ struct pcmcia_socket *s = p_dev->socket;
+ if (!(p_dev->state & CLIENT_IRQ_REQ))
return CS_BAD_HANDLE;
- handle->state &= ~CLIENT_IRQ_REQ;
- s = SOCKET(handle);
+ p_dev->state &= ~CLIENT_IRQ_REQ;
- if (!(handle->state & CLIENT_STALE)) {
- config_t *c = CONFIG(handle);
+ if (!(p_dev->state & CLIENT_STALE)) {
+ config_t *c = CONFIG(p_dev);
if (c->state & CONFIG_LOCKED)
return CS_CONFIGURATION_LOCKED;
if (c->irq.Attributes != req->Attributes)
@@ -623,29 +595,21 @@ int pcmcia_release_window(window_handle_t win)
EXPORT_SYMBOL(pcmcia_release_window);
-int pcmcia_request_configuration(client_handle_t handle,
+int pcmcia_request_configuration(struct pcmcia_device *p_dev,
config_req_t *req)
{
int i;
u_int base;
- struct pcmcia_socket *s;
+ struct pcmcia_socket *s = p_dev->socket;
config_t *c;
pccard_io_map iomap;
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
if (!(s->state & SOCKET_PRESENT))
return CS_NO_CARD;
-#ifdef CONFIG_CARDBUS
- if (handle->state & CLIENT_CARDBUS)
- return CS_UNSUPPORTED_MODE;
-#endif
-
if (req->IntType & INT_CARDBUS)
return CS_UNSUPPORTED_MODE;
- c = CONFIG(handle);
+ c = CONFIG(p_dev);
if (c->state & CONFIG_LOCKED)
return CS_CONFIGURATION_LOCKED;
@@ -746,7 +710,7 @@ int pcmcia_request_configuration(client_handle_t handle,
}
c->state |= CONFIG_LOCKED;
- handle->state |= CLIENT_CONFIG_LOCKED;
+ p_dev->state |= CLIENT_CONFIG_LOCKED;
return CS_SUCCESS;
} /* pcmcia_request_configuration */
EXPORT_SYMBOL(pcmcia_request_configuration);
@@ -757,29 +721,17 @@ EXPORT_SYMBOL(pcmcia_request_configuration);
* Request_io() reserves ranges of port addresses for a socket.
* I have not implemented range sharing or alias addressing.
*/
-int pcmcia_request_io(client_handle_t handle, io_req_t *req)
+int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req)
{
- struct pcmcia_socket *s;
+ struct pcmcia_socket *s = p_dev->socket;
config_t *c;
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
if (!(s->state & SOCKET_PRESENT))
return CS_NO_CARD;
- if (handle->state & CLIENT_CARDBUS) {
-#ifdef CONFIG_CARDBUS
- handle->state |= CLIENT_IO_REQ;
- return CS_SUCCESS;
-#else
- return CS_UNSUPPORTED_FUNCTION;
-#endif
- }
-
if (!req)
return CS_UNSUPPORTED_MODE;
- c = CONFIG(handle);
+ c = CONFIG(p_dev);
if (c->state & CONFIG_LOCKED)
return CS_CONFIGURATION_LOCKED;
if (c->state & CONFIG_IO_REQ)
@@ -804,7 +756,7 @@ int pcmcia_request_io(client_handle_t handle, io_req_t *req)
c->io = *req;
c->state |= CONFIG_IO_REQ;
- handle->state |= CLIENT_IO_REQ;
+ p_dev->state |= CLIENT_IO_REQ;
return CS_SUCCESS;
} /* pcmcia_request_io */
EXPORT_SYMBOL(pcmcia_request_io);
@@ -827,19 +779,15 @@ static irqreturn_t test_action(int cpl, void *dev_id, struct pt_regs *regs)
}
#endif
-int pcmcia_request_irq(client_handle_t handle, irq_req_t *req)
+int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
{
- struct pcmcia_socket *s;
+ struct pcmcia_socket *s = p_dev->socket;
config_t *c;
int ret = CS_IN_USE, irq = 0;
- struct pcmcia_device *p_dev = handle_to_pdev(handle);
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
if (!(s->state & SOCKET_PRESENT))
return CS_NO_CARD;
- c = CONFIG(handle);
+ c = CONFIG(p_dev);
if (c->state & CONFIG_LOCKED)
return CS_CONFIGURATION_LOCKED;
if (c->state & CONFIG_IRQ_REQ)
@@ -903,7 +851,7 @@ int pcmcia_request_irq(client_handle_t handle, irq_req_t *req)
s->irq.Config++;
c->state |= CONFIG_IRQ_REQ;
- handle->state |= CLIENT_IRQ_REQ;
+ p_dev->state |= CLIENT_IRQ_REQ;
#ifdef CONFIG_PCMCIA_PROBE
pcmcia_used_irq[irq]++;
@@ -919,16 +867,13 @@ EXPORT_SYMBOL(pcmcia_request_irq);
* Request_window() establishes a mapping between card memory space
* and system memory space.
*/
-int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle_t *wh)
+int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_handle_t *wh)
{
- struct pcmcia_socket *s;
+ struct pcmcia_socket *s = (*p_dev)->socket;
window_t *win;
u_long align;
int w;
- if (CHECK_HANDLE(*handle))
- return CS_BAD_HANDLE;
- s = (*handle)->Socket;
if (!(s->state & SOCKET_PRESENT))
return CS_NO_CARD;
if (req->Attributes & (WIN_PAGED | WIN_SHARED))
@@ -957,7 +902,7 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle
win = &s->win[w];
win->magic = WINDOW_MAGIC;
win->index = w;
- win->handle = *handle;
+ win->handle = *p_dev;
win->sock = s;
if (!(s->features & SS_CAP_STATIC_MAP)) {
@@ -966,7 +911,7 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle
if (!win->ctl.res)
return CS_IN_USE;
}
- (*handle)->state |= CLIENT_WIN_REQ(w);
+ (*p_dev)->state |= CLIENT_WIN_REQ(w);
/* Configure the socket controller */
win->ctl.map = w+1;
diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
index f1bb7915302..e98bb3d80e7 100644
--- a/drivers/pcmcia/sa1100_generic.c
+++ b/drivers/pcmcia/sa1100_generic.c
@@ -34,7 +34,6 @@
#include <linux/init.h>
#include <linux/config.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h
index 700a155fbc7..6f14126889b 100644
--- a/drivers/pcmcia/soc_common.h
+++ b/drivers/pcmcia/soc_common.h
@@ -11,7 +11,6 @@
/* include the world */
#include <linux/cpufreq.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index fcef54c1c2d..1040a6c1a8a 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -29,7 +29,6 @@
#include <asm/irq.h>
#define IN_CARD_SERVICES
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index aacbbb5f055..d5a61eae611 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -50,7 +50,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h
index c7ba99871ac..fbe233e19ce 100644
--- a/drivers/pcmcia/ti113x.h
+++ b/drivers/pcmcia/ti113x.h
@@ -154,8 +154,6 @@
#define ENE_TEST_C9 0xc9 /* 8bit */
#define ENE_TEST_C9_TLTENABLE 0x02
-#ifdef CONFIG_CARDBUS
-
/*
* Texas Instruments CardBus controller overrides.
*/
@@ -843,7 +841,5 @@ static int ti1250_override(struct yenta_socket *socket)
return ti12xx_override(socket);
}
-#endif /* CONFIG_CARDBUS */
-
#endif /* _LINUX_TI113X_H */
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 02b23abc2df..0e7aa817669 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -18,7 +18,6 @@
#include <linux/delay.h>
#include <linux/module.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
@@ -869,14 +868,11 @@ static int yenta_probe_cb_irq(struct yenta_socket *socket)
*/
static void yenta_get_socket_capabilities(struct yenta_socket *socket, u32 isa_irq_mask)
{
- socket->socket.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS;
- socket->socket.map_size = 0x1000;
socket->socket.pci_irq = socket->cb_irq;
if (isa_probe)
socket->socket.irq_mask = yenta_probe_irq(socket, isa_irq_mask);
else
socket->socket.irq_mask = 0;
- socket->socket.cb_dev = socket->dev;
printk(KERN_INFO "Yenta: ISA IRQ mask 0x%04x, PCI irq %d\n",
socket->socket.irq_mask, socket->cb_irq);
@@ -942,6 +938,9 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
socket->socket.dev.dev = &dev->dev;
socket->socket.driver_data = socket;
socket->socket.owner = THIS_MODULE;
+ socket->socket.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD;
+ socket->socket.map_size = 0x1000;
+ socket->socket.cb_dev = dev;
/* prepare struct yenta_socket */
socket->dev = dev;
@@ -1012,6 +1011,10 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
socket->poll_timer.data = (unsigned long)socket;
socket->poll_timer.expires = jiffies + HZ;
add_timer(&socket->poll_timer);
+ printk(KERN_INFO "Yenta: no PCI IRQ, CardBus support disabled for this socket.\n"
+ KERN_INFO "Yenta: check your BIOS CardBus, BIOS IRQ or ACPI settings.\n");
+ } else {
+ socket->socket.features |= SS_CAP_CARDBUS;
}
/* Figure out what the dang thing can do for the PCMCIA layer... */
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
index f1f6bf596dc..7c530649983 100644
--- a/drivers/scsi/pcmcia/aha152x_stub.c
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -50,7 +50,6 @@
#include <scsi/scsi_host.h>
#include "aha152x.h"
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -134,11 +133,6 @@ static dev_link_t *aha152x_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.event_handler = &aha152x_event;
- client_reg.EventMask =
- CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -334,6 +328,7 @@ static struct pcmcia_driver aha152x_cs_driver = {
.name = "aha152x_cs",
},
.attach = aha152x_attach,
+ .event = aha152x_event,
.detach = aha152x_detach,
.id_table = aha152x_ids,
};
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c
index 853e6ee9b71..db8f5cd85ff 100644
--- a/drivers/scsi/pcmcia/fdomain_stub.c
+++ b/drivers/scsi/pcmcia/fdomain_stub.c
@@ -47,7 +47,6 @@
#include <scsi/scsi_host.h>
#include "fdomain.h"
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -120,11 +119,6 @@ static dev_link_t *fdomain_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.event_handler = &fdomain_event;
- client_reg.EventMask =
- CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -314,6 +308,7 @@ static struct pcmcia_driver fdomain_cs_driver = {
.name = "fdomain_cs",
},
.attach = fdomain_attach,
+ .event = fdomain_event,
.detach = fdomain_detach,
.id_table = fdomain_ids,
};
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index 91b3f28e7a1..3cd3b40b1a4 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -51,7 +51,6 @@
#include <scsi/scsi.h>
#include <scsi/scsi_ioctl.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -1642,11 +1641,6 @@ static dev_link_t *nsp_cs_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME ;
- client_reg.event_handler = &nsp_cs_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -2138,12 +2132,13 @@ static struct pcmcia_device_id nsp_cs_ids[] = {
MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids);
static struct pcmcia_driver nsp_driver = {
- .owner = THIS_MODULE,
- .drv = {
- .name = "nsp_cs",
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "nsp_cs",
},
- .attach = nsp_cs_attach,
- .detach = nsp_cs_detach,
+ .attach = nsp_cs_attach,
+ .event = nsp_cs_event,
+ .detach = nsp_cs_detach,
.id_table = nsp_cs_ids,
};
#endif
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
index 0dcf41102ab..7a516f35834 100644
--- a/drivers/scsi/pcmcia/qlogic_stub.c
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -49,7 +49,6 @@
#include <scsi/scsi_host.h>
#include "../qlogicfas408.h"
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -194,8 +193,6 @@ static dev_link_t *qlogic_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.event_handler = &qlogic_event;
- client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -423,6 +420,7 @@ static struct pcmcia_driver qlogic_cs_driver = {
.name = "qlogic_cs",
},
.attach = qlogic_attach,
+ .event = qlogic_event,
.detach = qlogic_detach,
.id_table = qlogic_ids,
};
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index 7d4b16b6797..b4b3a1a8a0c 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -979,10 +979,6 @@ SYM53C500_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.event_handler = &SYM53C500_event;
- client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -1013,6 +1009,7 @@ static struct pcmcia_driver sym53c500_cs_driver = {
.name = "sym53c500_cs",
},
.attach = SYM53C500_attach,
+ .event = SYM53C500_event,
.detach = SYM53C500_detach,
.id_table = sym53c500_ids,
};
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index 73a34b18866..de0136cc593 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -45,7 +45,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -232,11 +231,6 @@ static dev_link_t *serial_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &serial_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -883,6 +877,7 @@ static struct pcmcia_driver serial_cs_driver = {
.name = "serial_cs",
},
.attach = serial_attach,
+ .event = serial_event,
.detach = serial_detach,
.id_table = serial_ids,
};
diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c
index ce5ebfe4af2..57c0c6e3fbe 100644
--- a/drivers/telephony/ixj_pcmcia.c
+++ b/drivers/telephony/ixj_pcmcia.c
@@ -9,7 +9,6 @@
#include <linux/errno.h> /* error codes */
#include <linux/slab.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -69,11 +68,6 @@ static dev_link_t *ixj_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &ixj_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -307,6 +301,7 @@ static struct pcmcia_driver ixj_driver = {
.name = "ixj_cs",
},
.attach = ixj_attach,
+ .event = ixj_event,
.detach = ixj_detach,
.id_table = ixj_ids,
};
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c
index 269d8ef0145..38aebe361ca 100644
--- a/drivers/usb/host/sl811_cs.c
+++ b/drivers/usb/host/sl811_cs.c
@@ -20,7 +20,6 @@
#include <linux/timer.h>
#include <linux/ioport.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -389,11 +388,6 @@ static dev_link_t *sl811_cs_attach(void)
dev_list = link;
client_reg.dev_info = (dev_info_t *) &driver_name;
client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &sl811_cs_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -418,6 +412,7 @@ static struct pcmcia_driver sl811_cs_driver = {
.name = (char *)driver_name,
},
.attach = sl811_cs_attach,
+ .event = sl811_cs_event,
.detach = sl811_cs_detach,
.id_table = sl811_ids,
};
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 7dfbf39b4ed..ddc9443254d 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -256,7 +256,7 @@ static ssize_t show_cmap(struct class_device *class_device, char *buf)
unsigned int offset = 0, i;
if (!fb_info->cmap.red || !fb_info->cmap.blue ||
- fb_info->cmap.green || fb_info->cmap.transp)
+ !fb_info->cmap.green || !fb_info->cmap.transp)
return -EINVAL;
for (i = 0; i < fb_info->cmap.len; i++) {
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
index 6ba10e3acef..3e9ccf370ab 100644
--- a/drivers/video/logo/Kconfig
+++ b/drivers/video/logo/Kconfig
@@ -63,5 +63,10 @@ config LOGO_SUPERH_CLUT224
depends on LOGO && SUPERH
default y
+config LOGO_M32R_CLUT224
+ bool "224-color M32R Linux logo"
+ depends on LOGO && M32R
+ default y
+
endmenu
diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile
index b0d995020bd..d0244c04af5 100644
--- a/drivers/video/logo/Makefile
+++ b/drivers/video/logo/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_LOGO_SUN_CLUT224) += logo_sun_clut224.o
obj-$(CONFIG_LOGO_SUPERH_MONO) += logo_superh_mono.o
obj-$(CONFIG_LOGO_SUPERH_VGA16) += logo_superh_vga16.o
obj-$(CONFIG_LOGO_SUPERH_CLUT224) += logo_superh_clut224.o
+obj-$(CONFIG_LOGO_M32R_CLUT224) += logo_m32r_clut224.o
# How to generate logo's
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
index 77b62207500..788fa812c87 100644
--- a/drivers/video/logo/logo.c
+++ b/drivers/video/logo/logo.c
@@ -33,6 +33,7 @@ extern const struct linux_logo logo_sun_clut224;
extern const struct linux_logo logo_superh_mono;
extern const struct linux_logo logo_superh_vga16;
extern const struct linux_logo logo_superh_clut224;
+extern const struct linux_logo logo_m32r_clut224;
const struct linux_logo *fb_find_logo(int depth)
@@ -97,6 +98,10 @@ const struct linux_logo *fb_find_logo(int depth)
/* SuperH Linux logo */
logo = &logo_superh_clut224;
#endif
+#ifdef CONFIG_LOGO_M32R_CLUT224
+ /* M32R Linux logo */
+ logo = &logo_m32r_clut224;
+#endif
}
return logo;
}
diff --git a/drivers/video/logo/logo_m32r_clut224.ppm b/drivers/video/logo/logo_m32r_clut224.ppm
new file mode 100644
index 00000000000..8b2983c5a0b
--- /dev/null
+++ b/drivers/video/logo/logo_m32r_clut224.ppm
@@ -0,0 +1,1292 @@
+P3
+# CREATOR: The GIMP's PNM Filter Version 1.0
+#
+# Note: how to convert ppm to pnm(ascii).
+# $ convert -posterize 224 m32r.ppm - | pnm2asc -f5 >logo_m32r_clut224.ppm
+#
+# convert - imagemagick: /usr/bin/convert
+# pnm2asc - pnm to ascii-pnm format converter
+# http://www.is.aist.go.jp/etlcdb/util/p2a.htm#English
+
+80 80
+255
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 43 43 43 75 75 75 27 27 27 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 59 59 59 123 123 123 67 67 67 27 27 27
+ 2 2 3 2 2 3 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 10 6 3 59 59 59 80 80 80 43 43 43 27 27 27
+ 2 2 3 2 2 3 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 19 19 19 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 2 2 3 10 6 3 10 6 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 10 6 3 11 11 11 11 11 11 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 2 2 3 2 2 3 27 27 27 10 6 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 19 19 19 2 2 3 2 2 3 51 51 51 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 123 123 123 196 196 196 115 115 115 2 2 3
+ 2 2 3 2 2 3 2 2 3 75 75 75 141 141 140
+ 172 172 172 196 196 196 190 189 188 2 2 3 11 11 11
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 27 27 27 164 164 164 228 228 228 221 221 220 10 6 3
+ 2 2 3 2 2 3 2 2 3 172 172 172 245 245 245
+ 254 254 252 254 254 252 221 221 220 35 35 35 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 164 164 164 228 228 228 35 35 35 236 236 236 236 236 236
+ 2 2 3 11 11 11 2 2 3 254 254 252 245 245 245
+ 2 2 3 75 75 75 245 245 245 245 245 245 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 212 212 212 2 2 3 51 51 51 11 11 11 245 245 245
+ 27 27 27 80 80 80 10 6 3 254 254 252 2 2 3
+ 2 2 3 91 91 91 19 19 19 254 254 252 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 196 196 196 10 6 3 2 2 3 11 11 11 107 107 107
+ 49 35 5 57 42 11 31 22 3 236 236 236 2 2 3
+ 2 2 3 2 2 3 2 2 3 254 254 252 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 107 107 107 221 221 220 2 2 3 64 43 7 194 148 10
+ 236 188 10 225 180 10 170 126 10 236 188 10 94 86 67
+ 2 2 3 2 2 3 204 204 204 236 236 236 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 228 228 228 182 126 10 218 164 9 236 188 10
+ 236 188 10 237 204 14 236 205 40 246 214 48 246 214 48
+ 245 189 11 209 156 9 196 196 196 11 11 11 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 165 114 10 207 148 7 229 172 9 236 180 10
+ 236 196 11 237 204 14 242 218 43 246 218 75 246 218 19
+ 246 213 13 246 218 19 244 205 11 218 164 9 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 164 109 5 192 133 7 224 165 9 236 180 10 236 188 10
+ 236 196 11 241 212 42 246 218 75 246 218 19 246 218 19
+ 246 218 19 236 196 11 150 114 10 229 172 9 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 165 114 10 201 142 7 229 172 9 242 182 11 236 188 10
+ 237 204 14 245 213 67 246 218 19 246 213 13 246 213 13
+ 154 119 10 207 148 7 218 164 9 216 156 8 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 120 78 3 225 180 10 245 189 11 236 205 40
+ 241 212 42 241 212 17 237 204 14 148 107 9 182 126 10
+ 216 156 8 218 164 9 207 148 7 82 70 43 2 2 3
+ 2 2 3 123 123 123 35 35 35 2 2 3 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 10 6 3 180 180 180 156 102 5 135 88 5 142 106 7
+ 126 98 11 165 114 10 185 132 9 207 148 7 215 150 13
+ 199 140 8 188 148 71 196 196 196 190 189 188 2 2 3
+ 2 2 3 11 11 11 132 132 132 75 75 75 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 10 6 3 190 189 188 190 189 188 151 97 5 192 133 7
+ 207 148 7 206 142 8 199 140 8 180 121 7 180 132 31
+ 190 189 188 190 189 188 212 212 212 212 212 212 107 107 107
+ 2 2 3 2 2 3 99 99 99 51 51 51 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 190 189 188 190 189 188 190 189 188 136 95 7
+ 151 97 5 151 97 5 151 97 5 183 156 91 190 189 188
+ 190 189 188 228 228 228 254 254 252 254 254 252 221 221 220
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 10 6 3 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3
+ 75 75 75 245 245 245 196 196 196 190 189 188 190 189 188
+ 190 189 188 196 196 196 190 189 188 190 189 188 204 204 204
+ 236 236 236 254 254 252 254 254 252 254 254 252 254 254 252
+ 35 35 35 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 2 2 3 27 27 27 2 2 3
+ 245 245 245 254 254 252 245 245 245 190 189 188 190 189 188
+ 190 189 188 190 189 188 190 189 188 212 212 212 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 10 6 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 2 2 3 2 2 3 132 132 132
+ 254 254 252 254 254 252 254 254 252 236 236 236 196 196 196
+ 190 189 188 204 204 204 245 245 245 245 245 245 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 80 80 80 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 2 2 3 2 2 3 2 2 3 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 2 2 3 2 2 3 2 2 3 212 212 212 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 2 2 3 2 2 3 204 204 204 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 245 245 245 236 236 236 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3
+ 2 2 3 2 2 3 11 11 11 164 164 164 212 212 212
+ 236 236 236 245 245 245 254 254 252 236 236 236 221 221 220
+ 221 221 220 228 228 228 245 245 245 245 245 245 245 245 245
+ 236 236 236 221 221 220 212 212 212 204 204 204 204 204 204
+ 196 196 196 204 204 204 59 59 59 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3
+ 2 2 3 2 2 3 27 27 27 172 172 172 212 212 212
+ 236 236 236 254 254 252 254 254 252 254 254 252 228 228 228
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 245 245 245 221 221 220 204 204 204 196 196 196
+ 196 196 196 196 196 196 228 228 228 19 19 19 2 2 3
+ 80 80 80 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 2 2 3 2 2 3 2 2 3
+ 11 11 11 2 2 3 164 164 164 236 236 236 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 236 236 236 212 212 212 196 196 196 245 245 245 2 2 3
+ 2 2 3 11 11 11 51 51 51 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 2 2 3 2 2 3 86 86 83
+ 2 2 3 27 27 27 236 236 236 254 254 252 254 254 252
+ 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 212 212 212 196 196 196 91 91 91
+ 2 2 3 2 2 3 2 2 3 11 11 11 2 2 3
+ 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 2 2 3 2 2 3 2 2 3
+ 2 2 3 245 245 245 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 254 254 252 245 245 245 254 254 252 254 254 252 254 254 252
+ 254 254 252 245 245 245 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 221 221 220 245 245 245
+ 2 2 3 11 11 11 43 43 43 19 19 19 10 6 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 2 2 3 80 80 80 2 2 3
+ 2 2 3 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 43 43 43 27 27 27 80 80 80 19 19 19 80 80 80
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 2 2 3 2 2 3 2 2 3 2 2 3
+ 245 245 245 254 254 252 254 254 252 17 11 233 254 254 252
+ 254 254 252 254 254 252 254 254 252 236 236 236 17 11 233
+ 17 11 233 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 11 11 11 11 11 11 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 2 2 3 67 67 67 2 2 3 19 19 19
+ 254 254 252 254 254 252 245 245 245 17 11 233 245 245 245
+ 254 254 252 254 254 252 17 11 233 228 228 228 17 11 233
+ 17 11 233 17 11 233 17 11 233 254 254 252 17 11 233
+ 17 11 233 254 254 252 254 254 252 17 11 233 17 11 233
+ 17 11 233 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 2 2 3 2 2 3 2 2 3 2 2 3
+ 11 11 11 2 2 3 2 2 3 2 2 3 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 2 2 3 10 6 3 11 11 11 2 2 3 228 228 228
+ 254 254 252 254 254 252 254 254 252 17 11 233 254 254 252
+ 254 254 252 17 11 233 17 11 233 17 11 233 245 245 245
+ 254 254 252 254 254 252 17 11 233 17 11 233 17 11 233
+ 17 11 233 17 11 233 254 254 252 17 11 233 17 11 233
+ 17 11 233 17 11 233 254 254 252 254 254 252 254 254 252
+ 254 254 252 2 2 3 2 2 3 2 2 3 2 2 3
+ 27 27 27 2 2 3 2 2 3 2 2 3 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 2 2 3 2 2 3 2 2 3 2 2 3 254 254 252
+ 254 254 252 254 254 252 254 254 252 17 11 233 17 11 233
+ 17 11 233 17 11 233 17 11 233 17 11 233 254 254 252
+ 17 11 233 17 11 233 17 11 233 254 254 252 254 254 252
+ 17 11 233 17 11 233 254 254 252 17 11 233 17 11 233
+ 254 254 252 17 11 233 254 254 252 254 254 252 254 254 252
+ 254 254 252 2 2 3 2 2 3 2 2 3 2 2 3
+ 11 11 11 2 2 3 2 2 3 2 2 3 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 19 19 19 2 2 3 2 2 3 254 254 252
+ 254 254 252 254 254 252 17 11 233 245 245 245 17 11 233
+ 17 11 233 245 245 245 254 254 252 17 11 233 254 254 252
+ 17 11 233 17 11 233 17 11 233 254 254 252 254 254 252
+ 17 11 233 17 11 233 254 254 252 17 11 233 17 11 233
+ 17 11 233 17 11 233 254 254 252 254 254 252 254 254 252
+ 254 254 252 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 19 19 19 2 2 3 19 19 19 254 254 252
+ 254 254 252 245 245 245 17 11 233 254 254 252 17 11 233
+ 17 11 233 254 254 252 254 254 252 17 11 233 254 254 252
+ 254 254 252 254 254 252 17 11 233 17 11 233 254 254 252
+ 17 11 233 17 11 233 254 254 252 17 11 233 17 11 233
+ 17 11 233 17 11 233 17 11 233 254 254 252 254 254 252
+ 254 254 252 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3
+ 2 2 3 43 43 43 2 2 3 43 43 43 254 254 252
+ 245 245 245 254 254 252 17 11 233 254 254 252 17 11 233
+ 254 254 252 254 254 252 254 254 252 17 11 233 17 11 233
+ 17 11 233 17 11 233 17 11 233 254 254 252 17 11 233
+ 17 11 233 17 11 233 17 11 233 17 11 233 17 11 233
+ 245 245 245 254 254 252 17 11 233 254 254 252 254 254 252
+ 245 245 245 2 2 3 2 2 3 2 2 3 11 11 11
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3
+ 2 2 3 75 75 75 2 2 3 99 99 99 254 254 252
+ 254 254 252 254 254 252 17 11 233 254 254 252 254 254 252
+ 254 254 252 254 254 252 245 245 245 228 228 228 254 254 252
+ 254 254 252 17 11 233 245 245 245 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 17 11 233 17 11 233
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 2 2 3 2 2 3 2 2 3 75 75 75
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3
+ 2 2 3 2 2 3 11 11 11 107 107 107 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 245 245 245 254 254 252 245 245 245 236 236 236 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 2 2 3 2 2 3 11 11 11 19 19 19
+ 11 11 11 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 2 2 3 11 11 11
+ 140 102 3 11 11 11 10 6 3 67 67 67 254 254 252
+ 245 245 245 245 245 245 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 245 245 245 228 228 228 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 245 245 245 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 2 2 3 43 43 43 2 2 3 2 2 3
+ 2 2 3 11 11 11 67 67 67 11 11 11 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 185 132 9 242 182 11
+ 245 189 11 245 189 11 49 35 5 2 2 3 228 228 228
+ 254 254 252 254 254 252 254 254 252 245 245 245 254 254 252
+ 254 254 252 254 254 252 254 254 252 228 228 228 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 245 238 222 232 189 94
+ 226 186 99 43 43 43 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 59 59 59 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 216 156 8 236 180 22
+ 245 189 11 245 189 11 245 189 11 49 35 5 11 11 11
+ 212 212 212 245 245 245 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 245 245 245 228 228 228 254 254 252
+ 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 245 245 245 254 254 252 254 254 252 229 172 9 246 218 19
+ 246 218 19 41 27 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 19 19 19 27 27 27 196 154 14
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 199 140 8 229 172 9 242 182 11
+ 245 189 11 245 189 11 245 189 11 244 196 10 2 2 3
+ 2 2 3 115 115 115 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 245 245 245 228 228 228 254 254 252
+ 254 254 252 245 245 245 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 224 165 9 245 189 11
+ 236 196 11 19 19 19 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 11 11 11 236 196 11
+ 244 205 11 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 182 126 10 209 156 9 215 150 13
+ 193 140 10 207 148 24 216 156 8 242 182 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 209 156 9
+ 2 2 3 2 2 3 43 43 43 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 236 236 236 216 156 8 245 189 11
+ 229 172 9 64 43 7 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 207 148 7 236 188 10
+ 245 189 11 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 180 121 7 216 156 8 242 182 11 236 180 10
+ 229 172 9 242 182 11 242 182 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 237 204 14
+ 170 126 10 2 2 3 2 2 3 11 11 11 236 236 236
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 204 204 204 196 196 196 216 156 8 236 180 10
+ 224 165 9 182 126 10 73 48 6 2 2 3 2 2 3
+ 2 2 3 41 27 3 199 140 8 229 172 9 236 180 10
+ 245 189 11 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 185 132 9 229 172 9 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 226 188 11 2 2 3 2 2 3 2 2 3 11 11 11
+ 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 245 245 245 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 196 196 196 196 196 196 215 150 13 236 180 10
+ 229 172 9 201 142 7 185 132 9 180 121 7 173 120 10
+ 180 121 7 192 133 7 229 172 9 242 182 11 245 189 11
+ 245 189 11 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 180 126 47 224 165 9 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 236 188 10 193 140 10 2 2 3 2 2 3 2 2 3
+ 2 2 3 212 212 212 254 254 252 245 245 245 245 245 245
+ 254 254 252 254 254 252 254 254 252 245 245 245 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 204 204 204 196 196 196 199 140 8 229 172 9
+ 236 180 10 218 164 9 215 150 13 207 148 7 207 148 7
+ 216 156 8 229 172 9 245 189 11 245 189 11 245 189 11
+ 245 189 11 242 182 11 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 185 132 9 216 156 8 242 182 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 236 196 11 19 19 19 2 2 3 2 2 3
+ 2 2 3 11 11 11 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 245 245 245 254 254 252 254 254 252
+ 245 245 245 221 221 220 196 196 196 185 132 9 229 172 9
+ 242 182 11 229 172 9 224 165 9 218 164 9 224 165 9
+ 229 172 9 236 180 10 245 189 11 245 189 11 245 189 11
+ 245 189 11 236 180 22 242 182 11 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 236 180 22 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 236 188 10 225 180 10 2 2 3 2 2 3
+ 2 2 3 11 11 11 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 221 221 220 19 19 19 185 132 9 224 165 9
+ 245 189 11 245 189 11 242 182 11 236 180 10 236 180 10
+ 242 182 11 242 182 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 196 154 14
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 207 148 7 236 180 22 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 242 182 11
+ 245 189 11 245 189 11 237 204 14 135 88 5 2 2 3
+ 27 27 27 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 245 245 245 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 67 67 67 19 13 3 185 132 9 229 172 9
+ 242 182 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 236 180 22 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 245 189 11 242 182 11
+ 242 182 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 236 188 10 226 188 11 104 83 48
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 245 245 245 254 254 252 245 245 245
+ 254 254 252 245 245 245 254 254 252 254 254 252 254 254 252
+ 2 2 3 2 2 3 56 38 5 185 132 9 229 172 9
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 242 182 11
+ 229 172 9 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 182 126 10 215 150 13 242 182 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 242 182 11 245 189 11 236 196 11 216 156 8
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 245 245 245 2 2 3
+ 2 2 3 2 2 3 75 54 3 182 126 10 229 172 9
+ 242 182 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 229 172 9
+ 207 148 24 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 192 133 7 229 172 9 242 182 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 242 182 11 225 180 10 224 165 9
+ 107 69 5 245 245 245 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 236 236 236 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 91 67 9 182 126 10 229 172 9
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 242 182 11 242 182 11 216 156 8 180 126 47
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 206 142 8 224 165 9 245 189 11 242 182 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 242 182 11
+ 245 189 11 245 189 11 242 182 11 242 182 11 216 156 8
+ 156 102 5 19 13 3 43 43 43 196 196 196 254 254 252
+ 245 245 245 254 254 252 254 254 252 204 204 204 51 51 51
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 95 62 5 185 132 9 229 172 9
+ 242 182 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 242 182 11 245 189 11 245 189 11
+ 236 180 22 216 156 8 206 142 8 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 192 133 7 215 150 13 229 172 9 229 172 9
+ 236 180 10 236 180 22 242 182 11 242 182 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 229 172 9 216 156 8
+ 156 102 5 83 54 6 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 115 73 3 185 132 9 229 172 9
+ 242 182 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 242 182 11 229 172 9 229 172 9 216 156 8
+ 180 121 7 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 180 121 7 182 126 10 192 133 7 199 140 8
+ 207 148 7 215 150 13 216 156 8 224 165 9 229 172 9
+ 236 180 22 245 189 11 242 182 11 245 189 11 242 182 11
+ 245 189 11 245 189 11 242 182 11 229 172 9 199 140 8
+ 151 97 5 101 67 7 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 115 73 3 180 121 7 216 156 8
+ 236 180 22 242 182 11 245 189 11 245 189 11 242 182 11
+ 236 180 10 224 165 9 215 150 13 206 142 8 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 156 102 5 164 109 5 172 114 5 180 121 7 180 121 7
+ 192 133 7 201 142 7 216 156 8 224 165 9 236 180 22
+ 245 189 11 242 182 11 229 172 9 201 142 7 172 114 5
+ 125 83 5 83 54 6 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 91 58 5 156 102 5 192 133 7
+ 216 156 8 229 172 9 236 180 10 236 180 10 229 172 9
+ 215 150 13 199 140 8 164 109 5 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 120 78 3 132 82 3
+ 151 97 5 157 106 7 180 121 7 185 132 9 193 140 10
+ 207 148 7 207 148 7 192 133 7 172 114 5 132 82 3
+ 101 67 7 41 27 3 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 73 48 6 143 90 3 180 121 7
+ 192 133 7 207 148 7 207 148 7 201 142 7 185 132 9
+ 173 120 10 136 95 7 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 91 58 5 125 83 5 135 88 5
+ 144 95 7 151 97 5 132 82 3 115 73 3 95 62 5
+ 64 43 7 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 64 43 7 91 58 5 151 97 5
+ 157 106 7 172 114 5 172 114 5 164 109 5 151 97 5
+ 85 59 6 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 73 48 6
+ 91 58 5 95 62 5 95 62 5 91 58 5 56 38 5
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 83 54 6
+ 107 69 5 132 82 3 125 83 5 101 67 7 71 47 31
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c
index 789de13f461..3848be2b9d2 100644
--- a/drivers/video/s1d13xxxfb.c
+++ b/drivers/video/s1d13xxxfb.c
@@ -67,12 +67,18 @@ static struct fb_fix_screeninfo __devinitdata s1d13xxxfb_fix = {
static inline u8
s1d13xxxfb_readreg(struct s1d13xxxfb_par *par, u16 regno)
{
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
+ regno=((regno & 1) ? (regno & ~1L) : (regno + 1));
+#endif
return readb(par->regs + regno);
}
static inline void
s1d13xxxfb_writereg(struct s1d13xxxfb_par *par, u16 regno, u8 value)
{
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
+ regno=((regno & 1) ? (regno & ~1L) : (regno + 1));
+#endif
writeb(value, par->regs + regno);
}
@@ -259,7 +265,11 @@ s1d13xxxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
dbg("s1d13xxxfb_setcolreg: pseudo %d, val %08x\n",
regno, pseudo_val);
+#if defined(CONFIG_PLAT_MAPPI)
+ ((u32 *)info->pseudo_palette)[regno] = cpu_to_le16(pseudo_val);
+#else
((u32 *)info->pseudo_palette)[regno] = pseudo_val;
+#endif
break;
case FB_VISUAL_PSEUDOCOLOR:
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index 8fadcdae6f4..f4633d1891f 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -2113,7 +2113,7 @@ static int savagefb_suspend (struct pci_dev* dev, pm_message_t state)
printk(KERN_DEBUG "state: %u\n", state);
acquire_console_sem();
- fb_set_suspend(info, state);
+ fb_set_suspend(info, pci_choose_state(dev, state));
savage_disable_mmio(par);
release_console_sem();
diff --git a/fs/Kconfig b/fs/Kconfig
index 06217795623..aae0686a15f 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -29,6 +29,7 @@ config EXT2_FS_XATTR
config EXT2_FS_POSIX_ACL
bool "Ext2 POSIX Access Control Lists"
depends on EXT2_FS_XATTR
+ select FS_POSIX_ACL
help
Posix Access Control Lists (ACLs) support permissions for users and
groups beyond the owner/group/world scheme.
@@ -114,6 +115,7 @@ config EXT3_FS_XATTR
config EXT3_FS_POSIX_ACL
bool "Ext3 POSIX Access Control Lists"
depends on EXT3_FS_XATTR
+ select FS_POSIX_ACL
help
Posix Access Control Lists (ACLs) support permissions for users and
groups beyond the owner/group/world scheme.
@@ -241,6 +243,7 @@ config REISERFS_FS_XATTR
config REISERFS_FS_POSIX_ACL
bool "ReiserFS POSIX Access Control Lists"
depends on REISERFS_FS_XATTR
+ select FS_POSIX_ACL
help
Posix Access Control Lists (ACLs) support permissions for users and
groups beyond the owner/group/world scheme.
@@ -274,6 +277,7 @@ config JFS_FS
config JFS_POSIX_ACL
bool "JFS POSIX Access Control Lists"
depends on JFS_FS
+ select FS_POSIX_ACL
help
Posix Access Control Lists (ACLs) support permissions for users and
groups beyond the owner/group/world scheme.
@@ -318,8 +322,7 @@ config FS_POSIX_ACL
# Never use this symbol for ifdefs.
#
bool
- depends on EXT2_FS_POSIX_ACL || EXT3_FS_POSIX_ACL || JFS_POSIX_ACL || REISERFS_FS_POSIX_ACL || NFSD_V4
- default y
+ default n
source "fs/xfs/Kconfig"
@@ -1438,6 +1441,7 @@ config NFSD_V4
select NFSD_TCP
select CRYPTO_MD5
select CRYPTO
+ select FS_POSIX_ACL
help
If you would like to include the NFSv4 server as well as the NFSv2
and NFSv3 servers, say Y here. This feature is experimental, and
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index fa2348dcd67..3df86285a1c 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -231,8 +231,8 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
int type = (notify == NFY_MOUNT ?
autofs_ptype_missing : autofs_ptype_expire_multi);
- DPRINTK(("new wait id = 0x%08lx, name = %.*s, nfy=%d\n",
- (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify));
+ DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d\n",
+ (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify);
/* autofs4_notify_daemon() may block */
autofs4_notify_daemon(sbi, wq, type);
diff --git a/fs/bio.c b/fs/bio.c
index 3a1472acc36..ca8f7a850fe 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -52,7 +52,7 @@ struct biovec_slab {
*/
#define BV(x) { .nr_vecs = x, .name = "biovec-"__stringify(x) }
-static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] = {
+static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly = {
BV(1), BV(4), BV(16), BV(64), BV(128), BV(BIO_MAX_PAGES),
};
#undef BV
diff --git a/fs/buffer.c b/fs/buffer.c
index 561e63a1496..6a25d7df89b 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -513,8 +513,8 @@ static void free_more_memory(void)
*/
static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
{
- static DEFINE_SPINLOCK(page_uptodate_lock);
unsigned long flags;
+ struct buffer_head *first;
struct buffer_head *tmp;
struct page *page;
int page_uptodate = 1;
@@ -536,7 +536,9 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
* two buffer heads end IO at almost the same time and both
* decide that the page is now completely done.
*/
- spin_lock_irqsave(&page_uptodate_lock, flags);
+ first = page_buffers(page);
+ local_irq_save(flags);
+ bit_spin_lock(BH_Uptodate_Lock, &first->b_state);
clear_buffer_async_read(bh);
unlock_buffer(bh);
tmp = bh;
@@ -549,7 +551,8 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
}
tmp = tmp->b_this_page;
} while (tmp != bh);
- spin_unlock_irqrestore(&page_uptodate_lock, flags);
+ bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
+ local_irq_restore(flags);
/*
* If none of the buffers had errors and they are all
@@ -561,7 +564,8 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
return;
still_busy:
- spin_unlock_irqrestore(&page_uptodate_lock, flags);
+ bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
+ local_irq_restore(flags);
return;
}
@@ -572,8 +576,8 @@ still_busy:
void end_buffer_async_write(struct buffer_head *bh, int uptodate)
{
char b[BDEVNAME_SIZE];
- static DEFINE_SPINLOCK(page_uptodate_lock);
unsigned long flags;
+ struct buffer_head *first;
struct buffer_head *tmp;
struct page *page;
@@ -594,7 +598,10 @@ void end_buffer_async_write(struct buffer_head *bh, int uptodate)
SetPageError(page);
}
- spin_lock_irqsave(&page_uptodate_lock, flags);
+ first = page_buffers(page);
+ local_irq_save(flags);
+ bit_spin_lock(BH_Uptodate_Lock, &first->b_state);
+
clear_buffer_async_write(bh);
unlock_buffer(bh);
tmp = bh->b_this_page;
@@ -605,12 +612,14 @@ void end_buffer_async_write(struct buffer_head *bh, int uptodate)
}
tmp = tmp->b_this_page;
}
- spin_unlock_irqrestore(&page_uptodate_lock, flags);
+ bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
+ local_irq_restore(flags);
end_page_writeback(page);
return;
still_busy:
- spin_unlock_irqrestore(&page_uptodate_lock, flags);
+ bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
+ local_irq_restore(flags);
return;
}
diff --git a/fs/dcookies.c b/fs/dcookies.c
index 581aac959cd..02aa0ddc582 100644
--- a/fs/dcookies.c
+++ b/fs/dcookies.c
@@ -94,12 +94,10 @@ static struct dcookie_struct * alloc_dcookie(struct dentry * dentry,
if (!dcs)
return NULL;
- atomic_inc(&dentry->d_count);
- atomic_inc(&vfsmnt->mnt_count);
dentry->d_cookie = dcs;
- dcs->dentry = dentry;
- dcs->vfsmnt = vfsmnt;
+ dcs->dentry = dget(dentry);
+ dcs->vfsmnt = mntget(vfsmnt);
hash_dcookie(dcs);
return dcs;
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 0b2db4f618c..9989fdcf4d5 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -2663,7 +2663,7 @@ static int ext3_do_update_inode(handle_t *handle,
} else for (block = 0; block < EXT3_N_BLOCKS; block++)
raw_inode->i_block[block] = ei->i_data[block];
- if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
+ if (ei->i_extra_isize)
raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize);
BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c
index f8e0cbd0cb6..6f553e17c37 100644
--- a/fs/hppfs/hppfs_kern.c
+++ b/fs/hppfs/hppfs_kern.c
@@ -4,6 +4,7 @@
*/
#include <linux/fs.h>
+#include <linux/file.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -491,7 +492,7 @@ static int hppfs_open(struct inode *inode, struct file *file)
fd = open_host_sock(host_file, &filter);
if(fd > 0){
data->contents = hppfs_get_data(fd, filter,
- &data->proc_file,
+ data->proc_file,
file, &data->len);
if(!IS_ERR(data->contents))
data->host_fd = fd;
@@ -543,7 +544,7 @@ static int hppfs_dir_open(struct inode *inode, struct file *file)
static loff_t hppfs_llseek(struct file *file, loff_t off, int where)
{
struct hppfs_private *data = file->private_data;
- struct file *proc_file = &data->proc_file;
+ struct file *proc_file = data->proc_file;
loff_t (*llseek)(struct file *, loff_t, int);
loff_t ret;
@@ -586,7 +587,7 @@ static int hppfs_filldir(void *d, const char *name, int size,
static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir)
{
struct hppfs_private *data = file->private_data;
- struct file *proc_file = &data->proc_file;
+ struct file *proc_file = data->proc_file;
int (*readdir)(struct file *, void *, filldir_t);
struct hppfs_dirent dirent = ((struct hppfs_dirent)
{ .vfs_dirent = ent,
diff --git a/fs/inode.c b/fs/inode.c
index 1f9a3a2b89b..6d695037a0a 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1052,7 +1052,7 @@ static void generic_forget_inode(struct inode *inode)
* inode when the usage count drops to zero, and
* i_nlink is zero.
*/
-static void generic_drop_inode(struct inode *inode)
+void generic_drop_inode(struct inode *inode)
{
if (!inode->i_nlink)
generic_delete_inode(inode);
@@ -1060,6 +1060,8 @@ static void generic_drop_inode(struct inode *inode)
generic_forget_inode(inode);
}
+EXPORT_SYMBOL_GPL(generic_drop_inode);
+
/*
* Called when we're dropping the last reference
* to an inode.
diff --git a/fs/ioprio.c b/fs/ioprio.c
index 663e420636d..97e1f088ba0 100644
--- a/fs/ioprio.c
+++ b/fs/ioprio.c
@@ -43,7 +43,7 @@ static int set_task_ioprio(struct task_struct *task, int ioprio)
return 0;
}
-asmlinkage int sys_ioprio_set(int which, int who, int ioprio)
+asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
{
int class = IOPRIO_PRIO_CLASS(ioprio);
int data = IOPRIO_PRIO_DATA(ioprio);
@@ -115,7 +115,7 @@ asmlinkage int sys_ioprio_set(int which, int who, int ioprio)
return ret;
}
-asmlinkage int sys_ioprio_get(int which, int who)
+asmlinkage long sys_ioprio_get(int which, int who)
{
struct task_struct *g, *p;
struct user_struct *user;
diff --git a/fs/locks.c b/fs/locks.c
index a0bc03495bd..29fa5da6c11 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1276,7 +1276,7 @@ int fcntl_getlease(struct file *filp)
*/
static int __setlease(struct file *filp, long arg, struct file_lock **flp)
{
- struct file_lock *fl, **before, **my_before = NULL, *lease = *flp;
+ struct file_lock *fl, **before, **my_before = NULL, *lease;
struct dentry *dentry = filp->f_dentry;
struct inode *inode = dentry->d_inode;
int error, rdlease_count = 0, wrlease_count = 0;
@@ -1287,6 +1287,8 @@ static int __setlease(struct file *filp, long arg, struct file_lock **flp)
if (!flp || !(*flp) || !(*flp)->fl_lmops || !(*flp)->fl_lmops->fl_break)
goto out;
+ lease = *flp;
+
error = -EAGAIN;
if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
goto out;
diff --git a/fs/namei.c b/fs/namei.c
index fa8df81ce8c..1d93cb4f7c5 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -314,7 +314,7 @@ void path_release(struct nameidata *nd)
void path_release_on_umount(struct nameidata *nd)
{
dput(nd->dentry);
- _mntput(nd->mnt);
+ mntput_no_expire(nd->mnt);
}
/*
diff --git a/fs/namespace.c b/fs/namespace.c
index 208c079e9fd..587eb0d707e 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -61,7 +61,7 @@ struct vfsmount *alloc_vfsmnt(const char *name)
INIT_LIST_HEAD(&mnt->mnt_child);
INIT_LIST_HEAD(&mnt->mnt_mounts);
INIT_LIST_HEAD(&mnt->mnt_list);
- INIT_LIST_HEAD(&mnt->mnt_fslink);
+ INIT_LIST_HEAD(&mnt->mnt_expire);
if (name) {
int size = strlen(name)+1;
char *newname = kmalloc(size, GFP_KERNEL);
@@ -165,8 +165,8 @@ clone_mnt(struct vfsmount *old, struct dentry *root)
/* stick the duplicate mount on the same expiry list
* as the original if that was on one */
spin_lock(&vfsmount_lock);
- if (!list_empty(&old->mnt_fslink))
- list_add(&mnt->mnt_fslink, &old->mnt_fslink);
+ if (!list_empty(&old->mnt_expire))
+ list_add(&mnt->mnt_expire, &old->mnt_expire);
spin_unlock(&vfsmount_lock);
}
return mnt;
@@ -345,12 +345,13 @@ static void umount_tree(struct vfsmount *mnt)
for (p = mnt; p; p = next_mnt(p, mnt)) {
list_del(&p->mnt_list);
list_add(&p->mnt_list, &kill);
+ p->mnt_namespace = NULL;
}
while (!list_empty(&kill)) {
mnt = list_entry(kill.next, struct vfsmount, mnt_list);
list_del_init(&mnt->mnt_list);
- list_del_init(&mnt->mnt_fslink);
+ list_del_init(&mnt->mnt_expire);
if (mnt->mnt_parent == mnt) {
spin_unlock(&vfsmount_lock);
} else {
@@ -644,7 +645,7 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse)
if (mnt) {
/* stop bind mounts from expiring */
spin_lock(&vfsmount_lock);
- list_del_init(&mnt->mnt_fslink);
+ list_del_init(&mnt->mnt_expire);
spin_unlock(&vfsmount_lock);
err = graft_tree(mnt, nd);
@@ -743,7 +744,7 @@ static int do_move_mount(struct nameidata *nd, char *old_name)
/* if the mount is moved, it should no longer be expire
* automatically */
- list_del_init(&old_nd.mnt->mnt_fslink);
+ list_del_init(&old_nd.mnt->mnt_expire);
out2:
spin_unlock(&vfsmount_lock);
out1:
@@ -807,12 +808,13 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd,
goto unlock;
newmnt->mnt_flags = mnt_flags;
+ newmnt->mnt_namespace = current->namespace;
err = graft_tree(newmnt, nd);
if (err == 0 && fslist) {
/* add to the specified expiration list */
spin_lock(&vfsmount_lock);
- list_add_tail(&newmnt->mnt_fslink, fslist);
+ list_add_tail(&newmnt->mnt_expire, fslist);
spin_unlock(&vfsmount_lock);
}
@@ -824,6 +826,54 @@ unlock:
EXPORT_SYMBOL_GPL(do_add_mount);
+static void expire_mount(struct vfsmount *mnt, struct list_head *mounts)
+{
+ spin_lock(&vfsmount_lock);
+
+ /*
+ * Check if mount is still attached, if not, let whoever holds it deal
+ * with the sucker
+ */
+ if (mnt->mnt_parent == mnt) {
+ spin_unlock(&vfsmount_lock);
+ return;
+ }
+
+ /*
+ * Check that it is still dead: the count should now be 2 - as
+ * contributed by the vfsmount parent and the mntget above
+ */
+ if (atomic_read(&mnt->mnt_count) == 2) {
+ struct nameidata old_nd;
+
+ /* delete from the namespace */
+ list_del_init(&mnt->mnt_list);
+ mnt->mnt_namespace = NULL;
+ detach_mnt(mnt, &old_nd);
+ spin_unlock(&vfsmount_lock);
+ path_release(&old_nd);
+
+ /*
+ * Now lay it to rest if this was the last ref on the superblock
+ */
+ if (atomic_read(&mnt->mnt_sb->s_active) == 1) {
+ /* last instance - try to be smart */
+ lock_kernel();
+ DQUOT_OFF(mnt->mnt_sb);
+ acct_auto_close(mnt->mnt_sb);
+ unlock_kernel();
+ }
+ mntput(mnt);
+ } else {
+ /*
+ * Someone brought it back to life whilst we didn't have any
+ * locks held so return it to the expiration list
+ */
+ list_add_tail(&mnt->mnt_expire, mounts);
+ spin_unlock(&vfsmount_lock);
+ }
+}
+
/*
* process a list of expirable mountpoints with the intent of discarding any
* mountpoints that aren't in use and haven't been touched since last we came
@@ -846,13 +896,13 @@ void mark_mounts_for_expiry(struct list_head *mounts)
* - still marked for expiry (marked on the last call here; marks are
* cleared by mntput())
*/
- list_for_each_entry_safe(mnt, next, mounts, mnt_fslink) {
+ list_for_each_entry_safe(mnt, next, mounts, mnt_expire) {
if (!xchg(&mnt->mnt_expiry_mark, 1) ||
atomic_read(&mnt->mnt_count) != 1)
continue;
mntget(mnt);
- list_move(&mnt->mnt_fslink, &graveyard);
+ list_move(&mnt->mnt_expire, &graveyard);
}
/*
@@ -862,61 +912,19 @@ void mark_mounts_for_expiry(struct list_head *mounts)
* - dispose of the corpse
*/
while (!list_empty(&graveyard)) {
- mnt = list_entry(graveyard.next, struct vfsmount, mnt_fslink);
- list_del_init(&mnt->mnt_fslink);
+ mnt = list_entry(graveyard.next, struct vfsmount, mnt_expire);
+ list_del_init(&mnt->mnt_expire);
/* don't do anything if the namespace is dead - all the
* vfsmounts from it are going away anyway */
namespace = mnt->mnt_namespace;
- if (!namespace || atomic_read(&namespace->count) <= 0)
+ if (!namespace || !namespace->root)
continue;
get_namespace(namespace);
spin_unlock(&vfsmount_lock);
down_write(&namespace->sem);
- spin_lock(&vfsmount_lock);
-
- /* check that it is still dead: the count should now be 2 - as
- * contributed by the vfsmount parent and the mntget above */
- if (atomic_read(&mnt->mnt_count) == 2) {
- struct vfsmount *xdmnt;
- struct dentry *xdentry;
-
- /* delete from the namespace */
- list_del_init(&mnt->mnt_list);
- list_del_init(&mnt->mnt_child);
- list_del_init(&mnt->mnt_hash);
- mnt->mnt_mountpoint->d_mounted--;
-
- xdentry = mnt->mnt_mountpoint;
- mnt->mnt_mountpoint = mnt->mnt_root;
- xdmnt = mnt->mnt_parent;
- mnt->mnt_parent = mnt;
-
- spin_unlock(&vfsmount_lock);
-
- mntput(xdmnt);
- dput(xdentry);
-
- /* now lay it to rest if this was the last ref on the
- * superblock */
- if (atomic_read(&mnt->mnt_sb->s_active) == 1) {
- /* last instance - try to be smart */
- lock_kernel();
- DQUOT_OFF(mnt->mnt_sb);
- acct_auto_close(mnt->mnt_sb);
- unlock_kernel();
- }
-
- mntput(mnt);
- } else {
- /* someone brought it back to life whilst we didn't
- * have any locks held so return it to the expiration
- * list */
- list_add_tail(&mnt->mnt_fslink, mounts);
- spin_unlock(&vfsmount_lock);
- }
-
+ expire_mount(mnt, mounts);
up_write(&namespace->sem);
mntput(mnt);
@@ -1449,16 +1457,12 @@ void __init mnt_init(unsigned long mempages)
void __put_namespace(struct namespace *namespace)
{
- struct vfsmount *mnt;
-
+ struct vfsmount *root = namespace->root;
+ namespace->root = NULL;
+ spin_unlock(&vfsmount_lock);
down_write(&namespace->sem);
spin_lock(&vfsmount_lock);
-
- list_for_each_entry(mnt, &namespace->list, mnt_list) {
- mnt->mnt_namespace = NULL;
- }
-
- umount_tree(namespace->root);
+ umount_tree(root);
spin_unlock(&vfsmount_lock);
up_write(&namespace->sem);
kfree(namespace);
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index d71f14517b9..e08edc17c6a 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -169,12 +169,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
(int)open->op_fname.len, open->op_fname.data,
open->op_stateowner);
- if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
- return nfserr_grace;
-
- if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
- return nfserr_no_grace;
-
/* This check required by spec. */
if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
return nfserr_inval;
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 095f1740f3a..57ed50fe7f8 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -119,25 +119,12 @@ out:
return status;
}
-static int
-nfsd4_rec_fsync(struct dentry *dentry)
+static void
+nfsd4_sync_rec_dir(void)
{
- struct file *filp;
- int status = nfs_ok;
-
- dprintk("NFSD: nfs4_fsync_rec_dir\n");
- filp = dentry_open(dget(dentry), mntget(rec_dir.mnt), O_RDWR);
- if (IS_ERR(filp)) {
- status = PTR_ERR(filp);
- goto out;
- }
- if (filp->f_op && filp->f_op->fsync)
- status = filp->f_op->fsync(filp, filp->f_dentry, 0);
- fput(filp);
-out:
- if (status)
- printk("nfsd4: unable to sync recovery directory\n");
- return status;
+ down(&rec_dir.dentry->d_inode->i_sem);
+ nfsd_sync_dir(rec_dir.dentry);
+ up(&rec_dir.dentry->d_inode->i_sem);
}
int
@@ -176,7 +163,7 @@ out_unlock:
up(&rec_dir.dentry->d_inode->i_sem);
if (status == 0) {
clp->cl_firststate = 1;
- status = nfsd4_rec_fsync(rec_dir.dentry);
+ nfsd4_sync_rec_dir();
}
nfs4_reset_user(uid, gid);
dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status);
@@ -302,7 +289,9 @@ nfsd4_unlink_clid_dir(char *name, int namlen)
dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name);
+ down(&rec_dir.dentry->d_inode->i_sem);
dentry = lookup_one_len(name, rec_dir.dentry, namlen);
+ up(&rec_dir.dentry->d_inode->i_sem);
if (IS_ERR(dentry)) {
status = PTR_ERR(dentry);
return status;
@@ -327,11 +316,12 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
if (!rec_dir_init || !clp->cl_firststate)
return;
+ clp->cl_firststate = 0;
nfs4_save_user(&uid, &gid);
status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
nfs4_reset_user(uid, gid);
if (status == 0)
- status = nfsd4_rec_fsync(rec_dir.dentry);
+ nfsd4_sync_rec_dir();
if (status)
printk("NFSD: Failed to remove expired client state directory"
" %.*s\n", HEXDIR_LEN, clp->cl_recdir);
@@ -362,7 +352,7 @@ nfsd4_recdir_purge_old(void) {
return;
status = nfsd4_list_rec_dir(rec_dir.dentry, purge_old);
if (status == 0)
- status = nfsd4_rec_fsync(rec_dir.dentry);
+ nfsd4_sync_rec_dir();
if (status)
printk("nfsd4: failed to purge old clients from recovery"
" directory %s\n", rec_dir.dentry->d_name.name);
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 89e36526d7f..b83f8fb441e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -874,6 +874,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confi
* change request correctly. */
atomic_set(&conf->cl_callback.cb_set, 0);
gen_confirm(conf);
+ nfsd4_remove_clid_dir(unconf);
expire_client(unconf);
status = nfs_ok;
@@ -1159,6 +1160,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *
stp->st_deny_bmap = 0;
__set_bit(open->op_share_access, &stp->st_access_bmap);
__set_bit(open->op_share_deny, &stp->st_deny_bmap);
+ stp->st_openstp = NULL;
}
static void
@@ -1294,7 +1296,7 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
fp = find_file(ino);
if (!fp)
return nfs_ok;
- ret = nfserr_share_denied;
+ ret = nfserr_locked;
/* Search for conflicting share reservations */
list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
if (test_bit(deny_type, &stp->st_deny_bmap) ||
@@ -1482,7 +1484,7 @@ nfsd4_process_open1(struct nfsd4_open *open)
if (sop) {
open->op_stateowner = sop;
/* check for replay */
- if (open->op_seqid == sop->so_seqid){
+ if (open->op_seqid == sop->so_seqid - 1){
if (sop->so_replay.rp_buflen)
return NFSERR_REPLAY_ME;
else {
@@ -1497,7 +1499,7 @@ nfsd4_process_open1(struct nfsd4_open *open)
goto renew;
}
} else if (sop->so_confirmed) {
- if (open->op_seqid == sop->so_seqid + 1)
+ if (open->op_seqid == sop->so_seqid)
goto renew;
status = nfserr_bad_seqid;
goto out;
@@ -1530,8 +1532,6 @@ renew:
status = nfs_ok;
renew_client(sop->so_client);
out:
- if (status && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
- status = nfserr_reclaim_bad;
return status;
}
@@ -1685,19 +1685,11 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_sta
}
-/* decrement seqid on successful reclaim, it will be bumped in encode_open */
static void
-nfs4_set_claim_prev(struct nfsd4_open *open, int *status)
+nfs4_set_claim_prev(struct nfsd4_open *open)
{
- if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) {
- if (*status)
- *status = nfserr_reclaim_bad;
- else {
- open->op_stateowner->so_confirmed = 1;
- open->op_stateowner->so_client->cl_firststate = 1;
- open->op_stateowner->so_seqid--;
- }
- }
+ open->op_stateowner->so_confirmed = 1;
+ open->op_stateowner->so_client->cl_firststate = 1;
}
/*
@@ -1789,6 +1781,12 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
struct nfs4_delegation *dp = NULL;
int status;
+ if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
+ return nfserr_grace;
+
+ if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+ return nfserr_no_grace;
+
status = nfserr_inval;
if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny))
goto out;
@@ -1823,6 +1821,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
status = nfs4_upgrade_open(rqstp, current_fh, stp, open);
if (status)
goto out;
+ update_stateid(&stp->st_stateid);
} else {
/* Stateid was not found, this is a new OPEN */
int flags = 0;
@@ -1856,8 +1855,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
out:
if (fp)
put_nfs4_file(fp);
- /* CLAIM_PREVIOUS has different error returns */
- nfs4_set_claim_prev(open, &status);
+ if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+ nfs4_set_claim_prev(open);
/*
* To finish the open response, we just need to set the rflags.
*/
@@ -1990,14 +1989,11 @@ laundromat_main(void *not_used)
queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);
}
-/* search ownerid_hashtbl[] and close_lru for stateid owner
- * (stateid->si_stateownerid)
- */
static struct nfs4_stateowner *
-find_openstateowner_id(u32 st_id, int flags) {
+search_close_lru(u32 st_id, int flags)
+{
struct nfs4_stateowner *local = NULL;
- dprintk("NFSD: find_openstateowner_id %d\n", st_id);
if (flags & CLOSE_STATE) {
list_for_each_entry(local, &close_lru, so_close_lru) {
if (local->so_id == st_id)
@@ -2163,14 +2159,19 @@ out:
return status;
}
+static inline int
+setlkflg (int type)
+{
+ return (type == NFS4_READW_LT || type == NFS4_READ_LT) ?
+ RD_STATE : WR_STATE;
+}
/*
* Checks for sequence id mutating operations.
*/
static int
-nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, clientid_t *lockclid)
+nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, struct nfsd4_lock *lock)
{
- int status;
struct nfs4_stateid *stp;
struct nfs4_stateowner *sop;
@@ -2178,53 +2179,65 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
"stateid = (%08x/%08x/%08x/%08x)\n", seqid,
stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
stateid->si_generation);
-
+
*stpp = NULL;
*sopp = NULL;
- status = nfserr_bad_stateid;
if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
printk("NFSD: preprocess_seqid_op: magic stateid!\n");
- goto out;
+ return nfserr_bad_stateid;
}
- status = nfserr_stale_stateid;
if (STALE_STATEID(stateid))
- goto out;
+ return nfserr_stale_stateid;
/*
* We return BAD_STATEID if filehandle doesn't match stateid,
* the confirmed flag is incorrecly set, or the generation
* number is incorrect.
- * If there is no entry in the openfile table for this id,
- * we can't always return BAD_STATEID;
- * this might be a retransmitted CLOSE which has arrived after
- * the openfile has been released.
*/
- if (!(stp = find_stateid(stateid, flags)))
- goto no_nfs4_stateid;
-
- status = nfserr_bad_stateid;
+ stp = find_stateid(stateid, flags);
+ if (stp == NULL) {
+ /*
+ * Also, we should make sure this isn't just the result of
+ * a replayed close:
+ */
+ sop = search_close_lru(stateid->si_stateownerid, flags);
+ if (sop == NULL)
+ return nfserr_bad_stateid;
+ *sopp = sop;
+ goto check_replay;
+ }
- /* for new lock stateowners:
- * check that the lock->v.new.open_stateid
- * refers to an open stateowner
- *
- * check that the lockclid (nfs4_lock->v.new.clientid) is the same
- * as the open_stateid->st_stateowner->so_client->clientid
- */
- if (lockclid) {
+ if (lock) {
struct nfs4_stateowner *sop = stp->st_stateowner;
+ clientid_t *lockclid = &lock->v.new.clientid;
struct nfs4_client *clp = sop->so_client;
+ int lkflg = 0;
+ int status;
+
+ lkflg = setlkflg(lock->lk_type);
+
+ if (lock->lk_is_new) {
+ if (!sop->so_is_open_owner)
+ return nfserr_bad_stateid;
+ if (!cmp_clid(&clp->cl_clientid, lockclid))
+ return nfserr_bad_stateid;
+ /* stp is the open stateid */
+ status = nfs4_check_openmode(stp, lkflg);
+ if (status)
+ return status;
+ } else {
+ /* stp is the lock stateid */
+ status = nfs4_check_openmode(stp->st_openstp, lkflg);
+ if (status)
+ return status;
+ }
- if (!sop->so_is_open_owner)
- goto out;
- if (!cmp_clid(&clp->cl_clientid, lockclid))
- goto out;
}
if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
- goto out;
+ return nfserr_bad_stateid;
}
*stpp = stp;
@@ -2235,63 +2248,41 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
* For the moment, we ignore the possibility of
* generation number wraparound.
*/
- if (seqid != sop->so_seqid + 1)
+ if (seqid != sop->so_seqid)
goto check_replay;
- if (sop->so_confirmed) {
- if (flags & CONFIRM) {
- printk("NFSD: preprocess_seqid_op: expected unconfirmed stateowner!\n");
- goto out;
- }
+ if (sop->so_confirmed && flags & CONFIRM) {
+ printk("NFSD: preprocess_seqid_op: expected"
+ " unconfirmed stateowner!\n");
+ return nfserr_bad_stateid;
}
- else {
- if (!(flags & CONFIRM)) {
- printk("NFSD: preprocess_seqid_op: stateowner not confirmed yet!\n");
- goto out;
- }
+ if (!sop->so_confirmed && !(flags & CONFIRM)) {
+ printk("NFSD: preprocess_seqid_op: stateowner not"
+ " confirmed yet!\n");
+ return nfserr_bad_stateid;
}
if (stateid->si_generation > stp->st_stateid.si_generation) {
printk("NFSD: preprocess_seqid_op: future stateid?!\n");
- goto out;
+ return nfserr_bad_stateid;
}
- status = nfserr_old_stateid;
if (stateid->si_generation < stp->st_stateid.si_generation) {
printk("NFSD: preprocess_seqid_op: old stateid!\n");
- goto out;
+ return nfserr_old_stateid;
}
- /* XXX renew the client lease here */
- status = nfs_ok;
-
-out:
- return status;
-
-no_nfs4_stateid:
-
- /*
- * We determine whether this is a bad stateid or a replay,
- * starting by trying to look up the stateowner.
- * If stateowner is not found - stateid is bad.
- */
- if (!(sop = find_openstateowner_id(stateid->si_stateownerid, flags))) {
- printk("NFSD: preprocess_seqid_op: no stateowner or nfs4_stateid!\n");
- status = nfserr_bad_stateid;
- goto out;
- }
- *sopp = sop;
+ renew_client(sop->so_client);
+ return nfs_ok;
check_replay:
- if (seqid == sop->so_seqid) {
+ if (seqid == sop->so_seqid - 1) {
printk("NFSD: preprocess_seqid_op: retransmission?\n");
/* indicate replay to calling function */
- status = NFSERR_REPLAY_ME;
- } else {
- printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid +1, seqid);
-
- *sopp = NULL;
- status = nfserr_bad_seqid;
+ return NFSERR_REPLAY_ME;
}
- goto out;
+ printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
+ sop->so_seqid, seqid);
+ *sopp = NULL;
+ return nfserr_bad_seqid;
}
int
@@ -2609,7 +2600,6 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid,
* occured.
*
* strhashval = lock_ownerstr_hashval
- * so_seqid = lock->lk_new_lock_seqid - 1: it gets bumped in encode
*/
static struct nfs4_stateowner *
@@ -2634,7 +2624,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
sop->so_is_open_owner = 0;
sop->so_id = current_ownerid++;
sop->so_client = clp;
- sop->so_seqid = lock->lk_new_lock_seqid - 1;
+ sop->so_seqid = lock->lk_new_lock_seqid;
sop->so_confirmed = 1;
rp = &sop->so_replay;
rp->rp_status = NFSERR_SERVERFAULT;
@@ -2669,6 +2659,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */
stp->st_access_bmap = open_stp->st_access_bmap;
stp->st_deny_bmap = open_stp->st_deny_bmap;
+ stp->st_openstp = open_stp;
out:
return stp;
@@ -2699,22 +2690,17 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
(long long) lock->lk_offset,
(long long) lock->lk_length);
- if (nfs4_in_grace() && !lock->lk_reclaim)
- return nfserr_grace;
- if (!nfs4_in_grace() && lock->lk_reclaim)
- return nfserr_no_grace;
-
if (check_lock_length(lock->lk_offset, lock->lk_length))
return nfserr_inval;
nfs4_lock_state();
if (lock->lk_is_new) {
- /*
- * Client indicates that this is a new lockowner.
- * Use open owner and open stateid to create lock owner and lock
- * stateid.
- */
+ /*
+ * Client indicates that this is a new lockowner.
+ * Use open owner and open stateid to create lock owner and
+ * lock stateid.
+ */
struct nfs4_stateid *open_stp = NULL;
struct nfs4_file *fp;
@@ -2724,23 +2710,14 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
goto out;
}
- /* is the new lock seqid presented by the client zero? */
- status = nfserr_bad_seqid;
- if (lock->v.new.lock_seqid != 0)
- goto out;
-
/* validate and update open stateid and open seqid */
status = nfs4_preprocess_seqid_op(current_fh,
lock->lk_new_open_seqid,
&lock->lk_new_open_stateid,
CHECK_FH | OPEN_STATE,
- &open_sop, &open_stp,
- &lock->v.new.clientid);
- if (status) {
- if (lock->lk_reclaim)
- status = nfserr_reclaim_bad;
+ &open_sop, &open_stp, lock);
+ if (status)
goto out;
- }
/* create lockowner and lock stateid */
fp = open_stp->st_file;
strhashval = lock_ownerstr_hashval(fp->fi_inode,
@@ -2766,7 +2743,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
lock->lk_old_lock_seqid,
&lock->lk_old_lock_stateid,
CHECK_FH | LOCK_STATE,
- &lock->lk_stateowner, &lock_stp, NULL);
+ &lock->lk_stateowner, &lock_stp, lock);
if (status)
goto out;
}
@@ -2778,6 +2755,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
goto out;
}
+ status = nfserr_grace;
+ if (nfs4_in_grace() && !lock->lk_reclaim)
+ goto out;
+ status = nfserr_no_grace;
+ if (!nfs4_in_grace() && lock->lk_reclaim)
+ goto out;
+
locks_init_lock(&file_lock);
switch (lock->lk_type) {
case NFS4_READ_LT:
@@ -2844,10 +2828,10 @@ conflicting_lock:
out_destroy_new_stateid:
if (lock->lk_is_new) {
dprintk("NFSD: nfsd4_lock: destroy new stateid!\n");
- /*
- * An error encountered after instantiation of the new
- * stateid has forced us to destroy it.
- */
+ /*
+ * An error encountered after instantiation of the new
+ * stateid has forced us to destroy it.
+ */
if (!seqid_mutating_err(status))
open_sop->so_seqid--;
@@ -3083,7 +3067,12 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *
* of the lockowner state released; so don't release any until all
* have been checked. */
status = nfs_ok;
- list_for_each_entry(sop, &matches, so_perclient) {
+ while (!list_empty(&matches)) {
+ sop = list_entry(matches.next, struct nfs4_stateowner,
+ so_perclient);
+ /* unhash_stateowner deletes so_perclient only
+ * for openowners. */
+ list_del(&sop->so_perclient);
release_stateowner(sop);
}
out:
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 91fb171d2ac..4c414635023 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1210,16 +1210,15 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
save = resp->p;
/*
- * Routine for encoding the result of a
- * "seqid-mutating" NFSv4 operation. This is
- * where seqids are incremented, and the
- * replay cache is filled.
+ * Routine for encoding the result of a "seqid-mutating" NFSv4 operation. This
+ * is where sequence id's are incremented, and the replay cache is filled.
+ * Note that we increment sequence id's here, at the last moment, so we're sure
+ * we know whether the error to be returned is a sequence id mutating error.
*/
#define ENCODE_SEQID_OP_TAIL(stateowner) do { \
if (seqid_mutating_err(nfserr) && stateowner) { \
- if (stateowner->so_confirmed) \
- stateowner->so_seqid++; \
+ stateowner->so_seqid++; \
stateowner->so_replay.rp_status = nfserr; \
stateowner->so_replay.rp_buflen = \
(((char *)(resp)->p - (char *)save)); \
@@ -1367,9 +1366,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
if ((buflen -= 4) < 0)
goto out_resource;
if (exp->ex_flags & NFSEXP_NOSUBTREECHECK)
- WRITE32(NFS4_FH_VOLATILE_ANY);
+ WRITE32(NFS4_FH_PERSISTENT);
else
- WRITE32(NFS4_FH_VOLATILE_ANY|NFS4_FH_VOL_RENAME);
+ WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME);
}
if (bmval0 & FATTR4_WORD0_CHANGE) {
/*
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index be24ead89d9..5e0bf391760 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -733,7 +733,7 @@ nfsd_sync(struct file *filp)
up(&inode->i_sem);
}
-static void
+void
nfsd_sync_dir(struct dentry *dp)
{
nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
diff --git a/fs/super.c b/fs/super.c
index 25bc1ec6bc5..6e57ee252e1 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -840,7 +840,6 @@ do_kern_mount(const char *fstype, int flags, const char *name, void *data)
mnt->mnt_root = dget(sb->s_root);
mnt->mnt_mountpoint = sb->s_root;
mnt->mnt_parent = mnt;
- mnt->mnt_namespace = current->namespace;
up_write(&sb->s_umount);
free_secdata(secdata);
put_filesystem(type);
diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h
index 408aea55e0c..e139463d9a0 100644
--- a/include/asm-alpha/pgtable.h
+++ b/include/asm-alpha/pgtable.h
@@ -132,6 +132,8 @@
#define __S110 _PAGE_S(0)
#define __S111 _PAGE_S(0)
+#define pgprot_noncached(prot) (prot)
+
/*
* BAD_PAGETABLE is used when we need a bogus page-table, while
* BAD_PAGE is used for a bogus page.
diff --git a/include/asm-i386/mmzone.h b/include/asm-i386/mmzone.h
index 33ce5d37e89..516421300ea 100644
--- a/include/asm-i386/mmzone.h
+++ b/include/asm-i386/mmzone.h
@@ -8,20 +8,15 @@
#include <asm/smp.h>
-#if CONFIG_NUMA
+#ifdef CONFIG_NUMA
extern struct pglist_data *node_data[];
#define NODE_DATA(nid) (node_data[nid])
-#ifdef CONFIG_NUMA
- #ifdef CONFIG_X86_NUMAQ
- #include <asm/numaq.h>
- #else /* summit or generic arch */
- #include <asm/srat.h>
- #endif
-#else /* !CONFIG_NUMA */
- #define get_memcfg_numa get_memcfg_numa_flat
- #define get_zholes_size(n) (0)
-#endif /* CONFIG_NUMA */
+#ifdef CONFIG_X86_NUMAQ
+ #include <asm/numaq.h>
+#else /* summit or generic arch */
+ #include <asm/srat.h>
+#endif
extern int get_memcfg_numa_flat(void );
/*
@@ -42,6 +37,11 @@ static inline void get_memcfg_numa(void)
get_memcfg_numa_flat();
}
+extern int early_pfn_to_nid(unsigned long pfn);
+
+#else /* !CONFIG_NUMA */
+#define get_memcfg_numa get_memcfg_numa_flat
+#define get_zholes_size(n) (0)
#endif /* CONFIG_NUMA */
#ifdef CONFIG_DISCONTIGMEM
@@ -151,6 +151,4 @@ static inline int pfn_valid(int pfn)
#endif /* CONFIG_NEED_MULTIPLE_NODES */
-extern int early_pfn_to_nid(unsigned long pfn);
-
#endif /* _ASM_MMZONE_H_ */
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index 6f0f93d0d41..5d06e6bd6ba 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -694,4 +694,12 @@ extern unsigned long boot_option_idle_override;
extern void enable_sep_cpu(void);
extern int sysenter_setup(void);
+#ifdef CONFIG_MTRR
+extern void mtrr_ap_init(void);
+extern void mtrr_bp_init(void);
+#else
+#define mtrr_ap_init() do {} while (0)
+#define mtrr_bp_init() do {} while (0)
+#endif
+
#endif /* __ASM_I386_PROCESSOR_H */
diff --git a/include/asm-m32r/s1d13806.h b/include/asm-m32r/s1d13806.h
new file mode 100644
index 00000000000..248d36a82d7
--- /dev/null
+++ b/include/asm-m32r/s1d13806.h
@@ -0,0 +1,199 @@
+//----------------------------------------------------------------------------
+//
+// File generated by S1D13806CFG.EXE
+//
+// Copyright (c) 2000,2001 Epson Research and Development, Inc.
+// All rights reserved.
+//
+//----------------------------------------------------------------------------
+
+// Panel: (active) 640x480 77Hz STN Single 8-bit (PCLK=CLKI=25.175MHz)
+// Memory: Embedded SDRAM (MCLK=CLKI3=50.000MHz) (BUSCLK=33.333MHz)
+
+#define SWIVEL_VIEW 0 /* 0:none, 1:90 not completed */
+
+static struct s1d13xxxfb_regval s1d13xxxfb_initregs[] = {
+
+ {0x0001,0x00}, // Miscellaneous Register
+ {0x01FC,0x00}, // Display Mode Register
+#if defined(CONFIG_PLAT_MAPPI)
+ {0x0004,0x00}, // General IO Pins Configuration Register 0
+ {0x0005,0x00}, // General IO Pins Configuration Register 1
+ {0x0008,0x00}, // General IO Pins Control Register 0
+ {0x0009,0x00}, // General IO Pins Control Register 1
+ {0x0010,0x00}, // Memory Clock Configuration Register
+ {0x0014,0x00}, // LCD Pixel Clock Configuration Register
+ {0x0018,0x00}, // CRT/TV Pixel Clock Configuration Register
+ {0x001C,0x00}, // MediaPlug Clock Configuration Register
+/*
+ * .. 10MHz: 0x00
+ * .. 30MHz: 0x01
+ * 30MHz ..: 0x02
+ */
+ {0x001E,0x02}, // CPU To Memory Wait State Select Register
+ {0x0021,0x02}, // DRAM Refresh Rate Register
+ {0x002A,0x11}, // DRAM Timings Control Register 0
+ {0x002B,0x13}, // DRAM Timings Control Register 1
+ {0x0020,0x80}, // Memory Configuration Register
+ {0x0030,0x25}, // Panel Type Register
+ {0x0031,0x00}, // MOD Rate Register
+ {0x0032,0x4F}, // LCD Horizontal Display Width Register
+ {0x0034,0x12}, // LCD Horizontal Non-Display Period Register
+ {0x0035,0x01}, // TFT FPLINE Start Position Register
+ {0x0036,0x0B}, // TFT FPLINE Pulse Width Register
+ {0x0038,0xDF}, // LCD Vertical Display Height Register 0
+ {0x0039,0x01}, // LCD Vertical Display Height Register 1
+ {0x003A,0x2C}, // LCD Vertical Non-Display Period Register
+ {0x003B,0x0A}, // TFT FPFRAME Start Position Register
+ {0x003C,0x01}, // TFT FPFRAME Pulse Width Register
+
+ {0x0041,0x00}, // LCD Miscellaneous Register
+ {0x0042,0x00}, // LCD Display Start Address Register 0
+ {0x0043,0x00}, // LCD Display Start Address Register 1
+ {0x0044,0x00}, // LCD Display Start Address Register 2
+
+#elif defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
+ {0x0004,0x07}, // GPIO[0:7] direction
+ {0x0005,0x00}, // GPIO[8:12] direction
+ {0x0008,0x00}, // GPIO[0:7] data
+ {0x0009,0x00}, // GPIO[8:12] data
+ {0x0008,0x04}, // LCD panel Vcc on
+ {0x0008,0x05}, // LCD panel reset
+ {0x0010,0x01}, // Memory Clock Configuration Register
+ {0x0014,0x30}, // LCD Pixel Clock Configuration Register (CLKI 22MHz/4)
+ {0x0018,0x00}, // CRT/TV Pixel Clock Configuration Register
+ {0x001C,0x00}, // MediaPlug Clock Configuration Register(10MHz)
+ {0x001E,0x00}, // CPU To Memory Wait State Select Register
+ {0x0020,0x80}, // Memory Configuration Register
+ {0x0021,0x03}, // DRAM Refresh Rate Register
+ {0x002A,0x00}, // DRAM Timings Control Register 0
+ {0x002B,0x01}, // DRAM Timings Control Register 1
+ {0x0030,0x25}, // Panel Type Register
+ {0x0031,0x00}, // MOD Rate Register
+ {0x0032,0x1d}, // LCD Horizontal Display Width Register
+ {0x0034,0x05}, // LCD Horizontal Non-Display Period Register
+ {0x0035,0x01}, // TFT FPLINE Start Position Register
+ {0x0036,0x01}, // TFT FPLINE Pulse Width Register
+ {0x0038,0x3F}, // LCD Vertical Display Height Register 0
+ {0x0039,0x01}, // LCD Vertical Display Height Register 1
+ {0x003A,0x0b}, // LCD Vertical Non-Display Period Register
+ {0x003B,0x07}, // TFT FPFRAME Start Position Register
+ {0x003C,0x02}, // TFT FPFRAME Pulse Width Register
+
+ {0x0041,0x00}, // LCD Miscellaneous Register
+#if (SWIVEL_VIEW == 0)
+ {0x0042,0x00}, // LCD Display Start Address Register 0
+ {0x0043,0x00}, // LCD Display Start Address Register 1
+ {0x0044,0x00}, // LCD Display Start Address Register 2
+
+#elif (SWIVEL_VIEW == 1)
+ // 1024 - W(320) = 0x2C0
+ {0x0042,0xC0}, // LCD Display Start Address Register 0
+ {0x0043,0x02}, // LCD Display Start Address Register 1
+ {0x0044,0x00}, // LCD Display Start Address Register 2
+ // 1024
+ {0x0046,0x00}, // LCD Memory Address Offset Register 0
+ {0x0047,0x02}, // LCD Memory Address Offset Register 1
+#else
+#error unsupported SWIVEL_VIEW mode
+#endif
+#else
+#error no platform configuration
+#endif /* CONFIG_PLAT_XXX */
+
+ {0x0048,0x00}, // LCD Pixel Panning Register
+ {0x004A,0x00}, // LCD Display FIFO High Threshold Control Register
+ {0x004B,0x00}, // LCD Display FIFO Low Threshold Control Register
+ {0x0050,0x4F}, // CRT/TV Horizontal Display Width Register
+ {0x0052,0x13}, // CRT/TV Horizontal Non-Display Period Register
+ {0x0053,0x01}, // CRT/TV HRTC Start Position Register
+ {0x0054,0x0B}, // CRT/TV HRTC Pulse Width Register
+ {0x0056,0xDF}, // CRT/TV Vertical Display Height Register 0
+ {0x0057,0x01}, // CRT/TV Vertical Display Height Register 1
+ {0x0058,0x2B}, // CRT/TV Vertical Non-Display Period Register
+ {0x0059,0x09}, // CRT/TV VRTC Start Position Register
+ {0x005A,0x01}, // CRT/TV VRTC Pulse Width Register
+ {0x005B,0x10}, // TV Output Control Register
+
+ {0x0062,0x00}, // CRT/TV Display Start Address Register 0
+ {0x0063,0x00}, // CRT/TV Display Start Address Register 1
+ {0x0064,0x00}, // CRT/TV Display Start Address Register 2
+
+ {0x0068,0x00}, // CRT/TV Pixel Panning Register
+ {0x006A,0x00}, // CRT/TV Display FIFO High Threshold Control Register
+ {0x006B,0x00}, // CRT/TV Display FIFO Low Threshold Control Register
+ {0x0070,0x00}, // LCD Ink/Cursor Control Register
+ {0x0071,0x01}, // LCD Ink/Cursor Start Address Register
+ {0x0072,0x00}, // LCD Cursor X Position Register 0
+ {0x0073,0x00}, // LCD Cursor X Position Register 1
+ {0x0074,0x00}, // LCD Cursor Y Position Register 0
+ {0x0075,0x00}, // LCD Cursor Y Position Register 1
+ {0x0076,0x00}, // LCD Ink/Cursor Blue Color 0 Register
+ {0x0077,0x00}, // LCD Ink/Cursor Green Color 0 Register
+ {0x0078,0x00}, // LCD Ink/Cursor Red Color 0 Register
+ {0x007A,0x1F}, // LCD Ink/Cursor Blue Color 1 Register
+ {0x007B,0x3F}, // LCD Ink/Cursor Green Color 1 Register
+ {0x007C,0x1F}, // LCD Ink/Cursor Red Color 1 Register
+ {0x007E,0x00}, // LCD Ink/Cursor FIFO Threshold Register
+ {0x0080,0x00}, // CRT/TV Ink/Cursor Control Register
+ {0x0081,0x01}, // CRT/TV Ink/Cursor Start Address Register
+ {0x0082,0x00}, // CRT/TV Cursor X Position Register 0
+ {0x0083,0x00}, // CRT/TV Cursor X Position Register 1
+ {0x0084,0x00}, // CRT/TV Cursor Y Position Register 0
+ {0x0085,0x00}, // CRT/TV Cursor Y Position Register 1
+ {0x0086,0x00}, // CRT/TV Ink/Cursor Blue Color 0 Register
+ {0x0087,0x00}, // CRT/TV Ink/Cursor Green Color 0 Register
+ {0x0088,0x00}, // CRT/TV Ink/Cursor Red Color 0 Register
+ {0x008A,0x1F}, // CRT/TV Ink/Cursor Blue Color 1 Register
+ {0x008B,0x3F}, // CRT/TV Ink/Cursor Green Color 1 Register
+ {0x008C,0x1F}, // CRT/TV Ink/Cursor Red Color 1 Register
+ {0x008E,0x00}, // CRT/TV Ink/Cursor FIFO Threshold Register
+ {0x0100,0x00}, // BitBlt Control Register 0
+ {0x0101,0x00}, // BitBlt Control Register 1
+ {0x0102,0x00}, // BitBlt ROP Code/Color Expansion Register
+ {0x0103,0x00}, // BitBlt Operation Register
+ {0x0104,0x00}, // BitBlt Source Start Address Register 0
+ {0x0105,0x00}, // BitBlt Source Start Address Register 1
+ {0x0106,0x00}, // BitBlt Source Start Address Register 2
+ {0x0108,0x00}, // BitBlt Destination Start Address Register 0
+ {0x0109,0x00}, // BitBlt Destination Start Address Register 1
+ {0x010A,0x00}, // BitBlt Destination Start Address Register 2
+ {0x010C,0x00}, // BitBlt Memory Address Offset Register 0
+ {0x010D,0x00}, // BitBlt Memory Address Offset Register 1
+ {0x0110,0x00}, // BitBlt Width Register 0
+ {0x0111,0x00}, // BitBlt Width Register 1
+ {0x0112,0x00}, // BitBlt Height Register 0
+ {0x0113,0x00}, // BitBlt Height Register 1
+ {0x0114,0x00}, // BitBlt Background Color Register 0
+ {0x0115,0x00}, // BitBlt Background Color Register 1
+ {0x0118,0x00}, // BitBlt Foreground Color Register 0
+ {0x0119,0x00}, // BitBlt Foreground Color Register 1
+ {0x01E0,0x00}, // Look-Up Table Mode Register
+ {0x01E2,0x00}, // Look-Up Table Address Register
+ {0x01F0,0x10}, // Power Save Configuration Register
+ {0x01F1,0x00}, // Power Save Status Register
+ {0x01F4,0x00}, // CPU-to-Memory Access Watchdog Timer Register
+#if (SWIVEL_VIEW == 0)
+ {0x01FC,0x01}, // Display Mode Register(0x01:LCD, 0x02:CRT, 0x03:LCD&CRT)
+#elif (SWIVEL_VIEW == 1)
+ {0x01FC,0x41}, // Display Mode Register(0x01:LCD, 0x02:CRT, 0x03:LCD&CRT)
+#else
+#error unsupported SWIVEL_VIEW mode
+#endif /* SWIVEL_VIEW */
+
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
+ {0x0008,0x07}, // LCD panel Vdd & Vg on
+#endif
+
+ {0x0040,0x05}, // LCD Display Mode Register (2:4bpp,3:8bpp,5:16bpp)
+#if defined(CONFIG_PLAT_MAPPI)
+ {0x0046,0x80}, // LCD Memory Address Offset Register 0
+ {0x0047,0x02}, // LCD Memory Address Offset Register 1
+#elif defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
+ {0x0046,0xf0}, // LCD Memory Address Offset Register 0
+ {0x0047,0x00}, // LCD Memory Address Offset Register 1
+#endif
+ {0x0060,0x05}, // CRT/TV Display Mode Register (2:4bpp,3:8bpp,5:16bpp)
+ {0x0066,0x80}, // CRT/TV Memory Address Offset Register 0 // takeo
+ {0x0067,0x02}, // CRT/TV Memory Address Offset Register 1
+};
diff --git a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h
index e8b79220b29..a7894e0fbbb 100644
--- a/include/asm-ppc/unistd.h
+++ b/include/asm-ppc/unistd.h
@@ -262,7 +262,7 @@
#define __NR_rtas 255
#define __NR_sys_debug_setcontext 256
/* Number 257 is reserved for vserver */
-/* Number 258 is reserved for new sys_remap_file_pages */
+/* 258 currently unused */
/* Number 259 is reserved for new sys_mbind */
/* Number 260 is reserved for new sys_get_mempolicy */
/* Number 261 is reserved for new sys_set_mempolicy */
diff --git a/include/asm-ppc64/cputable.h b/include/asm-ppc64/cputable.h
index cbbfbec78b6..d67fa9e2607 100644
--- a/include/asm-ppc64/cputable.h
+++ b/include/asm-ppc64/cputable.h
@@ -138,6 +138,7 @@ extern firmware_feature_t firmware_features_table[];
#define CPU_FTR_COHERENT_ICACHE ASM_CONST(0x0000020000000000)
#define CPU_FTR_LOCKLESS_TLBIE ASM_CONST(0x0000040000000000)
#define CPU_FTR_MMCRA_SIHV ASM_CONST(0x0000080000000000)
+#define CPU_FTR_CTRL ASM_CONST(0x0000100000000000)
/* Platform firmware features */
#define FW_FTR_ ASM_CONST(0x0000000000000001)
@@ -148,7 +149,7 @@ extern firmware_feature_t firmware_features_table[];
#define CPU_FTR_PPCAS_ARCH_V2_BASE (CPU_FTR_SLB | \
CPU_FTR_TLBIEL | CPU_FTR_NOEXECUTE | \
- CPU_FTR_NODSISRALIGN)
+ CPU_FTR_NODSISRALIGN | CPU_FTR_CTRL)
/* iSeries doesn't support large pages */
#ifdef CONFIG_PPC_ISERIES
diff --git a/include/asm-ppc64/hvconsole.h b/include/asm-ppc64/hvconsole.h
index d89d94c9181..6da93ce74dc 100644
--- a/include/asm-ppc64/hvconsole.h
+++ b/include/asm-ppc64/hvconsole.h
@@ -29,12 +29,21 @@
*/
#define MAX_NR_HVC_CONSOLES 16
+/* implemented by a low level driver */
+struct hv_ops {
+ int (*get_chars)(uint32_t vtermno, char *buf, int count);
+ int (*put_chars)(uint32_t vtermno, const char *buf, int count);
+};
extern int hvc_get_chars(uint32_t vtermno, char *buf, int count);
extern int hvc_put_chars(uint32_t vtermno, const char *buf, int count);
-/* Early discovery of console adapters. */
-extern int hvc_find_vtys(void);
+struct hvc_struct;
-/* Implemented by a console driver */
-extern int hvc_instantiate(uint32_t vtermno, int index);
+/* Register a vterm and a slot index for use as a console (console_init) */
+extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops);
+/* register a vterm for hvc tty operation (module_init or hotplug add) */
+extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq,
+ struct hv_ops *ops);
+/* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */
+extern int __devexit hvc_remove(struct hvc_struct *hp);
#endif /* _PPC64_HVCONSOLE_H */
diff --git a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h
index 9cdad3ed152..1e6ad482413 100644
--- a/include/asm-ppc64/machdep.h
+++ b/include/asm-ppc64/machdep.h
@@ -140,8 +140,13 @@ struct machdep_calls {
unsigned long size,
pgprot_t vma_prot);
+ /* Idle loop for this platform, leave empty for default idle loop */
+ int (*idle_loop)(void);
};
+extern int default_idle(void);
+extern int native_idle(void);
+
extern struct machdep_calls ppc_md;
extern char cmd_line[COMMAND_LINE_SIZE];
diff --git a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h
index af28aa55d8c..352306cfb57 100644
--- a/include/asm-ppc64/processor.h
+++ b/include/asm-ppc64/processor.h
@@ -20,6 +20,7 @@
#include <asm/ptrace.h>
#include <asm/types.h>
#include <asm/systemcfg.h>
+#include <asm/cputable.h>
/* Machine State Register (MSR) Fields */
#define MSR_SF_LG 63 /* Enable 64 bit mode */
@@ -501,24 +502,37 @@ static inline void ppc64_runlatch_on(void)
{
unsigned long ctrl;
- ctrl = mfspr(SPRN_CTRLF);
- ctrl |= CTRL_RUNLATCH;
- mtspr(SPRN_CTRLT, ctrl);
+ if (cpu_has_feature(CPU_FTR_CTRL)) {
+ ctrl = mfspr(SPRN_CTRLF);
+ ctrl |= CTRL_RUNLATCH;
+ mtspr(SPRN_CTRLT, ctrl);
+ }
}
static inline void ppc64_runlatch_off(void)
{
unsigned long ctrl;
- ctrl = mfspr(SPRN_CTRLF);
- ctrl &= ~CTRL_RUNLATCH;
- mtspr(SPRN_CTRLT, ctrl);
+ if (cpu_has_feature(CPU_FTR_CTRL)) {
+ ctrl = mfspr(SPRN_CTRLF);
+ ctrl &= ~CTRL_RUNLATCH;
+ mtspr(SPRN_CTRLT, ctrl);
+ }
}
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
+#ifdef __KERNEL__
+#define RUNLATCH_ON(REG) \
+BEGIN_FTR_SECTION \
+ mfspr (REG),SPRN_CTRLF; \
+ ori (REG),(REG),CTRL_RUNLATCH; \
+ mtspr SPRN_CTRLT,(REG); \
+END_FTR_SECTION_IFSET(CPU_FTR_CTRL)
+#endif
+
/*
* Number of entries in the SLB. If this ever changes we should handle
* it with a use a cpu feature fixup.
diff --git a/include/asm-ppc64/unistd.h b/include/asm-ppc64/unistd.h
index 605d91e011e..4a94acf6bfe 100644
--- a/include/asm-ppc64/unistd.h
+++ b/include/asm-ppc64/unistd.h
@@ -268,7 +268,7 @@
#define __NR_rtas 255
/* Number 256 is reserved for sys_debug_setcontext */
/* Number 257 is reserved for vserver */
-/* Number 258 is reserved for new sys_remap_file_pages */
+/* 258 currently unused */
#define __NR_mbind 259
#define __NR_get_mempolicy 260
#define __NR_set_mempolicy 261
@@ -283,8 +283,10 @@
#define __NR_request_key 270
#define __NR_keyctl 271
#define __NR_waitid 272
+#define __NR_ioprio_set 273
+#define __NR_ioprio_get 274
-#define __NR_syscalls 273
+#define __NR_syscalls 275
#ifdef __KERNEL__
#define NR_syscalls __NR_syscalls
#endif
diff --git a/include/asm-um/mmu_context.h b/include/asm-um/mmu_context.h
index 89bff310b7a..7529c9c853d 100644
--- a/include/asm-um/mmu_context.h
+++ b/include/asm-um/mmu_context.h
@@ -7,7 +7,9 @@
#define __UM_MMU_CONTEXT_H
#include "linux/sched.h"
+#include "linux/config.h"
#include "choose-mode.h"
+#include "um_mmu.h"
#define get_mmu_context(task) do ; while(0)
#define activate_context(tsk) do ; while(0)
@@ -18,8 +20,6 @@ static inline void activate_mm(struct mm_struct *old, struct mm_struct *new)
{
}
-extern void switch_mm_skas(int mm_fd);
-
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk)
{
@@ -30,7 +30,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
cpu_set(cpu, next->cpu_vm_mask);
if(next != &init_mm)
CHOOSE_MODE((void) 0,
- switch_mm_skas(next->context.skas.mm_fd));
+ switch_mm_skas(&next->context.skas.id));
}
}
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
index f2f073642d6..6c813eb521f 100644
--- a/include/asm-x86_64/proto.h
+++ b/include/asm-x86_64/proto.h
@@ -15,6 +15,13 @@ extern void pda_init(int);
extern void early_idt_handler(void);
extern void mcheck_init(struct cpuinfo_x86 *c);
+#ifdef CONFIG_MTRR
+extern void mtrr_ap_init(void);
+extern void mtrr_bp_init(void);
+#else
+#define mtrr_ap_init() do {} while (0)
+#define mtrr_bp_init() do {} while (0)
+#endif
extern void init_memory_mapping(unsigned long start, unsigned long end);
extern void system_call(void);
diff --git a/include/asm-xtensa/unistd.h b/include/asm-xtensa/unistd.h
index 64c64dd83ba..6b39d6609d9 100644
--- a/include/asm-xtensa/unistd.h
+++ b/include/asm-xtensa/unistd.h
@@ -13,42 +13,31 @@
#include <linux/linkage.h>
-//#define __NR_setup 0 /* used only by init, to get system going */
#define __NR_spill 0
#define __NR_exit 1
-#define __NR_fork 2
#define __NR_read 3
#define __NR_write 4
#define __NR_open 5
#define __NR_close 6
-#define __NR_waitpid 7
#define __NR_creat 8
#define __NR_link 9
#define __NR_unlink 10
#define __NR_execve 11
#define __NR_chdir 12
-#define __NR_time 13
#define __NR_mknod 14
#define __NR_chmod 15
#define __NR_lchown 16
#define __NR_break 17
-#define __NR_oldstat 18
#define __NR_lseek 19
#define __NR_getpid 20
#define __NR_mount 21
-#define __NR_oldumount 22
#define __NR_setuid 23
#define __NR_getuid 24
-#define __NR_stime 25
#define __NR_ptrace 26
-#define __NR_alarm 27
-#define __NR_oldfstat 28
-#define __NR_pause 29
#define __NR_utime 30
#define __NR_stty 31
#define __NR_gtty 32
#define __NR_access 33
-#define __NR_nice 34
#define __NR_ftime 35
#define __NR_sync 36
#define __NR_kill 37
@@ -66,24 +55,18 @@
#define __NR_geteuid 49
#define __NR_getegid 50
#define __NR_acct 51
-#define __NR_umount 52
#define __NR_lock 53
#define __NR_ioctl 54
#define __NR_fcntl 55
-#define __NR_mpx 56
#define __NR_setpgid 57
#define __NR_ulimit 58
-#define __NR_oldolduname 59
#define __NR_umask 60
#define __NR_chroot 61
#define __NR_ustat 62
#define __NR_dup2 63
#define __NR_getppid 64
-#define __NR_getpgrp 65
#define __NR_setsid 66
#define __NR_sigaction 67
-#define __NR_sgetmask 68
-#define __NR_ssetmask 69
#define __NR_setreuid 70
#define __NR_setregid 71
#define __NR_sigsuspend 72
@@ -98,13 +81,10 @@
#define __NR_setgroups 81
#define __NR_select 82
#define __NR_symlink 83
-#define __NR_oldlstat 84
#define __NR_readlink 85
#define __NR_uselib 86
#define __NR_swapon 87
#define __NR_reboot 88
-#define __NR_readdir 89
-#define __NR_mmap 90
#define __NR_munmap 91
#define __NR_truncate 92
#define __NR_ftruncate 93
@@ -116,22 +96,18 @@
#define __NR_statfs 99
#define __NR_fstatfs 100
#define __NR_ioperm 101
-#define __NR_socketcall 102
#define __NR_syslog 103
#define __NR_setitimer 104
#define __NR_getitimer 105
#define __NR_stat 106
#define __NR_lstat 107
#define __NR_fstat 108
-#define __NR_olduname 109
#define __NR_iopl 110
#define __NR_vhangup 111
#define __NR_idle 112
-#define __NR_vm86 113
#define __NR_wait4 114
#define __NR_swapoff 115
#define __NR_sysinfo 116
-#define __NR_ipc 117
#define __NR_fsync 118
#define __NR_sigreturn 119
#define __NR_clone 120
@@ -140,18 +116,15 @@
#define __NR_modify_ldt 123
#define __NR_adjtimex 124
#define __NR_mprotect 125
-#define __NR_sigprocmask 126
#define __NR_create_module 127
#define __NR_init_module 128
#define __NR_delete_module 129
-#define __NR_get_kernel_syms 130
#define __NR_quotactl 131
#define __NR_getpgid 132
#define __NR_fchdir 133
#define __NR_bdflush 134
#define __NR_sysfs 135
#define __NR_personality 136
-#define __NR_afs_syscall 137 /* Syscall for Andrew File System */
#define __NR_setfsuid 138
#define __NR_setfsgid 139
#define __NR__llseek 140
@@ -222,8 +195,6 @@
#define __NR_capset 205
#define __NR_sigaltstack 206
#define __NR_sendfile 207
-#define __NR_streams1 208 /* some people actually want it */
-#define __NR_streams2 209 /* some people actually want it */
#define __NR_mmap2 210
#define __NR_truncate64 211
#define __NR_ftruncate64 212
@@ -234,7 +205,6 @@
#define __NR_mincore 217
#define __NR_madvise 218
#define __NR_getdents64 219
-#define __NR_vfork 220
/* Keep this last; should always equal the last valid call number. */
#define __NR_Linux_syscalls 220
@@ -448,55 +418,7 @@ __syscall_return(type,__res); \
#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <linux/syscalls.h>
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-
-#define __NR__exit __NR_exit
-
-static __inline__ _syscall0(int,pause)
-//static __inline__ _syscall1(int,setup,int,magic) FIXME
-static __inline__ _syscall0(int,sync)
-static __inline__ _syscall0(pid_t,setsid)
-static __inline__ _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static __inline__ _syscall3(int,read,int,fd,char *,buf,off_t,count)
-static __inline__ _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
-static __inline__ _syscall1(int,dup,int,fd)
static __inline__ _syscall3(int,execve,const char*,file,char**,argv,char**,envp)
-static __inline__ _syscall3(int,open,const char *,file,int,flag,int,mode)
-static __inline__ _syscall1(int,close,int,fd)
-static __inline__ _syscall1(int,_exit,int,exitcode)
-static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-static __inline__ _syscall1(int,delete_module,const char *,name)
-
-struct stat;
-static __inline__ _syscall2(int,fstat,int,fd,struct stat *,buf)
-static __inline__ _syscall0(pid_t,getpid)
-static __inline__ _syscall2(int,kill,int,pid,int,sig)
-static __inline__ _syscall2(int,stat,const char *, path,struct stat *,buf)
-static __inline__ _syscall1(int,unlink,char *,pathname)
-
-
-
-extern pid_t waitpid(int, int*, int );
-static __inline__ pid_t wait(int * wait_stat)
-{
- return waitpid(-1,wait_stat,0);
-}
#endif
/*
@@ -508,30 +430,10 @@ static __inline__ pid_t wait(int * wait_stat)
#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
#ifdef __KERNEL__
-#define __ARCH_WANT_IPC_PARSE_VERSION
-#define __ARCH_WANT_OLD_READDIR
-#define __ARCH_WANT_OLD_STAT
#define __ARCH_WANT_STAT64
-#define __ARCH_WANT_SYS_ALARM
-#define __ARCH_WANT_SYS_GETHOSTNAME
-#define __ARCH_WANT_SYS_PAUSE
-#define __ARCH_WANT_SYS_SGETMASK
-#define __ARCH_WANT_SYS_SIGNAL
-#define __ARCH_WANT_SYS_TIME
#define __ARCH_WANT_SYS_UTIME
-#define __ARCH_WANT_SYS_WAITPID
-#define __ARCH_WANT_SYS_SOCKETCALL
-#define __ARCH_WANT_SYS_FADVISE64
-#define __ARCH_WANT_SYS_GETPGRP
#define __ARCH_WANT_SYS_LLSEEK
-#define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_SYS_OLD_GETRLIMIT
-#define __ARCH_WANT_SYS_OLDUMOUNT
-#define __ARCH_WANT_SYS_SIGPENDING
-#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
#endif
-
-
#endif /* _XTENSA_UNISTD_H */
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 802c91e9b3d..90828493791 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -19,6 +19,9 @@ enum bh_state_bits {
BH_Dirty, /* Is dirty */
BH_Lock, /* Is locked */
BH_Req, /* Has been submitted for I/O */
+ BH_Uptodate_Lock,/* Used by the first bh in a page, to serialise
+ * IO completion of other buffers in the page
+ */
BH_Mapped, /* Has a disk mapping */
BH_New, /* Disk mapping was newly created by get_block */
diff --git a/include/linux/cache.h b/include/linux/cache.h
index 4d767b93738..2b66a36d85f 100644
--- a/include/linux/cache.h
+++ b/include/linux/cache.h
@@ -13,6 +13,12 @@
#define SMP_CACHE_BYTES L1_CACHE_BYTES
#endif
+#ifdef CONFIG_X86
+#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#else
+#define __read_mostly
+#endif
+
#ifndef ____cacheline_aligned
#define ____cacheline_aligned __attribute__((__aligned__(SMP_CACHE_BYTES)))
#endif
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 927daa86c9b..ff7f80f48df 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -201,7 +201,7 @@ struct cpufreq_driver {
/* optional */
int (*exit) (struct cpufreq_policy *policy);
- int (*suspend) (struct cpufreq_policy *policy, u32 state);
+ int (*suspend) (struct cpufreq_policy *policy, pm_message_t pmsg);
int (*resume) (struct cpufreq_policy *policy);
struct freq_attr **attr;
};
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 047bde30836..302ec20838c 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1435,6 +1435,7 @@ extern struct inode * igrab(struct inode *);
extern ino_t iunique(struct super_block *, ino_t);
extern int inode_needs_sync(struct inode *inode);
extern void generic_delete_inode(struct inode *inode);
+extern void generic_drop_inode(struct inode *inode);
extern struct inode *ilookup5(struct super_block *sb, unsigned long hashval,
int (*test)(struct inode *, void *), void *data);
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 8d6bf608b19..7c7400137e9 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -12,8 +12,8 @@ struct vm_area_struct;
* GFP bitmasks..
*/
/* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low two bits) */
-#define __GFP_DMA 0x01
-#define __GFP_HIGHMEM 0x02
+#define __GFP_DMA 0x01u
+#define __GFP_HIGHMEM 0x02u
/*
* Action modifiers - doesn't change the zoning
diff --git a/include/linux/ioprio.h b/include/linux/ioprio.h
index 8a453a0b5e4..88d5961f7a3 100644
--- a/include/linux/ioprio.h
+++ b/include/linux/ioprio.h
@@ -34,9 +34,6 @@ enum {
*/
#define IOPRIO_BE_NR (8)
-asmlinkage int sys_ioprio_set(int, int, int);
-asmlinkage int sys_ioprio_get(int, int);
-
enum {
IOPRIO_WHO_PROCESS = 1,
IOPRIO_WHO_PGRP,
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 8b8d3b9beef..74b4727a4e3 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -34,7 +34,7 @@ struct vfsmount
int mnt_expiry_mark; /* true if marked for expiry */
char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
struct list_head mnt_list;
- struct list_head mnt_fslink; /* link in fs-specific expiry list */
+ struct list_head mnt_expire; /* link in fs-specific expiry list */
struct namespace *mnt_namespace; /* containing namespace */
};
@@ -47,7 +47,7 @@ static inline struct vfsmount *mntget(struct vfsmount *mnt)
extern void __mntput(struct vfsmount *mnt);
-static inline void _mntput(struct vfsmount *mnt)
+static inline void mntput_no_expire(struct vfsmount *mnt)
{
if (mnt) {
if (atomic_dec_and_test(&mnt->mnt_count))
@@ -59,7 +59,7 @@ static inline void mntput(struct vfsmount *mnt)
{
if (mnt) {
mnt->mnt_expiry_mark = 0;
- _mntput(mnt);
+ mntput_no_expire(mnt);
}
}
diff --git a/include/linux/namespace.h b/include/linux/namespace.h
index 697991b69f9..0e5a86f13b2 100644
--- a/include/linux/namespace.h
+++ b/include/linux/namespace.h
@@ -17,7 +17,8 @@ extern void __put_namespace(struct namespace *namespace);
static inline void put_namespace(struct namespace *namespace)
{
- if (atomic_dec_and_test(&namespace->count))
+ if (atomic_dec_and_lock(&namespace->count, &vfsmount_lock))
+ /* releases vfsmount_lock */
__put_namespace(namespace);
}
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 5791dfd30dd..6d5a24f3fc6 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -124,6 +124,7 @@ int nfsd_statfs(struct svc_rqst *, struct svc_fh *,
int nfsd_notify_change(struct inode *, struct iattr *);
int nfsd_permission(struct svc_export *, struct dentry *, int);
+void nfsd_sync_dir(struct dentry *dp);
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
#ifdef CONFIG_NFSD_V2_ACL
@@ -230,6 +231,7 @@ void nfsd_lockd_shutdown(void);
#define nfserr_reclaim_bad __constant_htonl(NFSERR_RECLAIM_BAD)
#define nfserr_badname __constant_htonl(NFSERR_BADNAME)
#define nfserr_cb_path_down __constant_htonl(NFSERR_CB_PATH_DOWN)
+#define nfserr_locked __constant_htonl(NFSERR_LOCKED)
/* error codes for internal use */
/* if a request fails due to kmalloc failure, it gets dropped.
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index a84a3fa99be..8bf23cf8b60 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -203,7 +203,9 @@ struct nfs4_stateowner {
int so_is_open_owner; /* 1=openowner,0=lockowner */
u32 so_id;
struct nfs4_client * so_client;
- u32 so_seqid;
+ /* after increment in ENCODE_SEQID_OP_TAIL, represents the next
+ * sequence id expected from the client: */
+ u32 so_seqid;
struct xdr_netobj so_owner; /* open owner name */
int so_confirmed; /* successful OPEN_CONFIRM? */
struct nfs4_replay so_replay;
@@ -235,6 +237,10 @@ struct nfs4_file {
* st_perlockowner: (open stateid) list of lock nfs4_stateowners
* st_access_bmap: used only for open stateid
* st_deny_bmap: used only for open stateid
+* st_openstp: open stateid lock stateid was derived from
+*
+* XXX: open stateids and lock stateids have diverged sufficiently that
+* we should consider defining separate structs for the two cases.
*/
struct nfs4_stateid {
@@ -248,6 +254,7 @@ struct nfs4_stateid {
struct file * st_vfs_file;
unsigned long st_access_bmap;
unsigned long st_deny_bmap;
+ struct nfs4_stateid * st_openstp;
};
/* flags for preprocess_seqid_op() */
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 76cf7e60216..4c8e552471b 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -65,7 +65,7 @@ extern void *kmem_cache_alloc(kmem_cache_t *, unsigned int __nocast);
extern void kmem_cache_free(kmem_cache_t *, void *);
extern unsigned int kmem_cache_size(kmem_cache_t *);
extern const char *kmem_cache_name(kmem_cache_t *);
-extern kmem_cache_t *kmem_find_general_cachep(size_t size, int gfpflags);
+extern kmem_cache_t *kmem_find_general_cachep(size_t size, unsigned int __nocast gfpflags);
/* Size description struct for general caches. */
struct cache_sizes {
@@ -105,7 +105,7 @@ extern unsigned int ksize(const void *);
#ifdef CONFIG_NUMA
extern void *kmem_cache_alloc_node(kmem_cache_t *, int flags, int node);
-extern void *kmalloc_node(size_t size, int flags, int node);
+extern void *kmalloc_node(size_t size, unsigned int __nocast flags, int node);
#else
static inline void *kmem_cache_alloc_node(kmem_cache_t *cachep, int flags, int node)
{
diff --git a/include/linux/string.h b/include/linux/string.h
index 93994c61309..dab2652acbd 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -88,7 +88,7 @@ extern int memcmp(const void *,const void *,__kernel_size_t);
extern void * memchr(const void *,int,__kernel_size_t);
#endif
-extern char *kstrdup(const char *s, int gfp);
+extern char *kstrdup(const char *s, unsigned int __nocast gfp);
#ifdef __cplusplus
}
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 2343f999e6e..c75954f2d86 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -148,7 +148,7 @@ struct swap_list_t {
#define vm_swap_full() (nr_swap_pages*2 < total_swap_pages)
/* linux/mm/oom_kill.c */
-extern void out_of_memory(unsigned int __nocast gfp_mask);
+extern void out_of_memory(unsigned int __nocast gfp_mask, int order);
/* linux/mm/memory.c */
extern void swapin_readahead(swp_entry_t, unsigned long, struct vm_area_struct *);
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 52830b6d94e..425f58c8ea4 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -506,4 +506,7 @@ asmlinkage long sys_request_key(const char __user *_type,
asmlinkage long sys_keyctl(int cmd, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5);
+asmlinkage long sys_ioprio_set(int which, int who, int ioprio);
+asmlinkage long sys_ioprio_get(int which, int who);
+
#endif
diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h
index b42ddc0c114..2cab39f49eb 100644
--- a/include/pcmcia/cs.h
+++ b/include/pcmcia/cs.h
@@ -68,21 +68,9 @@ typedef struct adjust_t {
#define RES_ALLOCATED 0x20
#define RES_REMOVED 0x40
-typedef struct servinfo_t {
- char Signature[2];
- u_int Count;
- u_int Revision;
- u_int CSLevel;
- char *VendorString;
-} servinfo_t;
-
typedef struct event_callback_args_t {
- client_handle_t client_handle;
- void *info;
- void *mtdrequest;
- void *buffer;
- void *misc;
- void *client_data;
+ struct pcmcia_device *client_handle;
+ void *client_data;
} event_callback_args_t;
/* for GetConfigurationInfo */
@@ -393,25 +381,25 @@ enum service {
struct pcmcia_socket;
-int pcmcia_access_configuration_register(client_handle_t handle, conf_reg_t *reg);
-int pcmcia_deregister_client(client_handle_t handle);
-int pcmcia_get_configuration_info(client_handle_t handle, config_info_t *config);
+int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, conf_reg_t *reg);
+int pcmcia_deregister_client(struct pcmcia_device *p_dev);
+int pcmcia_get_configuration_info(struct pcmcia_device *p_dev, config_info_t *config);
int pcmcia_get_first_window(window_handle_t *win, win_req_t *req);
int pcmcia_get_next_window(window_handle_t *win, win_req_t *req);
-int pcmcia_get_status(client_handle_t handle, cs_status_t *status);
+int pcmcia_get_status(struct pcmcia_device *p_dev, cs_status_t *status);
int pcmcia_get_mem_page(window_handle_t win, memreq_t *req);
int pcmcia_map_mem_page(window_handle_t win, memreq_t *req);
-int pcmcia_modify_configuration(client_handle_t handle, modconf_t *mod);
+int pcmcia_modify_configuration(struct pcmcia_device *p_dev, modconf_t *mod);
int pcmcia_register_client(client_handle_t *handle, client_reg_t *req);
-int pcmcia_release_configuration(client_handle_t handle);
-int pcmcia_release_io(client_handle_t handle, io_req_t *req);
-int pcmcia_release_irq(client_handle_t handle, irq_req_t *req);
+int pcmcia_release_configuration(struct pcmcia_device *p_dev);
+int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req);
+int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req);
int pcmcia_release_window(window_handle_t win);
-int pcmcia_request_configuration(client_handle_t handle, config_req_t *req);
-int pcmcia_request_io(client_handle_t handle, io_req_t *req);
-int pcmcia_request_irq(client_handle_t handle, irq_req_t *req);
-int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle_t *wh);
-int pcmcia_reset_card(client_handle_t handle, client_req_t *req);
+int pcmcia_request_configuration(struct pcmcia_device *p_dev, config_req_t *req);
+int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req);
+int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req);
+int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_handle_t *wh);
+int pcmcia_reset_card(struct pcmcia_device *p_dev, client_req_t *req);
int pcmcia_suspend_card(struct pcmcia_socket *skt);
int pcmcia_resume_card(struct pcmcia_socket *skt);
int pcmcia_eject_card(struct pcmcia_socket *skt);
diff --git a/include/pcmcia/cs_types.h b/include/pcmcia/cs_types.h
index 7881d40aac8..c1d1629fcd2 100644
--- a/include/pcmcia/cs_types.h
+++ b/include/pcmcia/cs_types.h
@@ -34,8 +34,8 @@ typedef u_int event_t;
typedef u_char cisdata_t;
typedef u_short page_t;
-struct client_t;
-typedef struct client_t *client_handle_t;
+struct pcmcia_device;
+typedef struct pcmcia_device *client_handle_t;
struct window_t;
typedef struct window_t *window_handle_t;
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h
index 2b52553f2d9..0190e766e1a 100644
--- a/include/pcmcia/ds.h
+++ b/include/pcmcia/ds.h
@@ -49,7 +49,6 @@ typedef struct mtd_info_t {
} mtd_info_t;
typedef union ds_ioctl_arg_t {
- servinfo_t servinfo;
adjust_t adjust;
config_info_t config;
tuple_t tuple;
@@ -65,7 +64,6 @@ typedef union ds_ioctl_arg_t {
cisdump_t cisdump;
} ds_ioctl_arg_t;
-#define DS_GET_CARD_SERVICES_INFO _IOR ('d', 1, servinfo_t)
#define DS_ADJUST_RESOURCE_INFO _IOWR('d', 2, adjust_t)
#define DS_GET_CONFIGURATION_INFO _IOWR('d', 3, config_info_t)
#define DS_GET_FIRST_TUPLE _IOWR('d', 4, tuple_t)
@@ -133,6 +131,8 @@ struct pcmcia_socket;
struct pcmcia_driver {
dev_link_t *(*attach)(void);
+ int (*event) (event_t event, int priority,
+ event_callback_args_t *);
void (*detach)(dev_link_t *);
struct module *owner;
struct pcmcia_device_id *id_table;
@@ -159,16 +159,8 @@ struct pcmcia_device {
/* deprecated, a cleaned up version will be moved into this
struct soon */
dev_link_t *instance;
- struct client_t {
- u_short client_magic;
- struct pcmcia_socket *Socket;
- u_char Function;
- u_int state;
- event_t EventMask;
- int (*event_handler) (event_t event, int priority,
- event_callback_args_t *);
- event_callback_args_t event_callback_args;
- } client;
+ event_callback_args_t event_callback_args;
+ u_int state;
/* information about this device */
u8 has_manf_id:1;
@@ -193,8 +185,8 @@ struct pcmcia_device {
#define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev)
#define to_pcmcia_drv(n) container_of(n, struct pcmcia_driver, drv)
-#define handle_to_pdev(handle) container_of(handle, struct pcmcia_device, client);
-#define handle_to_dev(handle) ((container_of(handle, struct pcmcia_device, client))->dev)
+#define handle_to_pdev(handle) (handle)
+#define handle_to_dev(handle) (handle->dev)
/* error reporting */
void cs_error(client_handle_t handle, int func, int ret);
diff --git a/include/pcmcia/version.h b/include/pcmcia/version.h
index eb88263fc8d..5ad9c5e198b 100644
--- a/include/pcmcia/version.h
+++ b/include/pcmcia/version.h
@@ -1,4 +1,3 @@
/* version.h 1.94 2000/10/03 17:55:48 (David Hinds) */
-#define CS_RELEASE "3.1.22"
-#define CS_RELEASE_CODE 0x3116
+/* This file will be removed, please don't include it */
diff --git a/ipc/compat.c b/ipc/compat.c
index 70e4e4e10fd..3881d564c66 100644
--- a/ipc/compat.c
+++ b/ipc/compat.c
@@ -572,6 +572,7 @@ static inline int put_compat_shminfo(struct shminfo64 *smi,
err |= __put_user(smi->shmmni, &up->shmmni);
err |= __put_user(smi->shmseg, &up->shmseg);
err |= __put_user(smi->shmall, &up->shmall);
+ return err;
}
static inline int put_compat_shm_info(struct shm_info __user *ip,
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index fb8de63c291..c51a4d96d4e 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -234,6 +234,16 @@ static int software_resume(void)
{
int error;
+ if (!swsusp_resume_device) {
+ if (!strlen(resume_file))
+ return -ENOENT;
+ swsusp_resume_device = name_to_dev_t(resume_file);
+ pr_debug("swsusp: Resume From Partition %s\n", resume_file);
+ } else {
+ pr_debug("swsusp: Resume From Partition %d:%d\n",
+ MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
+ }
+
if (noresume) {
/**
* FIXME: If noresume is specified, we need to find the partition
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 0a086640bcf..3bd0d261818 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -59,6 +59,7 @@ int freeze_processes(void)
int todo;
unsigned long start_time;
struct task_struct *g, *p;
+ unsigned long flags;
printk( "Stopping tasks: " );
start_time = jiffies;
@@ -66,12 +67,9 @@ int freeze_processes(void)
todo = 0;
read_lock(&tasklist_lock);
do_each_thread(g, p) {
- unsigned long flags;
if (!freezeable(p))
continue;
- if ((frozen(p)) ||
- (p->state == TASK_TRACED) ||
- (p->state == TASK_STOPPED))
+ if (frozen(p))
continue;
freeze(p);
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index c285fc5a232..7d7801cd01f 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -869,13 +869,6 @@ extern asmlinkage int swsusp_arch_resume(void);
asmlinkage int swsusp_save(void)
{
- int error = 0;
-
- if ((error = swsusp_swap_check())) {
- printk(KERN_ERR "swsusp: FATAL: cannot find swap device, try "
- "swapon -a!\n");
- return error;
- }
return suspend_prepare_image();
}
@@ -892,14 +885,20 @@ int swsusp_suspend(void)
* at resume time, and evil weirdness ensues.
*/
if ((error = device_power_down(PMSG_FREEZE))) {
- printk(KERN_ERR "Some devices failed to power down, aborting suspend\n");
local_irq_enable();
- swsusp_free();
return error;
}
+
+ if ((error = swsusp_swap_check())) {
+ printk(KERN_ERR "swsusp: FATAL: cannot find swap device, try "
+ "swapon -a!\n");
+ local_irq_enable();
+ return error;
+ }
+
save_processor_state();
if ((error = swsusp_arch_suspend()))
- swsusp_free();
+ printk("Error %d suspending\n", error);
/* Restore control flow magically appears here */
restore_processor_state();
BUG_ON (nr_copy_pages_check != nr_copy_pages);
@@ -1166,9 +1165,9 @@ static int bio_write_page(pgoff_t page_off, void * page)
static const char * sanity_check(void)
{
dump_info();
- if(swsusp_info.version_code != LINUX_VERSION_CODE)
+ if (swsusp_info.version_code != LINUX_VERSION_CODE)
return "kernel version";
- if(swsusp_info.num_physpages != num_physpages)
+ if (swsusp_info.num_physpages != num_physpages)
return "memory size";
if (strcmp(swsusp_info.uts.sysname,system_utsname.sysname))
return "system type";
@@ -1356,16 +1355,6 @@ int swsusp_check(void)
{
int error;
- if (!swsusp_resume_device) {
- if (!strlen(resume_file))
- return -ENOENT;
- swsusp_resume_device = name_to_dev_t(resume_file);
- pr_debug("swsusp: Resume From Partition %s\n", resume_file);
- } else {
- pr_debug("swsusp: Resume From Partition %d:%d\n",
- MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
- }
-
resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
if (!IS_ERR(resume_bdev)) {
set_blocksize(resume_bdev, PAGE_SIZE);
diff --git a/kernel/profile.c b/kernel/profile.c
index ad8cbb75ffa..f89248e6d70 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -35,11 +35,11 @@ struct profile_hit {
#define NR_PROFILE_GRP (NR_PROFILE_HIT/PROFILE_GRPSZ)
/* Oprofile timer tick hook */
-int (*timer_hook)(struct pt_regs *);
+int (*timer_hook)(struct pt_regs *) __read_mostly;
static atomic_t *prof_buffer;
static unsigned long prof_len, prof_shift;
-static int prof_on;
+static int prof_on __read_mostly;
static cpumask_t prof_cpu_mask = CPU_MASK_ALL;
#ifdef CONFIG_SMP
static DEFINE_PER_CPU(struct profile_hit *[2], cpu_profile_hits);
diff --git a/kernel/sched.c b/kernel/sched.c
index 5f2182d4224..4107db0dc09 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -3877,6 +3877,13 @@ asmlinkage long sys_sched_yield(void)
static inline void __cond_resched(void)
{
+ /*
+ * The BKS might be reacquired before we have dropped
+ * PREEMPT_ACTIVE, which could trigger a second
+ * cond_resched() call.
+ */
+ if (unlikely(preempt_count()))
+ return;
do {
add_preempt_count(PREEMPT_ACTIVE);
schedule();
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 04d664377f2..10bed1c8c3c 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -58,7 +58,7 @@ struct radix_tree_path {
#define RADIX_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long))
#define RADIX_TREE_MAX_PATH (RADIX_TREE_INDEX_BITS/RADIX_TREE_MAP_SHIFT + 2)
-static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH];
+static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH] __read_mostly;
/*
* Radix tree node cache.
diff --git a/mm/mempool.c b/mm/mempool.c
index 9a72f7d918f..65f2957b8d5 100644
--- a/mm/mempool.c
+++ b/mm/mempool.c
@@ -205,7 +205,7 @@ void * mempool_alloc(mempool_t *pool, unsigned int __nocast gfp_mask)
void *element;
unsigned long flags;
wait_queue_t wait;
- int gfp_temp;
+ unsigned int gfp_temp;
might_sleep_if(gfp_mask & __GFP_WAIT);
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 59666d905f1..1e56076672f 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -253,14 +253,16 @@ static struct mm_struct *oom_kill_process(struct task_struct *p)
* OR try to be smart about which process to kill. Note that we
* don't have to be perfect here, we just have to be good.
*/
-void out_of_memory(unsigned int __nocast gfp_mask)
+void out_of_memory(unsigned int __nocast gfp_mask, int order)
{
struct mm_struct *mm = NULL;
task_t * p;
- printk("oom-killer: gfp_mask=0x%x\n", gfp_mask);
- /* print memory stats */
- show_mem();
+ if (printk_ratelimit()) {
+ printk("oom-killer: gfp_mask=0x%x, order=%d\n",
+ gfp_mask, order);
+ show_mem();
+ }
read_lock(&tasklist_lock);
retry:
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 3c9f7f88112..1d6ba6a4b59 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -897,12 +897,6 @@ rebalance:
cond_resched();
if (likely(did_some_progress)) {
- /*
- * Go through the zonelist yet one more time, keep
- * very high watermark here, this is only to catch
- * a parallel oom killing, we must fail if we're still
- * under heavy pressure.
- */
for (i = 0; (z = zones[i]) != NULL; i++) {
if (!zone_watermark_ok(z, order, z->pages_min,
classzone_idx, can_try_harder,
@@ -936,7 +930,7 @@ rebalance:
goto got_pg;
}
- out_of_memory(gfp_mask);
+ out_of_memory(gfp_mask, order);
goto restart;
}
diff --git a/mm/slab.c b/mm/slab.c
index e57abd45eed..c9e706db463 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -584,7 +584,8 @@ static inline struct array_cache *ac_data(kmem_cache_t *cachep)
return cachep->array[smp_processor_id()];
}
-static inline kmem_cache_t *__find_general_cachep(size_t size, int gfpflags)
+static inline kmem_cache_t *__find_general_cachep(size_t size,
+ unsigned int __nocast gfpflags)
{
struct cache_sizes *csizep = malloc_sizes;
@@ -608,7 +609,8 @@ static inline kmem_cache_t *__find_general_cachep(size_t size, int gfpflags)
return csizep->cs_cachep;
}
-kmem_cache_t *kmem_find_general_cachep(size_t size, int gfpflags)
+kmem_cache_t *kmem_find_general_cachep(size_t size,
+ unsigned int __nocast gfpflags)
{
return __find_general_cachep(size, gfpflags);
}
@@ -2100,7 +2102,7 @@ cache_alloc_debugcheck_before(kmem_cache_t *cachep, unsigned int __nocast flags)
#if DEBUG
static void *
cache_alloc_debugcheck_after(kmem_cache_t *cachep,
- unsigned long flags, void *objp, void *caller)
+ unsigned int __nocast flags, void *objp, void *caller)
{
if (!objp)
return objp;
@@ -2442,7 +2444,7 @@ got_slabp:
}
EXPORT_SYMBOL(kmem_cache_alloc_node);
-void *kmalloc_node(size_t size, int flags, int node)
+void *kmalloc_node(size_t size, unsigned int __nocast flags, int node)
{
kmem_cache_t *cachep;
@@ -3094,7 +3096,7 @@ unsigned int ksize(const void *objp)
* @s: the string to duplicate
* @gfp: the GFP mask used in the kmalloc() call when allocating memory
*/
-char *kstrdup(const char *s, int gfp)
+char *kstrdup(const char *s, unsigned int __nocast gfp)
{
size_t len;
char *buf;
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 269f217918a..3c654e06b08 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -145,8 +145,6 @@ __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
if (test_and_set_bit(XPRT_LOCKED, &xprt->sockstate)) {
if (task == xprt->snd_task)
return 1;
- if (task == NULL)
- return 0;
goto out_sleep;
}
if (xprt->nocong || __xprt_get_cong(xprt, task)) {
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 90a551e4da6..a1f6bac647a 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -129,7 +129,7 @@ static int keyring_duplicate(struct key *keyring, const struct key *source)
int loop, ret;
const unsigned limit =
- (PAGE_SIZE - sizeof(*klist)) / sizeof(struct key);
+ (PAGE_SIZE - sizeof(*klist)) / sizeof(struct key *);
ret = 0;
@@ -150,7 +150,7 @@ static int keyring_duplicate(struct key *keyring, const struct key *source)
max = limit;
ret = -ENOMEM;
- size = sizeof(*klist) + sizeof(struct key) * max;
+ size = sizeof(*klist) + sizeof(struct key *) * max;
klist = kmalloc(size, GFP_KERNEL);
if (!klist)
goto error;
@@ -163,7 +163,7 @@ static int keyring_duplicate(struct key *keyring, const struct key *source)
klist->nkeys = sklist->nkeys;
memcpy(klist->keys,
sklist->keys,
- sklist->nkeys * sizeof(struct key));
+ sklist->nkeys * sizeof(struct key *));
for (loop = klist->nkeys - 1; loop >= 0; loop--)
atomic_inc(&klist->keys[loop]->usage);
@@ -783,7 +783,7 @@ int __key_link(struct key *keyring, struct key *key)
ret = -ENFILE;
if (max > 65535)
goto error3;
- size = sizeof(*klist) + sizeof(*key) * max;
+ size = sizeof(*klist) + sizeof(struct key *) * max;
if (size > PAGE_SIZE)
goto error3;
@@ -895,7 +895,8 @@ int key_unlink(struct key *keyring, struct key *key)
key_is_present:
/* we need to copy the key list for RCU purposes */
- nklist = kmalloc(sizeof(*klist) + sizeof(*key) * klist->maxkeys,
+ nklist = kmalloc(sizeof(*klist) +
+ sizeof(struct key *) * klist->maxkeys,
GFP_KERNEL);
if (!nklist)
goto nomem;
@@ -905,12 +906,12 @@ key_is_present:
if (loop > 0)
memcpy(&nklist->keys[0],
&klist->keys[0],
- loop * sizeof(klist->keys[0]));
+ loop * sizeof(struct key *));
if (loop < nklist->nkeys)
memcpy(&nklist->keys[loop],
&klist->keys[loop + 1],
- (nklist->nkeys - loop) * sizeof(klist->keys[0]));
+ (nklist->nkeys - loop) * sizeof(struct key *));
/* adjust the user's quota */
key_payload_reserve(keyring,
diff --git a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c
index 9e42a1a67ca..cb998e8c0fd 100644
--- a/sound/oss/cs46xx.c
+++ b/sound/oss/cs46xx.c
@@ -4174,7 +4174,7 @@ static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int
list_for_each(entry, &cs46xx_devs)
{
card = list_entry(entry, struct cs_card, list);
- cs46xx_suspend(card, 0);
+ cs46xx_suspend(card, PMSG_ON);
}
}
@@ -5749,7 +5749,7 @@ static int cs46xx_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
case PM_SUSPEND:
CS_DBGOUT(CS_PM, 2, printk(KERN_INFO
"cs46xx: PM suspend request\n"));
- if(cs46xx_suspend(card, 0))
+ if(cs46xx_suspend(card, PMSG_SUSPEND))
{
CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
"cs46xx: PM suspend request refused\n"));
@@ -5779,7 +5779,7 @@ static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state)
struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
CS_DBGOUT(CS_PM | CS_FUNCTION, 2,
printk(KERN_INFO "cs46xx: cs46xx_suspend_tbl request\n"));
- cs46xx_suspend(s, 0);
+ cs46xx_suspend(s, state);
return 0;
}
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
index 2d4f8e28478..d6918b453f2 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c
@@ -22,7 +22,6 @@
#include <sound/core.h>
#include <linux/slab.h>
#include <linux/moduleparam.h>
-#include <pcmcia/version.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/cisreg.h>
#include "pdaudiocf.h"
@@ -171,14 +170,6 @@ static dev_link_t *snd_pdacf_attach(void)
/* Register with Card Services */
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL
-#ifdef CONFIG_PM
- | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET
- | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME
-#endif
- ;
- client_reg.event_handler = &pdacf_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -387,12 +378,13 @@ static struct pcmcia_device_id snd_pdacf_ids[] = {
MODULE_DEVICE_TABLE(pcmcia, snd_pdacf_ids);
static struct pcmcia_driver pdacf_cs_driver = {
- .owner = THIS_MODULE,
- .drv = {
- .name = "snd-pdaudiocf",
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "snd-pdaudiocf",
},
- .attach = snd_pdacf_attach,
- .detach = snd_pdacf_detach,
+ .attach = snd_pdacf_attach,
+ .event = pdacf_event,
+ .detach = snd_pdacf_detach,
.id_table = snd_pdacf_ids,
};
diff --git a/sound/pcmcia/vx/vx_entry.c b/sound/pcmcia/vx/vx_entry.c
index 332bbca3dfc..df7a39ba968 100644
--- a/sound/pcmcia/vx/vx_entry.c
+++ b/sound/pcmcia/vx/vx_entry.c
@@ -35,7 +35,6 @@ MODULE_LICENSE("GPL");
* prototypes
*/
static void vxpocket_config(dev_link_t *link);
-static int vxpocket_event(event_t event, int priority, event_callback_args_t *args);
static void vxpocket_release(dev_link_t *link)
@@ -169,14 +168,6 @@ dev_link_t *snd_vxpocket_attach(struct snd_vxp_entry *hw)
/* Register with Card Services */
memset(&client_reg, 0, sizeof(client_reg));
client_reg.dev_info = hw->dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL
-#ifdef CONFIG_PM
- | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET
- | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME
-#endif
- ;
- client_reg.event_handler = &vxpocket_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -321,7 +312,7 @@ failed:
/*
* event callback
*/
-static int vxpocket_event(event_t event, int priority, event_callback_args_t *args)
+int vxpocket_event(event_t event, int priority, event_callback_args_t *args)
{
dev_link_t *link = args->client_data;
vx_core_t *chip = link->priv;
@@ -380,4 +371,5 @@ static int vxpocket_event(event_t event, int priority, event_callback_args_t *ar
*/
EXPORT_SYMBOL(snd_vxpocket_ops);
EXPORT_SYMBOL(snd_vxpocket_attach);
+EXPORT_SYMBOL(vxpocket_event);
EXPORT_SYMBOL(snd_vxpocket_detach);
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index 5f4c1326415..62d6fa12814 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <sound/core.h>
-#include <pcmcia/version.h>
#include "vxpocket.h"
#include <sound/initval.h>