summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/dvb/avermedia.txt3
-rw-r--r--Documentation/dvb/get_dvb_firmware23
-rw-r--r--Documentation/dvb/ttusb-dec.txt3
-rw-r--r--Documentation/fb/cyblafb/bugs1
-rw-r--r--Documentation/fb/cyblafb/fb.modes57
-rw-r--r--Documentation/fb/cyblafb/performance1
-rw-r--r--Documentation/fb/cyblafb/todo5
-rw-r--r--Documentation/fb/cyblafb/usage33
-rw-r--r--Documentation/fb/cyblafb/whatsnew29
-rw-r--r--Documentation/filesystems/spufs.txt521
-rw-r--r--Documentation/kernel-parameters.txt2
-rw-r--r--Documentation/kprobes.txt3
-rw-r--r--Documentation/networking/bonding.txt2
-rw-r--r--Documentation/powerpc/00-INDEX10
-rw-r--r--Documentation/video4linux/CARDLIST.bttv1
-rw-r--r--Documentation/video4linux/CARDLIST.cx8810
-rw-r--r--Documentation/video4linux/CARDLIST.saa71345
-rw-r--r--Documentation/video4linux/CARDLIST.tuner6
-rw-r--r--MAINTAINERS1
-rw-r--r--arch/mips/kernel/vpe.c3
-rw-r--r--arch/powerpc/Kconfig30
-rw-r--r--arch/powerpc/Makefile2
-rw-r--r--arch/powerpc/boot/Makefile30
-rw-r--r--arch/powerpc/configs/pmac32_defconfig1729
-rw-r--r--arch/powerpc/kernel/Makefile22
-rw-r--r--arch/powerpc/kernel/asm-offsets.c6
-rw-r--r--arch/powerpc/kernel/btext.c136
-rw-r--r--arch/powerpc/kernel/cputable.c106
-rw-r--r--arch/powerpc/kernel/crash.c264
-rw-r--r--arch/powerpc/kernel/crash_dump.c109
-rw-r--r--arch/powerpc/kernel/dma_64.c9
-rw-r--r--arch/powerpc/kernel/entry_32.S167
-rw-r--r--arch/powerpc/kernel/entry_64.S218
-rw-r--r--arch/powerpc/kernel/head_32.S56
-rw-r--r--arch/powerpc/kernel/head_64.S41
-rw-r--r--arch/powerpc/kernel/ibmebus.c396
-rw-r--r--arch/powerpc/kernel/irq.c81
-rw-r--r--arch/powerpc/kernel/legacy_serial.c557
-rw-r--r--arch/powerpc/kernel/lparmap.c12
-rw-r--r--arch/powerpc/kernel/machine_kexec.c67
-rw-r--r--arch/powerpc/kernel/machine_kexec_32.c65
-rw-r--r--arch/powerpc/kernel/machine_kexec_64.c43
-rw-r--r--arch/powerpc/kernel/misc_32.S113
-rw-r--r--arch/powerpc/kernel/nvram_64.c106
-rw-r--r--arch/powerpc/kernel/paca.c11
-rw-r--r--arch/powerpc/kernel/pci_64.c87
-rw-r--r--arch/powerpc/kernel/pmc.c5
-rw-r--r--arch/powerpc/kernel/ppc_ksyms.c5
-rw-r--r--arch/powerpc/kernel/prom.c468
-rw-r--r--arch/powerpc/kernel/prom_init.c60
-rw-r--r--arch/powerpc/kernel/prom_parse.c547
-rw-r--r--arch/powerpc/kernel/rtas_pci.c49
-rw-r--r--arch/powerpc/kernel/setup-common.c129
-rw-r--r--arch/powerpc/kernel/setup_32.c34
-rw-r--r--arch/powerpc/kernel/setup_64.c207
-rw-r--r--arch/powerpc/kernel/signal_32.c68
-rw-r--r--arch/powerpc/kernel/signal_64.c23
-rw-r--r--arch/powerpc/kernel/smp.c29
-rw-r--r--arch/powerpc/kernel/syscalls.c28
-rw-r--r--arch/powerpc/kernel/systbl.S14
-rw-r--r--arch/powerpc/kernel/time.c4
-rw-r--r--arch/powerpc/kernel/traps.c25
-rw-r--r--arch/powerpc/kernel/udbg.c27
-rw-r--r--arch/powerpc/kernel/udbg_16550.c69
-rw-r--r--arch/powerpc/mm/fault.c7
-rw-r--r--arch/powerpc/mm/hash_utils_64.c7
-rw-r--r--arch/powerpc/mm/hugetlbpage.c42
-rw-r--r--arch/powerpc/mm/imalloc.c2
-rw-r--r--arch/powerpc/mm/init_32.c5
-rw-r--r--arch/powerpc/mm/mem.c13
-rw-r--r--arch/powerpc/mm/numa.c139
-rw-r--r--arch/powerpc/mm/slb.c16
-rw-r--r--arch/powerpc/mm/slb_low.S6
-rw-r--r--arch/powerpc/mm/stab.c16
-rw-r--r--arch/powerpc/mm/tlb_64.c2
-rw-r--r--arch/powerpc/oprofile/Makefile1
-rw-r--r--arch/powerpc/oprofile/common.c83
-rw-r--r--arch/powerpc/oprofile/op_model_7450.c206
-rw-r--r--arch/powerpc/oprofile/op_model_power4.c4
-rw-r--r--arch/powerpc/oprofile/op_model_rs64.c3
-rw-r--r--arch/powerpc/platforms/cell/Kconfig13
-rw-r--r--arch/powerpc/platforms/cell/Makefile8
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c42
-rw-r--r--arch/powerpc/platforms/cell/interrupt.h1
-rw-r--r--arch/powerpc/platforms/cell/iommu.c225
-rw-r--r--arch/powerpc/platforms/cell/pervasive.c229
-rw-r--r--arch/powerpc/platforms/cell/pervasive.h62
-rw-r--r--arch/powerpc/platforms/cell/setup.c93
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c711
-rw-r--r--arch/powerpc/platforms/cell/spu_priv1.c133
-rw-r--r--arch/powerpc/platforms/cell/spu_syscalls.c88
-rw-r--r--arch/powerpc/platforms/cell/spufs/Makefile54
-rw-r--r--arch/powerpc/platforms/cell/spufs/backing_ops.c308
-rw-r--r--arch/powerpc/platforms/cell/spufs/context.c167
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c794
-rw-r--r--arch/powerpc/platforms/cell/spufs/hw_ops.c255
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c486
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c131
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c461
-rw-r--r--arch/powerpc/platforms/cell/spufs/spu_restore.c336
-rw-r--r--arch/powerpc/platforms/cell/spufs/spu_restore_crt0.S116
-rw-r--r--arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped231
-rw-r--r--arch/powerpc/platforms/cell/spufs/spu_save.c195
-rw-r--r--arch/powerpc/platforms/cell/spufs/spu_save_crt0.S102
-rw-r--r--arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped191
-rw-r--r--arch/powerpc/platforms/cell/spufs/spu_utils.h160
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h163
-rw-r--r--arch/powerpc/platforms/cell/spufs/switch.c2180
-rw-r--r--arch/powerpc/platforms/cell/spufs/syscalls.c101
-rw-r--r--arch/powerpc/platforms/chrp/setup.c16
-rw-r--r--arch/powerpc/platforms/iseries/irq.c337
-rw-r--r--arch/powerpc/platforms/iseries/irq.h1
-rw-r--r--arch/powerpc/platforms/iseries/lpardata.c7
-rw-r--r--arch/powerpc/platforms/iseries/setup.c10
-rw-r--r--arch/powerpc/platforms/maple/setup.c24
-rw-r--r--arch/powerpc/platforms/powermac/Makefile7
-rw-r--r--arch/powerpc/platforms/powermac/bootx_init.c547
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_64.c496
-rw-r--r--arch/powerpc/platforms/powermac/feature.c367
-rw-r--r--arch/powerpc/platforms/powermac/low_i2c.c1414
-rw-r--r--arch/powerpc/platforms/powermac/nvram.c53
-rw-r--r--arch/powerpc/platforms/powermac/pci.c299
-rw-r--r--arch/powerpc/platforms/powermac/pfunc_base.c405
-rw-r--r--arch/powerpc/platforms/powermac/pfunc_core.c989
-rw-r--r--arch/powerpc/platforms/powermac/pic.c474
-rw-r--r--arch/powerpc/platforms/powermac/pmac.h6
-rw-r--r--arch/powerpc/platforms/powermac/setup.c107
-rw-r--r--arch/powerpc/platforms/powermac/smp.c382
-rw-r--r--arch/powerpc/platforms/powermac/time.c15
-rw-r--r--arch/powerpc/platforms/powermac/udbg_adb.c221
-rw-r--r--arch/powerpc/platforms/powermac/udbg_scc.c (renamed from arch/powerpc/kernel/udbg_scc.c)66
-rw-r--r--arch/powerpc/platforms/pseries/Makefile2
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c26
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c12
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c76
-rw-r--r--arch/powerpc/platforms/pseries/pci_dlpar.c174
-rw-r--r--arch/powerpc/platforms/pseries/ras.c11
-rw-r--r--arch/powerpc/platforms/pseries/ras.h9
-rw-r--r--arch/powerpc/platforms/pseries/setup.c55
-rw-r--r--arch/powerpc/platforms/pseries/xics.c2
-rw-r--r--arch/powerpc/sysdev/Makefile3
-rw-r--r--arch/powerpc/sysdev/dart.h41
-rw-r--r--arch/powerpc/sysdev/dart_iommu.c (renamed from arch/powerpc/sysdev/u3_iommu.c)173
-rw-r--r--arch/powerpc/sysdev/ipic.c (renamed from arch/ppc/syslib/ipic.c)0
-rw-r--r--arch/powerpc/sysdev/ipic.h (renamed from arch/ppc/syslib/ipic.h)0
-rw-r--r--arch/powerpc/sysdev/mpic.c247
-rw-r--r--arch/powerpc/xmon/Makefile8
-rw-r--r--arch/powerpc/xmon/start.c (renamed from arch/powerpc/xmon/start_64.c)0
-rw-r--r--arch/powerpc/xmon/start_32.c441
-rw-r--r--arch/powerpc/xmon/start_8xx.c44
-rw-r--r--arch/powerpc/xmon/xmon.c8
-rw-r--r--arch/ppc/boot/common/util.S6
-rw-r--r--arch/ppc/boot/images/Makefile2
-rw-r--r--arch/ppc/configs/TQM8540_defconfig973
-rw-r--r--arch/ppc/configs/TQM8541_defconfig986
-rw-r--r--arch/ppc/configs/TQM8555_defconfig983
-rw-r--r--arch/ppc/configs/TQM8560_defconfig992
-rw-r--r--arch/ppc/kernel/Makefile1
-rw-r--r--arch/ppc/kernel/asm-offsets.c2
-rw-r--r--arch/ppc/kernel/entry.S167
-rw-r--r--arch/ppc/kernel/misc.S6
-rw-r--r--arch/ppc/kernel/pci.c28
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c5
-rw-r--r--arch/ppc/kernel/setup.c3
-rw-r--r--arch/ppc/platforms/85xx/Kconfig28
-rw-r--r--arch/ppc/platforms/85xx/Makefile4
-rw-r--r--arch/ppc/platforms/85xx/tqm85xx.c419
-rw-r--r--arch/ppc/platforms/85xx/tqm85xx.h56
-rw-r--r--arch/ppc/platforms/chrp_setup.c1
-rw-r--r--arch/ppc/platforms/prep_setup.c2
-rw-r--r--arch/ppc/syslib/Makefile2
-rw-r--r--arch/ppc/syslib/m8xx_setup.c15
-rw-r--r--arch/ppc/syslib/m8xx_wdt.c92
-rw-r--r--arch/ppc/syslib/m8xx_wdt.h4
-rw-r--r--block/elevator.c3
-rw-r--r--block/ll_rw_blk.c131
-rw-r--r--block/scsi_ioctl.c13
-rw-r--r--drivers/block/cciss.c72
-rw-r--r--drivers/block/swim3.c38
-rw-r--r--drivers/char/watchdog/mpc8xx_wdt.c20
-rw-r--r--drivers/i2c/busses/Kconfig24
-rw-r--r--drivers/i2c/busses/Makefile3
-rw-r--r--drivers/i2c/busses/i2c-keywest.c751
-rw-r--r--drivers/i2c/busses/i2c-keywest.h108
-rw-r--r--drivers/i2c/busses/i2c-pmac-smu.c315
-rw-r--r--drivers/i2c/busses/i2c-powermac.c290
-rw-r--r--drivers/ide/ide-cd.c10
-rw-r--r--drivers/ide/ide-io.c42
-rw-r--r--drivers/ide/ide-probe.c2
-rw-r--r--drivers/ide/ppc/pmac.c6
-rw-r--r--drivers/macintosh/Kconfig10
-rw-r--r--drivers/macintosh/macio_asic.c254
-rw-r--r--drivers/macintosh/mediabay.c8
-rw-r--r--drivers/macintosh/smu.c50
-rw-r--r--drivers/macintosh/via-cuda.c52
-rw-r--r--drivers/macintosh/via-pmu.c364
-rw-r--r--drivers/macintosh/windfarm_lm75_sensor.c50
-rw-r--r--drivers/media/common/saa7146_fops.c38
-rw-r--r--drivers/media/common/saa7146_hlp.c13
-rw-r--r--drivers/media/common/saa7146_vbi.c6
-rw-r--r--drivers/media/common/saa7146_video.c9
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c33
-rw-r--r--drivers/media/dvb/b2c2/flexcop-reg.h4
-rw-r--r--drivers/media/dvb/bt8xx/dst.c52
-rw-r--r--drivers/media/dvb/bt8xx/dst_ca.c3
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.c16
-rw-r--r--drivers/media/dvb/cinergyT2/Kconfig20
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c82
-rw-r--r--drivers/media/dvb/dvb-core/Kconfig2
-rw-r--r--drivers/media/dvb/dvb-core/Makefile2
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ca_en50221.c4
-rw-r--r--drivers/media/dvb/dvb-core/dvb_filter.c16
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c315
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h16
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c6
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ringbuffer.c32
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ringbuffer.h8
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c22
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.h2
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig24
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c294
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.h2
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mb.c46
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u.c6
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u.h31
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-common.h2
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-firmware.c154
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-i2c.c8
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h12
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-init.c59
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb.h29
-rw-r--r--drivers/media/dvb/dvb-usb/nova-t-usb2.c7
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x-fe.c2
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x.h43
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045.c2
-rw-r--r--drivers/media/dvb/frontends/Kconfig46
-rw-r--r--drivers/media/dvb/frontends/Makefile1
-rw-r--r--drivers/media/dvb/frontends/bcm3510.c6
-rw-r--r--drivers/media/dvb/frontends/cx22702.c22
-rw-r--r--drivers/media/dvb/frontends/cx24110.c23
-rw-r--r--drivers/media/dvb/frontends/cx24123.c889
-rw-r--r--drivers/media/dvb/frontends/cx24123.h51
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c15
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h2
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.c3
-rw-r--r--drivers/media/dvb/frontends/mt312.c3
-rw-r--r--drivers/media/dvb/frontends/nxt2002.c3
-rw-r--r--drivers/media/dvb/frontends/nxt6000.c10
-rw-r--r--drivers/media/dvb/frontends/or51211.c5
-rw-r--r--drivers/media/dvb/frontends/s5h1420.c4
-rw-r--r--drivers/media/dvb/frontends/sp8870.c3
-rw-r--r--drivers/media/dvb/frontends/sp887x.c5
-rw-r--r--drivers/media/dvb/frontends/stv0299.c12
-rw-r--r--drivers/media/dvb/frontends/stv0299.h1
-rw-r--r--drivers/media/dvb/frontends/tda10021.c4
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c141
-rw-r--r--drivers/media/dvb/pluto2/Kconfig2
-rw-r--r--drivers/media/dvb/ttpci/Kconfig7
-rw-r--r--drivers/media/dvb/ttpci/Makefile2
-rw-r--r--drivers/media/dvb/ttpci/av7110.c133
-rw-r--r--drivers/media/dvb/ttpci/av7110.h17
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.c12
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.c7
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.h3
-rw-r--r--drivers/media/dvb/ttpci/av7110_ir.c14
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c118
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c184
-rw-r--r--drivers/media/dvb/ttpci/budget-core.c4
-rw-r--r--drivers/media/dvb/ttpci/budget.c13
-rw-r--r--drivers/media/dvb/ttpci/ttpci-eeprom.c2
-rw-r--r--drivers/media/dvb/ttusb-budget/Kconfig2
-rw-r--r--drivers/media/dvb/ttusb-dec/Kconfig13
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusb_dec.c20
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusbdecfe.c53
-rw-r--r--drivers/media/radio/miropcm20-radio.c1
-rw-r--r--drivers/media/radio/radio-aimslab.c1
-rw-r--r--drivers/media/radio/radio-aztech.c1
-rw-r--r--drivers/media/radio/radio-cadet.c1
-rw-r--r--drivers/media/radio/radio-gemtek-pci.c1
-rw-r--r--drivers/media/radio/radio-gemtek.c1
-rw-r--r--drivers/media/radio/radio-maestro.c1
-rw-r--r--drivers/media/radio/radio-maxiradio.c1
-rw-r--r--drivers/media/radio/radio-rtrack2.c1
-rw-r--r--drivers/media/radio/radio-sf16fmi.c1
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c1
-rw-r--r--drivers/media/radio/radio-terratec.c1
-rw-r--r--drivers/media/radio/radio-trust.c1
-rw-r--r--drivers/media/radio/radio-typhoon.c1
-rw-r--r--drivers/media/radio/radio-zoltrix.c1
-rw-r--r--drivers/media/video/Kconfig11
-rw-r--r--drivers/media/video/Makefile10
-rw-r--r--drivers/media/video/arv.c1
-rw-r--r--drivers/media/video/bt832.c70
-rw-r--r--drivers/media/video/bttv-cards.c56
-rw-r--r--drivers/media/video/bttv-driver.c68
-rw-r--r--drivers/media/video/bttv-gpio.c18
-rw-r--r--drivers/media/video/bttv-i2c.c15
-rw-r--r--drivers/media/video/bttv-input.c (renamed from drivers/media/video/ir-kbd-gpio.c)256
-rw-r--r--drivers/media/video/bttv-vbi.c57
-rw-r--r--drivers/media/video/bttv.h37
-rw-r--r--drivers/media/video/bttvp.h13
-rw-r--r--drivers/media/video/bw-qcam.c1
-rw-r--r--drivers/media/video/c-qcam.c1
-rw-r--r--drivers/media/video/compat_ioctl32.c732
-rw-r--r--drivers/media/video/cpia.c1
-rw-r--r--drivers/media/video/cs53l32a.c92
-rw-r--r--drivers/media/video/cx25840/cx25840-audio.c91
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c388
-rw-r--r--drivers/media/video/cx25840/cx25840-firmware.c36
-rw-r--r--drivers/media/video/cx25840/cx25840-vbi.c4
-rw-r--r--drivers/media/video/cx25840/cx25840.h81
-rw-r--r--drivers/media/video/cx88/Kconfig25
-rw-r--r--drivers/media/video/cx88/Makefile4
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c848
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c18
-rw-r--r--drivers/media/video/cx88/cx88-cards.c227
-rw-r--r--drivers/media/video/cx88/cx88-core.c67
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c215
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c13
-rw-r--r--drivers/media/video/cx88/cx88-input.c142
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c5
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c10
-rw-r--r--drivers/media/video/cx88/cx88-video.c94
-rw-r--r--drivers/media/video/cx88/cx88-vp3054-i2c.c173
-rw-r--r--drivers/media/video/cx88/cx88-vp3054-i2c.h35
-rw-r--r--drivers/media/video/cx88/cx88.h17
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c8
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c61
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c3
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c167
-rw-r--r--drivers/media/video/em28xx/em28xx.h6
-rw-r--r--drivers/media/video/ir-kbd-i2c.c18
-rw-r--r--drivers/media/video/meye.c1
-rw-r--r--drivers/media/video/msp3400-driver.c1274
-rw-r--r--drivers/media/video/msp3400-kthreads.c1010
-rw-r--r--drivers/media/video/msp3400.c2229
-rw-r--r--drivers/media/video/msp3400.h102
-rw-r--r--drivers/media/video/mt20xx.c16
-rw-r--r--drivers/media/video/mxb.c1
-rw-r--r--drivers/media/video/pms.c1
-rw-r--r--drivers/media/video/saa5249.c1
-rw-r--r--drivers/media/video/saa6588.c12
-rw-r--r--drivers/media/video/saa7115.c319
-rw-r--r--drivers/media/video/saa711x.c2
-rw-r--r--drivers/media/video/saa7127.c82
-rw-r--r--drivers/media/video/saa7134/saa6752hs.c8
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c83
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c138
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c1
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c3
-rw-r--r--drivers/media/video/saa7134/saa7134-i2c.c3
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c39
-rw-r--r--drivers/media/video/saa7134/saa7134-oss.c40
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c7
-rw-r--r--drivers/media/video/saa7134/saa7134.h10
-rw-r--r--drivers/media/video/stradis.c1
-rw-r--r--drivers/media/video/tda7432.c43
-rw-r--r--drivers/media/video/tda8290.c6
-rw-r--r--drivers/media/video/tda9875.c7
-rw-r--r--drivers/media/video/tda9887.c228
-rw-r--r--drivers/media/video/tea5767.c7
-rw-r--r--drivers/media/video/tuner-core.c138
-rw-r--r--drivers/media/video/tuner-simple.c889
-rw-r--r--drivers/media/video/tvaudio.c177
-rw-r--r--drivers/media/video/tveeprom.c43
-rw-r--r--drivers/media/video/tvmixer.c20
-rw-r--r--drivers/media/video/tvp5150.c535
-rw-r--r--drivers/media/video/v4l1-compat.c11
-rw-r--r--drivers/media/video/v4l2-common.c219
-rw-r--r--drivers/media/video/videodev.c10
-rw-r--r--drivers/media/video/w9966.c1
-rw-r--r--drivers/media/video/wm8775.c88
-rw-r--r--drivers/media/video/zoran_driver.c1
-rw-r--r--drivers/media/video/zr36120.c1
-rw-r--r--drivers/mmc/mmc.c1
-rw-r--r--drivers/mmc/mmc_block.c8
-rw-r--r--drivers/mmc/wbsd.c533
-rw-r--r--drivers/net/3c503.c16
-rw-r--r--drivers/net/Kconfig4
-rw-r--r--drivers/net/ac3200.c16
-rw-r--r--drivers/net/bonding/bonding.h8
-rw-r--r--drivers/net/e1000/e1000_param.c10
-rw-r--r--drivers/net/e2100.c14
-rw-r--r--drivers/net/es3210.c14
-rw-r--r--drivers/net/forcedeth.c164
-rw-r--r--drivers/net/gianfar.h4
-rw-r--r--drivers/net/hp-plus.c12
-rw-r--r--drivers/net/hp.c12
-rw-r--r--drivers/net/ibm_emac/ibm_emac.h3
-rw-r--r--drivers/net/ibm_emac/ibm_emac_core.c2
-rw-r--r--drivers/net/lance.c22
-rw-r--r--drivers/net/lne390.c14
-rw-r--r--drivers/net/mv643xx_eth.c2
-rw-r--r--drivers/net/ne.c18
-rw-r--r--drivers/net/ne2.c16
-rw-r--r--drivers/net/sk98lin/skge.c129
-rw-r--r--drivers/net/smc-ultra.c24
-rw-r--r--drivers/net/tulip/tulip_core.c2
-rw-r--r--drivers/net/wd.c14
-rw-r--r--drivers/net/wireless/ipw2100.c5
-rw-r--r--drivers/scsi/mac53c94.c22
-rw-r--r--drivers/scsi/mesh.c3
-rw-r--r--drivers/scsi/sata_nv.c30
-rw-r--r--drivers/scsi/scsi.c109
-rw-r--r--drivers/scsi/scsi_lib.c36
-rw-r--r--drivers/scsi/scsi_priv.h1
-rw-r--r--drivers/scsi/sg.c2
-rw-r--r--drivers/serial/8250.c28
-rw-r--r--drivers/serial/Kconfig10
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c2
-rw-r--r--drivers/serial/pmac_zilog.c15
-rw-r--r--drivers/serial/serial_core.c1
-rw-r--r--drivers/usb/media/dsbr100.c1
-rw-r--r--drivers/usb/media/ov511.c1
-rw-r--r--drivers/usb/media/pwc/pwc-if.c1
-rw-r--r--drivers/usb/media/se401.c1
-rw-r--r--drivers/usb/media/stv680.c1
-rw-r--r--drivers/usb/media/usbvideo.c1
-rw-r--r--drivers/usb/media/vicam.c1
-rw-r--r--drivers/usb/media/w9968cf.c1
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/controlfb.c114
-rw-r--r--drivers/video/cyblafb.c1523
-rw-r--r--drivers/video/offb.c122
-rw-r--r--drivers/video/platinumfb.c98
-rw-r--r--drivers/video/platinumfb.h4
-rw-r--r--drivers/video/valkyriefb.c12
-rw-r--r--fs/bio.c1
-rw-r--r--fs/compat_ioctl.c246
-rw-r--r--include/asm-powerpc/abs_addr.h2
-rw-r--r--include/asm-powerpc/agp.h2
-rw-r--r--include/asm-powerpc/asm-compat.h3
-rw-r--r--include/asm-powerpc/bootx.h171
-rw-r--r--include/asm-powerpc/btext.h19
-rw-r--r--include/asm-powerpc/bug.h2
-rw-r--r--include/asm-powerpc/checksum.h2
-rw-r--r--include/asm-powerpc/compat.h2
-rw-r--r--include/asm-powerpc/cputable.h36
-rw-r--r--include/asm-powerpc/current.h2
-rw-r--r--include/asm-powerpc/delay.h2
-rw-r--r--include/asm-powerpc/dma-mapping.h2
-rw-r--r--include/asm-powerpc/dma.h2
-rw-r--r--include/asm-powerpc/eeh.h15
-rw-r--r--include/asm-powerpc/eeh_event.h2
-rw-r--r--include/asm-powerpc/elf.h3
-rw-r--r--include/asm-powerpc/firmware.h6
-rw-r--r--include/asm-powerpc/floppy.h2
-rw-r--r--include/asm-powerpc/grackle.h5
-rw-r--r--include/asm-powerpc/hardirq.h2
-rw-r--r--include/asm-powerpc/heathrow.h5
-rw-r--r--include/asm-powerpc/hvcall.h2
-rw-r--r--include/asm-powerpc/hvconsole.h2
-rw-r--r--include/asm-powerpc/hvcserver.h2
-rw-r--r--include/asm-powerpc/i8259.h2
-rw-r--r--include/asm-powerpc/ibmebus.h85
-rw-r--r--include/asm-powerpc/io.h6
-rw-r--r--include/asm-powerpc/iommu.h8
-rw-r--r--include/asm-powerpc/ipic.h (renamed from include/asm-ppc/ipic.h)0
-rw-r--r--include/asm-powerpc/iseries/it_lp_reg_save.h2
-rw-r--r--include/asm-powerpc/kdebug.h2
-rw-r--r--include/asm-powerpc/kdump.h13
-rw-r--r--include/asm-powerpc/kexec.h19
-rw-r--r--include/asm-powerpc/keylargo.h15
-rw-r--r--include/asm-powerpc/kprobes.h2
-rw-r--r--include/asm-powerpc/lmb.h2
-rw-r--r--include/asm-powerpc/lppaca.h2
-rw-r--r--include/asm-powerpc/machdep.h12
-rw-r--r--include/asm-powerpc/macio.h2
-rw-r--r--include/asm-powerpc/mmu.h9
-rw-r--r--include/asm-powerpc/mmu_context.h2
-rw-r--r--include/asm-powerpc/mmzone.h2
-rw-r--r--include/asm-powerpc/module.h2
-rw-r--r--include/asm-powerpc/mpic.h6
-rw-r--r--include/asm-powerpc/numnodes.h2
-rw-r--r--include/asm-powerpc/nvram.h4
-rw-r--r--include/asm-powerpc/of_device.h2
-rw-r--r--include/asm-powerpc/ohare.h6
-rw-r--r--include/asm-powerpc/oprofile_impl.h33
-rw-r--r--include/asm-powerpc/pSeries_reconfig.h2
-rw-r--r--include/asm-powerpc/paca.h21
-rw-r--r--include/asm-powerpc/page.h32
-rw-r--r--include/asm-powerpc/page_32.h2
-rw-r--r--include/asm-powerpc/page_64.h12
-rw-r--r--include/asm-powerpc/param.h2
-rw-r--r--include/asm-powerpc/parport.h2
-rw-r--r--include/asm-powerpc/pci-bridge.h24
-rw-r--r--include/asm-powerpc/pci.h2
-rw-r--r--include/asm-powerpc/pgalloc.h2
-rw-r--r--include/asm-powerpc/pgtable-64k.h6
-rw-r--r--include/asm-powerpc/pgtable.h13
-rw-r--r--include/asm-powerpc/pmac_feature.h25
-rw-r--r--include/asm-powerpc/pmac_low_i2c.h92
-rw-r--r--include/asm-powerpc/pmac_pfunc.h253
-rw-r--r--include/asm-powerpc/pmc.h2
-rw-r--r--include/asm-powerpc/ppc-pci.h2
-rw-r--r--include/asm-powerpc/ppc_asm.h3
-rw-r--r--include/asm-powerpc/processor.h5
-rw-r--r--include/asm-powerpc/prom.h71
-rw-r--r--include/asm-powerpc/ptrace.h2
-rw-r--r--include/asm-powerpc/reg.h58
-rw-r--r--include/asm-powerpc/rtas.h2
-rw-r--r--include/asm-powerpc/seccomp.h4
-rw-r--r--include/asm-powerpc/sections.h2
-rw-r--r--include/asm-powerpc/serial.h2
-rw-r--r--include/asm-powerpc/signal.h7
-rw-r--r--include/asm-powerpc/smu.h34
-rw-r--r--include/asm-powerpc/sparsemem.h10
-rw-r--r--include/asm-powerpc/spinlock.h2
-rw-r--r--include/asm-powerpc/spu.h600
-rw-r--r--include/asm-powerpc/spu_csa.h255
-rw-r--r--include/asm-powerpc/synch.h4
-rw-r--r--include/asm-powerpc/system.h3
-rw-r--r--include/asm-powerpc/tce.h2
-rw-r--r--include/asm-powerpc/thread_info.h12
-rw-r--r--include/asm-powerpc/tlb.h2
-rw-r--r--include/asm-powerpc/topology.h6
-rw-r--r--include/asm-powerpc/udbg.h17
-rw-r--r--include/asm-powerpc/unistd.h4
-rw-r--r--include/asm-powerpc/vdso_datapage.h2
-rw-r--r--include/asm-powerpc/vio.h2
-rw-r--r--include/asm-ppc/bseip.h38
-rw-r--r--include/asm-ppc/btext.h2
-rw-r--r--include/asm-ppc/machdep.h4
-rw-r--r--include/asm-ppc/mpc85xx.h4
-rw-r--r--include/asm-ppc/pci-bridge.h9
-rw-r--r--include/asm-ppc/prom.h32
-rw-r--r--include/linux/blkdev.h22
-rw-r--r--include/linux/compat_ioctl.h26
-rw-r--r--include/linux/dvb/frontend.h10
-rw-r--r--include/linux/elevator.h2
-rw-r--r--include/linux/i2c-id.h1
-rw-r--r--include/linux/ide.h1
-rw-r--r--include/linux/interrupt.h2
-rw-r--r--include/linux/mmc/mmc.h6
-rw-r--r--include/linux/pci_regs.h1
-rw-r--r--include/linux/pmu.h8
-rw-r--r--include/linux/rcupdate.h31
-rw-r--r--include/linux/syscalls.h5
-rw-r--r--include/linux/video_decoder.h2
-rw-r--r--include/linux/videodev2.h16
-rw-r--r--include/media/audiochip.h16
-rw-r--r--include/media/saa7146_vv.h2
-rw-r--r--include/media/tuner.h98
-rw-r--r--include/media/v4l2-common.h85
-rw-r--r--include/video/cyblafb.h4
-rw-r--r--kernel/crash_dump.c3
-rw-r--r--kernel/rcupdate.c30
-rw-r--r--kernel/sys_ni.c2
-rw-r--r--mm/memory.c2
-rw-r--r--net/ieee80211/ieee80211_crypt_wep.c61
-rw-r--r--net/ieee80211/ieee80211_tx.c2
-rw-r--r--net/ieee80211/ieee80211_wx.c2
-rw-r--r--net/netlink/af_netlink.c2
-rw-r--r--sound/oss/dmasound/dmasound_awacs.c81
-rw-r--r--sound/ppc/pmac.c100
-rw-r--r--sound/ppc/pmac.h3
558 files changed, 39668 insertions, 12468 deletions
diff --git a/Documentation/dvb/avermedia.txt b/Documentation/dvb/avermedia.txt
index 2dc260b2b0a4..068070ff13cd 100644
--- a/Documentation/dvb/avermedia.txt
+++ b/Documentation/dvb/avermedia.txt
@@ -150,7 +150,8 @@ Getting the card going
The frontend module sp887x.o, requires an external firmware.
Please use the command "get_dvb_firmware sp887x" to download
- it. Then copy it to /usr/lib/hotplug/firmware.
+ it. Then copy it to /usr/lib/hotplug/firmware or /lib/firmware/
+ (depending on configuration of firmware hotplug).
Receiving DVB-T in Australia
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index be6eb4c75991..75c28a174092 100644
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -23,7 +23,7 @@ use IO::Handle;
@components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t",
"dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
- "or51211", "or51132_qam", "or51132_vsb");
+ "or51211", "or51132_qam", "or51132_vsb", "bluebird");
# Check args
syntax() if (scalar(@ARGV) != 1);
@@ -34,7 +34,11 @@ for ($i=0; $i < scalar(@components); $i++) {
if ($cid eq $components[$i]) {
$outfile = eval($cid);
die $@ if $@;
- print STDERR "Firmware $outfile extracted successfully. Now copy it to either /lib/firmware or /usr/lib/hotplug/firmware/ (depending on your hotplug version).\n";
+ print STDERR <<EOF;
+Firmware $outfile extracted successfully.
+Now copy it to either /usr/lib/hotplug/firmware or /lib/firmware
+(depending on configuration of firmware hotplug).
+EOF
exit(0);
}
}
@@ -243,7 +247,7 @@ sub nxt2002 {
my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
checkstandard();
-
+
wgetfile($sourcefile, $url);
unzip($sourcefile, $tmpdir);
verify("$tmpdir/SkyNETU.sys", $hash);
@@ -308,6 +312,19 @@ sub or51132_vsb {
$fwfile;
}
+sub bluebird {
+ my $url = "http://www.linuxtv.org/download/dvb/firmware/dvb-usb-bluebird-01.fw";
+ my $outfile = "dvb-usb-bluebird-01.fw";
+ my $hash = "658397cb9eba9101af9031302671f49d";
+
+ checkstandard();
+
+ wgetfile($outfile, $url);
+ verify($outfile,$hash);
+
+ $outfile;
+}
+
# ---------------------------------------------------------------
# Utilities
diff --git a/Documentation/dvb/ttusb-dec.txt b/Documentation/dvb/ttusb-dec.txt
index 5c1e984c26a7..b2f271cd784b 100644
--- a/Documentation/dvb/ttusb-dec.txt
+++ b/Documentation/dvb/ttusb-dec.txt
@@ -41,4 +41,5 @@ Hotplug Firmware Loading for 2.6 kernels
For 2.6 kernels the firmware is loaded at the point that the driver module is
loaded. See linux/Documentation/dvb/firmware.txt for more information.
-Copy the three files downloaded above into the /usr/lib/hotplug/firmware directory.
+Copy the three files downloaded above into the /usr/lib/hotplug/firmware or
+/lib/firmware directory (depending on configuration of firmware hotplug).
diff --git a/Documentation/fb/cyblafb/bugs b/Documentation/fb/cyblafb/bugs
index f90cc66ea919..9443a6d72cdd 100644
--- a/Documentation/fb/cyblafb/bugs
+++ b/Documentation/fb/cyblafb/bugs
@@ -11,4 +11,3 @@ Untested features
All LCD stuff is untested. If it worked in tridentfb, it should work in
cyblafb. Please test and report the results to Knut_Petersen@t-online.de.
-
diff --git a/Documentation/fb/cyblafb/fb.modes b/Documentation/fb/cyblafb/fb.modes
index cf4351fc32ff..fe0e5223ba86 100644
--- a/Documentation/fb/cyblafb/fb.modes
+++ b/Documentation/fb/cyblafb/fb.modes
@@ -14,142 +14,141 @@
#
mode "640x480-50"
- geometry 640 480 640 3756 8
+ geometry 640 480 2048 4096 8
timings 47619 4294967256 24 17 0 216 3
endmode
mode "640x480-60"
- geometry 640 480 640 3756 8
+ geometry 640 480 2048 4096 8
timings 39682 4294967256 24 17 0 216 3
endmode
mode "640x480-70"
- geometry 640 480 640 3756 8
+ geometry 640 480 2048 4096 8
timings 34013 4294967256 24 17 0 216 3
endmode
mode "640x480-72"
- geometry 640 480 640 3756 8
+ geometry 640 480 2048 4096 8
timings 33068 4294967256 24 17 0 216 3
endmode
mode "640x480-75"
- geometry 640 480 640 3756 8
+ geometry 640 480 2048 4096 8
timings 31746 4294967256 24 17 0 216 3
endmode
mode "640x480-80"
- geometry 640 480 640 3756 8
+ geometry 640 480 2048 4096 8
timings 29761 4294967256 24 17 0 216 3
endmode
mode "640x480-85"
- geometry 640 480 640 3756 8
+ geometry 640 480 2048 4096 8
timings 28011 4294967256 24 17 0 216 3
endmode
mode "800x600-50"
- geometry 800 600 800 3221 8
+ geometry 800 600 2048 4096 8
timings 30303 96 24 14 0 136 11
endmode
mode "800x600-60"
- geometry 800 600 800 3221 8
+ geometry 800 600 2048 4096 8
timings 25252 96 24 14 0 136 11
endmode
mode "800x600-70"
- geometry 800 600 800 3221 8
+ geometry 800 600 2048 4096 8
timings 21645 96 24 14 0 136 11
endmode
mode "800x600-72"
- geometry 800 600 800 3221 8
+ geometry 800 600 2048 4096 8
timings 21043 96 24 14 0 136 11
endmode
mode "800x600-75"
- geometry 800 600 800 3221 8
+ geometry 800 600 2048 4096 8
timings 20202 96 24 14 0 136 11
endmode
mode "800x600-80"
- geometry 800 600 800 3221 8
+ geometry 800 600 2048 4096 8
timings 18939 96 24 14 0 136 11
endmode
mode "800x600-85"
- geometry 800 600 800 3221 8
+ geometry 800 600 2048 4096 8
timings 17825 96 24 14 0 136 11
endmode
mode "1024x768-50"
- geometry 1024 768 1024 2815 8
+ geometry 1024 768 2048 4096 8
timings 19054 144 24 29 0 120 3
endmode
mode "1024x768-60"
- geometry 1024 768 1024 2815 8
+ geometry 1024 768 2048 4096 8
timings 15880 144 24 29 0 120 3
endmode
mode "1024x768-70"
- geometry 1024 768 1024 2815 8
+ geometry 1024 768 2048 4096 8
timings 13610 144 24 29 0 120 3
endmode
mode "1024x768-72"
- geometry 1024 768 1024 2815 8
+ geometry 1024 768 2048 4096 8
timings 13232 144 24 29 0 120 3
endmode
mode "1024x768-75"
- geometry 1024 768 1024 2815 8
+ geometry 1024 768 2048 4096 8
timings 12703 144 24 29 0 120 3
endmode
mode "1024x768-80"
- geometry 1024 768 1024 2815 8
+ geometry 1024 768 2048 4096 8
timings 11910 144 24 29 0 120 3
endmode
mode "1024x768-85"
- geometry 1024 768 1024 2815 8
+ geometry 1024 768 2048 4096 8
timings 11209 144 24 29 0 120 3
endmode
mode "1280x1024-50"
- geometry 1280 1024 1280 2662 8
+ geometry 1280 1024 2048 4096 8
timings 11114 232 16 39 0 160 3
endmode
mode "1280x1024-60"
- geometry 1280 1024 1280 2662 8
+ geometry 1280 1024 2048 4096 8
timings 9262 232 16 39 0 160 3
endmode
mode "1280x1024-70"
- geometry 1280 1024 1280 2662 8
+ geometry 1280 1024 2048 4096 8
timings 7939 232 16 39 0 160 3
endmode
mode "1280x1024-72"
- geometry 1280 1024 1280 2662 8
+ geometry 1280 1024 2048 4096 8
timings 7719 232 16 39 0 160 3
endmode
mode "1280x1024-75"
- geometry 1280 1024 1280 2662 8
+ geometry 1280 1024 2048 4096 8
timings 7410 232 16 39 0 160 3
endmode
mode "1280x1024-80"
- geometry 1280 1024 1280 2662 8
+ geometry 1280 1024 2048 4096 8
timings 6946 232 16 39 0 160 3
endmode
mode "1280x1024-85"
- geometry 1280 1024 1280 2662 8
+ geometry 1280 1024 2048 4096 8
timings 6538 232 16 39 0 160 3
endmode
-
diff --git a/Documentation/fb/cyblafb/performance b/Documentation/fb/cyblafb/performance
index eb4e47a9cea6..8d15d5dfc6b3 100644
--- a/Documentation/fb/cyblafb/performance
+++ b/Documentation/fb/cyblafb/performance
@@ -77,4 +77,3 @@ patch that speeds up kernel bitblitting a lot ( > 20%).
| | | | |
| | | | |
+-----------+-----------------+-----------------+-----------------+
-
diff --git a/Documentation/fb/cyblafb/todo b/Documentation/fb/cyblafb/todo
index 80fb2f89b6c1..c5f6d0eae545 100644
--- a/Documentation/fb/cyblafb/todo
+++ b/Documentation/fb/cyblafb/todo
@@ -22,11 +22,10 @@ accelerated color blitting Who needs it? The console driver does use color
everything else is done using color expanding
blitting of 1bpp character bitmaps.
-xpanning Who needs it?
-
ioctls Who needs it?
-TV-out Will be done later
+TV-out Will be done later. Use "vga= " at boot time
+ to set a suitable video mode.
??? Feel free to contact me if you have any
feature requests
diff --git a/Documentation/fb/cyblafb/usage b/Documentation/fb/cyblafb/usage
index e627c8f54211..a39bb3d402a2 100644
--- a/Documentation/fb/cyblafb/usage
+++ b/Documentation/fb/cyblafb/usage
@@ -40,6 +40,16 @@ Selecting Modes
None of the modes possible to select as startup modes are affected by
the problems described at the end of the next subsection.
+ For all startup modes cyblafb chooses a virtual x resolution of 2048,
+ the only exception is mode 1280x1024 in combination with 32 bpp. This
+ allows ywrap scrolling for all those modes if rotation is 0 or 2, and
+ also fast scrolling if rotation is 1 or 3. The default virtual y reso-
+ lution is 4096 for bpp == 8, 2048 for bpp==16 and 1024 for bpp == 32,
+ again with the only exception of 1280x1024 at 32 bpp.
+
+ Please do set your video memory size to 8 Mb in the Bios setup. Other
+ values will work, but performace is decreased for a lot of modes.
+
Mode changes using fbset
========================
@@ -54,20 +64,26 @@ Selecting Modes
- if a flat panel is found, cyblafb does not allow you
to program a resolution higher than the physical
resolution of the flat panel monitor
- - cyblafb does not allow xres to differ from xres_virtual
- cyblafb does not allow vclk to exceed 230 MHz. As 32 bpp
and (currently) 24 bit modes use a doubled vclk internally,
the dotclock limit as seen by fbset is 115 MHz for those
modes and 230 MHz for 8 and 16 bpp modes.
+ - cyblafb will allow you to select very high resolutions as
+ long as the hardware can be programmed to these modes. The
+ documented limit 1600x1200 is not enforced, but don't expect
+ perfect signal quality.
- Any request that violates the rules given above will be ignored and
- fbset will return an error.
+ Any request that violates the rules given above will be either changed
+ to something the hardware supports or an error value will be returned.
If you program a virtual y resolution higher than the hardware limit,
cyblafb will silently decrease that value to the highest possible
- value.
+ value. The same is true for a virtual x resolution that is not
+ supported by the hardware. Cyblafb tries to adapt vyres first because
+ vxres decides if ywrap scrolling is possible or not.
- Attempts to disable acceleration are ignored.
+ Attempts to disable acceleration are ignored, I believe that this is
+ safe.
Some video modes that should work do not work as expected. If you use
the standard fb.modes, fbset 640x480-60 will program that mode, but
@@ -129,10 +145,6 @@ mode 640x480 or 800x600 or 1024x768 or 1280x1024
verbosity 0 is the default, increase to at least 2 for every
bug report!
-vesafb allows cyblafb to be loaded after vesafb has been
- loaded. See sections "Module unloading ...".
-
-
Development hints
=================
@@ -195,7 +207,7 @@ a graphics mode.
After booting, load cyblafb without any mode and bpp parameter and assign
cyblafb to individual ttys using con2fb, e.g.:
- modprobe cyblafb vesafb=1
+ modprobe cyblafb
con2fb /dev/fb1 /dev/tty1
Unloading cyblafb works without problems after you assign vesafb to all
@@ -203,4 +215,3 @@ ttys again, e.g.:
con2fb /dev/fb0 /dev/tty1
rmmod cyblafb
-
diff --git a/Documentation/fb/cyblafb/whatsnew b/Documentation/fb/cyblafb/whatsnew
new file mode 100644
index 000000000000..76c07a26e044
--- /dev/null
+++ b/Documentation/fb/cyblafb/whatsnew
@@ -0,0 +1,29 @@
+0.62
+====
+
+ - the vesafb parameter has been removed as I decided to allow the
+ feature without any special parameter.
+
+ - Cyblafb does not use the vga style of panning any longer, now the
+ "right view" register in the graphics engine IO space is used. Without
+ that change it was impossible to use all available memory, and without
+ access to all available memory it is impossible to ywrap.
+
+ - The imageblit function now uses hardware acceleration for all font
+ widths. Hardware blitting across pixel column 2048 is broken in the
+ cyberblade/i1 graphics core, but we work around that hardware bug.
+
+ - modes with vxres != xres are supported now.
+
+ - ywrap scrolling is supported now and the default. This is a big
+ performance gain.
+
+ - default video modes use vyres > yres and vxres > xres to allow
+ almost optimal scrolling speed for normal and rotated screens
+
+ - some features mainly usefull for debugging the upper layers of the
+ framebuffer system have been added, have a look at the code
+
+ - fixed: Oops after unloading cyblafb when reading /proc/io*
+
+ - we work around some bugs of the higher framebuffer layers.
diff --git a/Documentation/filesystems/spufs.txt b/Documentation/filesystems/spufs.txt
new file mode 100644
index 000000000000..8edc3952eff4
--- /dev/null
+++ b/Documentation/filesystems/spufs.txt
@@ -0,0 +1,521 @@
+SPUFS(2) Linux Programmer's Manual SPUFS(2)
+
+
+
+NAME
+ spufs - the SPU file system
+
+
+DESCRIPTION
+ The SPU file system is used on PowerPC machines that implement the Cell
+ Broadband Engine Architecture in order to access Synergistic Processor
+ Units (SPUs).
+
+ The file system provides a name space similar to posix shared memory or
+ message queues. Users that have write permissions on the file system
+ can use spu_create(2) to establish SPU contexts in the spufs root.
+
+ Every SPU context is represented by a directory containing a predefined
+ set of files. These files can be used for manipulating the state of the
+ logical SPU. Users can change permissions on those files, but not actu-
+ ally add or remove files.
+
+
+MOUNT OPTIONS
+ uid=<uid>
+ set the user owning the mount point, the default is 0 (root).
+
+ gid=<gid>
+ set the group owning the mount point, the default is 0 (root).
+
+
+FILES
+ The files in spufs mostly follow the standard behavior for regular sys-
+ tem calls like read(2) or write(2), but often support only a subset of
+ the operations supported on regular file systems. This list details the
+ supported operations and the deviations from the behaviour in the
+ respective man pages.
+
+ All files that support the read(2) operation also support readv(2) and
+ all files that support the write(2) operation also support writev(2).
+ All files support the access(2) and stat(2) family of operations, but
+ only the st_mode, st_nlink, st_uid and st_gid fields of struct stat
+ contain reliable information.
+
+ All files support the chmod(2)/fchmod(2) and chown(2)/fchown(2) opera-
+ tions, but will not be able to grant permissions that contradict the
+ possible operations, e.g. read access on the wbox file.
+
+ The current set of files is:
+
+
+ /mem
+ the contents of the local storage memory of the SPU. This can be
+ accessed like a regular shared memory file and contains both code and
+ data in the address space of the SPU. The possible operations on an
+ open mem file are:
+
+ read(2), pread(2), write(2), pwrite(2), lseek(2)
+ These operate as documented, with the exception that seek(2),
+ write(2) and pwrite(2) are not supported beyond the end of the
+ file. The file size is the size of the local storage of the SPU,
+ which normally is 256 kilobytes.
+
+ mmap(2)
+ Mapping mem into the process address space gives access to the
+ SPU local storage within the process address space. Only
+ MAP_SHARED mappings are allowed.
+
+
+ /mbox
+ The first SPU to CPU communication mailbox. This file is read-only and
+ can be read in units of 32 bits. The file can only be used in non-
+ blocking mode and it even poll() will not block on it. The possible
+ operations on an open mbox file are:
+
+ read(2)
+ If a count smaller than four is requested, read returns -1 and
+ sets errno to EINVAL. If there is no data available in the mail
+ box, the return value is set to -1 and errno becomes EAGAIN.
+ When data has been read successfully, four bytes are placed in
+ the data buffer and the value four is returned.
+
+
+ /ibox
+ The second SPU to CPU communication mailbox. This file is similar to
+ the first mailbox file, but can be read in blocking I/O mode, and the
+ poll familiy of system calls can be used to wait for it. The possible
+ operations on an open ibox file are:
+
+ read(2)
+ If a count smaller than four is requested, read returns -1 and
+ sets errno to EINVAL. If there is no data available in the mail
+ box and the file descriptor has been opened with O_NONBLOCK, the
+ return value is set to -1 and errno becomes EAGAIN.
+
+ If there is no data available in the mail box and the file
+ descriptor has been opened without O_NONBLOCK, the call will
+ block until the SPU writes to its interrupt mailbox channel.
+ When data has been read successfully, four bytes are placed in
+ the data buffer and the value four is returned.
+
+ poll(2)
+ Poll on the ibox file returns (POLLIN | POLLRDNORM) whenever
+ data is available for reading.
+
+
+ /wbox
+ The CPU to SPU communation mailbox. It is write-only can can be written
+ in units of 32 bits. If the mailbox is full, write() will block and
+ poll can be used to wait for it becoming empty again. The possible
+ operations on an open wbox file are: write(2) If a count smaller than
+ four is requested, write returns -1 and sets errno to EINVAL. If there
+ is no space available in the mail box and the file descriptor has been
+ opened with O_NONBLOCK, the return value is set to -1 and errno becomes
+ EAGAIN.
+
+ If there is no space available in the mail box and the file descriptor
+ has been opened without O_NONBLOCK, the call will block until the SPU
+ reads from its PPE mailbox channel. When data has been read success-
+ fully, four bytes are placed in the data buffer and the value four is
+ returned.
+
+ poll(2)
+ Poll on the ibox file returns (POLLOUT | POLLWRNORM) whenever
+ space is available for writing.
+
+
+ /mbox_stat
+ /ibox_stat
+ /wbox_stat
+ Read-only files that contain the length of the current queue, i.e. how
+ many words can be read from mbox or ibox or how many words can be
+ written to wbox without blocking. The files can be read only in 4-byte
+ units and return a big-endian binary integer number. The possible
+ operations on an open *box_stat file are:
+
+ read(2)
+ If a count smaller than four is requested, read returns -1 and
+ sets errno to EINVAL. Otherwise, a four byte value is placed in
+ the data buffer, containing the number of elements that can be
+ read from (for mbox_stat and ibox_stat) or written to (for
+ wbox_stat) the respective mail box without blocking or resulting
+ in EAGAIN.
+
+
+ /npc
+ /decr
+ /decr_status
+ /spu_tag_mask
+ /event_mask
+ /srr0
+ Internal registers of the SPU. The representation is an ASCII string
+ with the numeric value of the next instruction to be executed. These
+ can be used in read/write mode for debugging, but normal operation of
+ programs should not rely on them because access to any of them except
+ npc requires an SPU context save and is therefore very inefficient.
+
+ The contents of these files are:
+
+ npc Next Program Counter
+
+ decr SPU Decrementer
+
+ decr_status Decrementer Status
+
+ spu_tag_mask MFC tag mask for SPU DMA
+
+ event_mask Event mask for SPU interrupts
+
+ srr0 Interrupt Return address register
+
+
+ The possible operations on an open npc, decr, decr_status,
+ spu_tag_mask, event_mask or srr0 file are:
+
+ read(2)
+ When the count supplied to the read call is shorter than the
+ required length for the pointer value plus a newline character,
+ subsequent reads from the same file descriptor will result in
+ completing the string, regardless of changes to the register by
+ a running SPU task. When a complete string has been read, all
+ subsequent read operations will return zero bytes and a new file
+ descriptor needs to be opened to read the value again.
+
+ write(2)
+ A write operation on the file results in setting the register to
+ the value given in the string. The string is parsed from the
+ beginning to the first non-numeric character or the end of the
+ buffer. Subsequent writes to the same file descriptor overwrite
+ the previous setting.
+
+
+ /fpcr
+ This file gives access to the Floating Point Status and Control Regis-
+ ter as a four byte long file. The operations on the fpcr file are:
+
+ read(2)
+ If a count smaller than four is requested, read returns -1 and
+ sets errno to EINVAL. Otherwise, a four byte value is placed in
+ the data buffer, containing the current value of the fpcr regis-
+ ter.
+
+ write(2)
+ If a count smaller than four is requested, write returns -1 and
+ sets errno to EINVAL. Otherwise, a four byte value is copied
+ from the data buffer, updating the value of the fpcr register.
+
+
+ /signal1
+ /signal2
+ The two signal notification channels of an SPU. These are read-write
+ files that operate on a 32 bit word. Writing to one of these files
+ triggers an interrupt on the SPU. The value writting to the signal
+ files can be read from the SPU through a channel read or from host user
+ space through the file. After the value has been read by the SPU, it
+ is reset to zero. The possible operations on an open signal1 or sig-
+ nal2 file are:
+
+ read(2)
+ If a count smaller than four is requested, read returns -1 and
+ sets errno to EINVAL. Otherwise, a four byte value is placed in
+ the data buffer, containing the current value of the specified
+ signal notification register.
+
+ write(2)
+ If a count smaller than four is requested, write returns -1 and
+ sets errno to EINVAL. Otherwise, a four byte value is copied
+ from the data buffer, updating the value of the specified signal
+ notification register. The signal notification register will
+ either be replaced with the input data or will be updated to the
+ bitwise OR or the old value and the input data, depending on the
+ contents of the signal1_type, or signal2_type respectively,
+ file.
+
+
+ /signal1_type
+ /signal2_type
+ These two files change the behavior of the signal1 and signal2 notifi-
+ cation files. The contain a numerical ASCII string which is read as
+ either "1" or "0". In mode 0 (overwrite), the hardware replaces the
+ contents of the signal channel with the data that is written to it. in
+ mode 1 (logical OR), the hardware accumulates the bits that are subse-
+ quently written to it. The possible operations on an open signal1_type
+ or signal2_type file are:
+
+ read(2)
+ When the count supplied to the read call is shorter than the
+ required length for the digit plus a newline character, subse-
+ quent reads from the same file descriptor will result in com-
+ pleting the string. When a complete string has been read, all
+ subsequent read operations will return zero bytes and a new file
+ descriptor needs to be opened to read the value again.
+
+ write(2)
+ A write operation on the file results in setting the register to
+ the value given in the string. The string is parsed from the
+ beginning to the first non-numeric character or the end of the
+ buffer. Subsequent writes to the same file descriptor overwrite
+ the previous setting.
+
+
+EXAMPLES
+ /etc/fstab entry
+ none /spu spufs gid=spu 0 0
+
+
+AUTHORS
+ Arnd Bergmann <arndb@de.ibm.com>, Mark Nutter <mnutter@us.ibm.com>,
+ Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
+
+SEE ALSO
+ capabilities(7), close(2), spu_create(2), spu_run(2), spufs(7)
+
+
+
+Linux 2005-09-28 SPUFS(2)
+
+------------------------------------------------------------------------------
+
+SPU_RUN(2) Linux Programmer's Manual SPU_RUN(2)
+
+
+
+NAME
+ spu_run - execute an spu context
+
+
+SYNOPSIS
+ #include <sys/spu.h>
+
+ int spu_run(int fd, unsigned int *npc, unsigned int *event);
+
+DESCRIPTION
+ The spu_run system call is used on PowerPC machines that implement the
+ Cell Broadband Engine Architecture in order to access Synergistic Pro-
+ cessor Units (SPUs). It uses the fd that was returned from spu_cre-
+ ate(2) to address a specific SPU context. When the context gets sched-
+ uled to a physical SPU, it starts execution at the instruction pointer
+ passed in npc.
+
+ Execution of SPU code happens synchronously, meaning that spu_run does
+ not return while the SPU is still running. If there is a need to exe-
+ cute SPU code in parallel with other code on either the main CPU or
+ other SPUs, you need to create a new thread of execution first, e.g.
+ using the pthread_create(3) call.
+
+ When spu_run returns, the current value of the SPU instruction pointer
+ is written back to npc, so you can call spu_run again without updating
+ the pointers.
+
+ event can be a NULL pointer or point to an extended status code that
+ gets filled when spu_run returns. It can be one of the following con-
+ stants:
+
+ SPE_EVENT_DMA_ALIGNMENT
+ A DMA alignment error
+
+ SPE_EVENT_SPE_DATA_SEGMENT
+ A DMA segmentation error
+
+ SPE_EVENT_SPE_DATA_STORAGE
+ A DMA storage error
+
+ If NULL is passed as the event argument, these errors will result in a
+ signal delivered to the calling process.
+
+RETURN VALUE
+ spu_run returns the value of the spu_status register or -1 to indicate
+ an error and set errno to one of the error codes listed below. The
+ spu_status register value contains a bit mask of status codes and
+ optionally a 14 bit code returned from the stop-and-signal instruction
+ on the SPU. The bit masks for the status codes are:
+
+ 0x02 SPU was stopped by stop-and-signal.
+
+ 0x04 SPU was stopped by halt.
+
+ 0x08 SPU is waiting for a channel.
+
+ 0x10 SPU is in single-step mode.
+
+ 0x20 SPU has tried to execute an invalid instruction.
+
+ 0x40 SPU has tried to access an invalid channel.
+
+ 0x3fff0000
+ The bits masked with this value contain the code returned from
+ stop-and-signal.
+
+ There are always one or more of the lower eight bits set or an error
+ code is returned from spu_run.
+
+ERRORS
+ EAGAIN or EWOULDBLOCK
+ fd is in non-blocking mode and spu_run would block.
+
+ EBADF fd is not a valid file descriptor.
+
+ EFAULT npc is not a valid pointer or status is neither NULL nor a valid
+ pointer.
+
+ EINTR A signal occured while spu_run was in progress. The npc value
+ has been updated to the new program counter value if necessary.
+
+ EINVAL fd is not a file descriptor returned from spu_create(2).
+
+ ENOMEM Insufficient memory was available to handle a page fault result-
+ ing from an MFC direct memory access.
+
+ ENOSYS the functionality is not provided by the current system, because
+ either the hardware does not provide SPUs or the spufs module is
+ not loaded.
+
+
+NOTES
+ spu_run is meant to be used from libraries that implement a more
+ abstract interface to SPUs, not to be used from regular applications.
+ See http://www.bsc.es/projects/deepcomputing/linuxoncell/ for the rec-
+ ommended libraries.
+
+
+CONFORMING TO
+ This call is Linux specific and only implemented by the ppc64 architec-
+ ture. Programs using this system call are not portable.
+
+
+BUGS
+ The code does not yet fully implement all features lined out here.
+
+
+AUTHOR
+ Arnd Bergmann <arndb@de.ibm.com>
+
+SEE ALSO
+ capabilities(7), close(2), spu_create(2), spufs(7)
+
+
+
+Linux 2005-09-28 SPU_RUN(2)
+
+------------------------------------------------------------------------------
+
+SPU_CREATE(2) Linux Programmer's Manual SPU_CREATE(2)
+
+
+
+NAME
+ spu_create - create a new spu context
+
+
+SYNOPSIS
+ #include <sys/types.h>
+ #include <sys/spu.h>
+
+ int spu_create(const char *pathname, int flags, mode_t mode);
+
+DESCRIPTION
+ The spu_create system call is used on PowerPC machines that implement
+ the Cell Broadband Engine Architecture in order to access Synergistic
+ Processor Units (SPUs). It creates a new logical context for an SPU in
+ pathname and returns a handle to associated with it. pathname must
+ point to a non-existing directory in the mount point of the SPU file
+ system (spufs). When spu_create is successful, a directory gets cre-
+ ated on pathname and it is populated with files.
+
+ The returned file handle can only be passed to spu_run(2) or closed,
+ other operations are not defined on it. When it is closed, all associ-
+ ated directory entries in spufs are removed. When the last file handle
+ pointing either inside of the context directory or to this file
+ descriptor is closed, the logical SPU context is destroyed.
+
+ The parameter flags can be zero or any bitwise or'd combination of the
+ following constants:
+
+ SPU_RAWIO
+ Allow mapping of some of the hardware registers of the SPU into
+ user space. This flag requires the CAP_SYS_RAWIO capability, see
+ capabilities(7).
+
+ The mode parameter specifies the permissions used for creating the new
+ directory in spufs. mode is modified with the user's umask(2) value
+ and then used for both the directory and the files contained in it. The
+ file permissions mask out some more bits of mode because they typically
+ support only read or write access. See stat(2) for a full list of the
+ possible mode values.
+
+
+RETURN VALUE
+ spu_create returns a new file descriptor. It may return -1 to indicate
+ an error condition and set errno to one of the error codes listed
+ below.
+
+
+ERRORS
+ EACCESS
+ The current user does not have write access on the spufs mount
+ point.
+
+ EEXIST An SPU context already exists at the given path name.
+
+ EFAULT pathname is not a valid string pointer in the current address
+ space.
+
+ EINVAL pathname is not a directory in the spufs mount point.
+
+ ELOOP Too many symlinks were found while resolving pathname.
+
+ EMFILE The process has reached its maximum open file limit.
+
+ ENAMETOOLONG
+ pathname was too long.
+
+ ENFILE The system has reached the global open file limit.
+
+ ENOENT Part of pathname could not be resolved.
+
+ ENOMEM The kernel could not allocate all resources required.
+
+ ENOSPC There are not enough SPU resources available to create a new
+ context or the user specific limit for the number of SPU con-
+ texts has been reached.
+
+ ENOSYS the functionality is not provided by the current system, because
+ either the hardware does not provide SPUs or the spufs module is
+ not loaded.
+
+ ENOTDIR
+ A part of pathname is not a directory.
+
+
+
+NOTES
+ spu_create is meant to be used from libraries that implement a more
+ abstract interface to SPUs, not to be used from regular applications.
+ See http://www.bsc.es/projects/deepcomputing/linuxoncell/ for the rec-
+ ommended libraries.
+
+
+FILES
+ pathname must point to a location beneath the mount point of spufs. By
+ convention, it gets mounted in /spu.
+
+
+CONFORMING TO
+ This call is Linux specific and only implemented by the ppc64 architec-
+ ture. Programs using this system call are not portable.
+
+
+BUGS
+ The code does not yet fully implement all features lined out here.
+
+
+AUTHOR
+ Arnd Bergmann <arndb@de.ibm.com>
+
+SEE ALSO
+ capabilities(7), close(2), spu_run(2), spufs(7)
+
+
+
+Linux 2005-09-28 SPU_CREATE(2)
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index acb010bb087b..0dc848bf0b56 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -998,6 +998,8 @@ running once the system is up.
nowb [ARM]
+ nr_uarts= [SERIAL] maximum number of UARTs to be registered.
+
opl3= [HW,OSS]
Format: <io>
diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt
index 0541fe1de704..0ea5a0c6e827 100644
--- a/Documentation/kprobes.txt
+++ b/Documentation/kprobes.txt
@@ -411,7 +411,8 @@ int init_module(void)
printk("Couldn't find %s to plant kprobe\n", "do_fork");
return -1;
}
- if ((ret = register_kprobe(&kp) < 0)) {
+ ret = register_kprobe(&kp);
+ if (ret < 0) {
printk("register_kprobe failed, returned %d\n", ret);
return -1;
}
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index b0fe41da007b..8d8b4e5ea184 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -945,7 +945,6 @@ bond0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4
collisions:0 txqueuelen:0
eth0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4
- inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0
UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1
RX packets:3573025 errors:0 dropped:0 overruns:0 frame:0
TX packets:1643167 errors:1 dropped:0 overruns:1 carrier:0
@@ -953,7 +952,6 @@ eth0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4
Interrupt:10 Base address:0x1080
eth1 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4
- inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0
UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1
RX packets:3651769 errors:0 dropped:0 overruns:0 frame:0
TX packets:1643480 errors:0 dropped:0 overruns:0 carrier:0
diff --git a/Documentation/powerpc/00-INDEX b/Documentation/powerpc/00-INDEX
index e7bea0a407b4..d6d65b9bcfe3 100644
--- a/Documentation/powerpc/00-INDEX
+++ b/Documentation/powerpc/00-INDEX
@@ -8,12 +8,18 @@ please mail me.
cpu_features.txt
- info on how we support a variety of CPUs with minimal compile-time
options.
+eeh-pci-error-recovery.txt
+ - info on PCI Bus EEH Error Recovery
+hvcs.txt
+ - IBM "Hypervisor Virtual Console Server" Installation Guide
+mpc52xx.txt
+ - Linux 2.6.x on MPC52xx family
ppc_htab.txt
- info about the Linux/PPC /proc/ppc_htab entry
-smp.txt
- - use and state info about Linux/PPC on MP machines
SBC8260_memory_mapping.txt
- EST SBC8260 board info
+smp.txt
+ - use and state info about Linux/PPC on MP machines
sound.txt
- info on sound support under Linux/PPC
zImage_layout.txt
diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv
index 330246ac80f8..74fb085e178b 100644
--- a/Documentation/video4linux/CARDLIST.bttv
+++ b/Documentation/video4linux/CARDLIST.bttv
@@ -141,3 +141,4 @@
140 -> Osprey 440 [0070:ff07]
141 -> Asound Skyeye PCTV
142 -> Sabrent TV-FM (bttv version)
+143 -> Hauppauge ImpactVCB (bt878) [0070:13eb]
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index a1017d1a85d4..34b6e59f2968 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -16,7 +16,7 @@
15 -> DViCO FusionHDTV DVB-T1 [18ac:db00]
16 -> KWorld LTV883RF
17 -> DViCO FusionHDTV 3 Gold-Q [18ac:d810]
- 18 -> Hauppauge Nova-T DVB-T [0070:9002]
+ 18 -> Hauppauge Nova-T DVB-T [0070:9002,0070:9001]
19 -> Conexant DVB-T reference design [14f1:0187]
20 -> Provideo PV259 [1540:2580]
21 -> DViCO FusionHDTV DVB-T Plus [18ac:db10]
@@ -35,3 +35,11 @@
34 -> ATI HDTV Wonder [1002:a101]
35 -> WinFast DTV1000-T [107d:665f]
36 -> AVerTV 303 (M126) [1461:000a]
+ 37 -> Hauppauge Nova-S-Plus DVB-S [0070:9201,0070:9202]
+ 38 -> Hauppauge Nova-SE2 DVB-S [0070:9200]
+ 39 -> KWorld DVB-S 100 [17de:08b2]
+ 40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid [0070:9400,0070:9402]
+ 41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile) [0070:9800,0070:9802]
+ 42 -> digitalnow DNTV Live! DVB-T Pro [1822:0025]
+ 43 -> KWorld/VStream XPert DVB-T with cx22702 [17de:08a1]
+ 44 -> DViCO FusionHDTV DVB-T Dual Digital [18ac:db50]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index efb708ec116a..cb3a59bbeb17 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -56,7 +56,7 @@
55 -> LifeView FlyDVB-T DUO [5168:0502,5168:0306]
56 -> Avermedia AVerTV 307 [1461:a70a]
57 -> Avermedia AVerTV GO 007 FM [1461:f31f]
- 58 -> ADS Tech Instant TV (saa7135) [1421:0350,1421:0370,1421:1370]
+ 58 -> ADS Tech Instant TV (saa7135) [1421:0350,1421:0351,1421:0370,1421:1370]
59 -> Kworld/Tevion V-Stream Xpert TV PVR7134
60 -> Typhoon DVB-T Duo Digital/Analog Cardbus [4e42:0502]
61 -> Philips TOUGH DVB-T reference design [1131:2004]
@@ -81,4 +81,5 @@
80 -> ASUS Digimatrix TV [1043:0210]
81 -> Philips Tiger reference design [1131:2018]
82 -> MSI TV@Anywhere plus [1462:6231]
-
+ 83 -> Terratec Cinergy 250 PCI TV [153b:1160]
+ 84 -> LifeView FlyDVB Trio [5168:0319]
diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner
index 9d6544ea9f41..0bf3d5bf9ef8 100644
--- a/Documentation/video4linux/CARDLIST.tuner
+++ b/Documentation/video4linux/CARDLIST.tuner
@@ -40,7 +40,7 @@ tuner=38 - Philips PAL/SECAM multi (FM1216ME MK3)
tuner=39 - LG NTSC (newer TAPC series)
tuner=40 - HITACHI V7-J180AT
tuner=41 - Philips PAL_MK (FI1216 MK)
-tuner=42 - Philips 1236D ATSC/NTSC daul in
+tuner=42 - Philips 1236D ATSC/NTSC dual in
tuner=43 - Philips NTSC MK3 (FM1236MK3 or FM1236/F)
tuner=44 - Philips 4 in 1 (ATI TV Wonder Pro/Conexant)
tuner=45 - Microtune 4049 FM5
@@ -50,7 +50,7 @@ tuner=48 - Tenna TNF 8831 BGFF)
tuner=49 - Microtune 4042 FI5 ATSC/NTSC dual in
tuner=50 - TCL 2002N
tuner=51 - Philips PAL/SECAM_D (FM 1256 I-H3)
-tuner=52 - Thomson DDT 7610 (ATSC/NTSC)
+tuner=52 - Thomson DTT 7610 (ATSC/NTSC)
tuner=53 - Philips FQ1286
tuner=54 - tda8290+75
tuner=55 - TCL 2002MB
@@ -58,7 +58,7 @@ tuner=56 - Philips PAL/SECAM multi (FQ1216AME MK4)
tuner=57 - Philips FQ1236A MK4
tuner=58 - Ymec TVision TVF-8531MF/8831MF/8731MF
tuner=59 - Ymec TVision TVF-5533MF
-tuner=60 - Thomson DDT 7611 (ATSC/NTSC)
+tuner=60 - Thomson DTT 761X (ATSC/NTSC)
tuner=61 - Tena TNF9533-D/IF/TNF9533-B/DF
tuner=62 - Philips TEA5767HN FM Radio
tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner
diff --git a/MAINTAINERS b/MAINTAINERS
index 76dc820bc889..270e28c0506a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1697,7 +1697,6 @@ S: Maintained
MARVELL MV64340 ETHERNET DRIVER
P: Manish Lachwani
-M: Manish_Lachwani@pmc-sierra.com
L: linux-mips@linux-mips.org
L: netdev@vger.kernel.org
S: Supported
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index 06be405be399..9c89eebc356f 100644
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -1171,7 +1171,8 @@ static int __init vpe_module_init(void)
return -ENODEV;
}
- if ((major = register_chrdev(0, module_name, &vpe_fops) < 0)) {
+ major = register_chrdev(0, module_name, &vpe_fops);
+ if (major < 0) {
printk("VPE loader: unable to register character device\n");
return major;
}
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 331483ace0d9..28004f002ec9 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -47,7 +47,7 @@ config PPC
config EARLY_PRINTK
bool
- default y if PPC64
+ default y
config COMPAT
bool
@@ -297,6 +297,7 @@ config PPC_PMAC64
bool
depends on PPC_PMAC && POWER4
select U3_DART
+ select MPIC_BROKEN_U3
select GENERIC_TBSYNC
default y
@@ -325,9 +326,7 @@ config PPC_CELL
select MMIO_NVRAM
config PPC_OF
- bool
- depends on PPC_MULTIPLATFORM # for now
- default y
+ def_bool y
config XICS
depends on PPC_PSERIES
@@ -376,11 +375,28 @@ config CELL_IIC
bool
default y
+config CRASH_DUMP
+ bool "kernel crash dumps (EXPERIMENTAL)"
+ depends on PPC_MULTIPLATFORM
+ depends on EXPERIMENTAL
+ help
+ Build a kernel suitable for use as a kdump capture kernel.
+ The kernel will be linked at a different address than normal, and
+ so can only be used for Kdump.
+
+ Don't change this unless you know what you are doing.
+
config IBMVIO
depends on PPC_PSERIES || PPC_ISERIES
bool
default y
+config IBMEBUS
+ depends on PPC_PSERIES
+ bool "Support for GX bus based adapters"
+ help
+ Bus device driver for GX bus based adapters.
+
config PPC_MPC106
bool
default n
@@ -472,6 +488,7 @@ source arch/powerpc/platforms/embedded6xx/Kconfig
source arch/powerpc/platforms/4xx/Kconfig
source arch/powerpc/platforms/85xx/Kconfig
source arch/powerpc/platforms/8xx/Kconfig
+source arch/powerpc/platforms/cell/Kconfig
menu "Kernel options"
@@ -575,11 +592,12 @@ config ARCH_SELECT_MEMORY_MODEL
depends on PPC64
config ARCH_FLATMEM_ENABLE
- def_bool y
- depends on PPC64 && !NUMA
+ def_bool y
+ depends on (PPC64 && !NUMA) || PPC32
config ARCH_SPARSEMEM_ENABLE
def_bool y
+ depends on PPC64
config ARCH_SPARSEMEM_DEFAULT
def_bool y
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index a13eb575f834..5f80e58e5cb3 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -151,7 +151,7 @@ CPPFLAGS_vmlinux.lds := -Upowerpc
# All the instructions talk about "make bzImage".
bzImage: zImage
-BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm
+BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm uImage
.PHONY: $(BOOT_TARGETS)
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 9770f587af73..22726aefc8ea 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -143,6 +143,36 @@ $(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote
@cp -f $< $@
$(call if_changed,addnote)
+#-----------------------------------------------------------
+# build u-boot images
+#-----------------------------------------------------------
+quiet_cmd_mygzip = GZIP $@
+cmd_mygzip = gzip -f -9 < $< > $@.$$$$ && mv $@.$$$$ $@
+
+quiet_cmd_objbin = OBJCOPY $@
+ cmd_objbin = $(OBJCOPY) -O binary $< $@
+
+quiet_cmd_uimage = UIMAGE $@
+ cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A ppc -O linux -T kernel \
+ -C gzip -a 00000000 -e 00000000 -n 'Linux-$(KERNELRELEASE)' \
+ -d $< $@
+
+MKIMAGE := $(srctree)/scripts/mkuboot.sh
+targets += uImage
+extra-y += vmlinux.bin vmlinux.gz
+
+$(obj)/vmlinux.bin: vmlinux FORCE
+ $(call if_changed,objbin)
+
+$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,mygzip)
+
+$(obj)/uImage: $(obj)/vmlinux.gz
+ $(Q)rm -f $@
+ $(call cmd,uimage)
+ @echo -n ' Image: $@ '
+ @if [ -f $@ ]; then echo 'is ready' ; else echo 'not made'; fi
+
install: $(CONFIGURE) $(BOOTIMAGE)
sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" "$(BOOTIMAGE)"
diff --git a/arch/powerpc/configs/pmac32_defconfig b/arch/powerpc/configs/pmac32_defconfig
new file mode 100644
index 000000000000..398203bd98eb
--- /dev/null
+++ b/arch/powerpc/configs/pmac32_defconfig
@@ -0,0 +1,1729 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.15-rc5
+# Tue Dec 13 17:24:05 2005
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# Processor support
+#
+CONFIG_6xx=y
+# CONFIG_PPC_52xx is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+# CONFIG_E500 is not set
+CONFIG_PPC_FPU=y
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_SMP 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_LOCALVERSION_AUTO is not set
+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=y
+CONFIG_KOBJECT_UEVENT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_EMBEDDED is not set
+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_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=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_LBD=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Platform support
+#
+CONFIG_PPC_MULTIPLATFORM=y
+# CONFIG_PPC_ISERIES is not set
+# CONFIG_EMBEDDED6xx is not set
+# CONFIG_APUS is not set
+# CONFIG_PPC_CHRP is not set
+CONFIG_PPC_PMAC=y
+CONFIG_PPC_OF=y
+CONFIG_MPIC=y
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_PPC_MPC106=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_PMAC=y
+CONFIG_PPC601_SYNC_FIX=y
+# CONFIG_TAU is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+# CONFIG_KEXEC is not set
+CONFIG_ARCH_FLATMEM_ENABLE=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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+CONFIG_PM_DEBUG=y
+CONFIG_SOFTWARE_SUSPEND=y
+CONFIG_PM_STD_PARTITION=""
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_LEGACY_PROC=y
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=m
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+CONFIG_CARDBUS=y
+
+#
+# PC-card bridges
+#
+CONFIG_YENTA=m
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+CONFIG_PCCARD_NONSTATIC=m
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+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=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# 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_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+# CONFIG_IP_NF_CT_ACCT is not set
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_REALM is not set
+# CONFIG_IP_NF_MATCH_SCTP is not set
+CONFIG_IP_NF_MATCH_DCCP=m
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
+CONFIG_IP_NF_MATCH_STRING=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+# CONFIG_IP_NF_TARGET_LOG is not set
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+# CONFIG_IP_NF_TARGET_NFQUEUE is not set
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+# CONFIG_IP_NF_MANGLE is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP=m
+CONFIG_INET_DCCP_DIAG=m
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP_CCID3=m
+CONFIG_IP_DCCP_TFRC_LIB=m
+
+#
+# DCCP Kernel Hacking
+#
+# CONFIG_IP_DCCP_DEBUG is not set
+# CONFIG_IP_DCCP_UNLOAD_HACK 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
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_SIGMATEL_FIR is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+# CONFIG_VIA_FIR is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+# CONFIG_BT_HCIUSB_SCO is not set
+# CONFIG_BT_HCIUART is not set
+CONFIG_BT_HCIBCM203X=m
+# CONFIG_BT_HCIBPA10X is not set
+CONFIG_BT_HCIBFUSB=m
+# CONFIG_BT_HCIDTL1 is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBLUECARD is not set
+# CONFIG_BT_HCIBTUART is not set
+# CONFIG_BT_HCIVHCI is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_CRYPT_TKIP=m
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+
+#
+# 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_MAC_FLOPPY=y
+# 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=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_UB=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC is not set
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_SL82C105=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=y
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_IDE_PMAC=y
+CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y
+CONFIG_BLK_DEV_IDEDMA_PMAC=y
+CONFIG_BLK_DEV_IDE_PMAC_BLINK=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+CONFIG_AIC7XXX_DEBUG_ENABLE=y
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+CONFIG_SCSI_AIC7XXX_OLD=m
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_SCSI_MESH=y
+CONFIG_SCSI_MESH_SYNC_RATE=5
+CONFIG_SCSI_MESH_RESET_DELAY_MS=1000
+CONFIG_SCSI_MAC53C94=y
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_SYM53C500 is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+# CONFIG_DM_SNAPSHOT is not set
+# CONFIG_DM_MIRROR is not set
+# CONFIG_DM_ZERO is not set
+# CONFIG_DM_MULTIPATH is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+CONFIG_IEEE1394=m
+
+#
+# Subsystem Options
+#
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+# CONFIG_IEEE1394_OUI_DB is not set
+CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
+CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
+# CONFIG_IEEE1394_EXPORT_FULL_API is not set
+
+#
+# Device Drivers
+#
+# CONFIG_IEEE1394_PCILYNX is not set
+CONFIG_IEEE1394_OHCI1394=m
+
+#
+# Protocol Drivers
+#
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_IEEE1394_SBP2=m
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+CONFIG_IEEE1394_ETH1394=m
+CONFIG_IEEE1394_DV1394=m
+CONFIG_IEEE1394_RAWIO=m
+# CONFIG_IEEE1394_CMP is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+CONFIG_ADB=y
+CONFIG_ADB_CUDA=y
+CONFIG_ADB_PMU=y
+CONFIG_PMAC_APM_EMU=y
+CONFIG_PMAC_MEDIABAY=y
+CONFIG_PMAC_BACKLIGHT=y
+CONFIG_INPUT_ADBHID=y
+CONFIG_MAC_EMUMOUSEBTN=y
+CONFIG_THERM_WINDTUNNEL=m
+CONFIG_THERM_ADT746X=m
+# CONFIG_WINDFARM is not set
+# CONFIG_ANSLCD is not set
+
+#
+# Network device support
+#
+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
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_MACE=y
+# CONFIG_MACE_AAUI_PORT is not set
+CONFIG_BMAC=y
+# CONFIG_HAPPYMEAL is not set
+CONFIG_SUNGEM=y
+# CONFIG_CASSINI 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=y
+# 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 is not set
+# 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_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_MV643XX_ETH 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=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_PCMCIA_WAVELAN is not set
+# CONFIG_PCMCIA_NETWAVE is not set
+
+#
+# Wireless 802.11 Frequency Hopping cards support
+#
+# CONFIG_PCMCIA_RAYCS is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_AIRO is not set
+CONFIG_HERMES=m
+CONFIG_APPLE_AIRPORT=m
+# CONFIG_PLX_HERMES is not set
+# CONFIG_TMD_HERMES is not set
+# CONFIG_NORTEL_HERMES is not set
+# CONFIG_PCI_HERMES is not set
+# CONFIG_ATMEL is not set
+
+#
+# Wireless 802.11b Pcmcia/Cardbus cards support
+#
+# CONFIG_PCMCIA_HERMES is not set
+# CONFIG_PCMCIA_SPECTRUM is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_PCMCIA_WL3501 is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+CONFIG_PRISM54=m
+# CONFIG_HOSTAP is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=m
+# CONFIG_SERIAL_8250_CS is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=m
+# CONFIG_SERIAL_PMACZILOG is not set
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_NVRAM=y
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X 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_AGP=m
+CONFIG_AGP_UNINORTH=m
+CONFIG_DRM=m
+# CONFIG_DRM_TDFX is not set
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
+# CONFIG_DRM_VIA is not set
+# CONFIG_DRM_SAVAGE is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_KEYWEST=m
+# CONFIG_I2C_MPC is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_MACMODES=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+CONFIG_FB_OF=y
+CONFIG_FB_CONTROL=y
+CONFIG_FB_PLATINUM=y
+CONFIG_FB_VALKYRIE=y
+CONFIG_FB_CT65550=y
+# CONFIG_FB_ASILIANT is not set
+CONFIG_FB_IMSTT=y
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_NVIDIA=y
+CONFIG_FB_NVIDIA_I2C=y
+# CONFIG_FB_RIVA is not set
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+# CONFIG_FB_MATROX_G is not set
+# CONFIG_FB_MATROX_I2C is not set
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_RADEON_OLD is not set
+CONFIG_FB_RADEON=y
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_ATY128=y
+CONFIG_FB_ATY=y
+CONFIG_FB_ATY_CT=y
+# CONFIG_FB_ATY_GENERIC_LCD is not set
+# CONFIG_FB_ATY_XL_INIT is not set
+CONFIG_FB_ATY_GX=y
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+CONFIG_FB_3DFX=y
+# CONFIG_FB_3DFX_ACCEL is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_CYBLA is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+CONFIG_DMASOUND_PMAC=m
+CONFIG_DMASOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_GENERIC_DRIVER=y
+
+#
+# Generic devices
+#
+CONFIG_SND_DUMMY=m
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_YMFPCI is not set
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_HDA_INTEL is not set
+
+#
+# ALSA PowerMac devices
+#
+CONFIG_SND_POWERMAC=m
+# CONFIG_SND_POWERMAC_AUTO_DRC is not set
+
+#
+# USB devices
+#
+CONFIG_SND_USB_AUDIO=m
+# CONFIG_SND_USB_USX2Y is not set
+
+#
+# PCMCIA devices
+#
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_STORAGE is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+CONFIG_USB_APPLETOUCH=y
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=m
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+CONFIG_USB_NET_ZAURUS=m
+# CONFIG_USB_ZD1201 is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_AIRPRIME is not set
+# CONFIG_USB_SERIAL_ANYDATA is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+CONFIG_USB_EZUSB=y
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# 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
+
+#
+# SN Devices
+#
+
+#
+# File systems
+#
+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=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# 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
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+CONFIG_RELAYFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# 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=y
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_LOCKD=y
+CONFIG_EXPORTFS=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=m
+# CONFIG_SMB_NLS_DEFAULT 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
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+
+#
+# Instrumentation Support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+
+#
+# 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_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_DEBUGGER=y
+CONFIG_XMON=y
+CONFIG_XMON_DEFAULT=y
+# CONFIG_BDI_SWITCH is not set
+CONFIG_BOOTX_TEXT=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 9ed551b6c172..6e03b595b6c8 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -17,11 +17,11 @@ obj-y += vdso32/
obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \
signal_64.o ptrace32.o systbl.o \
paca.o ioctl32.o cpu_setup_power4.o \
- firmware.o sysfs.o udbg.o idle_64.o
+ firmware.o sysfs.o idle_64.o
obj-$(CONFIG_PPC64) += vdso64/
obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
obj-$(CONFIG_POWER4) += idle_power4.o
-obj-$(CONFIG_PPC_OF) += of_device.o
+obj-$(CONFIG_PPC_OF) += of_device.o prom_parse.o
procfs-$(CONFIG_PPC64) := proc_ppc64.o
obj-$(CONFIG_PROC_FS) += $(procfs-y)
rtaspci-$(CONFIG_PPC64) := rtas_pci.o
@@ -30,12 +30,10 @@ obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o
obj-$(CONFIG_RTAS_PROC) += rtas-proc.o
obj-$(CONFIG_LPARCFG) += lparcfg.o
obj-$(CONFIG_IBMVIO) += vio.o
+obj-$(CONFIG_IBMEBUS) += ibmebus.o
obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o
-obj-$(CONFIG_PPC_PSERIES) += udbg_16550.o
-obj-$(CONFIG_PPC_MAPLE) += udbg_16550.o
-udbgscc-$(CONFIG_PPC64) := udbg_scc.o
-obj-$(CONFIG_PPC_PMAC) += $(udbgscc-y)
obj64-$(CONFIG_PPC_MULTIPLATFORM) += nvram_64.o
+obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
ifeq ($(CONFIG_PPC_MERGE),y)
@@ -48,25 +46,25 @@ extra-$(CONFIG_8xx) := head_8xx.o
extra-y += vmlinux.lds
obj-y += process.o init_task.o time.o \
- prom.o traps.o setup-common.o
+ prom.o traps.o setup-common.o udbg.o
obj-$(CONFIG_PPC32) += entry_32.o setup_32.o misc_32.o systbl.o
obj-$(CONFIG_PPC64) += misc_64.o dma_64.o iommu.o
-obj-$(CONFIG_PPC_OF) += prom_init.o
+obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o
obj-$(CONFIG_MODULES) += ppc_ksyms.o
obj-$(CONFIG_BOOTX_TEXT) += btext.o
obj-$(CONFIG_6xx) += idle_6xx.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_KPROBES) += kprobes.o
-
+obj-$(CONFIG_SERIAL_8250) += legacy_serial.o udbg_16550.o
module-$(CONFIG_PPC64) += module_64.o
obj-$(CONFIG_MODULES) += $(module-y)
pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o pci_iommu.o \
pci_direct_iommu.o iomap.o
obj-$(CONFIG_PCI) += $(pci64-y)
-
-kexec64-$(CONFIG_PPC64) += machine_kexec_64.o
-obj-$(CONFIG_KEXEC) += $(kexec64-y)
+kexec-$(CONFIG_PPC64) := machine_kexec_64.o
+kexec-$(CONFIG_PPC32) := machine_kexec_32.o
+obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o $(kexec-y)
ifeq ($(CONFIG_PPC_ISERIES),y)
$(obj)/head_64.o: $(obj)/lparmap.s
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 91538d2445bf..56399c5c931a 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -92,9 +92,9 @@ int main(void)
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
- DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror));
-#ifdef CONFIG_PPC32
+ DEFINE(TI_SIGFRAME, offsetof(struct thread_info, nvgprs_frame));
DEFINE(TI_TASK, offsetof(struct thread_info, task));
+#ifdef CONFIG_PPC32
DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
#endif /* CONFIG_PPC32 */
@@ -131,11 +131,9 @@ int main(void)
DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas));
DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas));
#endif /* CONFIG_HUGETLB_PAGE */
- DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr));
DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen));
DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc));
DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb));
- DEFINE(PACA_EXDSI, offsetof(struct paca_struct, exdsi));
DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp));
DEFINE(PACALPPACA, offsetof(struct paca_struct, lppaca));
DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c
index bdfba92b2b38..6223d39177cb 100644
--- a/arch/powerpc/kernel/btext.c
+++ b/arch/powerpc/kernel/btext.c
@@ -31,15 +31,18 @@ static void draw_byte_32(unsigned char *bits, unsigned int *base, int rb);
static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb);
static void draw_byte_8(unsigned char *bits, unsigned int *base, int rb);
-static int g_loc_X;
-static int g_loc_Y;
-static int g_max_loc_X;
-static int g_max_loc_Y;
+#define __force_data __attribute__((__section__(".data")))
-static int dispDeviceRowBytes;
-static int dispDeviceDepth;
-static int dispDeviceRect[4];
-static unsigned char *dispDeviceBase, *logicalDisplayBase;
+static int g_loc_X __force_data;
+static int g_loc_Y __force_data;
+static int g_max_loc_X __force_data;
+static int g_max_loc_Y __force_data;
+
+static int dispDeviceRowBytes __force_data;
+static int dispDeviceDepth __force_data;
+static int dispDeviceRect[4] __force_data;
+static unsigned char *dispDeviceBase __force_data;
+static unsigned char *logicalDisplayBase __force_data;
unsigned long disp_BAT[2] __initdata = {0, 0};
@@ -47,7 +50,7 @@ unsigned long disp_BAT[2] __initdata = {0, 0};
static unsigned char vga_font[cmapsz];
-int boot_text_mapped;
+int boot_text_mapped __force_data = 0;
int force_printk_to_btext = 0;
#ifdef CONFIG_PPC32
@@ -57,7 +60,7 @@ int force_printk_to_btext = 0;
*
* The display is mapped to virtual address 0xD0000000, rather
* than 1:1, because some some CHRP machines put the frame buffer
- * in the region starting at 0xC0000000 (KERNELBASE).
+ * in the region starting at 0xC0000000 (PAGE_OFFSET).
* This mapping is temporary and will disappear as soon as the
* setup done by MMU_Init() is applied.
*
@@ -66,10 +69,9 @@ int force_printk_to_btext = 0;
* is really badly aligned, but I didn't encounter this case
* yet.
*/
-void __init
-btext_prepare_BAT(void)
+void __init btext_prepare_BAT(void)
{
- unsigned long vaddr = KERNELBASE + 0x10000000;
+ unsigned long vaddr = PAGE_OFFSET + 0x10000000;
unsigned long addr;
unsigned long lowbits;
@@ -95,12 +97,13 @@ btext_prepare_BAT(void)
}
#endif
-/* This function will enable the early boot text when doing OF booting. This
- * way, xmon output should work too
+
+/* This function can be used to enable the early boot text when doing
+ * OF booting or within bootx init. It must be followed by a btext_unmap()
+ * call before the logical address becomes unuseable
*/
-void __init
-btext_setup_display(int width, int height, int depth, int pitch,
- unsigned long address)
+void __init btext_setup_display(int width, int height, int depth, int pitch,
+ unsigned long address)
{
g_loc_X = 0;
g_loc_Y = 0;
@@ -116,6 +119,11 @@ btext_setup_display(int width, int height, int depth, int pitch,
boot_text_mapped = 1;
}
+void __init btext_unmap(void)
+{
+ boot_text_mapped = 0;
+}
+
/* Here's a small text engine to use during early boot
* or for debugging purposes
*
@@ -127,7 +135,7 @@ btext_setup_display(int width, int height, int depth, int pitch,
* changes.
*/
-void map_boot_text(void)
+static void map_boot_text(void)
{
unsigned long base, offset, size;
unsigned char *vbase;
@@ -175,8 +183,9 @@ int btext_initialize(struct device_node *np)
if (prop)
address = *prop;
- /* FIXME: Add support for PCI reg properties */
-
+ /* FIXME: Add support for PCI reg properties. Right now, only
+ * reliable on macs
+ */
if (address == 0)
return -EINVAL;
@@ -184,7 +193,6 @@ int btext_initialize(struct device_node *np)
g_loc_Y = 0;
g_max_loc_X = width / 8;
g_max_loc_Y = height / 16;
- logicalDisplayBase = (unsigned char *)address;
dispDeviceBase = (unsigned char *)address;
dispDeviceRowBytes = pitch;
dispDeviceDepth = depth;
@@ -197,14 +205,12 @@ int btext_initialize(struct device_node *np)
return 0;
}
-void __init init_boot_display(void)
+int __init btext_find_display(int allow_nonstdout)
{
char *name;
struct device_node *np = NULL;
int rc = -ENODEV;
- printk("trying to initialize btext ...\n");
-
name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
if (name != NULL) {
np = of_find_node_by_path(name);
@@ -218,8 +224,8 @@ void __init init_boot_display(void)
}
if (np)
rc = btext_initialize(np);
- if (rc == 0)
- return;
+ if (rc == 0 || !allow_nonstdout)
+ return rc;
for (np = NULL; (np = of_find_node_by_type(np, "display"));) {
if (get_property(np, "linux,opened", NULL)) {
@@ -228,8 +234,9 @@ void __init init_boot_display(void)
printk("result: %d\n", rc);
}
if (rc == 0)
- return;
+ break;
}
+ return rc;
}
/* Calc the base address of a given point (x,y) */
@@ -277,44 +284,83 @@ EXPORT_SYMBOL(btext_update_display);
void btext_clearscreen(void)
{
- unsigned long *base = (unsigned long *)calc_base(0, 0);
+ unsigned int *base = (unsigned int *)calc_base(0, 0);
unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
- (dispDeviceDepth >> 3)) >> 3;
+ (dispDeviceDepth >> 3)) >> 2;
int i,j;
for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++)
{
- unsigned long *ptr = base;
+ unsigned int *ptr = base;
for(j=width; j; --j)
*(ptr++) = 0;
- base += (dispDeviceRowBytes >> 3);
+ base += (dispDeviceRowBytes >> 2);
}
}
+void btext_flushscreen(void)
+{
+ unsigned int *base = (unsigned int *)calc_base(0, 0);
+ unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
+ (dispDeviceDepth >> 3)) >> 2;
+ int i,j;
+
+ for (i=0; i < (dispDeviceRect[3] - dispDeviceRect[1]); i++)
+ {
+ unsigned int *ptr = base;
+ for(j = width; j > 0; j -= 8) {
+ __asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr));
+ ptr += 8;
+ }
+ base += (dispDeviceRowBytes >> 2);
+ }
+ __asm__ __volatile__ ("sync" ::: "memory");
+}
+
+void btext_flushline(void)
+{
+ unsigned int *base = (unsigned int *)calc_base(0, g_loc_Y << 4);
+ unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
+ (dispDeviceDepth >> 3)) >> 2;
+ int i,j;
+
+ for (i=0; i < 16; i++)
+ {
+ unsigned int *ptr = base;
+ for(j = width; j > 0; j -= 8) {
+ __asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr));
+ ptr += 8;
+ }
+ base += (dispDeviceRowBytes >> 2);
+ }
+ __asm__ __volatile__ ("sync" ::: "memory");
+}
+
+
#ifndef NO_SCROLL
static void scrollscreen(void)
{
- unsigned long *src = (unsigned long *)calc_base(0,16);
- unsigned long *dst = (unsigned long *)calc_base(0,0);
+ unsigned int *src = (unsigned int *)calc_base(0,16);
+ unsigned int *dst = (unsigned int *)calc_base(0,0);
unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
- (dispDeviceDepth >> 3)) >> 3;
+ (dispDeviceDepth >> 3)) >> 2;
int i,j;
for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++)
{
- unsigned long *src_ptr = src;
- unsigned long *dst_ptr = dst;
+ unsigned int *src_ptr = src;
+ unsigned int *dst_ptr = dst;
for(j=width; j; --j)
*(dst_ptr++) = *(src_ptr++);
- src += (dispDeviceRowBytes >> 3);
- dst += (dispDeviceRowBytes >> 3);
+ src += (dispDeviceRowBytes >> 2);
+ dst += (dispDeviceRowBytes >> 2);
}
for (i=0; i<16; i++)
{
- unsigned long *dst_ptr = dst;
+ unsigned int *dst_ptr = dst;
for(j=width; j; --j)
*(dst_ptr++) = 0;
- dst += (dispDeviceRowBytes >> 3);
+ dst += (dispDeviceRowBytes >> 2);
}
}
#endif /* ndef NO_SCROLL */
@@ -377,6 +423,14 @@ void btext_drawstring(const char *c)
btext_drawchar(*c++);
}
+void btext_drawtext(const char *c, unsigned int len)
+{
+ if (!boot_text_mapped)
+ return;
+ while (len--)
+ btext_drawchar(*c++);
+}
+
void btext_drawhex(unsigned long v)
{
char *hex_table = "0123456789abcdef";
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 1d85cedbbb7b..43c74a6b07b1 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -78,10 +78,8 @@ struct cpu_spec cpu_specs[] = {
.dcache_bsize = 128,
.num_pmcs = 8,
.cpu_setup = __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
.oprofile_cpu_type = "ppc64/power3",
- .oprofile_model = &op_model_rs64,
-#endif
+ .oprofile_type = RS64,
},
{ /* Power3+ */
.pvr_mask = 0xffff0000,
@@ -93,10 +91,8 @@ struct cpu_spec cpu_specs[] = {
.dcache_bsize = 128,
.num_pmcs = 8,
.cpu_setup = __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
.oprofile_cpu_type = "ppc64/power3",
- .oprofile_model = &op_model_rs64,
-#endif
+ .oprofile_type = RS64,
},
{ /* Northstar */
.pvr_mask = 0xffff0000,
@@ -108,10 +104,8 @@ struct cpu_spec cpu_specs[] = {
.dcache_bsize = 128,
.num_pmcs = 8,
.cpu_setup = __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
.oprofile_cpu_type = "ppc64/rs64",
- .oprofile_model = &op_model_rs64,
-#endif
+ .oprofile_type = RS64,
},
{ /* Pulsar */
.pvr_mask = 0xffff0000,
@@ -123,10 +117,8 @@ struct cpu_spec cpu_specs[] = {
.dcache_bsize = 128,
.num_pmcs = 8,
.cpu_setup = __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
.oprofile_cpu_type = "ppc64/rs64",
- .oprofile_model = &op_model_rs64,
-#endif
+ .oprofile_type = RS64,
},
{ /* I-star */
.pvr_mask = 0xffff0000,
@@ -138,10 +130,8 @@ struct cpu_spec cpu_specs[] = {
.dcache_bsize = 128,
.num_pmcs = 8,
.cpu_setup = __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
.oprofile_cpu_type = "ppc64/rs64",
- .oprofile_model = &op_model_rs64,
-#endif
+ .oprofile_type = RS64,
},
{ /* S-star */
.pvr_mask = 0xffff0000,
@@ -153,10 +143,8 @@ struct cpu_spec cpu_specs[] = {
.dcache_bsize = 128,
.num_pmcs = 8,
.cpu_setup = __setup_cpu_power3,
-#ifdef CONFIG_OPROFILE
.oprofile_cpu_type = "ppc64/rs64",
- .oprofile_model = &op_model_rs64,
-#endif
+ .oprofile_type = RS64,
},
{ /* Power4 */
.pvr_mask = 0xffff0000,
@@ -168,10 +156,8 @@ struct cpu_spec cpu_specs[] = {
.dcache_bsize = 128,
.num_pmcs = 8,
.cpu_setup = __setup_cpu_power4,
-#ifdef CONFIG_OPROFILE
.oprofile_cpu_type = "ppc64/power4",
- .oprofile_model = &op_model_rs64,
-#endif
+ .oprofile_type = POWER4,
},
{ /* Power4+ */
.pvr_mask = 0xffff0000,
@@ -183,10 +169,8 @@ struct cpu_spec cpu_specs[] = {
.dcache_bsize = 128,
.num_pmcs = 8,
.cpu_setup = __setup_cpu_power4,
-#ifdef CONFIG_OPROFILE
.oprofile_cpu_type = "ppc64/power4",
- .oprofile_model = &op_model_power4,
-#endif
+ .oprofile_type = POWER4,
},
{ /* PPC970 */
.pvr_mask = 0xffff0000,
@@ -199,10 +183,8 @@ struct cpu_spec cpu_specs[] = {
.dcache_bsize = 128,
.num_pmcs = 8,
.cpu_setup = __setup_cpu_ppc970,
-#ifdef CONFIG_OPROFILE
.oprofile_cpu_type = "ppc64/970",
- .oprofile_model = &op_model_power4,
-#endif
+ .oprofile_type = POWER4,
},
#endif /* CONFIG_PPC64 */
#if defined(CONFIG_PPC64) || defined(CONFIG_POWER4)
@@ -221,10 +203,8 @@ struct cpu_spec cpu_specs[] = {
.dcache_bsize = 128,
.num_pmcs = 8,
.cpu_setup = __setup_cpu_ppc970,
-#ifdef CONFIG_OPROFILE
.oprofile_cpu_type = "ppc64/970",
- .oprofile_model = &op_model_power4,
-#endif
+ .oprofile_type = POWER4,
},
#endif /* defined(CONFIG_PPC64) || defined(CONFIG_POWER4) */
#ifdef CONFIG_PPC64
@@ -238,10 +218,8 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_ppc970,
-#ifdef CONFIG_OPROFILE
.oprofile_cpu_type = "ppc64/970",
- .oprofile_model = &op_model_power4,
-#endif
+ .oprofile_type = POWER4,
},
{ /* Power5 GR */
.pvr_mask = 0xffff0000,
@@ -253,27 +231,23 @@ struct cpu_spec cpu_specs[] = {
.dcache_bsize = 128,
.num_pmcs = 6,
.cpu_setup = __setup_cpu_power4,
-#ifdef CONFIG_OPROFILE
.oprofile_cpu_type = "ppc64/power5",
- .oprofile_model = &op_model_power4,
-#endif
+ .oprofile_type = POWER4,
},
{ /* Power5 GS */
.pvr_mask = 0xffff0000,
.pvr_value = 0x003b0000,
- .cpu_name = "POWER5 (gs)",
+ .cpu_name = "POWER5+ (gs)",
.cpu_features = CPU_FTRS_POWER5,
.cpu_user_features = COMMON_USER_POWER5_PLUS,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 6,
.cpu_setup = __setup_cpu_power4,
-#ifdef CONFIG_OPROFILE
- .oprofile_cpu_type = "ppc64/power5",
- .oprofile_model = &op_model_power4,
-#endif
+ .oprofile_cpu_type = "ppc64/power5+",
+ .oprofile_type = POWER4,
},
- { /* BE DD1.x */
+ { /* Cell Broadband Engine */
.pvr_mask = 0xffff0000,
.pvr_value = 0x00700000,
.cpu_name = "Cell Broadband Engine",
@@ -545,7 +519,9 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
- .cpu_setup = __setup_cpu_745x
+ .cpu_setup = __setup_cpu_745x,
+ .oprofile_cpu_type = "ppc/7450",
+ .oprofile_type = G4,
},
{ /* 7450 2.1 */
.pvr_mask = 0xffffffff,
@@ -556,7 +532,9 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
- .cpu_setup = __setup_cpu_745x
+ .cpu_setup = __setup_cpu_745x,
+ .oprofile_cpu_type = "ppc/7450",
+ .oprofile_type = G4,
},
{ /* 7450 2.3 and newer */
.pvr_mask = 0xffff0000,
@@ -567,7 +545,9 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
- .cpu_setup = __setup_cpu_745x
+ .cpu_setup = __setup_cpu_745x,
+ .oprofile_cpu_type = "ppc/7450",
+ .oprofile_type = G4,
},
{ /* 7455 rev 1.x */
.pvr_mask = 0xffffff00,
@@ -578,7 +558,9 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
- .cpu_setup = __setup_cpu_745x
+ .cpu_setup = __setup_cpu_745x,
+ .oprofile_cpu_type = "ppc/7450",
+ .oprofile_type = G4,
},
{ /* 7455 rev 2.0 */
.pvr_mask = 0xffffffff,
@@ -589,7 +571,9 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
- .cpu_setup = __setup_cpu_745x
+ .cpu_setup = __setup_cpu_745x,
+ .oprofile_cpu_type = "ppc/7450",
+ .oprofile_type = G4,
},
{ /* 7455 others */
.pvr_mask = 0xffff0000,
@@ -600,7 +584,9 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
- .cpu_setup = __setup_cpu_745x
+ .cpu_setup = __setup_cpu_745x,
+ .oprofile_cpu_type = "ppc/7450",
+ .oprofile_type = G4,
},
{ /* 7447/7457 Rev 1.0 */
.pvr_mask = 0xffffffff,
@@ -611,7 +597,9 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
- .cpu_setup = __setup_cpu_745x
+ .cpu_setup = __setup_cpu_745x,
+ .oprofile_cpu_type = "ppc/7450",
+ .oprofile_type = G4,
},
{ /* 7447/7457 Rev 1.1 */
.pvr_mask = 0xffffffff,
@@ -622,7 +610,9 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
- .cpu_setup = __setup_cpu_745x
+ .cpu_setup = __setup_cpu_745x,
+ .oprofile_cpu_type = "ppc/7450",
+ .oprofile_type = G4,
},
{ /* 7447/7457 Rev 1.2 and later */
.pvr_mask = 0xffff0000,
@@ -633,7 +623,9 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
- .cpu_setup = __setup_cpu_745x
+ .cpu_setup = __setup_cpu_745x,
+ .oprofile_cpu_type = "ppc/7450",
+ .oprofile_type = G4,
},
{ /* 7447A */
.pvr_mask = 0xffff0000,
@@ -644,7 +636,9 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
- .cpu_setup = __setup_cpu_745x
+ .cpu_setup = __setup_cpu_745x,
+ .oprofile_cpu_type = "ppc/7450",
+ .oprofile_type = G4,
},
{ /* 7448 */
.pvr_mask = 0xffff0000,
@@ -655,7 +649,9 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
- .cpu_setup = __setup_cpu_745x
+ .cpu_setup = __setup_cpu_745x,
+ .oprofile_cpu_type = "ppc/7450",
+ .oprofile_type = G4,
},
{ /* 82xx (8240, 8245, 8260 are all 603e cores) */
.pvr_mask = 0x7fff0000,
@@ -979,6 +975,8 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
+ .oprofile_cpu_type = "ppc/e500",
+ .oprofile_type = BOOKE,
},
{ /* e500v2 */
.pvr_mask = 0xffff0000,
@@ -992,6 +990,8 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
+ .oprofile_cpu_type = "ppc/e500",
+ .oprofile_type = BOOKE,
},
#endif
#if !CLASSIC_PPC
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
new file mode 100644
index 000000000000..4681155121ef
--- /dev/null
+++ b/arch/powerpc/kernel/crash.c
@@ -0,0 +1,264 @@
+/*
+ * Architecture specific (PPC64) functions for kexec based crash dumps.
+ *
+ * Copyright (C) 2005, IBM Corp.
+ *
+ * Created by: Haren Myneni
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/reboot.h>
+#include <linux/kexec.h>
+#include <linux/bootmem.h>
+#include <linux/crash_dump.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/elf.h>
+#include <linux/elfcore.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/kdump.h>
+#include <asm/lmb.h>
+#include <asm/firmware.h>
+
+#ifdef DEBUG
+#include <asm/udbg.h>
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+/* This keeps a track of which one is crashing cpu. */
+int crashing_cpu = -1;
+
+static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data,
+ size_t data_len)
+{
+ struct elf_note note;
+
+ note.n_namesz = strlen(name) + 1;
+ note.n_descsz = data_len;
+ note.n_type = type;
+ memcpy(buf, &note, sizeof(note));
+ buf += (sizeof(note) +3)/4;
+ memcpy(buf, name, note.n_namesz);
+ buf += (note.n_namesz + 3)/4;
+ memcpy(buf, data, note.n_descsz);
+ buf += (note.n_descsz + 3)/4;
+
+ return buf;
+}
+
+static void final_note(u32 *buf)
+{
+ struct elf_note note;
+
+ note.n_namesz = 0;
+ note.n_descsz = 0;
+ note.n_type = 0;
+ memcpy(buf, &note, sizeof(note));
+}
+
+static void crash_save_this_cpu(struct pt_regs *regs, int cpu)
+{
+ struct elf_prstatus prstatus;
+ u32 *buf;
+
+ if ((cpu < 0) || (cpu >= NR_CPUS))
+ return;
+
+ /* Using ELF notes here is opportunistic.
+ * I need a well defined structure format
+ * for the data I pass, and I need tags
+ * on the data to indicate what information I have
+ * squirrelled away. ELF notes happen to provide
+ * all of that that no need to invent something new.
+ */
+ buf = &crash_notes[cpu][0];
+ memset(&prstatus, 0, sizeof(prstatus));
+ prstatus.pr_pid = current->pid;
+ elf_core_copy_regs(&prstatus.pr_reg, regs);
+ buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus,
+ sizeof(prstatus));
+ final_note(buf);
+}
+
+/* FIXME Merge this with xmon_save_regs ?? */
+static inline void crash_get_current_regs(struct pt_regs *regs)
+{
+ unsigned long tmp1, tmp2;
+
+ __asm__ __volatile__ (
+ "std 0,0(%2)\n"
+ "std 1,8(%2)\n"
+ "std 2,16(%2)\n"
+ "std 3,24(%2)\n"
+ "std 4,32(%2)\n"
+ "std 5,40(%2)\n"
+ "std 6,48(%2)\n"
+ "std 7,56(%2)\n"
+ "std 8,64(%2)\n"
+ "std 9,72(%2)\n"
+ "std 10,80(%2)\n"
+ "std 11,88(%2)\n"
+ "std 12,96(%2)\n"
+ "std 13,104(%2)\n"
+ "std 14,112(%2)\n"
+ "std 15,120(%2)\n"
+ "std 16,128(%2)\n"
+ "std 17,136(%2)\n"
+ "std 18,144(%2)\n"
+ "std 19,152(%2)\n"
+ "std 20,160(%2)\n"
+ "std 21,168(%2)\n"
+ "std 22,176(%2)\n"
+ "std 23,184(%2)\n"
+ "std 24,192(%2)\n"
+ "std 25,200(%2)\n"
+ "std 26,208(%2)\n"
+ "std 27,216(%2)\n"
+ "std 28,224(%2)\n"
+ "std 29,232(%2)\n"
+ "std 30,240(%2)\n"
+ "std 31,248(%2)\n"
+ "mfmsr %0\n"
+ "std %0, 264(%2)\n"
+ "mfctr %0\n"
+ "std %0, 280(%2)\n"
+ "mflr %0\n"
+ "std %0, 288(%2)\n"
+ "bl 1f\n"
+ "1: mflr %1\n"
+ "std %1, 256(%2)\n"
+ "mtlr %0\n"
+ "mfxer %0\n"
+ "std %0, 296(%2)\n"
+ : "=&r" (tmp1), "=&r" (tmp2)
+ : "b" (regs));
+}
+
+/* We may have saved_regs from where the error came from
+ * or it is NULL if via a direct panic().
+ */
+static void crash_save_self(struct pt_regs *saved_regs)
+{
+ struct pt_regs regs;
+ int cpu;
+
+ cpu = smp_processor_id();
+ if (saved_regs)
+ memcpy(&regs, saved_regs, sizeof(regs));
+ else
+ crash_get_current_regs(&regs);
+ crash_save_this_cpu(&regs, cpu);
+}
+
+#ifdef CONFIG_SMP
+static atomic_t waiting_for_crash_ipi;
+
+void crash_ipi_callback(struct pt_regs *regs)
+{
+ int cpu = smp_processor_id();
+
+ if (cpu == crashing_cpu)
+ return;
+
+ if (!cpu_online(cpu))
+ return;
+
+ if (ppc_md.kexec_cpu_down)
+ ppc_md.kexec_cpu_down(1, 1);
+
+ local_irq_disable();
+
+ crash_save_this_cpu(regs, cpu);
+ atomic_dec(&waiting_for_crash_ipi);
+ kexec_smp_wait();
+ /* NOTREACHED */
+}
+
+static void crash_kexec_prepare_cpus(void)
+{
+ unsigned int msecs;
+
+ atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
+
+ crash_send_ipi(crash_ipi_callback);
+ smp_wmb();
+
+ /*
+ * FIXME: Until we will have the way to stop other CPUSs reliabally,
+ * the crash CPU will send an IPI and wait for other CPUs to
+ * respond. If not, proceed the kexec boot even though we failed to
+ * capture other CPU states.
+ */
+ msecs = 1000000;
+ while ((atomic_read(&waiting_for_crash_ipi) > 0) && (--msecs > 0)) {
+ barrier();
+ mdelay(1);
+ }
+
+ /* Would it be better to replace the trap vector here? */
+
+ /*
+ * FIXME: In case if we do not get all CPUs, one possibility: ask the
+ * user to do soft reset such that we get all.
+ * IPI handler is already set by the panic cpu initially. Therefore,
+ * all cpus could invoke this handler from die() and the panic CPU
+ * will call machine_kexec() directly from this handler to do
+ * kexec boot.
+ */
+ if (atomic_read(&waiting_for_crash_ipi))
+ printk(KERN_ALERT "done waiting: %d cpus not responding\n",
+ atomic_read(&waiting_for_crash_ipi));
+ /* Leave the IPI callback set */
+}
+#else
+static void crash_kexec_prepare_cpus(void)
+{
+ /*
+ * move the secondarys to us so that we can copy
+ * the new kernel 0-0x100 safely
+ *
+ * do this if kexec in setup.c ?
+ */
+ smp_release_cpus();
+}
+
+#endif
+
+void default_machine_crash_shutdown(struct pt_regs *regs)
+{
+ /*
+ * This function is only called after the system
+ * has paniced or is otherwise in a critical state.
+ * The minimum amount of code to allow a kexec'd kernel
+ * to run successfully needs to happen here.
+ *
+ * In practice this means stopping other cpus in
+ * an SMP system.
+ * The kernel is broken so disable interrupts.
+ */
+ local_irq_disable();
+
+ if (ppc_md.kexec_cpu_down)
+ ppc_md.kexec_cpu_down(1, 0);
+
+ /*
+ * Make a note of crashing cpu. Will be used in machine_kexec
+ * such that another IPI will not be sent.
+ */
+ crashing_cpu = smp_processor_id();
+ crash_kexec_prepare_cpus();
+ crash_save_self(regs);
+}
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
new file mode 100644
index 000000000000..87effa3f21a7
--- /dev/null
+++ b/arch/powerpc/kernel/crash_dump.c
@@ -0,0 +1,109 @@
+/*
+ * Routines for doing kexec-based kdump.
+ *
+ * Copyright (C) 2005, IBM Corp.
+ *
+ * Created by: Michael Ellerman
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#undef DEBUG
+
+#include <linux/crash_dump.h>
+#include <linux/bootmem.h>
+#include <asm/kdump.h>
+#include <asm/lmb.h>
+#include <asm/firmware.h>
+#include <asm/uaccess.h>
+
+#ifdef DEBUG
+#include <asm/udbg.h>
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+static void __init create_trampoline(unsigned long addr)
+{
+ /* The maximum range of a single instruction branch, is the current
+ * instruction's address + (32 MB - 4) bytes. For the trampoline we
+ * need to branch to current address + 32 MB. So we insert a nop at
+ * the trampoline address, then the next instruction (+ 4 bytes)
+ * does a branch to (32 MB - 4). The net effect is that when we
+ * branch to "addr" we jump to ("addr" + 32 MB). Although it requires
+ * two instructions it doesn't require any registers.
+ */
+ create_instruction(addr, 0x60000000); /* nop */
+ create_branch(addr + 4, addr + PHYSICAL_START, 0);
+}
+
+void __init kdump_setup(void)
+{
+ unsigned long i;
+
+ DBG(" -> kdump_setup()\n");
+
+ for (i = KDUMP_TRAMPOLINE_START; i < KDUMP_TRAMPOLINE_END; i += 8) {
+ create_trampoline(i);
+ }
+
+ create_trampoline(__pa(system_reset_fwnmi) - PHYSICAL_START);
+ create_trampoline(__pa(machine_check_fwnmi) - PHYSICAL_START);
+
+ DBG(" <- kdump_setup()\n");
+}
+
+static int __init parse_elfcorehdr(char *p)
+{
+ if (p)
+ elfcorehdr_addr = memparse(p, &p);
+
+ return 0;
+}
+__setup("elfcorehdr=", parse_elfcorehdr);
+
+static int __init parse_savemaxmem(char *p)
+{
+ if (p)
+ saved_max_pfn = (memparse(p, &p) >> PAGE_SHIFT) - 1;
+
+ return 0;
+}
+__setup("savemaxmem=", parse_savemaxmem);
+
+/*
+ * copy_oldmem_page - copy one page from "oldmem"
+ * @pfn: page frame number to be copied
+ * @buf: target memory address for the copy; this can be in kernel address
+ * space or user address space (see @userbuf)
+ * @csize: number of bytes to copy
+ * @offset: offset in bytes into the page (based on pfn) to begin the copy
+ * @userbuf: if set, @buf is in user address space, use copy_to_user(),
+ * otherwise @buf is in kernel address space, use memcpy().
+ *
+ * Copy a page from "oldmem". For this page, there is no pte mapped
+ * in the current kernel. We stitch up a pte, similar to kmap_atomic.
+ */
+ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
+ size_t csize, unsigned long offset, int userbuf)
+{
+ void *vaddr;
+
+ if (!csize)
+ return 0;
+
+ vaddr = __ioremap(pfn << PAGE_SHIFT, PAGE_SIZE, 0);
+
+ if (userbuf) {
+ if (copy_to_user((char __user *)buf, (vaddr + offset), csize)) {
+ iounmap(vaddr);
+ return -EFAULT;
+ }
+ } else
+ memcpy(buf, (vaddr + offset), csize);
+
+ iounmap(vaddr);
+ return csize;
+}
diff --git a/arch/powerpc/kernel/dma_64.c b/arch/powerpc/kernel/dma_64.c
index 7c3419656ccc..36aaa7663f02 100644
--- a/arch/powerpc/kernel/dma_64.c
+++ b/arch/powerpc/kernel/dma_64.c
@@ -10,6 +10,7 @@
/* Include the busses we support */
#include <linux/pci.h>
#include <asm/vio.h>
+#include <asm/ibmebus.h>
#include <asm/scatterlist.h>
#include <asm/bug.h>
@@ -23,6 +24,10 @@ static struct dma_mapping_ops *get_dma_ops(struct device *dev)
if (dev->bus == &vio_bus_type)
return &vio_dma_ops;
#endif
+#ifdef CONFIG_IBMEBUS
+ if (dev->bus == &ibmebus_bus_type)
+ return &ibmebus_dma_ops;
+#endif
return NULL;
}
@@ -47,6 +52,10 @@ int dma_set_mask(struct device *dev, u64 dma_mask)
if (dev->bus == &vio_bus_type)
return -EIO;
#endif /* CONFIG_IBMVIO */
+#ifdef CONFIG_IBMEBUS
+ if (dev->bus == &ibmebus_bus_type)
+ return -EIO;
+#endif
BUG();
return 0;
}
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 2e99ae41723c..036b71d2adfc 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -200,8 +200,6 @@ _GLOBAL(DoSyscall)
bl do_show_syscall
#endif /* SHOW_SYSCALLS */
rlwinm r10,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
- li r11,0
- stb r11,TI_SC_NOERR(r10)
lwz r11,TI_FLAGS(r10)
andi. r11,r11,_TIF_SYSCALL_T_OR_A
bne- syscall_dotrace
@@ -222,25 +220,21 @@ ret_from_syscall:
bl do_show_syscall_exit
#endif
mr r6,r3
- li r11,-_LAST_ERRNO
- cmplw 0,r3,r11
rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
- blt+ 30f
- lbz r11,TI_SC_NOERR(r12)
- cmpwi r11,0
- bne 30f
- neg r3,r3
- lwz r10,_CCR(r1) /* Set SO bit in CR */
- oris r10,r10,0x1000
- stw r10,_CCR(r1)
-
/* disable interrupts so current_thread_info()->flags can't change */
-30: LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
+ LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
SYNC
MTMSRD(r10)
lwz r9,TI_FLAGS(r12)
- andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+ li r8,-_LAST_ERRNO
+ andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
bne- syscall_exit_work
+ cmplw 0,r3,r8
+ blt+ syscall_exit_cont
+ lwz r11,_CCR(r1) /* Load CR */
+ neg r3,r3
+ oris r11,r11,0x1000 /* Set SO bit in CR */
+ stw r11,_CCR(r1)
syscall_exit_cont:
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
/* If the process has its own DBCR0 value, load it up. The single
@@ -292,46 +286,113 @@ syscall_dotrace:
b syscall_dotrace_cont
syscall_exit_work:
- stw r6,RESULT(r1) /* Save result */
+ andi. r0,r9,_TIF_RESTOREALL
+ bne- 2f
+ cmplw 0,r3,r8
+ blt+ 1f
+ andi. r0,r9,_TIF_NOERROR
+ bne- 1f
+ lwz r11,_CCR(r1) /* Load CR */
+ neg r3,r3
+ oris r11,r11,0x1000 /* Set SO bit in CR */
+ stw r11,_CCR(r1)
+
+1: stw r6,RESULT(r1) /* Save result */
stw r3,GPR3(r1) /* Update return value */
- andi. r0,r9,_TIF_SYSCALL_T_OR_A
- beq 5f
- ori r10,r10,MSR_EE
- SYNC
- MTMSRD(r10) /* re-enable interrupts */
+2: andi. r0,r9,(_TIF_PERSYSCALL_MASK)
+ beq 4f
+
+ /* Clear per-syscall TIF flags if any are set, but _leave_
+ _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that
+ yet. */
+
+ li r11,_TIF_PERSYSCALL_MASK
+ addi r12,r12,TI_FLAGS
+3: lwarx r8,0,r12
+ andc r8,r8,r11
+#ifdef CONFIG_IBM405_ERR77
+ dcbt 0,r12
+#endif
+ stwcx. r8,0,r12
+ bne- 3b
+ subi r12,r12,TI_FLAGS
+
+4: /* Anything which requires enabling interrupts? */
+ andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS)
+ beq 7f
+
+ /* Save NVGPRS if they're not saved already */
lwz r4,_TRAP(r1)
andi. r4,r4,1
- beq 4f
+ beq 5f
SAVE_NVGPRS(r1)
li r4,0xc00
stw r4,_TRAP(r1)
-4:
+
+ /* Re-enable interrupts */
+5: ori r10,r10,MSR_EE
+ SYNC
+ MTMSRD(r10)
+
+ andi. r0,r9,_TIF_SAVE_NVGPRS
+ bne save_user_nvgprs
+
+save_user_nvgprs_cont:
+ andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
+ beq 7f
+
addi r3,r1,STACK_FRAME_OVERHEAD
bl do_syscall_trace_leave
REST_NVGPRS(r1)
-2:
- lwz r3,GPR3(r1)
+
+6: lwz r3,GPR3(r1)
LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
SYNC
MTMSRD(r10) /* disable interrupts again */
rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
lwz r9,TI_FLAGS(r12)
-5:
+7:
andi. r0,r9,_TIF_NEED_RESCHED
- bne 1f
+ bne 8f
lwz r5,_MSR(r1)
andi. r5,r5,MSR_PR
- beq syscall_exit_cont
+ beq ret_from_except
andi. r0,r9,_TIF_SIGPENDING
- beq syscall_exit_cont
+ beq ret_from_except
b do_user_signal
-1:
+8:
ori r10,r10,MSR_EE
SYNC
MTMSRD(r10) /* re-enable interrupts */
bl schedule
- b 2b
+ b 6b
+
+save_user_nvgprs:
+ lwz r8,TI_SIGFRAME(r12)
+
+.macro savewords start, end
+ 1: stw \start,4*(\start)(r8)
+ .section __ex_table,"a"
+ .align 2
+ .long 1b,save_user_nvgprs_fault
+ .previous
+ .if \end - \start
+ savewords "(\start+1)",\end
+ .endif
+.endm
+ savewords 14,31
+ b save_user_nvgprs_cont
+
+
+save_user_nvgprs_fault:
+ li r3,11 /* SIGSEGV */
+ lwz r4,TI_TASK(r12)
+ bl force_sigsegv
+ rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
+ lwz r9,TI_FLAGS(r12)
+ b save_user_nvgprs_cont
+
#ifdef SHOW_SYSCALLS
do_show_syscall:
#ifdef SHOW_SYSCALLS_TASK
@@ -401,28 +462,10 @@ show_syscalls_task:
#endif /* SHOW_SYSCALLS */
/*
- * The sigsuspend and rt_sigsuspend system calls can call do_signal
- * and thus put the process into the stopped state where we might
- * want to examine its user state with ptrace. Therefore we need
- * to save all the nonvolatile registers (r13 - r31) before calling
- * the C code.
+ * The fork/clone functions need to copy the full register set into
+ * the child process. Therefore we need to save all the nonvolatile
+ * registers (r13 - r31) before calling the C code.
*/
- .globl ppc_sigsuspend
-ppc_sigsuspend:
- SAVE_NVGPRS(r1)
- lwz r0,_TRAP(r1)
- rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */
- stw r0,_TRAP(r1) /* register set saved */
- b sys_sigsuspend
-
- .globl ppc_rt_sigsuspend
-ppc_rt_sigsuspend:
- SAVE_NVGPRS(r1)
- lwz r0,_TRAP(r1)
- rlwinm r0,r0,0,0,30
- stw r0,_TRAP(r1)
- b sys_rt_sigsuspend
-
.globl ppc_fork
ppc_fork:
SAVE_NVGPRS(r1)
@@ -447,14 +490,6 @@ ppc_clone:
stw r0,_TRAP(r1) /* register set saved */
b sys_clone
- .globl ppc_swapcontext
-ppc_swapcontext:
- SAVE_NVGPRS(r1)
- lwz r0,_TRAP(r1)
- rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */
- stw r0,_TRAP(r1) /* register set saved */
- b sys_swapcontext
-
/*
* Top-level page fault handling.
* This is in assembler because if do_page_fault tells us that
@@ -626,16 +661,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_601)
.long ret_from_except
#endif
- .globl sigreturn_exit
-sigreturn_exit:
- subi r1,r3,STACK_FRAME_OVERHEAD
- rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
- lwz r9,TI_FLAGS(r12)
- andi. r0,r9,_TIF_SYSCALL_T_OR_A
- beq+ ret_from_except_full
- bl do_syscall_trace_leave
- /* fall through */
-
.globl ret_from_except_full
ret_from_except_full:
REST_NVGPRS(r1)
@@ -658,7 +683,7 @@ user_exc_return: /* r10 contains MSR_KERNEL here */
/* Check current_thread_info()->flags */
rlwinm r9,r1,0,0,(31-THREAD_SHIFT)
lwz r9,TI_FLAGS(r9)
- andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+ andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
bne do_work
restore_user:
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index bce33a38399f..aacebb33e98a 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -113,9 +113,7 @@ system_call_common:
addi r9,r1,STACK_FRAME_OVERHEAD
#endif
clrrdi r11,r1,THREAD_SHIFT
- li r12,0
ld r10,TI_FLAGS(r11)
- stb r12,TI_SC_NOERR(r11)
andi. r11,r10,_TIF_SYSCALL_T_OR_A
bne- syscall_dotrace
syscall_dotrace_cont:
@@ -144,24 +142,12 @@ system_call: /* label this so stack traces look sane */
bctrl /* Call handler */
syscall_exit:
+ std r3,RESULT(r1)
#ifdef SHOW_SYSCALLS
- std r3,GPR3(r1)
bl .do_show_syscall_exit
- ld r3,GPR3(r1)
+ ld r3,RESULT(r1)
#endif
- std r3,RESULT(r1)
- ld r5,_CCR(r1)
- li r10,-_LAST_ERRNO
- cmpld r3,r10
clrrdi r12,r1,THREAD_SHIFT
- bge- syscall_error
-syscall_error_cont:
-
- /* check for syscall tracing or audit */
- ld r9,TI_FLAGS(r12)
- andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
- bne- syscall_exit_trace
-syscall_exit_trace_cont:
/* disable interrupts so current_thread_info()->flags can't change,
and so that we don't get interrupted after loading SRR0/1. */
@@ -173,8 +159,13 @@ syscall_exit_trace_cont:
rotldi r10,r10,16
mtmsrd r10,1
ld r9,TI_FLAGS(r12)
- andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+ li r11,-_LAST_ERRNO
+ andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_SAVE_NVGPRS|_TIF_NOERROR)
bne- syscall_exit_work
+ cmpld r3,r11
+ ld r5,_CCR(r1)
+ bge- syscall_error
+syscall_error_cont:
ld r7,_NIP(r1)
stdcx. r0,0,r1 /* to clear the reservation */
andi. r6,r8,MSR_PR
@@ -193,21 +184,12 @@ syscall_exit_trace_cont:
rfid
b . /* prevent speculative execution */
-syscall_enosys:
- li r3,-ENOSYS
- std r3,RESULT(r1)
- clrrdi r12,r1,THREAD_SHIFT
- ld r5,_CCR(r1)
-
-syscall_error:
- lbz r11,TI_SC_NOERR(r12)
- cmpwi 0,r11,0
- bne- syscall_error_cont
- neg r3,r3
+syscall_error:
oris r5,r5,0x1000 /* Set SO bit in CR */
+ neg r3,r3
std r5,_CCR(r1)
b syscall_error_cont
-
+
/* Traced system call support */
syscall_dotrace:
bl .save_nvgprs
@@ -225,21 +207,69 @@ syscall_dotrace:
ld r10,TI_FLAGS(r10)
b syscall_dotrace_cont
-syscall_exit_trace:
- std r3,GPR3(r1)
- bl .save_nvgprs
+syscall_enosys:
+ li r3,-ENOSYS
+ b syscall_exit
+
+syscall_exit_work:
+ /* If TIF_RESTOREALL is set, don't scribble on either r3 or ccr.
+ If TIF_NOERROR is set, just save r3 as it is. */
+
+ andi. r0,r9,_TIF_RESTOREALL
+ bne- 2f
+ cmpld r3,r11 /* r10 is -LAST_ERRNO */
+ blt+ 1f
+ andi. r0,r9,_TIF_NOERROR
+ bne- 1f
+ ld r5,_CCR(r1)
+ neg r3,r3
+ oris r5,r5,0x1000 /* Set SO bit in CR */
+ std r5,_CCR(r1)
+1: std r3,GPR3(r1)
+2: andi. r0,r9,(_TIF_PERSYSCALL_MASK)
+ beq 4f
+
+ /* Clear per-syscall TIF flags if any are set, but _leave_
+ _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that
+ yet. */
+
+ li r11,_TIF_PERSYSCALL_MASK
+ addi r12,r12,TI_FLAGS
+3: ldarx r10,0,r12
+ andc r10,r10,r11
+ stdcx. r10,0,r12
+ bne- 3b
+ subi r12,r12,TI_FLAGS
+
+4: bl .save_nvgprs
+ /* Anything else left to do? */
+ andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS)
+ beq .ret_from_except_lite
+
+ /* Re-enable interrupts */
+ mfmsr r10
+ ori r10,r10,MSR_EE
+ mtmsrd r10,1
+
+ andi. r0,r9,_TIF_SAVE_NVGPRS
+ bne save_user_nvgprs
+
+ /* If tracing, re-enable interrupts and do it */
+save_user_nvgprs_cont:
+ andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
+ beq 5f
+
addi r3,r1,STACK_FRAME_OVERHEAD
bl .do_syscall_trace_leave
REST_NVGPRS(r1)
- ld r3,GPR3(r1)
- ld r5,_CCR(r1)
clrrdi r12,r1,THREAD_SHIFT
- b syscall_exit_trace_cont
-/* Stuff to do on exit from a system call. */
-syscall_exit_work:
- std r3,GPR3(r1)
- std r5,_CCR(r1)
+ /* Disable interrupts again and handle other work if any */
+5: mfmsr r10
+ rldicl r10,r10,48,1
+ rotldi r10,r10,16
+ mtmsrd r10,1
+
b .ret_from_except_lite
/* Save non-volatile GPRs, if not already saved. */
@@ -252,6 +282,52 @@ _GLOBAL(save_nvgprs)
std r0,_TRAP(r1)
blr
+
+save_user_nvgprs:
+ ld r10,TI_SIGFRAME(r12)
+ andi. r0,r9,_TIF_32BIT
+ beq- save_user_nvgprs_64
+
+ /* 32-bit save to userspace */
+
+.macro savewords start, end
+ 1: stw \start,4*(\start)(r10)
+ .section __ex_table,"a"
+ .align 3
+ .llong 1b,save_user_nvgprs_fault
+ .previous
+ .if \end - \start
+ savewords "(\start+1)",\end
+ .endif
+.endm
+ savewords 14,31
+ b save_user_nvgprs_cont
+
+save_user_nvgprs_64:
+ /* 64-bit save to userspace */
+
+.macro savelongs start, end
+ 1: std \start,8*(\start)(r10)
+ .section __ex_table,"a"
+ .align 3
+ .llong 1b,save_user_nvgprs_fault
+ .previous
+ .if \end - \start
+ savelongs "(\start+1)",\end
+ .endif
+.endm
+ savelongs 14,31
+ b save_user_nvgprs_cont
+
+save_user_nvgprs_fault:
+ li r3,11 /* SIGSEGV */
+ ld r4,TI_TASK(r12)
+ bl .force_sigsegv
+
+ clrrdi r12,r1,THREAD_SHIFT
+ ld r9,TI_FLAGS(r12)
+ b save_user_nvgprs_cont
+
/*
* The sigsuspend and rt_sigsuspend system calls can call do_signal
* and thus put the process into the stopped state where we might
@@ -260,35 +336,6 @@ _GLOBAL(save_nvgprs)
* the C code. Similarly, fork, vfork and clone need the full
* register state on the stack so that it can be copied to the child.
*/
-_GLOBAL(ppc32_sigsuspend)
- bl .save_nvgprs
- bl .compat_sys_sigsuspend
- b 70f
-
-_GLOBAL(ppc64_rt_sigsuspend)
- bl .save_nvgprs
- bl .sys_rt_sigsuspend
- b 70f
-
-_GLOBAL(ppc32_rt_sigsuspend)
- bl .save_nvgprs
- bl .compat_sys_rt_sigsuspend
-70: cmpdi 0,r3,0
- /* If it returned an error, we need to return via syscall_exit to set
- the SO bit in cr0 and potentially stop for ptrace. */
- bne syscall_exit
- /* If sigsuspend() returns zero, we are going into a signal handler. We
- may need to call audit_syscall_exit() to mark the exit from sigsuspend() */
-#ifdef CONFIG_AUDITSYSCALL
- ld r3,PACACURRENT(r13)
- ld r4,AUDITCONTEXT(r3)
- cmpdi 0,r4,0
- beq .ret_from_except /* No audit_context: Leave immediately. */
- li r4, 2 /* AUDITSC_FAILURE */
- li r5,-4 /* It's always -EINTR */
- bl .audit_syscall_exit
-#endif
- b .ret_from_except
_GLOBAL(ppc_fork)
bl .save_nvgprs
@@ -305,37 +352,6 @@ _GLOBAL(ppc_clone)
bl .sys_clone
b syscall_exit
-_GLOBAL(ppc32_swapcontext)
- bl .save_nvgprs
- bl .compat_sys_swapcontext
- b 80f
-
-_GLOBAL(ppc64_swapcontext)
- bl .save_nvgprs
- bl .sys_swapcontext
- b 80f
-
-_GLOBAL(ppc32_sigreturn)
- bl .compat_sys_sigreturn
- b 80f
-
-_GLOBAL(ppc32_rt_sigreturn)
- bl .compat_sys_rt_sigreturn
- b 80f
-
-_GLOBAL(ppc64_rt_sigreturn)
- bl .sys_rt_sigreturn
-
-80: cmpdi 0,r3,0
- blt syscall_exit
- clrrdi r4,r1,THREAD_SHIFT
- ld r4,TI_FLAGS(r4)
- andi. r4,r4,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
- beq+ 81f
- addi r3,r1,STACK_FRAME_OVERHEAD
- bl .do_syscall_trace_leave
-81: b .ret_from_except
-
_GLOBAL(ret_from_fork)
bl .schedule_tail
REST_NVGPRS(r1)
@@ -674,7 +690,7 @@ _GLOBAL(enter_rtas)
/* Setup our real return addr */
SET_REG_TO_LABEL(r4,.rtas_return_loc)
- SET_REG_TO_CONST(r9,KERNELBASE)
+ SET_REG_TO_CONST(r9,PAGE_OFFSET)
sub r4,r4,r9
mtlr r4
@@ -702,7 +718,7 @@ _GLOBAL(enter_rtas)
_STATIC(rtas_return_loc)
/* relocation is off at this point */
mfspr r4,SPRN_SPRG3 /* Get PACA */
- SET_REG_TO_CONST(r5, KERNELBASE)
+ SET_REG_TO_CONST(r5, PAGE_OFFSET)
sub r4,r4,r5 /* RELOC the PACA base pointer */
mfmsr r6
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index ccdf94731e30..03b25f9359f8 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -120,10 +120,25 @@ __start:
* because OF may have I/O devices mapped into that area
* (particularly on CHRP).
*/
+#ifdef CONFIG_PPC_MULTIPLATFORM
cmpwi 0,r5,0
beq 1f
bl prom_init
trap
+#endif
+
+/*
+ * Check for BootX signature when supporting PowerMac and branch to
+ * appropriate trampoline if it's present
+ */
+#ifdef CONFIG_PPC_PMAC
+1: lis r31,0x426f
+ ori r31,r31,0x6f58
+ cmpw 0,r3,r31
+ bne 1f
+ bl bootx_init
+ trap
+#endif /* CONFIG_PPC_PMAC */
1: mr r31,r3 /* save parameters */
mr r30,r4
@@ -153,6 +168,9 @@ __after_mmu_off:
bl flush_tlbs
bl initial_bats
+#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
+ bl setup_disp_bat
+#endif
/*
* Call setup_cpu for CPU 0 and initialize 6xx Idle
@@ -450,16 +468,11 @@ SystemCall:
* by executing an altivec instruction.
*/
. = 0xf00
- b Trap_0f
+ b PerformanceMonitor
. = 0xf20
b AltiVecUnavailable
-Trap_0f:
- EXCEPTION_PROLOG
- addi r3,r1,STACK_FRAME_OVERHEAD
- EXC_XFER_EE(0xf00, unknown_exception)
-
/*
* Handle TLB miss for instruction on 603/603e.
* Note: we get an alternate set of r0 - r3 to use automatically.
@@ -703,6 +716,11 @@ AltiVecUnavailable:
#endif /* CONFIG_ALTIVEC */
EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception)
+PerformanceMonitor:
+ EXCEPTION_PROLOG
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_STD(0xf00, performance_monitor_exception)
+
#ifdef CONFIG_ALTIVEC
/* Note that the AltiVec support is closely modeled after the FP
* support. Changes to one are likely to be applicable to the
@@ -1306,6 +1324,32 @@ initial_bats:
blr
+#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
+setup_disp_bat:
+ /*
+ * setup the display bat prepared for us in prom.c
+ */
+ mflr r8
+ bl reloc_offset
+ mtlr r8
+ addis r8,r3,disp_BAT@ha
+ addi r8,r8,disp_BAT@l
+ cmpwi cr0,r8,0
+ beqlr
+ lwz r11,0(r8)
+ lwz r8,4(r8)
+ mfspr r9,SPRN_PVR
+ rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
+ cmpwi 0,r9,1
+ beq 1f
+ mtspr SPRN_DBAT3L,r8
+ mtspr SPRN_DBAT3U,r11
+ blr
+1: mtspr SPRN_IBAT3L,r8
+ mtspr SPRN_IBAT3U,r11
+ blr
+#endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */
+
#ifdef CONFIG_8260
/* Jump into the system reset for the rom.
* We first disable the MMU, and then jump to the ROM reset address.
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 8a8bf79ef044..1c066d125375 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -154,11 +154,15 @@ _GLOBAL(__secondary_hold)
bne 100b
#ifdef CONFIG_HMT
- b .hmt_init
+ LOADADDR(r4, .hmt_init)
+ mtctr r4
+ bctr
#else
#ifdef CONFIG_SMP
+ LOADADDR(r4, .pSeries_secondary_smp_init)
+ mtctr r4
mr r3,r24
- b .pSeries_secondary_smp_init
+ bctr
#else
BUG_OPCODE
#endif
@@ -200,6 +204,20 @@ exception_marker:
#define EX_R3 64
#define EX_LR 72
+/*
+ * We're short on space and time in the exception prolog, so we can't use
+ * the normal LOADADDR macro. Normally we just need the low halfword of the
+ * address, but for Kdump we need the whole low word.
+ */
+#ifdef CONFIG_CRASH_DUMP
+#define LOAD_HANDLER(reg, label) \
+ oris reg,reg,(label)@h; /* virt addr of handler ... */ \
+ ori reg,reg,(label)@l; /* .. and the rest */
+#else
+#define LOAD_HANDLER(reg, label) \
+ ori reg,reg,(label)@l; /* virt addr of handler ... */
+#endif
+
#define EXCEPTION_PROLOG_PSERIES(area, label) \
mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \
std r9,area+EX_R9(r13); /* save r9 - r12 */ \
@@ -212,7 +230,7 @@ exception_marker:
clrrdi r12,r13,32; /* get high part of &label */ \
mfmsr r10; \
mfspr r11,SPRN_SRR0; /* save SRR0 */ \
- ori r12,r12,(label)@l; /* virt addr of handler */ \
+ LOAD_HANDLER(r12,label) \
ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \
mtspr SPRN_SRR0,r12; \
mfspr r12,SPRN_SRR1; /* and SRR1 */ \
@@ -553,6 +571,7 @@ slb_miss_user_pseries:
* Vectors for the FWNMI option. Share common code.
*/
.globl system_reset_fwnmi
+ .align 7
system_reset_fwnmi:
HMT_MEDIUM
mtspr SPRN_SPRG1,r13 /* save r13 */
@@ -560,6 +579,7 @@ system_reset_fwnmi:
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
.globl machine_check_fwnmi
+ .align 7
machine_check_fwnmi:
HMT_MEDIUM
mtspr SPRN_SPRG1,r13 /* save r13 */
@@ -726,7 +746,8 @@ iSeries_secondary_smp_loop:
decrementer_iSeries_masked:
li r11,1
stb r11,PACALPPACA+LPPACADECRINT(r13)
- lwz r12,PACADEFAULTDECR(r13)
+ LOADBASE(r12,tb_ticks_per_jiffy)
+ lwz r12,OFF(tb_ticks_per_jiffy)(r12)
mtspr SPRN_DEC,r12
/* fall through */
@@ -1345,7 +1366,7 @@ _GLOBAL(do_stab_bolted)
* fixed address (the linker can't compute (u64)&initial_stab >>
* PAGE_SHIFT).
*/
- . = STAB0_PHYS_ADDR /* 0x6000 */
+ . = STAB0_OFFSET /* 0x6000 */
.globl initial_stab
initial_stab:
.space 4096
@@ -1485,11 +1506,13 @@ _STATIC(__mmu_off)
*
*/
_GLOBAL(__start_initialization_multiplatform)
+#ifdef CONFIG_PPC_MULTIPLATFORM
/*
* Are we booted from a PROM Of-type client-interface ?
*/
cmpldi cr0,r5,0
bne .__boot_from_prom /* yes -> prom */
+#endif
/* Save parameters */
mr r31,r3
@@ -1510,6 +1533,7 @@ _GLOBAL(__start_initialization_multiplatform)
bl .__mmu_off
b .__after_prom_start
+#ifdef CONFIG_PPC_MULTIPLATFORM
_STATIC(__boot_from_prom)
/* Save parameters */
mr r31,r3
@@ -1542,6 +1566,7 @@ _STATIC(__boot_from_prom)
bl .prom_init
/* We never return */
trap
+#endif
/*
* At this point, r3 contains the physical address we are running at,
@@ -1550,7 +1575,7 @@ _STATIC(__boot_from_prom)
_STATIC(__after_prom_start)
/*
- * We need to run with __start at physical address 0.
+ * We need to run with __start at physical address PHYSICAL_START.
* This will leave some code in the first 256B of
* real memory, which are reserved for software use.
* The remainder of the first page is loaded with the fixed
@@ -1565,7 +1590,7 @@ _STATIC(__after_prom_start)
mr r26,r3
SET_REG_TO_CONST(r27,KERNELBASE)
- li r3,0 /* target addr */
+ LOADADDR(r3, PHYSICAL_START) /* target addr */
// XXX FIXME: Use phys returned by OF (r30)
add r4,r27,r26 /* source addr */
@@ -1846,7 +1871,7 @@ _STATIC(start_here_multiplatform)
mulli r13,r27,PACA_SIZE /* Calculate vaddr of right paca */
add r13,r13,r24 /* for this processor. */
add r13,r13,r26 /* convert to physical addr */
- mtspr SPRN_SPRG3,r13 /* PPPBBB: Temp... -Peter */
+ mtspr SPRN_SPRG3,r13
/* Do very early kernel initializations, including initial hash table,
* stab and slb setup before we turn on relocation. */
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
new file mode 100644
index 000000000000..e47d40ac6f39
--- /dev/null
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -0,0 +1,396 @@
+/*
+ * IBM PowerPC IBM eBus Infrastructure Support.
+ *
+ * Copyright (c) 2005 IBM Corporation
+ * Heiko J Schick <schickhj@de.ibm.com>
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/kobject.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <asm/ibmebus.h>
+#include <asm/abs_addr.h>
+
+static struct ibmebus_dev ibmebus_bus_device = { /* fake "parent" device */
+ .name = ibmebus_bus_device.ofdev.dev.bus_id,
+ .ofdev.dev.bus_id = "ibmebus",
+ .ofdev.dev.bus = &ibmebus_bus_type,
+};
+
+static void *ibmebus_alloc_coherent(struct device *dev,
+ size_t size,
+ dma_addr_t *dma_handle,
+ gfp_t flag)
+{
+ void *mem;
+
+ mem = kmalloc(size, flag);
+ *dma_handle = (dma_addr_t)mem;
+
+ return mem;
+}
+
+static void ibmebus_free_coherent(struct device *dev,
+ size_t size, void *vaddr,
+ dma_addr_t dma_handle)
+{
+ kfree(vaddr);
+}
+
+static dma_addr_t ibmebus_map_single(struct device *dev,
+ void *ptr,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ return (dma_addr_t)(ptr);
+}
+
+static void ibmebus_unmap_single(struct device *dev,
+ dma_addr_t dma_addr,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ return;
+}
+
+static int ibmebus_map_sg(struct device *dev,
+ struct scatterlist *sg,
+ int nents, enum dma_data_direction direction)
+{
+ int i;
+
+ for (i = 0; i < nents; i++) {
+ sg[i].dma_address = (dma_addr_t)page_address(sg[i].page)
+ + sg[i].offset;
+ sg[i].dma_length = sg[i].length;
+ }
+
+ return nents;
+}
+
+static void ibmebus_unmap_sg(struct device *dev,
+ struct scatterlist *sg,
+ int nents, enum dma_data_direction direction)
+{
+ return;
+}
+
+static int ibmebus_dma_supported(struct device *dev, u64 mask)
+{
+ return 1;
+}
+
+struct dma_mapping_ops ibmebus_dma_ops = {
+ .alloc_coherent = ibmebus_alloc_coherent,
+ .free_coherent = ibmebus_free_coherent,
+ .map_single = ibmebus_map_single,
+ .unmap_single = ibmebus_unmap_single,
+ .map_sg = ibmebus_map_sg,
+ .unmap_sg = ibmebus_unmap_sg,
+ .dma_supported = ibmebus_dma_supported,
+};
+
+static int ibmebus_bus_probe(struct device *dev)
+{
+ struct ibmebus_dev *ibmebusdev = to_ibmebus_dev(dev);
+ struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver);
+ const struct of_device_id *id;
+ int error = -ENODEV;
+
+ if (!ibmebusdrv->probe)
+ return error;
+
+ id = of_match_device(ibmebusdrv->id_table, &ibmebusdev->ofdev);
+ if (id) {
+ error = ibmebusdrv->probe(ibmebusdev, id);
+ }
+
+ return error;
+}
+
+static int ibmebus_bus_remove(struct device *dev)
+{
+ struct ibmebus_dev *ibmebusdev = to_ibmebus_dev(dev);
+ struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver);
+
+ if (ibmebusdrv->remove) {
+ return ibmebusdrv->remove(ibmebusdev);
+ }
+
+ return 0;
+}
+
+static void __devinit ibmebus_dev_release(struct device *dev)
+{
+ of_node_put(to_ibmebus_dev(dev)->ofdev.node);
+ kfree(to_ibmebus_dev(dev));
+}
+
+static ssize_t ibmebusdev_show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", to_ibmebus_dev(dev)->name);
+}
+static DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, ibmebusdev_show_name,
+ NULL);
+
+static struct ibmebus_dev* __devinit ibmebus_register_device_common(
+ struct ibmebus_dev *dev, char *name)
+{
+ int err = 0;
+
+ dev->name = name;
+ dev->ofdev.dev.parent = &ibmebus_bus_device.ofdev.dev;
+ dev->ofdev.dev.bus = &ibmebus_bus_type;
+ dev->ofdev.dev.release = ibmebus_dev_release;
+
+ /* An ibmebusdev is based on a of_device. We have to change the
+ * bus type to use our own DMA mapping operations.
+ */
+ if ((err = of_device_register(&dev->ofdev)) != 0) {
+ printk(KERN_ERR "%s: failed to register device (%d).\n",
+ __FUNCTION__, err);
+ return NULL;
+ }
+
+ device_create_file(&dev->ofdev.dev, &dev_attr_name);
+
+ return dev;
+}
+
+static struct ibmebus_dev* __devinit ibmebus_register_device_node(
+ struct device_node *dn)
+{
+ struct ibmebus_dev *dev;
+ char *loc_code;
+ int length;
+
+ loc_code = (char *)get_property(dn, "ibm,loc-code", NULL);
+ if (!loc_code) {
+ printk(KERN_WARNING "%s: node %s missing 'ibm,loc-code'\n",
+ __FUNCTION__, dn->name ? dn->name : "<unknown>");
+ return NULL;
+ }
+
+ if (strlen(loc_code) == 0) {
+ printk(KERN_WARNING "%s: 'ibm,loc-code' is invalid\n",
+ __FUNCTION__);
+ return NULL;
+ }
+
+ dev = kmalloc(sizeof(struct ibmebus_dev), GFP_KERNEL);
+ if (!dev) {
+ return NULL;
+ }
+ memset(dev, 0, sizeof(struct ibmebus_dev));
+
+ dev->ofdev.node = of_node_get(dn);
+
+ length = strlen(loc_code);
+ memcpy(dev->ofdev.dev.bus_id, loc_code
+ + (length - min(length, BUS_ID_SIZE - 1)),
+ min(length, BUS_ID_SIZE - 1));
+
+ /* Register with generic device framework. */
+ if (ibmebus_register_device_common(dev, dn->name) == NULL) {
+ kfree(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+
+static void ibmebus_probe_of_nodes(char* name)
+{
+ struct device_node *dn = NULL;
+
+ while ((dn = of_find_node_by_name(dn, name))) {
+ if (ibmebus_register_device_node(dn) == NULL) {
+ of_node_put(dn);
+
+ return;
+ }
+ }
+
+ of_node_put(dn);
+
+ return;
+}
+
+static void ibmebus_add_devices_by_id(struct of_device_id *idt)
+{
+ while (strlen(idt->name) > 0) {
+ ibmebus_probe_of_nodes(idt->name);
+ idt++;
+ }
+
+ return;
+}
+
+static int ibmebus_match_helper(struct device *dev, void *data)
+{
+ if (strcmp((char*)data, to_ibmebus_dev(dev)->name) == 0)
+ return 1;
+
+ return 0;
+}
+
+static int ibmebus_unregister_device(struct device *dev)
+{
+ device_remove_file(dev, &dev_attr_name);
+ of_device_unregister(to_of_device(dev));
+
+ return 0;
+}
+
+static void ibmebus_remove_devices_by_id(struct of_device_id *idt)
+{
+ struct device *dev;
+
+ while (strlen(idt->name) > 0) {
+ while ((dev = bus_find_device(&ibmebus_bus_type, NULL,
+ (void*)idt->name,
+ ibmebus_match_helper))) {
+ ibmebus_unregister_device(dev);
+ }
+ idt++;
+
+ }
+
+ return;
+}
+
+int ibmebus_register_driver(struct ibmebus_driver *drv)
+{
+ int err = 0;
+
+ drv->driver.name = drv->name;
+ drv->driver.bus = &ibmebus_bus_type;
+ drv->driver.probe = ibmebus_bus_probe;
+ drv->driver.remove = ibmebus_bus_remove;
+
+ if ((err = driver_register(&drv->driver) != 0))
+ return err;
+
+ ibmebus_add_devices_by_id(drv->id_table);
+
+ return 0;
+}
+EXPORT_SYMBOL(ibmebus_register_driver);
+
+void ibmebus_unregister_driver(struct ibmebus_driver *drv)
+{
+ driver_unregister(&drv->driver);
+ ibmebus_remove_devices_by_id(drv->id_table);
+}
+EXPORT_SYMBOL(ibmebus_unregister_driver);
+
+int ibmebus_request_irq(struct ibmebus_dev *dev,
+ u32 ist,
+ irqreturn_t (*handler)(int, void*, struct pt_regs *),
+ unsigned long irq_flags, const char * devname,
+ void *dev_id)
+{
+ unsigned int irq = virt_irq_create_mapping(ist);
+
+ if (irq == NO_IRQ)
+ return -EINVAL;
+
+ irq = irq_offset_up(irq);
+
+ return request_irq(irq, handler,
+ irq_flags, devname, dev_id);
+}
+EXPORT_SYMBOL(ibmebus_request_irq);
+
+void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id)
+{
+ unsigned int irq = virt_irq_create_mapping(ist);
+
+ irq = irq_offset_up(irq);
+ free_irq(irq, dev_id);
+
+ return;
+}
+EXPORT_SYMBOL(ibmebus_free_irq);
+
+static int ibmebus_bus_match(struct device *dev, struct device_driver *drv)
+{
+ const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
+ struct ibmebus_driver *ebus_drv = to_ibmebus_driver(drv);
+ const struct of_device_id *ids = ebus_drv->id_table;
+ const struct of_device_id *found_id;
+
+ if (!ids)
+ return 0;
+
+ found_id = of_match_device(ids, &ebus_dev->ofdev);
+ if (found_id)
+ return 1;
+
+ return 0;
+}
+
+struct bus_type ibmebus_bus_type = {
+ .name = "ibmebus",
+ .match = ibmebus_bus_match,
+};
+EXPORT_SYMBOL(ibmebus_bus_type);
+
+static int __init ibmebus_bus_init(void)
+{
+ int err;
+
+ printk(KERN_INFO "IBM eBus Device Driver\n");
+
+ err = bus_register(&ibmebus_bus_type);
+ if (err) {
+ printk(KERN_ERR ":%s: failed to register IBM eBus.\n",
+ __FUNCTION__);
+ return err;
+ }
+
+ err = device_register(&ibmebus_bus_device.ofdev.dev);
+ if (err) {
+ printk(KERN_WARNING "%s: device_register returned %i\n",
+ __FUNCTION__, err);
+ bus_unregister(&ibmebus_bus_type);
+
+ return err;
+ }
+
+ return 0;
+}
+__initcall(ibmebus_bus_init);
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 5a71ed9612fe..5651032d8706 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -31,7 +31,6 @@
* to reduce code space and undefined function references.
*/
-#include <linux/errno.h>
#include <linux/module.h>
#include <linux/threads.h>
#include <linux/kernel_stat.h>
@@ -44,18 +43,12 @@
#include <linux/config.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/irq.h>
-#include <linux/proc_fs.h>
-#include <linux/random.h>
#include <linux/seq_file.h>
#include <linux/cpumask.h>
#include <linux/profile.h>
#include <linux/bitops.h>
-#ifdef CONFIG_PPC64
-#include <linux/kallsyms.h>
-#endif
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -66,8 +59,7 @@
#include <asm/prom.h>
#include <asm/ptrace.h>
#include <asm/machdep.h>
-#ifdef CONFIG_PPC64
-#include <asm/iseries/it_lp_queue.h>
+#ifdef CONFIG_PPC_ISERIES
#include <asm/paca.h>
#endif
@@ -78,10 +70,6 @@ EXPORT_SYMBOL(__irq_offset_value);
static int ppc_spurious_interrupts;
-#if defined(CONFIG_PPC_ISERIES) && defined(CONFIG_SMP)
-extern void iSeries_smp_message_recv(struct pt_regs *);
-#endif
-
#ifdef CONFIG_PPC32
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
@@ -195,49 +183,6 @@ void fixup_irqs(cpumask_t map)
}
#endif
-#ifdef CONFIG_PPC_ISERIES
-void do_IRQ(struct pt_regs *regs)
-{
- struct paca_struct *lpaca;
-
- irq_enter();
-
-#ifdef CONFIG_DEBUG_STACKOVERFLOW
- /* Debugging check for stack overflow: is there less than 2KB free? */
- {
- long sp;
-
- sp = __get_SP() & (THREAD_SIZE-1);
-
- if (unlikely(sp < (sizeof(struct thread_info) + 2048))) {
- printk("do_IRQ: stack overflow: %ld\n",
- sp - sizeof(struct thread_info));
- dump_stack();
- }
- }
-#endif
-
- lpaca = get_paca();
-#ifdef CONFIG_SMP
- if (lpaca->lppaca.int_dword.fields.ipi_cnt) {
- lpaca->lppaca.int_dword.fields.ipi_cnt = 0;
- iSeries_smp_message_recv(regs);
- }
-#endif /* CONFIG_SMP */
- if (hvlpevent_is_pending())
- process_hvlpevents(regs);
-
- irq_exit();
-
- if (lpaca->lppaca.int_dword.fields.decr_int) {
- lpaca->lppaca.int_dword.fields.decr_int = 0;
- /* Signal a fake decrementer interrupt */
- timer_interrupt(regs);
- }
-}
-
-#else /* CONFIG_PPC_ISERIES */
-
void do_IRQ(struct pt_regs *regs)
{
int irq;
@@ -286,16 +231,24 @@ void do_IRQ(struct pt_regs *regs)
} else
#endif
__do_IRQ(irq, regs);
- } else
-#ifdef CONFIG_PPC32
- if (irq != -2)
-#endif
- /* That's not SMP safe ... but who cares ? */
- ppc_spurious_interrupts++;
+ } else if (irq != -2)
+ /* That's not SMP safe ... but who cares ? */
+ ppc_spurious_interrupts++;
+
irq_exit();
-}
-#endif /* CONFIG_PPC_ISERIES */
+#ifdef CONFIG_PPC_ISERIES
+ {
+ struct paca_struct *lpaca = get_paca();
+
+ if (lpaca->lppaca.int_dword.fields.decr_int) {
+ lpaca->lppaca.int_dword.fields.decr_int = 0;
+ /* Signal a fake decrementer interrupt */
+ timer_interrupt(regs);
+ }
+ }
+#endif
+}
void __init init_IRQ(void)
{
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
new file mode 100644
index 000000000000..f970ace208d3
--- /dev/null
+++ b/arch/powerpc/kernel/legacy_serial.c
@@ -0,0 +1,557 @@
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_core.h>
+#include <linux/console.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/mmu.h>
+#include <asm/prom.h>
+#include <asm/serial.h>
+#include <asm/udbg.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt...) do { printk(fmt); } while(0)
+#else
+#define DBG(fmt...) do { } while(0)
+#endif
+
+#define MAX_LEGACY_SERIAL_PORTS 8
+
+static struct plat_serial8250_port
+legacy_serial_ports[MAX_LEGACY_SERIAL_PORTS+1];
+static struct legacy_serial_info {
+ struct device_node *np;
+ unsigned int speed;
+ unsigned int clock;
+ phys_addr_t taddr;
+} legacy_serial_infos[MAX_LEGACY_SERIAL_PORTS];
+static unsigned int legacy_serial_count;
+static int legacy_serial_console = -1;
+
+static int __init add_legacy_port(struct device_node *np, int want_index,
+ int iotype, phys_addr_t base,
+ phys_addr_t taddr, unsigned long irq,
+ unsigned int flags)
+{
+ u32 *clk, *spd, clock = BASE_BAUD * 16;
+ int index;
+
+ /* get clock freq. if present */
+ clk = (u32 *)get_property(np, "clock-frequency", NULL);
+ if (clk && *clk)
+ clock = *clk;
+
+ /* get default speed if present */
+ spd = (u32 *)get_property(np, "current-speed", NULL);
+
+ /* If we have a location index, then try to use it */
+ if (want_index >= 0 && want_index < MAX_LEGACY_SERIAL_PORTS)
+ index = want_index;
+ else
+ index = legacy_serial_count;
+
+ /* if our index is still out of range, that mean that
+ * array is full, we could scan for a free slot but that
+ * make little sense to bother, just skip the port
+ */
+ if (index >= MAX_LEGACY_SERIAL_PORTS)
+ return -1;
+ if (index >= legacy_serial_count)
+ legacy_serial_count = index + 1;
+
+ /* Check if there is a port who already claimed our slot */
+ if (legacy_serial_infos[index].np != 0) {
+ /* if we still have some room, move it, else override */
+ if (legacy_serial_count < MAX_LEGACY_SERIAL_PORTS) {
+ printk(KERN_INFO "Moved legacy port %d -> %d\n",
+ index, legacy_serial_count);
+ legacy_serial_ports[legacy_serial_count] =
+ legacy_serial_ports[index];
+ legacy_serial_infos[legacy_serial_count] =
+ legacy_serial_infos[index];
+ legacy_serial_count++;
+ } else {
+ printk(KERN_INFO "Replacing legacy port %d\n", index);
+ }
+ }
+
+ /* Now fill the entry */
+ memset(&legacy_serial_ports[index], 0,
+ sizeof(struct plat_serial8250_port));
+ if (iotype == UPIO_PORT)
+ legacy_serial_ports[index].iobase = base;
+ else
+ legacy_serial_ports[index].mapbase = base;
+ legacy_serial_ports[index].iotype = iotype;
+ legacy_serial_ports[index].uartclk = clock;
+ legacy_serial_ports[index].irq = irq;
+ legacy_serial_ports[index].flags = flags;
+ legacy_serial_infos[index].taddr = taddr;
+ legacy_serial_infos[index].np = of_node_get(np);
+ legacy_serial_infos[index].clock = clock;
+ legacy_serial_infos[index].speed = spd ? *spd : 0;
+
+ printk(KERN_INFO "Found legacy serial port %d for %s\n",
+ index, np->full_name);
+ printk(KERN_INFO " %s=%llx, taddr=%llx, irq=%lx, clk=%d, speed=%d\n",
+ (iotype == UPIO_PORT) ? "port" : "mem",
+ (unsigned long long)base, (unsigned long long)taddr, irq,
+ legacy_serial_ports[index].uartclk,
+ legacy_serial_infos[index].speed);
+
+ return index;
+}
+
+static int __init add_legacy_soc_port(struct device_node *np,
+ struct device_node *soc_dev)
+{
+ phys_addr_t addr;
+ u32 *addrp;
+ unsigned int flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+
+ /* We only support ports that have a clock frequency properly
+ * encoded in the device-tree.
+ */
+ if (get_property(np, "clock-frequency", NULL) == NULL)
+ return -1;
+
+ /* Get the address */
+ addrp = of_get_address(soc_dev, 0, NULL, NULL);
+ if (addrp == NULL)
+ return -1;
+
+ addr = of_translate_address(soc_dev, addrp);
+
+ /* Add port, irq will be dealt with later. We passed a translated
+ * IO port value. It will be fixed up later along with the irq
+ */
+ return add_legacy_port(np, -1, UPIO_MEM, addr, addr, NO_IRQ, flags);
+}
+
+#ifdef CONFIG_ISA
+static int __init add_legacy_isa_port(struct device_node *np,
+ struct device_node *isa_brg)
+{
+ u32 *reg;
+ char *typep;
+ int index = -1;
+ phys_addr_t taddr;
+
+ /* Get the ISA port number */
+ reg = (u32 *)get_property(np, "reg", NULL);
+ if (reg == NULL)
+ return -1;
+
+ /* Verify it's an IO port, we don't support anything else */
+ if (!(reg[0] & 0x00000001))
+ return -1;
+
+ /* Now look for an "ibm,aix-loc" property that gives us ordering
+ * if any...
+ */
+ typep = (char *)get_property(np, "ibm,aix-loc", NULL);
+
+ /* If we have a location index, then use it */
+ if (typep && *typep == 'S')
+ index = simple_strtol(typep+1, NULL, 0) - 1;
+
+ /* Translate ISA address */
+ taddr = of_translate_address(np, reg);
+
+ /* Add port, irq will be dealt with later */
+ return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr, NO_IRQ, UPF_BOOT_AUTOCONF);
+
+}
+#endif
+
+#ifdef CONFIG_PCI
+static int __init add_legacy_pci_port(struct device_node *np,
+ struct device_node *pci_dev)
+{
+ phys_addr_t addr, base;
+ u32 *addrp;
+ unsigned int flags;
+ int iotype, index = -1, lindex = 0;
+
+ /* We only support ports that have a clock frequency properly
+ * encoded in the device-tree (that is have an fcode). Anything
+ * else can't be used that early and will be normally probed by
+ * the generic 8250_pci driver later on. The reason is that 8250
+ * compatible UARTs on PCI need all sort of quirks (port offsets
+ * etc...) that this code doesn't know about
+ */
+ if (get_property(np, "clock-frequency", NULL) == NULL)
+ return -1;
+
+ /* Get the PCI address. Assume BAR 0 */
+ addrp = of_get_pci_address(pci_dev, 0, NULL, &flags);
+ if (addrp == NULL)
+ return -1;
+
+ /* We only support BAR 0 for now */
+ iotype = (flags & IORESOURCE_MEM) ? UPIO_MEM : UPIO_PORT;
+ addr = of_translate_address(pci_dev, addrp);
+
+ /* Set the IO base to the same as the translated address for MMIO,
+ * or to the domain local IO base for PIO (it will be fixed up later)
+ */
+ if (iotype == UPIO_MEM)
+ base = addr;
+ else
+ base = addrp[2];
+
+ /* Try to guess an index... If we have subdevices of the pci dev,
+ * we get to their "reg" property
+ */
+ if (np != pci_dev) {
+ u32 *reg = (u32 *)get_property(np, "reg", NULL);
+ if (reg && (*reg < 4))
+ index = lindex = *reg;
+ }
+
+ /* Local index means it's the Nth port in the PCI chip. Unfortunately
+ * the offset to add here is device specific. We know about those
+ * EXAR ports and we default to the most common case. If your UART
+ * doesn't work for these settings, you'll have to add your own special
+ * cases here
+ */
+ if (device_is_compatible(pci_dev, "pci13a8,152") ||
+ device_is_compatible(pci_dev, "pci13a8,154") ||
+ device_is_compatible(pci_dev, "pci13a8,158")) {
+ addr += 0x200 * lindex;
+ base += 0x200 * lindex;
+ } else {
+ addr += 8 * lindex;
+ base += 8 * lindex;
+ }
+
+ /* Add port, irq will be dealt with later. We passed a translated
+ * IO port value. It will be fixed up later along with the irq
+ */
+ return add_legacy_port(np, index, iotype, base, addr, NO_IRQ, UPF_BOOT_AUTOCONF);
+}
+#endif
+
+/*
+ * This is called very early, as part of setup_system() or eventually
+ * setup_arch(), basically before anything else in this file. This function
+ * will try to build a list of all the available 8250-compatible serial ports
+ * in the machine using the Open Firmware device-tree. It currently only deals
+ * with ISA and PCI busses but could be extended. It allows a very early boot
+ * console to be initialized, that list is also used later to provide 8250 with
+ * the machine non-PCI ports and to properly pick the default console port
+ */
+void __init find_legacy_serial_ports(void)
+{
+ struct device_node *np, *stdout = NULL;
+ char *path;
+ int index;
+
+ DBG(" -> find_legacy_serial_port()\n");
+
+ /* Now find out if one of these is out firmware console */
+ path = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
+ if (path != NULL) {
+ stdout = of_find_node_by_path(path);
+ if (stdout)
+ DBG("stdout is %s\n", stdout->full_name);
+ } else {
+ DBG(" no linux,stdout-path !\n");
+ }
+
+ /* First fill our array with SOC ports */
+ for (np = NULL; (np = of_find_compatible_node(np, "serial", "ns16550")) != NULL;) {
+ struct device_node *soc = of_get_parent(np);
+ if (soc && !strcmp(soc->type, "soc")) {
+ index = add_legacy_soc_port(np, np);
+ if (index >= 0 && np == stdout)
+ legacy_serial_console = index;
+ }
+ of_node_put(soc);
+ }
+
+#ifdef CONFIG_ISA
+ /* First fill our array with ISA ports */
+ for (np = NULL; (np = of_find_node_by_type(np, "serial"));) {
+ struct device_node *isa = of_get_parent(np);
+ if (isa && !strcmp(isa->name, "isa")) {
+ index = add_legacy_isa_port(np, isa);
+ if (index >= 0 && np == stdout)
+ legacy_serial_console = index;
+ }
+ of_node_put(isa);
+ }
+#endif
+
+#ifdef CONFIG_PCI
+ /* Next, try to locate PCI ports */
+ for (np = NULL; (np = of_find_all_nodes(np));) {
+ struct device_node *pci, *parent = of_get_parent(np);
+ if (parent && !strcmp(parent->name, "isa")) {
+ of_node_put(parent);
+ continue;
+ }
+ if (strcmp(np->name, "serial") && strcmp(np->type, "serial")) {
+ of_node_put(parent);
+ continue;
+ }
+ /* Check for known pciclass, and also check wether we have
+ * a device with child nodes for ports or not
+ */
+ if (device_is_compatible(np, "pciclass,0700") ||
+ device_is_compatible(np, "pciclass,070002"))
+ pci = np;
+ else if (device_is_compatible(parent, "pciclass,0700") ||
+ device_is_compatible(parent, "pciclass,070002"))
+ pci = parent;
+ else {
+ of_node_put(parent);
+ continue;
+ }
+ index = add_legacy_pci_port(np, pci);
+ if (index >= 0 && np == stdout)
+ legacy_serial_console = index;
+ of_node_put(parent);
+ }
+#endif
+
+ DBG("legacy_serial_console = %d\n", legacy_serial_console);
+
+ /* udbg is 64 bits only for now, that will change soon though ... */
+ while (legacy_serial_console >= 0) {
+ struct legacy_serial_info *info =
+ &legacy_serial_infos[legacy_serial_console];
+ void __iomem *addr;
+
+ if (info->taddr == 0)
+ break;
+ addr = ioremap(info->taddr, 0x1000);
+ if (addr == NULL)
+ break;
+ if (info->speed == 0)
+ info->speed = udbg_probe_uart_speed(addr, info->clock);
+ DBG("default console speed = %d\n", info->speed);
+ udbg_init_uart(addr, info->speed, info->clock);
+ break;
+ }
+
+ DBG(" <- find_legacy_serial_port()\n");
+}
+
+static struct platform_device serial_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = legacy_serial_ports,
+ },
+};
+
+static void __init fixup_port_irq(int index,
+ struct device_node *np,
+ struct plat_serial8250_port *port)
+{
+ DBG("fixup_port_irq(%d)\n", index);
+
+ /* Check for interrupts in that node */
+ if (np->n_intrs > 0) {
+ port->irq = np->intrs[0].line;
+ DBG(" port %d (%s), irq=%d\n",
+ index, np->full_name, port->irq);
+ return;
+ }
+
+ /* Check for interrupts in the parent */
+ np = of_get_parent(np);
+ if (np == NULL)
+ return;
+
+ if (np->n_intrs > 0) {
+ port->irq = np->intrs[0].line;
+ DBG(" port %d (%s), irq=%d\n",
+ index, np->full_name, port->irq);
+ }
+ of_node_put(np);
+}
+
+static void __init fixup_port_pio(int index,
+ struct device_node *np,
+ struct plat_serial8250_port *port)
+{
+#ifdef CONFIG_PCI
+ struct pci_controller *hose;
+
+ DBG("fixup_port_pio(%d)\n", index);
+
+ hose = pci_find_hose_for_OF_device(np);
+ if (hose) {
+ unsigned long offset = (unsigned long)hose->io_base_virt -
+#ifdef CONFIG_PPC64
+ pci_io_base;
+#else
+ isa_io_base;
+#endif
+ DBG("port %d, IO %lx -> %lx\n",
+ index, port->iobase, port->iobase + offset);
+ port->iobase += offset;
+ }
+#endif
+}
+
+static void __init fixup_port_mmio(int index,
+ struct device_node *np,
+ struct plat_serial8250_port *port)
+{
+ DBG("fixup_port_mmio(%d)\n", index);
+
+ port->membase = ioremap(port->mapbase, 0x100);
+}
+
+/*
+ * This is called as an arch initcall, hopefully before the PCI bus is
+ * probed and/or the 8250 driver loaded since we need to register our
+ * platform devices before 8250 PCI ones are detected as some of them
+ * must properly "override" the platform ones.
+ *
+ * This function fixes up the interrupt value for platform ports as it
+ * couldn't be done earlier before interrupt maps have been parsed. It
+ * also "corrects" the IO address for PIO ports for the same reason,
+ * since earlier, the PHBs virtual IO space wasn't assigned yet. It then
+ * registers all those platform ports for use by the 8250 driver when it
+ * finally loads.
+ */
+static int __init serial_dev_init(void)
+{
+ int i;
+
+ if (legacy_serial_count == 0)
+ return -ENODEV;
+
+ /*
+ * Before we register the platfrom serial devices, we need
+ * to fixup their interrutps and their IO ports.
+ */
+ DBG("Fixing serial ports interrupts and IO ports ...\n");
+
+ for (i = 0; i < legacy_serial_count; i++) {
+ struct plat_serial8250_port *port = &legacy_serial_ports[i];
+ struct device_node *np = legacy_serial_infos[i].np;
+
+ if (port->irq == NO_IRQ)
+ fixup_port_irq(i, np, port);
+ if (port->iotype == UPIO_PORT)
+ fixup_port_pio(i, np, port);
+ if (port->iotype == UPIO_MEM)
+ fixup_port_mmio(i, np, port);
+ }
+
+ DBG("Registering platform serial ports\n");
+
+ return platform_device_register(&serial_device);
+}
+arch_initcall(serial_dev_init);
+
+
+/*
+ * This is called very early, as part of console_init() (typically just after
+ * time_init()). This function is respondible for trying to find a good
+ * default console on serial ports. It tries to match the open firmware
+ * default output with one of the available serial console drivers, either
+ * one of the platform serial ports that have been probed earlier by
+ * find_legacy_serial_ports() or some more platform specific ones.
+ */
+static int __init check_legacy_serial_console(void)
+{
+ struct device_node *prom_stdout = NULL;
+ int speed = 0, offset = 0;
+ char *name;
+ u32 *spd;
+
+ DBG(" -> check_legacy_serial_console()\n");
+
+ /* The user has requested a console so this is already set up. */
+ if (strstr(saved_command_line, "console=")) {
+ DBG(" console was specified !\n");
+ return -EBUSY;
+ }
+
+ if (!of_chosen) {
+ DBG(" of_chosen is NULL !\n");
+ return -ENODEV;
+ }
+
+ if (legacy_serial_console < 0) {
+ DBG(" legacy_serial_console not found !\n");
+ return -ENODEV;
+ }
+ /* We are getting a weird phandle from OF ... */
+ /* ... So use the full path instead */
+ name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
+ if (name == NULL) {
+ DBG(" no linux,stdout-path !\n");
+ return -ENODEV;
+ }
+ prom_stdout = of_find_node_by_path(name);
+ if (!prom_stdout) {
+ DBG(" can't find stdout package %s !\n", name);
+ return -ENODEV;
+ }
+ DBG("stdout is %s\n", prom_stdout->full_name);
+
+ name = (char *)get_property(prom_stdout, "name", NULL);
+ if (!name) {
+ DBG(" stdout package has no name !\n");
+ goto not_found;
+ }
+ spd = (u32 *)get_property(prom_stdout, "current-speed", NULL);
+ if (spd)
+ speed = *spd;
+
+ if (0)
+ ;
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+ else if (strcmp(name, "serial") == 0) {
+ int i;
+ /* Look for it in probed array */
+ for (i = 0; i < legacy_serial_count; i++) {
+ if (prom_stdout != legacy_serial_infos[i].np)
+ continue;
+ offset = i;
+ speed = legacy_serial_infos[i].speed;
+ break;
+ }
+ if (i >= legacy_serial_count)
+ goto not_found;
+ }
+#endif /* CONFIG_SERIAL_8250_CONSOLE */
+#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
+ else if (strcmp(name, "ch-a") == 0)
+ offset = 0;
+ else if (strcmp(name, "ch-b") == 0)
+ offset = 1;
+#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
+ else
+ goto not_found;
+ of_node_put(prom_stdout);
+
+ DBG("Found serial console at ttyS%d\n", offset);
+
+ if (speed) {
+ static char __initdata opt[16];
+ sprintf(opt, "%d", speed);
+ return add_preferred_console("ttyS", offset, opt);
+ } else
+ return add_preferred_console("ttyS", offset, NULL);
+
+ not_found:
+ DBG("No preferred console found !\n");
+ of_node_put(prom_stdout);
+ return -ENODEV;
+}
+console_initcall(check_legacy_serial_console);
+
diff --git a/arch/powerpc/kernel/lparmap.c b/arch/powerpc/kernel/lparmap.c
index 5a05a797485f..584d1e3c013d 100644
--- a/arch/powerpc/kernel/lparmap.c
+++ b/arch/powerpc/kernel/lparmap.c
@@ -7,7 +7,7 @@
* 2 of the License, or (at your option) any later version.
*/
#include <asm/mmu.h>
-#include <asm/page.h>
+#include <asm/pgtable.h>
#include <asm/iseries/lpar_map.h>
const struct LparMap __attribute__((__section__(".text"))) xLparMap = {
@@ -16,16 +16,16 @@ const struct LparMap __attribute__((__section__(".text"))) xLparMap = {
.xSegmentTableOffs = STAB0_PAGE,
.xEsids = {
- { .xKernelEsid = GET_ESID(KERNELBASE),
- .xKernelVsid = KERNEL_VSID(KERNELBASE), },
- { .xKernelEsid = GET_ESID(VMALLOCBASE),
- .xKernelVsid = KERNEL_VSID(VMALLOCBASE), },
+ { .xKernelEsid = GET_ESID(PAGE_OFFSET),
+ .xKernelVsid = KERNEL_VSID(PAGE_OFFSET), },
+ { .xKernelEsid = GET_ESID(VMALLOC_START),
+ .xKernelVsid = KERNEL_VSID(VMALLOC_START), },
},
.xRanges = {
{ .xPages = HvPagesToMap,
.xOffset = 0,
- .xVPN = KERNEL_VSID(KERNELBASE) << (SID_SHIFT - HW_PAGE_SHIFT),
+ .xVPN = KERNEL_VSID(PAGE_OFFSET) << (SID_SHIFT - HW_PAGE_SHIFT),
},
},
};
diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c
new file mode 100644
index 000000000000..a91e40c9ae45
--- /dev/null
+++ b/arch/powerpc/kernel/machine_kexec.c
@@ -0,0 +1,67 @@
+/*
+ * Code to handle transition of Linux booting another kernel.
+ *
+ * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com>
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ * Copyright (C) 2005 IBM Corporation.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/kexec.h>
+#include <linux/reboot.h>
+#include <linux/threads.h>
+#include <asm/machdep.h>
+
+/*
+ * Provide a dummy crash_notes definition until crash dump is implemented.
+ * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
+ */
+note_buf_t crash_notes[NR_CPUS];
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+ if (ppc_md.machine_crash_shutdown)
+ ppc_md.machine_crash_shutdown(regs);
+}
+
+/*
+ * Do what every setup is needed on image and the
+ * reboot code buffer to allow us to avoid allocations
+ * later.
+ */
+int machine_kexec_prepare(struct kimage *image)
+{
+ if (ppc_md.machine_kexec_prepare)
+ return ppc_md.machine_kexec_prepare(image);
+ /*
+ * Fail if platform doesn't provide its own machine_kexec_prepare
+ * implementation.
+ */
+ return -ENOSYS;
+}
+
+void machine_kexec_cleanup(struct kimage *image)
+{
+ if (ppc_md.machine_kexec_cleanup)
+ ppc_md.machine_kexec_cleanup(image);
+}
+
+/*
+ * Do not allocate memory (or fail in any way) in machine_kexec().
+ * We are past the point of no return, committed to rebooting now.
+ */
+NORET_TYPE void machine_kexec(struct kimage *image)
+{
+ if (ppc_md.machine_kexec)
+ ppc_md.machine_kexec(image);
+ else {
+ /*
+ * Fall back to normal restart if platform doesn't provide
+ * its own kexec function, and user insist to kexec...
+ */
+ machine_restart(NULL);
+ }
+ for(;;);
+}
diff --git a/arch/powerpc/kernel/machine_kexec_32.c b/arch/powerpc/kernel/machine_kexec_32.c
new file mode 100644
index 000000000000..443606134dff
--- /dev/null
+++ b/arch/powerpc/kernel/machine_kexec_32.c
@@ -0,0 +1,65 @@
+/*
+ * PPC32 code to handle Linux booting another kernel.
+ *
+ * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com>
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ * Copyright (C) 2005 IBM Corporation.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/kexec.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <asm/cacheflush.h>
+#include <asm/hw_irq.h>
+#include <asm/io.h>
+
+typedef NORET_TYPE void (*relocate_new_kernel_t)(
+ unsigned long indirection_page,
+ unsigned long reboot_code_buffer,
+ unsigned long start_address) ATTRIB_NORET;
+
+/*
+ * This is a generic machine_kexec function suitable at least for
+ * non-OpenFirmware embedded platforms.
+ * It merely copies the image relocation code to the control page and
+ * jumps to it.
+ * A platform specific function may just call this one.
+ */
+void default_machine_kexec(struct kimage *image)
+{
+ const extern unsigned char relocate_new_kernel[];
+ const extern unsigned int relocate_new_kernel_size;
+ unsigned long page_list;
+ unsigned long reboot_code_buffer, reboot_code_buffer_phys;
+ relocate_new_kernel_t rnk;
+
+ /* Interrupts aren't acceptable while we reboot */
+ local_irq_disable();
+
+ page_list = image->head;
+
+ /* we need both effective and real address here */
+ reboot_code_buffer =
+ (unsigned long)page_address(image->control_code_page);
+ reboot_code_buffer_phys = virt_to_phys((void *)reboot_code_buffer);
+
+ /* copy our kernel relocation code to the control code page */
+ memcpy((void *)reboot_code_buffer, relocate_new_kernel,
+ relocate_new_kernel_size);
+
+ flush_icache_range(reboot_code_buffer,
+ reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE);
+ printk(KERN_INFO "Bye!\n");
+
+ /* now call it */
+ rnk = (relocate_new_kernel_t) reboot_code_buffer;
+ (*rnk)(page_list, reboot_code_buffer_phys, image->start);
+}
+
+int default_machine_kexec_prepare(struct kimage *image)
+{
+ return 0;
+}
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index 97c51e452be7..d6431440c54f 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -1,5 +1,5 @@
/*
- * machine_kexec.c - handle transition of Linux booting another kernel
+ * PPC64 code to handle Linux booting another kernel.
*
* Copyright (C) 2004-2005, IBM Corp.
*
@@ -28,21 +28,7 @@
#define HASH_GROUP_SIZE 0x80 /* size of each hash group, asm/mmu.h */
-/* Have this around till we move it into crash specific file */
-note_buf_t crash_notes[NR_CPUS];
-
-/* Dummy for now. Not sure if we need to have a crash shutdown in here
- * and if what it will achieve. Letting it be now to compile the code
- * in generic kexec environment
- */
-void machine_crash_shutdown(struct pt_regs *regs)
-{
- /* do nothing right now */
- /* smp_relase_cpus() if we want smp on panic kernel */
- /* cpu_irq_down to isolate us until we are ready */
-}
-
-int machine_kexec_prepare(struct kimage *image)
+int default_machine_kexec_prepare(struct kimage *image)
{
int i;
unsigned long begin, end; /* limits of segment */
@@ -111,11 +97,6 @@ int machine_kexec_prepare(struct kimage *image)
return 0;
}
-void machine_kexec_cleanup(struct kimage *image)
-{
- /* we do nothing in prepare that needs to be undone */
-}
-
#define IND_FLAGS (IND_DESTINATION | IND_INDIRECTION | IND_DONE | IND_SOURCE)
static void copy_segments(unsigned long ind)
@@ -172,9 +153,8 @@ void kexec_copy_flush(struct kimage *image)
* including ones that were in place on the original copy
*/
for (i = 0; i < nr_segments; i++)
- flush_icache_range(ranges[i].mem + KERNELBASE,
- ranges[i].mem + KERNELBASE +
- ranges[i].memsz);
+ flush_icache_range((unsigned long)__va(ranges[i].mem),
+ (unsigned long)__va(ranges[i].mem + ranges[i].memsz));
}
#ifdef CONFIG_SMP
@@ -283,13 +263,20 @@ extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start,
void (*clear_all)(void)) ATTRIB_NORET;
/* too late to fail here */
-void machine_kexec(struct kimage *image)
+void default_machine_kexec(struct kimage *image)
{
-
/* prepare control code if any */
- /* shutdown other cpus into our wait loop and quiesce interrupts */
- kexec_prepare_cpus();
+ /*
+ * If the kexec boot is the normal one, need to shutdown other cpus
+ * into our wait loop and quiesce interrupts.
+ * Otherwise, in the case of crashed mode (crashing_cpu >= 0),
+ * stopping other CPUs and collecting their pt_regs is done before
+ * using debugger IPI.
+ */
+
+ if (crashing_cpu == -1)
+ kexec_prepare_cpus();
/* switch to a staticly allocated stack. Based on irq stack code.
* XXX: the task struct will likely be invalid once we do the copy!
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 624a983a9676..01d0d97a16e1 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -5,6 +5,10 @@
* Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
* and Paul Mackerras.
*
+ * kexec bits:
+ * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com>
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ *
* 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
@@ -24,6 +28,8 @@
#include <asm/ppc_asm.h>
#include <asm/thread_info.h>
#include <asm/asm-offsets.h>
+#include <asm/processor.h>
+#include <asm/kexec.h>
.text
@@ -1006,3 +1012,110 @@ _GLOBAL(execve)
*/
_GLOBAL(__main)
blr
+
+#ifdef CONFIG_KEXEC
+ /*
+ * Must be relocatable PIC code callable as a C function.
+ */
+ .globl relocate_new_kernel
+relocate_new_kernel:
+ /* r3 = page_list */
+ /* r4 = reboot_code_buffer */
+ /* r5 = start_address */
+
+ li r0, 0
+
+ /*
+ * Set Machine Status Register to a known status,
+ * switch the MMU off and jump to 1: in a single step.
+ */
+
+ mr r8, r0
+ ori r8, r8, MSR_RI|MSR_ME
+ mtspr SPRN_SRR1, r8
+ addi r8, r4, 1f - relocate_new_kernel
+ mtspr SPRN_SRR0, r8
+ sync
+ rfi
+
+1:
+ /* from this point address translation is turned off */
+ /* and interrupts are disabled */
+
+ /* set a new stack at the bottom of our page... */
+ /* (not really needed now) */
+ addi r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */
+ stw r0, 0(r1)
+
+ /* Do the copies */
+ li r6, 0 /* checksum */
+ mr r0, r3
+ b 1f
+
+0: /* top, read another word for the indirection page */
+ lwzu r0, 4(r3)
+
+1:
+ /* is it a destination page? (r8) */
+ rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */
+ beq 2f
+
+ rlwinm r8, r0, 0, 0, 19 /* clear kexec flags, page align */
+ b 0b
+
+2: /* is it an indirection page? (r3) */
+ rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */
+ beq 2f
+
+ rlwinm r3, r0, 0, 0, 19 /* clear kexec flags, page align */
+ subi r3, r3, 4
+ b 0b
+
+2: /* are we done? */
+ rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */
+ beq 2f
+ b 3f
+
+2: /* is it a source page? (r9) */
+ rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */
+ beq 0b
+
+ rlwinm r9, r0, 0, 0, 19 /* clear kexec flags, page align */
+
+ li r7, PAGE_SIZE / 4
+ mtctr r7
+ subi r9, r9, 4
+ subi r8, r8, 4
+9:
+ lwzu r0, 4(r9) /* do the copy */
+ xor r6, r6, r0
+ stwu r0, 4(r8)
+ dcbst 0, r8
+ sync
+ icbi 0, r8
+ bdnz 9b
+
+ addi r9, r9, 4
+ addi r8, r8, 4
+ b 0b
+
+3:
+
+ /* To be certain of avoiding problems with self-modifying code
+ * execute a serializing instruction here.
+ */
+ isync
+ sync
+
+ /* jump to the entry point, usually the setup routine */
+ mtlr r5
+ blrl
+
+1: b 1b
+
+relocate_new_kernel_end:
+
+ .globl relocate_new_kernel_size
+relocate_new_kernel_size:
+ .long relocate_new_kernel_end - relocate_new_kernel
+#endif
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index c0fcd29918ce..fd7db8d542db 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -80,80 +80,74 @@ static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin)
static ssize_t dev_nvram_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- ssize_t len;
- char *tmp_buffer;
- int size;
+ ssize_t ret;
+ char *tmp = NULL;
+ ssize_t size;
- if (ppc_md.nvram_size == NULL)
- return -ENODEV;
+ ret = -ENODEV;
+ if (!ppc_md.nvram_size)
+ goto out;
+
+ ret = 0;
size = ppc_md.nvram_size();
+ if (*ppos >= size || size < 0)
+ goto out;
- if (!access_ok(VERIFY_WRITE, buf, count))
- return -EFAULT;
- if (*ppos >= size)
- return 0;
- if (count > size)
- count = size;
+ count = min_t(size_t, count, size - *ppos);
+ count = min(count, PAGE_SIZE);
- tmp_buffer = (char *) kmalloc(count, GFP_KERNEL);
- if (!tmp_buffer) {
- printk(KERN_ERR "dev_read_nvram: kmalloc failed\n");
- return -ENOMEM;
- }
+ ret = -ENOMEM;
+ tmp = kmalloc(count, GFP_KERNEL);
+ if (!tmp)
+ goto out;
- len = ppc_md.nvram_read(tmp_buffer, count, ppos);
- if ((long)len <= 0) {
- kfree(tmp_buffer);
- return len;
- }
+ ret = ppc_md.nvram_read(tmp, count, ppos);
+ if (ret <= 0)
+ goto out;
- if (copy_to_user(buf, tmp_buffer, len)) {
- kfree(tmp_buffer);
- return -EFAULT;
- }
+ if (copy_to_user(buf, tmp, ret))
+ ret = -EFAULT;
- kfree(tmp_buffer);
- return len;
+out:
+ kfree(tmp);
+ return ret;
}
static ssize_t dev_nvram_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
- ssize_t len;
- char * tmp_buffer;
- int size;
+ ssize_t ret;
+ char *tmp = NULL;
+ ssize_t size;
- if (ppc_md.nvram_size == NULL)
- return -ENODEV;
+ ret = -ENODEV;
+ if (!ppc_md.nvram_size)
+ goto out;
+
+ ret = 0;
size = ppc_md.nvram_size();
+ if (*ppos >= size || size < 0)
+ goto out;
- if (!access_ok(VERIFY_READ, buf, count))
- return -EFAULT;
- if (*ppos >= size)
- return 0;
- if (count > size)
- count = size;
+ count = min_t(size_t, count, size - *ppos);
+ count = min(count, PAGE_SIZE);
- tmp_buffer = (char *) kmalloc(count, GFP_KERNEL);
- if (!tmp_buffer) {
- printk(KERN_ERR "dev_nvram_write: kmalloc failed\n");
- return -ENOMEM;
- }
-
- if (copy_from_user(tmp_buffer, buf, count)) {
- kfree(tmp_buffer);
- return -EFAULT;
- }
+ ret = -ENOMEM;
+ tmp = kmalloc(count, GFP_KERNEL);
+ if (!tmp)
+ goto out;
- len = ppc_md.nvram_write(tmp_buffer, count, ppos);
- if ((long)len <= 0) {
- kfree(tmp_buffer);
- return len;
- }
+ ret = -EFAULT;
+ if (copy_from_user(tmp, buf, count))
+ goto out;
+
+ ret = ppc_md.nvram_write(tmp, count, ppos);
+
+out:
+ kfree(tmp);
+ return ret;
- kfree(tmp_buffer);
- return len;
}
static int dev_nvram_ioctl(struct inode *inode, struct file *file,
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index a7b68f911eb1..999bdd816769 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -17,6 +17,7 @@
#include <asm/page.h>
#include <asm/lppaca.h>
#include <asm/iseries/it_lp_queue.h>
+#include <asm/iseries/it_lp_reg_save.h>
#include <asm/paca.h>
@@ -26,8 +27,7 @@ extern unsigned long __toc_start;
/* The Paca is an array with one entry per processor. Each contains an
* lppaca, which contains the information shared between the
- * hypervisor and Linux. Each also contains an ItLpRegSave area which
- * is used by the hypervisor to save registers.
+ * hypervisor and Linux.
* On systems with hardware multi-threading, there are two threads
* per processor. The Paca array must contain an entry for each thread.
* The VPD Areas will give a max logical processors = 2 * max physical
@@ -37,7 +37,6 @@ extern unsigned long __toc_start;
#define PACA_INIT_COMMON(number, start, asrr, asrv) \
.lock_token = 0x8000, \
.paca_index = (number), /* Paca Index */ \
- .default_decr = 0x00ff0000, /* Initial Decr */ \
.kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL, \
.stab_real = (asrr), /* Real pointer to segment table */ \
.stab_addr = (asrv), /* Virt pointer to segment table */ \
@@ -57,11 +56,7 @@ extern unsigned long __toc_start;
#ifdef CONFIG_PPC_ISERIES
#define PACA_INIT_ISERIES(number) \
.lppaca_ptr = &paca[number].lppaca, \
- .reg_save_ptr = &paca[number].reg_save, \
- .reg_save = { \
- .xDesc = 0xd397d9e2, /* "LpRS" */ \
- .xSize = sizeof(struct ItLpRegSave) \
- }
+ .reg_save_ptr = &iseries_reg_save[number],
#define PACA_INIT(number) \
{ \
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 8b6008ab217d..fc60a773af7d 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -34,7 +34,7 @@
#ifdef DEBUG
#include <asm/udbg.h>
-#define DBG(fmt...) udbg_printf(fmt)
+#define DBG(fmt...) printk(fmt)
#else
#define DBG(fmt...)
#endif
@@ -251,7 +251,7 @@ void pcibios_free_controller(struct pci_controller *phb)
kfree(phb);
}
-static void __init pcibios_claim_one_bus(struct pci_bus *b)
+void __devinit pcibios_claim_one_bus(struct pci_bus *b)
{
struct pci_dev *dev;
struct pci_bus *child_bus;
@@ -323,6 +323,7 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
addrs = (u32 *) get_property(node, "assigned-addresses", &proplen);
if (!addrs)
return;
+ DBG(" parse addresses (%d bytes) @ %p\n", proplen, addrs);
for (; proplen >= 20; proplen -= 20, addrs += 5) {
flags = pci_parse_of_flags(addrs[0]);
if (!flags)
@@ -332,6 +333,9 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
if (!size)
continue;
i = addrs[0] & 0xff;
+ DBG(" base: %llx, size: %llx, i: %x\n",
+ (unsigned long long)base, (unsigned long long)size, i);
+
if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) {
res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2];
} else if (i == dev->rom_base_reg) {
@@ -362,6 +366,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
if (type == NULL)
type = "";
+ DBG(" create device, devfn: %x, type: %s\n", devfn, type);
+
memset(dev, 0, sizeof(struct pci_dev));
dev->bus = bus;
dev->sysdata = node;
@@ -381,6 +387,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
dev->class = get_int_prop(node, "class-code", 0);
+ DBG(" class: 0x%x\n", dev->class);
+
dev->current_state = 4; /* unknown power state */
if (!strcmp(type, "pci")) {
@@ -402,6 +410,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
pci_parse_of_addrs(node, dev);
+ DBG(" adding to system ...\n");
+
pci_device_add(dev, bus);
/* XXX pci_scan_msi_device(dev); */
@@ -418,15 +428,21 @@ void __devinit of_scan_bus(struct device_node *node,
int reglen, devfn;
struct pci_dev *dev;
+ DBG("of_scan_bus(%s) bus no %d... \n", node->full_name, bus->number);
+
while ((child = of_get_next_child(node, child)) != NULL) {
+ DBG(" * %s\n", child->full_name);
reg = (u32 *) get_property(child, "reg", &reglen);
if (reg == NULL || reglen < 20)
continue;
devfn = (reg[0] >> 8) & 0xff;
+
/* create a new pci_dev for this device */
dev = of_create_pci_dev(child, bus, devfn);
if (!dev)
continue;
+ DBG("dev header type: %x\n", dev->hdr_type);
+
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
of_scan_pci_bridge(child, dev);
@@ -446,16 +462,18 @@ void __devinit of_scan_pci_bridge(struct device_node *node,
unsigned int flags;
u64 size;
+ DBG("of_scan_pci_bridge(%s)\n", node->full_name);
+
/* parse bus-range property */
busrange = (u32 *) get_property(node, "bus-range", &len);
if (busrange == NULL || len != 8) {
- printk(KERN_ERR "Can't get bus-range for PCI-PCI bridge %s\n",
+ printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n",
node->full_name);
return;
}
ranges = (u32 *) get_property(node, "ranges", &len);
if (ranges == NULL) {
- printk(KERN_ERR "Can't get ranges for PCI-PCI bridge %s\n",
+ printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n",
node->full_name);
return;
}
@@ -509,10 +527,13 @@ void __devinit of_scan_pci_bridge(struct device_node *node,
}
sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
bus->number);
+ DBG(" bus name: %s\n", bus->name);
mode = PCI_PROBE_NORMAL;
if (ppc_md.pci_probe_mode)
mode = ppc_md.pci_probe_mode(bus);
+ DBG(" probe mode: %d\n", mode);
+
if (mode == PCI_PROBE_DEVTREE)
of_scan_bus(node, bus);
else if (mode == PCI_PROBE_NORMAL)
@@ -528,6 +549,8 @@ void __devinit scan_phb(struct pci_controller *hose)
int i, mode;
struct resource *res;
+ DBG("Scanning PHB %s\n", node ? node->full_name : "<NO NAME>");
+
bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node);
if (bus == NULL) {
printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
@@ -552,8 +575,9 @@ void __devinit scan_phb(struct pci_controller *hose)
mode = PCI_PROBE_NORMAL;
#ifdef CONFIG_PPC_MULTIPLATFORM
- if (ppc_md.pci_probe_mode)
+ if (node && ppc_md.pci_probe_mode)
mode = ppc_md.pci_probe_mode(bus);
+ DBG(" probe mode: %d\n", mode);
if (mode == PCI_PROBE_DEVTREE) {
bus->subordinate = hose->last_busno;
of_scan_bus(node, bus);
@@ -842,8 +866,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
* Returns a negative error code on failure, zero on success.
*/
int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state,
- int write_combine)
+ enum pci_mmap_state mmap_state, int write_combine)
{
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
struct resource *rp;
@@ -896,6 +919,25 @@ static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
unsigned long phb_io_base_phys,
void __iomem * phb_io_base_virt)
{
+ /* Remove these asap */
+
+ struct pci_address {
+ u32 a_hi;
+ u32 a_mid;
+ u32 a_lo;
+ };
+
+ struct isa_address {
+ u32 a_hi;
+ u32 a_lo;
+ };
+
+ struct isa_range {
+ struct isa_address isa_addr;
+ struct pci_address pci_addr;
+ unsigned int size;
+ };
+
struct isa_range *range;
unsigned long pci_addr;
unsigned int isa_addr;
@@ -1223,6 +1265,7 @@ void __devinit pcibios_fixup_device_resources(struct pci_dev *dev,
}
EXPORT_SYMBOL(pcibios_fixup_device_resources);
+
static void __devinit do_bus_setup(struct pci_bus *bus)
{
struct pci_dev *dev;
@@ -1306,8 +1349,38 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
*end = rsrc->end + offset;
}
+struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
+{
+ if (!have_of)
+ return NULL;
+ while(node) {
+ struct pci_controller *hose, *tmp;
+ list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
+ if (hose->arch_data == node)
+ return hose;
+ node = node->parent;
+ }
+ return NULL;
+}
+
#endif /* CONFIG_PPC_MULTIPLATFORM */
+unsigned long pci_address_to_pio(phys_addr_t address)
+{
+ struct pci_controller *hose, *tmp;
+
+ list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+ if (address >= hose->io_base_phys &&
+ address < (hose->io_base_phys + hose->pci_io_size)) {
+ unsigned long base =
+ (unsigned long)hose->io_base_virt - pci_io_base;
+ return base + (address - hose->io_base_phys);
+ }
+ }
+ return (unsigned int)-1;
+}
+EXPORT_SYMBOL_GPL(pci_address_to_pio);
+
#define IOBASE_BRIDGE_NUMBER 0
#define IOBASE_MEMORY 1
diff --git a/arch/powerpc/kernel/pmc.c b/arch/powerpc/kernel/pmc.c
index 2d333cc84082..e6fb194fe537 100644
--- a/arch/powerpc/kernel/pmc.c
+++ b/arch/powerpc/kernel/pmc.c
@@ -43,8 +43,13 @@ static void dummy_perf(struct pt_regs *regs)
mtspr(SPRN_MMCR0, mmcr0);
}
#else
+/* Ensure exceptions are disabled */
static void dummy_perf(struct pt_regs *regs)
{
+ unsigned int mmcr0 = mfspr(SPRN_MMCR0);
+
+ mmcr0 &= ~(MMCR0_PMXE);
+ mtspr(SPRN_MMCR0, mmcr0);
}
#endif
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 94db25708456..b2758148a0de 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -76,11 +76,6 @@ EXPORT_SYMBOL(single_step_exception);
EXPORT_SYMBOL(sys_sigreturn);
#endif
-#if defined(CONFIG_PPC_PREP)
-EXPORT_SYMBOL(_prep_type);
-EXPORT_SYMBOL(ucSystemType);
-#endif
-
EXPORT_SYMBOL(strcpy);
EXPORT_SYMBOL(strncpy);
EXPORT_SYMBOL(strcat);
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 3bf968e74095..977ee3adaf2d 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -29,6 +29,7 @@
#include <linux/initrd.h>
#include <linux/bitops.h>
#include <linux/module.h>
+#include <linux/kexec.h>
#include <asm/prom.h>
#include <asm/rtas.h>
@@ -37,6 +38,7 @@
#include <asm/processor.h>
#include <asm/irq.h>
#include <asm/io.h>
+#include <asm/kdump.h>
#include <asm/smp.h>
#include <asm/system.h>
#include <asm/mmu.h>
@@ -55,21 +57,6 @@
#define DBG(fmt...)
#endif
-struct pci_reg_property {
- struct pci_address addr;
- u32 size_hi;
- u32 size_lo;
-};
-
-struct isa_reg_property {
- u32 space;
- u32 address;
- u32 size;
-};
-
-
-typedef int interpret_func(struct device_node *, unsigned long *,
- int, int, int);
static int __initdata dt_root_addr_cells;
static int __initdata dt_root_size_cells;
@@ -311,6 +298,16 @@ static int __devinit finish_node_interrupts(struct device_node *np,
int i, j, n, sense;
unsigned int *irq, virq;
struct device_node *ic;
+ int trace = 0;
+
+ //#define TRACE(fmt...) do { if (trace) { printk(fmt); mdelay(1000); } } while(0)
+#define TRACE(fmt...)
+
+ if (!strcmp(np->name, "smu-doorbell"))
+ trace = 1;
+
+ TRACE("Finishing SMU doorbell ! num_interrupt_controllers = %d\n",
+ num_interrupt_controllers);
if (num_interrupt_controllers == 0) {
/*
@@ -345,11 +342,12 @@ static int __devinit finish_node_interrupts(struct device_node *np,
}
ints = (unsigned int *) get_property(np, "interrupts", &intlen);
+ TRACE("ints=%p, intlen=%d\n", ints, intlen);
if (ints == NULL)
return 0;
intrcells = prom_n_intr_cells(np);
intlen /= intrcells * sizeof(unsigned int);
-
+ TRACE("intrcells=%d, new intlen=%d\n", intrcells, intlen);
np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start);
if (!np->intrs)
return -ENOMEM;
@@ -360,6 +358,7 @@ static int __devinit finish_node_interrupts(struct device_node *np,
intrcount = 0;
for (i = 0; i < intlen; ++i, ints += intrcells) {
n = map_interrupt(&irq, &ic, np, ints, intrcells);
+ TRACE("map, irq=%d, ic=%p, n=%d\n", irq, ic, n);
if (n <= 0)
continue;
@@ -370,6 +369,7 @@ static int __devinit finish_node_interrupts(struct device_node *np,
np->intrs[intrcount].sense = map_isa_senses[sense];
} else {
virq = virt_irq_create_mapping(irq[0]);
+ TRACE("virq=%d\n", virq);
#ifdef CONFIG_PPC64
if (virq == NO_IRQ) {
printk(KERN_CRIT "Could not allocate interrupt"
@@ -379,6 +379,12 @@ static int __devinit finish_node_interrupts(struct device_node *np,
#endif
np->intrs[intrcount].line = irq_offset_up(virq);
sense = (n > 1)? (irq[1] & 3): 1;
+
+ /* Apple uses bits in there in a different way, let's
+ * only keep the real sense bit on macs
+ */
+ if (_machine == PLATFORM_POWERMAC)
+ sense &= 0x1;
np->intrs[intrcount].sense = map_mpic_senses[sense];
}
@@ -388,12 +394,13 @@ static int __devinit finish_node_interrupts(struct device_node *np,
char *name = get_property(ic->parent, "name", NULL);
if (name && !strcmp(name, "u3"))
np->intrs[intrcount].line += 128;
- else if (!(name && !strcmp(name, "mac-io")))
+ else if (!(name && (!strcmp(name, "mac-io") ||
+ !strcmp(name, "u4"))))
/* ignore other cascaded controllers, such as
the k2-sata-root */
break;
}
-#endif
+#endif /* CONFIG_PPC64 */
if (n > 2) {
printk("hmmm, got %d intr cells for %s:", n,
np->full_name);
@@ -408,234 +415,19 @@ static int __devinit finish_node_interrupts(struct device_node *np,
return 0;
}
-static int __devinit interpret_pci_props(struct device_node *np,
- unsigned long *mem_start,
- int naddrc, int nsizec,
- int measure_only)
-{
- struct address_range *adr;
- struct pci_reg_property *pci_addrs;
- int i, l, n_addrs;
-
- pci_addrs = (struct pci_reg_property *)
- get_property(np, "assigned-addresses", &l);
- if (!pci_addrs)
- return 0;
-
- n_addrs = l / sizeof(*pci_addrs);
-
- adr = prom_alloc(n_addrs * sizeof(*adr), mem_start);
- if (!adr)
- return -ENOMEM;
-
- if (measure_only)
- return 0;
-
- np->addrs = adr;
- np->n_addrs = n_addrs;
-
- for (i = 0; i < n_addrs; i++) {
- adr[i].space = pci_addrs[i].addr.a_hi;
- adr[i].address = pci_addrs[i].addr.a_lo |
- ((u64)pci_addrs[i].addr.a_mid << 32);
- adr[i].size = pci_addrs[i].size_lo;
- }
-
- return 0;
-}
-
-static int __init interpret_dbdma_props(struct device_node *np,
- unsigned long *mem_start,
- int naddrc, int nsizec,
- int measure_only)
-{
- struct reg_property32 *rp;
- struct address_range *adr;
- unsigned long base_address;
- int i, l;
- struct device_node *db;
-
- base_address = 0;
- if (!measure_only) {
- for (db = np->parent; db != NULL; db = db->parent) {
- if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) {
- base_address = db->addrs[0].address;
- break;
- }
- }
- }
-
- rp = (struct reg_property32 *) get_property(np, "reg", &l);
- if (rp != 0 && l >= sizeof(struct reg_property32)) {
- i = 0;
- adr = (struct address_range *) (*mem_start);
- while ((l -= sizeof(struct reg_property32)) >= 0) {
- if (!measure_only) {
- adr[i].space = 2;
- adr[i].address = rp[i].address + base_address;
- adr[i].size = rp[i].size;
- }
- ++i;
- }
- np->addrs = adr;
- np->n_addrs = i;
- (*mem_start) += i * sizeof(struct address_range);
- }
-
- return 0;
-}
-
-static int __init interpret_macio_props(struct device_node *np,
- unsigned long *mem_start,
- int naddrc, int nsizec,
- int measure_only)
-{
- struct reg_property32 *rp;
- struct address_range *adr;
- unsigned long base_address;
- int i, l;
- struct device_node *db;
-
- base_address = 0;
- if (!measure_only) {
- for (db = np->parent; db != NULL; db = db->parent) {
- if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
- base_address = db->addrs[0].address;
- break;
- }
- }
- }
-
- rp = (struct reg_property32 *) get_property(np, "reg", &l);
- if (rp != 0 && l >= sizeof(struct reg_property32)) {
- i = 0;
- adr = (struct address_range *) (*mem_start);
- while ((l -= sizeof(struct reg_property32)) >= 0) {
- if (!measure_only) {
- adr[i].space = 2;
- adr[i].address = rp[i].address + base_address;
- adr[i].size = rp[i].size;
- }
- ++i;
- }
- np->addrs = adr;
- np->n_addrs = i;
- (*mem_start) += i * sizeof(struct address_range);
- }
-
- return 0;
-}
-
-static int __init interpret_isa_props(struct device_node *np,
- unsigned long *mem_start,
- int naddrc, int nsizec,
- int measure_only)
-{
- struct isa_reg_property *rp;
- struct address_range *adr;
- int i, l;
-
- rp = (struct isa_reg_property *) get_property(np, "reg", &l);
- if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
- i = 0;
- adr = (struct address_range *) (*mem_start);
- while ((l -= sizeof(struct isa_reg_property)) >= 0) {
- if (!measure_only) {
- adr[i].space = rp[i].space;
- adr[i].address = rp[i].address;
- adr[i].size = rp[i].size;
- }
- ++i;
- }
- np->addrs = adr;
- np->n_addrs = i;
- (*mem_start) += i * sizeof(struct address_range);
- }
-
- return 0;
-}
-
-static int __init interpret_root_props(struct device_node *np,
- unsigned long *mem_start,
- int naddrc, int nsizec,
- int measure_only)
-{
- struct address_range *adr;
- int i, l;
- unsigned int *rp;
- int rpsize = (naddrc + nsizec) * sizeof(unsigned int);
-
- rp = (unsigned int *) get_property(np, "reg", &l);
- if (rp != 0 && l >= rpsize) {
- i = 0;
- adr = (struct address_range *) (*mem_start);
- while ((l -= rpsize) >= 0) {
- if (!measure_only) {
- adr[i].space = 0;
- adr[i].address = rp[naddrc - 1];
- adr[i].size = rp[naddrc + nsizec - 1];
- }
- ++i;
- rp += naddrc + nsizec;
- }
- np->addrs = adr;
- np->n_addrs = i;
- (*mem_start) += i * sizeof(struct address_range);
- }
-
- return 0;
-}
-
static int __devinit finish_node(struct device_node *np,
unsigned long *mem_start,
- interpret_func *ifunc,
- int naddrc, int nsizec,
int measure_only)
{
struct device_node *child;
- int *ip, rc = 0;
-
- /* get the device addresses and interrupts */
- if (ifunc != NULL)
- rc = ifunc(np, mem_start, naddrc, nsizec, measure_only);
- if (rc)
- goto out;
+ int rc = 0;
rc = finish_node_interrupts(np, mem_start, measure_only);
if (rc)
goto out;
- /* Look for #address-cells and #size-cells properties. */
- ip = (int *) get_property(np, "#address-cells", NULL);
- if (ip != NULL)
- naddrc = *ip;
- ip = (int *) get_property(np, "#size-cells", NULL);
- if (ip != NULL)
- nsizec = *ip;
-
- if (!strcmp(np->name, "device-tree") || np->parent == NULL)
- ifunc = interpret_root_props;
- else if (np->type == 0)
- ifunc = NULL;
- else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
- ifunc = interpret_pci_props;
- else if (!strcmp(np->type, "dbdma"))
- ifunc = interpret_dbdma_props;
- else if (!strcmp(np->type, "mac-io") || ifunc == interpret_macio_props)
- ifunc = interpret_macio_props;
- else if (!strcmp(np->type, "isa"))
- ifunc = interpret_isa_props;
- else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3"))
- ifunc = interpret_root_props;
- else if (!((ifunc == interpret_dbdma_props
- || ifunc == interpret_macio_props)
- && (!strcmp(np->type, "escc")
- || !strcmp(np->type, "media-bay"))))
- ifunc = NULL;
-
for (child = np->child; child != NULL; child = child->sibling) {
- rc = finish_node(child, mem_start, ifunc,
- naddrc, nsizec, measure_only);
+ rc = finish_node(child, mem_start, measure_only);
if (rc)
goto out;
}
@@ -697,10 +489,10 @@ void __init finish_device_tree(void)
* reason and then remove those additional 16 bytes
*/
size = 16;
- finish_node(allnodes, &size, NULL, 0, 0, 1);
+ finish_node(allnodes, &size, 1);
size -= 16;
end = start = (unsigned long) __va(lmb_alloc(size, 128));
- finish_node(allnodes, &end, NULL, 0, 0, 0);
+ finish_node(allnodes, &end, 0);
BUG_ON(end != start + size);
DBG(" <- finish_device_tree\n");
@@ -1197,6 +989,16 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
}
#endif /* CONFIG_PPC_RTAS */
+#ifdef CONFIG_KEXEC
+ lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-base", NULL);
+ if (lprop)
+ crashk_res.start = *lprop;
+
+ lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-size", NULL);
+ if (lprop)
+ crashk_res.end = crashk_res.start + *lprop - 1;
+#endif
+
/* break now */
return 1;
}
@@ -1263,7 +1065,9 @@ static int __init early_init_dt_scan_memory(unsigned long node,
} else if (strcmp(type, "memory") != 0)
return 0;
- reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l);
+ reg = (cell_t *)of_get_flat_dt_prop(node, "linux,usable-memory", &l);
+ if (reg == NULL)
+ reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l);
if (reg == NULL)
return 0;
@@ -1335,11 +1139,14 @@ void __init early_init_devtree(void *params)
of_scan_flat_dt(early_init_dt_scan_memory, NULL);
lmb_enforce_memory_limit(memory_limit);
lmb_analyze();
- lmb_reserve(0, __pa(klimit));
DBG("Phys. mem: %lx\n", lmb_phys_mem_size());
/* Reserve LMB regions used by kernel, initrd, dt, etc... */
+ lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START);
+#ifdef CONFIG_CRASH_DUMP
+ lmb_reserve(0, KDUMP_RESERVE_LIMIT);
+#endif
early_reserve_mem();
DBG("Scanning CPUs ...\n");
@@ -1802,7 +1609,6 @@ static void of_node_release(struct kref *kref)
prop = next;
}
kfree(node->intrs);
- kfree(node->addrs);
kfree(node->full_name);
kfree(node->data);
kfree(node);
@@ -1884,9 +1690,7 @@ void of_detach_node(const struct device_node *np)
* This should probably be split up into smaller chunks.
*/
-static int of_finish_dynamic_node(struct device_node *node,
- unsigned long *unused1, int unused2,
- int unused3, int unused4)
+static int of_finish_dynamic_node(struct device_node *node)
{
struct device_node *parent = of_get_parent(node);
int err = 0;
@@ -1907,7 +1711,8 @@ static int of_finish_dynamic_node(struct device_node *node,
return -ENODEV;
/* fix up new node's linux_phandle field */
- if ((ibm_phandle = (unsigned int *)get_property(node, "ibm,phandle", NULL)))
+ if ((ibm_phandle = (unsigned int *)get_property(node,
+ "ibm,phandle", NULL)))
node->linux_phandle = *ibm_phandle;
out:
@@ -1922,7 +1727,9 @@ static int prom_reconfig_notifier(struct notifier_block *nb,
switch (action) {
case PSERIES_RECONFIG_ADD:
- err = finish_node(node, NULL, of_finish_dynamic_node, 0, 0, 0);
+ err = of_finish_dynamic_node(node);
+ if (!err)
+ finish_node(node, NULL, 0);
if (err < 0) {
printk(KERN_ERR "finish_node returned %d\n", err);
err = NOTIFY_BAD;
@@ -1996,175 +1803,4 @@ int prom_add_property(struct device_node* np, struct property* prop)
return 0;
}
-/* I quickly hacked that one, check against spec ! */
-static inline unsigned long
-bus_space_to_resource_flags(unsigned int bus_space)
-{
- u8 space = (bus_space >> 24) & 0xf;
- if (space == 0)
- space = 0x02;
- if (space == 0x02)
- return IORESOURCE_MEM;
- else if (space == 0x01)
- return IORESOURCE_IO;
- else {
- printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n",
- bus_space);
- return 0;
- }
-}
-
-#ifdef CONFIG_PCI
-static struct resource *find_parent_pci_resource(struct pci_dev* pdev,
- struct address_range *range)
-{
- unsigned long mask;
- int i;
-
- /* Check this one */
- mask = bus_space_to_resource_flags(range->space);
- for (i=0; i<DEVICE_COUNT_RESOURCE; i++) {
- if ((pdev->resource[i].flags & mask) == mask &&
- pdev->resource[i].start <= range->address &&
- pdev->resource[i].end > range->address) {
- if ((range->address + range->size - 1) > pdev->resource[i].end) {
- /* Add better message */
- printk(KERN_WARNING "PCI/OF resource overlap !\n");
- return NULL;
- }
- break;
- }
- }
- if (i == DEVICE_COUNT_RESOURCE)
- return NULL;
- return &pdev->resource[i];
-}
-
-/*
- * Request an OF device resource. Currently handles child of PCI devices,
- * or other nodes attached to the root node. Ultimately, put some
- * link to resources in the OF node.
- */
-struct resource *request_OF_resource(struct device_node* node, int index,
- const char* name_postfix)
-{
- struct pci_dev* pcidev;
- u8 pci_bus, pci_devfn;
- unsigned long iomask;
- struct device_node* nd;
- struct resource* parent;
- struct resource *res = NULL;
- int nlen, plen;
-
- if (index >= node->n_addrs)
- goto fail;
-
- /* Sanity check on bus space */
- iomask = bus_space_to_resource_flags(node->addrs[index].space);
- if (iomask & IORESOURCE_MEM)
- parent = &iomem_resource;
- else if (iomask & IORESOURCE_IO)
- parent = &ioport_resource;
- else
- goto fail;
-
- /* Find a PCI parent if any */
- nd = node;
- pcidev = NULL;
- while (nd) {
- if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
- pcidev = pci_find_slot(pci_bus, pci_devfn);
- if (pcidev) break;
- nd = nd->parent;
- }
- if (pcidev)
- parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
- if (!parent) {
- printk(KERN_WARNING "request_OF_resource(%s), parent not found\n",
- node->name);
- goto fail;
- }
- res = __request_region(parent, node->addrs[index].address,
- node->addrs[index].size, NULL);
- if (!res)
- goto fail;
- nlen = strlen(node->name);
- plen = name_postfix ? strlen(name_postfix) : 0;
- res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL);
- if (res->name) {
- strcpy((char *)res->name, node->name);
- if (plen)
- strcpy((char *)res->name+nlen, name_postfix);
- }
- return res;
-fail:
- return NULL;
-}
-EXPORT_SYMBOL(request_OF_resource);
-
-int release_OF_resource(struct device_node *node, int index)
-{
- struct pci_dev* pcidev;
- u8 pci_bus, pci_devfn;
- unsigned long iomask, start, end;
- struct device_node* nd;
- struct resource* parent;
- struct resource *res = NULL;
-
- if (index >= node->n_addrs)
- return -EINVAL;
-
- /* Sanity check on bus space */
- iomask = bus_space_to_resource_flags(node->addrs[index].space);
- if (iomask & IORESOURCE_MEM)
- parent = &iomem_resource;
- else if (iomask & IORESOURCE_IO)
- parent = &ioport_resource;
- else
- return -EINVAL;
-
- /* Find a PCI parent if any */
- nd = node;
- pcidev = NULL;
- while(nd) {
- if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
- pcidev = pci_find_slot(pci_bus, pci_devfn);
- if (pcidev) break;
- nd = nd->parent;
- }
- if (pcidev)
- parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
- if (!parent) {
- printk(KERN_WARNING "release_OF_resource(%s), parent not found\n",
- node->name);
- return -ENODEV;
- }
-
- /* Find us in the parent and its childs */
- res = parent->child;
- start = node->addrs[index].address;
- end = start + node->addrs[index].size - 1;
- while (res) {
- if (res->start == start && res->end == end &&
- (res->flags & IORESOURCE_BUSY))
- break;
- if (res->start <= start && res->end >= end)
- res = res->child;
- else
- res = res->sibling;
- }
- if (!res)
- return -ENODEV;
-
- if (res->name) {
- kfree(res->name);
- res->name = NULL;
- }
- release_resource(res);
- kfree(res);
-
- return 0;
-}
-EXPORT_SYMBOL(release_OF_resource);
-#endif /* CONFIG_PCI */
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index bcdc209dca85..e381f2fc121c 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -192,6 +192,11 @@ static unsigned long __initdata alloc_bottom;
static unsigned long __initdata rmo_top;
static unsigned long __initdata ram_top;
+#ifdef CONFIG_KEXEC
+static unsigned long __initdata prom_crashk_base;
+static unsigned long __initdata prom_crashk_size;
+#endif
+
static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE];
static int __initdata mem_reserve_cnt;
@@ -553,7 +558,8 @@ unsigned long prom_memparse(const char *ptr, const char **retptr)
static void __init early_cmdline_parse(void)
{
struct prom_t *_prom = &RELOC(prom);
- char *opt, *p;
+ const char *opt;
+ char *p;
int l = 0;
RELOC(prom_cmd_line[0]) = 0;
@@ -590,6 +596,34 @@ static void __init early_cmdline_parse(void)
RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000);
#endif
}
+
+#ifdef CONFIG_KEXEC
+ /*
+ * crashkernel=size@addr specifies the location to reserve for
+ * crash kernel.
+ */
+ opt = strstr(RELOC(prom_cmd_line), RELOC("crashkernel="));
+ if (opt) {
+ opt += 12;
+ RELOC(prom_crashk_size) = prom_memparse(opt, &opt);
+
+ if (ALIGN(RELOC(prom_crashk_size), 0x1000000) !=
+ RELOC(prom_crashk_size)) {
+ prom_printf("Warning: crashkernel size is not "
+ "aligned to 16MB\n");
+ }
+
+ /*
+ * At present, the crash kernel always run at 32MB.
+ * Just ignore whatever user passed.
+ */
+ RELOC(prom_crashk_base) = 0x2000000;
+ if (*opt == '@') {
+ prom_printf("Warning: PPC64 kdump kernel always runs "
+ "at 32 MB\n");
+ }
+ }
+#endif
}
#ifdef CONFIG_PPC_PSERIES
@@ -1011,6 +1045,12 @@ static void __init prom_init_mem(void)
prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high));
prom_printf(" rmo_top : %x\n", RELOC(rmo_top));
prom_printf(" ram_top : %x\n", RELOC(ram_top));
+#ifdef CONFIG_KEXEC
+ if (RELOC(prom_crashk_base)) {
+ prom_printf(" crashk_base : %x\n", RELOC(prom_crashk_base));
+ prom_printf(" crashk_size : %x\n", RELOC(prom_crashk_size));
+ }
+#endif
}
@@ -1500,6 +1540,8 @@ static int __init prom_find_machine_type(void)
#ifdef CONFIG_PPC64
if (strstr(p, RELOC("Momentum,Maple")))
return PLATFORM_MAPLE;
+ if (strstr(p, RELOC("IBM,CPB")))
+ return PLATFORM_CELL;
#endif
i += sl + 1;
}
@@ -1994,7 +2036,7 @@ static void __init prom_check_initrd(unsigned long r3, unsigned long r4)
if (r3 && r4 && r4 != 0xdeadbeef) {
unsigned long val;
- RELOC(prom_initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3;
+ RELOC(prom_initrd_start) = is_kernel_addr(r3) ? __pa(r3) : r3;
RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4;
val = RELOC(prom_initrd_start);
@@ -2094,6 +2136,10 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
*/
prom_init_mem();
+#ifdef CONFIG_KEXEC
+ if (RELOC(prom_crashk_base))
+ reserve_mem(RELOC(prom_crashk_base), RELOC(prom_crashk_size));
+#endif
/*
* Determine which cpu is actually running right _now_
*/
@@ -2150,6 +2196,16 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
}
#endif
+#ifdef CONFIG_KEXEC
+ if (RELOC(prom_crashk_base)) {
+ prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-base",
+ PTRRELOC(&prom_crashk_base),
+ sizeof(RELOC(prom_crashk_base)));
+ prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-size",
+ PTRRELOC(&prom_crashk_size),
+ sizeof(RELOC(prom_crashk_size)));
+ }
+#endif
/*
* Fixup any known bugs in the device-tree
*/
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
new file mode 100644
index 000000000000..309ae1d5fa77
--- /dev/null
+++ b/arch/powerpc/kernel/prom_parse.c
@@ -0,0 +1,547 @@
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/pci_regs.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+
+#ifdef DEBUG
+#define DBG(fmt...) do { printk(fmt); } while(0)
+#else
+#define DBG(fmt...) do { } while(0)
+#endif
+
+#ifdef CONFIG_PPC64
+#define PRu64 "%lx"
+#else
+#define PRu64 "%llx"
+#endif
+
+/* Max address size we deal with */
+#define OF_MAX_ADDR_CELLS 4
+#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
+ (ns) > 0)
+
+/* Debug utility */
+#ifdef DEBUG
+static void of_dump_addr(const char *s, u32 *addr, int na)
+{
+ printk("%s", s);
+ while(na--)
+ printk(" %08x", *(addr++));
+ printk("\n");
+}
+#else
+static void of_dump_addr(const char *s, u32 *addr, int na) { }
+#endif
+
+/* Read a big address */
+static inline u64 of_read_addr(u32 *cell, int size)
+{
+ u64 r = 0;
+ while (size--)
+ r = (r << 32) | *(cell++);
+ return r;
+}
+
+/* Callbacks for bus specific translators */
+struct of_bus {
+ const char *name;
+ const char *addresses;
+ int (*match)(struct device_node *parent);
+ void (*count_cells)(struct device_node *child,
+ int *addrc, int *sizec);
+ u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna);
+ int (*translate)(u32 *addr, u64 offset, int na);
+ unsigned int (*get_flags)(u32 *addr);
+};
+
+
+/*
+ * Default translator (generic bus)
+ */
+
+static void of_bus_default_count_cells(struct device_node *dev,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = prom_n_addr_cells(dev);
+ if (sizec)
+ *sizec = prom_n_size_cells(dev);
+}
+
+static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ cp = of_read_addr(range, na);
+ s = of_read_addr(range + na + pna, ns);
+ da = of_read_addr(addr, na);
+
+ DBG("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
+ cp, s, da);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_default_translate(u32 *addr, u64 offset, int na)
+{
+ u64 a = of_read_addr(addr, na);
+ memset(addr, 0, na * 4);
+ a += offset;
+ if (na > 1)
+ addr[na - 2] = a >> 32;
+ addr[na - 1] = a & 0xffffffffu;
+
+ return 0;
+}
+
+static unsigned int of_bus_default_get_flags(u32 *addr)
+{
+ return IORESOURCE_MEM;
+}
+
+
+/*
+ * PCI bus specific translator
+ */
+
+static int of_bus_pci_match(struct device_node *np)
+{
+ return !strcmp(np->type, "pci");
+}
+
+static void of_bus_pci_count_cells(struct device_node *np,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = 3;
+ if (sizec)
+ *sizec = 2;
+}
+
+static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ /* Check address type match */
+ if ((addr[0] ^ range[0]) & 0x03000000)
+ return OF_BAD_ADDR;
+
+ /* Read address values, skipping high cell */
+ cp = of_read_addr(range + 1, na - 1);
+ s = of_read_addr(range + na + pna, ns);
+ da = of_read_addr(addr + 1, na - 1);
+
+ DBG("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
+{
+ return of_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+static unsigned int of_bus_pci_get_flags(u32 *addr)
+{
+ unsigned int flags = 0;
+ u32 w = addr[0];
+
+ switch((w >> 24) & 0x03) {
+ case 0x01:
+ flags |= IORESOURCE_IO;
+ case 0x02: /* 32 bits */
+ case 0x03: /* 64 bits */
+ flags |= IORESOURCE_MEM;
+ }
+ if (w & 0x40000000)
+ flags |= IORESOURCE_PREFETCH;
+ return flags;
+}
+
+/*
+ * ISA bus specific translator
+ */
+
+static int of_bus_isa_match(struct device_node *np)
+{
+ return !strcmp(np->name, "isa");
+}
+
+static void of_bus_isa_count_cells(struct device_node *child,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = 2;
+ if (sizec)
+ *sizec = 1;
+}
+
+static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ /* Check address type match */
+ if ((addr[0] ^ range[0]) & 0x00000001)
+ return OF_BAD_ADDR;
+
+ /* Read address values, skipping high cell */
+ cp = of_read_addr(range + 1, na - 1);
+ s = of_read_addr(range + na + pna, ns);
+ da = of_read_addr(addr + 1, na - 1);
+
+ DBG("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
+{
+ return of_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+static unsigned int of_bus_isa_get_flags(u32 *addr)
+{
+ unsigned int flags = 0;
+ u32 w = addr[0];
+
+ if (w & 1)
+ flags |= IORESOURCE_IO;
+ else
+ flags |= IORESOURCE_MEM;
+ return flags;
+}
+
+
+/*
+ * Array of bus specific translators
+ */
+
+static struct of_bus of_busses[] = {
+ /* PCI */
+ {
+ .name = "pci",
+ .addresses = "assigned-addresses",
+ .match = of_bus_pci_match,
+ .count_cells = of_bus_pci_count_cells,
+ .map = of_bus_pci_map,
+ .translate = of_bus_pci_translate,
+ .get_flags = of_bus_pci_get_flags,
+ },
+ /* ISA */
+ {
+ .name = "isa",
+ .addresses = "reg",
+ .match = of_bus_isa_match,
+ .count_cells = of_bus_isa_count_cells,
+ .map = of_bus_isa_map,
+ .translate = of_bus_isa_translate,
+ .get_flags = of_bus_isa_get_flags,
+ },
+ /* Default */
+ {
+ .name = "default",
+ .addresses = "reg",
+ .match = NULL,
+ .count_cells = of_bus_default_count_cells,
+ .map = of_bus_default_map,
+ .translate = of_bus_default_translate,
+ .get_flags = of_bus_default_get_flags,
+ },
+};
+
+static struct of_bus *of_match_bus(struct device_node *np)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(of_busses); i ++)
+ if (!of_busses[i].match || of_busses[i].match(np))
+ return &of_busses[i];
+ BUG();
+ return NULL;
+}
+
+static int of_translate_one(struct device_node *parent, struct of_bus *bus,
+ struct of_bus *pbus, u32 *addr,
+ int na, int ns, int pna)
+{
+ u32 *ranges;
+ unsigned int rlen;
+ int rone;
+ u64 offset = OF_BAD_ADDR;
+
+ /* Normally, an absence of a "ranges" property means we are
+ * crossing a non-translatable boundary, and thus the addresses
+ * below the current not cannot be converted to CPU physical ones.
+ * Unfortunately, while this is very clear in the spec, it's not
+ * what Apple understood, and they do have things like /uni-n or
+ * /ht nodes with no "ranges" property and a lot of perfectly
+ * useable mapped devices below them. Thus we treat the absence of
+ * "ranges" as equivalent to an empty "ranges" property which means
+ * a 1:1 translation at that level. It's up to the caller not to try
+ * to translate addresses that aren't supposed to be translated in
+ * the first place. --BenH.
+ */
+ ranges = (u32 *)get_property(parent, "ranges", &rlen);
+ if (ranges == NULL || rlen == 0) {
+ offset = of_read_addr(addr, na);
+ memset(addr, 0, pna * 4);
+ DBG("OF: no ranges, 1:1 translation\n");
+ goto finish;
+ }
+
+ DBG("OF: walking ranges...\n");
+
+ /* Now walk through the ranges */
+ rlen /= 4;
+ rone = na + pna + ns;
+ for (; rlen >= rone; rlen -= rone, ranges += rone) {
+ offset = bus->map(addr, ranges, na, ns, pna);
+ if (offset != OF_BAD_ADDR)
+ break;
+ }
+ if (offset == OF_BAD_ADDR) {
+ DBG("OF: not found !\n");
+ return 1;
+ }
+ memcpy(addr, ranges + na, 4 * pna);
+
+ finish:
+ of_dump_addr("OF: parent translation for:", addr, pna);
+ DBG("OF: with offset: "PRu64"\n", offset);
+
+ /* Translate it into parent bus space */
+ return pbus->translate(addr, offset, pna);
+}
+
+
+/*
+ * Translate an address from the device-tree into a CPU physical address,
+ * this walks up the tree and applies the various bus mappings on the
+ * way.
+ *
+ * Note: We consider that crossing any level with #size-cells == 0 to mean
+ * that translation is impossible (that is we are not dealing with a value
+ * that can be mapped to a cpu physical address). This is not really specified
+ * that way, but this is traditionally the way IBM at least do things
+ */
+u64 of_translate_address(struct device_node *dev, u32 *in_addr)
+{
+ struct device_node *parent = NULL;
+ struct of_bus *bus, *pbus;
+ u32 addr[OF_MAX_ADDR_CELLS];
+ int na, ns, pna, pns;
+ u64 result = OF_BAD_ADDR;
+
+ DBG("OF: ** translation for device %s **\n", dev->full_name);
+
+ /* Increase refcount at current level */
+ of_node_get(dev);
+
+ /* Get parent & match bus type */
+ parent = of_get_parent(dev);
+ if (parent == NULL)
+ goto bail;
+ bus = of_match_bus(parent);
+
+ /* Cound address cells & copy address locally */
+ bus->count_cells(dev, &na, &ns);
+ if (!OF_CHECK_COUNTS(na, ns)) {
+ printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
+ dev->full_name);
+ goto bail;
+ }
+ memcpy(addr, in_addr, na * 4);
+
+ DBG("OF: bus is %s (na=%d, ns=%d) on %s\n",
+ bus->name, na, ns, parent->full_name);
+ of_dump_addr("OF: translating address:", addr, na);
+
+ /* Translate */
+ for (;;) {
+ /* Switch to parent bus */
+ of_node_put(dev);
+ dev = parent;
+ parent = of_get_parent(dev);
+
+ /* If root, we have finished */
+ if (parent == NULL) {
+ DBG("OF: reached root node\n");
+ result = of_read_addr(addr, na);
+ break;
+ }
+
+ /* Get new parent bus and counts */
+ pbus = of_match_bus(parent);
+ pbus->count_cells(dev, &pna, &pns);
+ if (!OF_CHECK_COUNTS(pna, pns)) {
+ printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
+ dev->full_name);
+ break;
+ }
+
+ DBG("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
+ pbus->name, pna, pns, parent->full_name);
+
+ /* Apply bus translation */
+ if (of_translate_one(dev, bus, pbus, addr, na, ns, pna))
+ break;
+
+ /* Complete the move up one level */
+ na = pna;
+ ns = pns;
+ bus = pbus;
+
+ of_dump_addr("OF: one level translation:", addr, na);
+ }
+ bail:
+ of_node_put(parent);
+ of_node_put(dev);
+
+ return result;
+}
+EXPORT_SYMBOL(of_translate_address);
+
+u32 *of_get_address(struct device_node *dev, int index, u64 *size,
+ unsigned int *flags)
+{
+ u32 *prop;
+ unsigned int psize;
+ struct device_node *parent;
+ struct of_bus *bus;
+ int onesize, i, na, ns;
+
+ /* Get parent & match bus type */
+ parent = of_get_parent(dev);
+ if (parent == NULL)
+ return NULL;
+ bus = of_match_bus(parent);
+ bus->count_cells(dev, &na, &ns);
+ of_node_put(parent);
+ if (!OF_CHECK_COUNTS(na, ns))
+ return NULL;
+
+ /* Get "reg" or "assigned-addresses" property */
+ prop = (u32 *)get_property(dev, bus->addresses, &psize);
+ if (prop == NULL)
+ return NULL;
+ psize /= 4;
+
+ onesize = na + ns;
+ for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
+ if (i == index) {
+ if (size)
+ *size = of_read_addr(prop + na, ns);
+ if (flags)
+ *flags = bus->get_flags(prop);
+ return prop;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(of_get_address);
+
+u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
+ unsigned int *flags)
+{
+ u32 *prop;
+ unsigned int psize;
+ struct device_node *parent;
+ struct of_bus *bus;
+ int onesize, i, na, ns;
+
+ /* Get parent & match bus type */
+ parent = of_get_parent(dev);
+ if (parent == NULL)
+ return NULL;
+ bus = of_match_bus(parent);
+ if (strcmp(bus->name, "pci"))
+ return NULL;
+ bus->count_cells(dev, &na, &ns);
+ of_node_put(parent);
+ if (!OF_CHECK_COUNTS(na, ns))
+ return NULL;
+
+ /* Get "reg" or "assigned-addresses" property */
+ prop = (u32 *)get_property(dev, bus->addresses, &psize);
+ if (prop == NULL)
+ return NULL;
+ psize /= 4;
+
+ onesize = na + ns;
+ for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
+ if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
+ if (size)
+ *size = of_read_addr(prop + na, ns);
+ if (flags)
+ *flags = bus->get_flags(prop);
+ return prop;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(of_get_pci_address);
+
+static int __of_address_to_resource(struct device_node *dev, u32 *addrp,
+ u64 size, unsigned int flags,
+ struct resource *r)
+{
+ u64 taddr;
+
+ if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
+ return -EINVAL;
+ taddr = of_translate_address(dev, addrp);
+ if (taddr == OF_BAD_ADDR)
+ return -EINVAL;
+ memset(r, 0, sizeof(struct resource));
+ if (flags & IORESOURCE_IO) {
+ unsigned long port;
+ port = pci_address_to_pio(taddr);
+ if (port == (unsigned long)-1)
+ return -EINVAL;
+ r->start = port;
+ r->end = port + size - 1;
+ } else {
+ r->start = taddr;
+ r->end = taddr + size - 1;
+ }
+ r->flags = flags;
+ r->name = dev->name;
+ return 0;
+}
+
+int of_address_to_resource(struct device_node *dev, int index,
+ struct resource *r)
+{
+ u32 *addrp;
+ u64 size;
+ unsigned int flags;
+
+ addrp = of_get_address(dev, index, &size, &flags);
+ if (addrp == NULL)
+ return -EINVAL;
+ return __of_address_to_resource(dev, addrp, size, flags, r);
+}
+EXPORT_SYMBOL_GPL(of_address_to_resource);
+
+int of_pci_address_to_resource(struct device_node *dev, int bar,
+ struct resource *r)
+{
+ u32 *addrp;
+ u64 size;
+ unsigned int flags;
+
+ addrp = of_get_pci_address(dev, bar, &size, &flags);
+ if (addrp == NULL)
+ return -EINVAL;
+ return __of_address_to_resource(dev, addrp, size, flags, r);
+}
+EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c
index 60dec2401c26..45b8109951fe 100644
--- a/arch/powerpc/kernel/rtas_pci.c
+++ b/arch/powerpc/kernel/rtas_pci.c
@@ -188,39 +188,19 @@ int is_python(struct device_node *dev)
return 0;
}
-static int get_phb_reg_prop(struct device_node *dev,
- unsigned int addr_size_words,
- struct reg_property64 *reg)
+static void python_countermeasures(struct device_node *dev)
{
- unsigned int *ui_ptr = NULL, len;
-
- /* Found a PHB, now figure out where his registers are mapped. */
- ui_ptr = (unsigned int *)get_property(dev, "reg", &len);
- if (ui_ptr == NULL)
- return 1;
-
- if (addr_size_words == 1) {
- reg->address = ((struct reg_property32 *)ui_ptr)->address;
- reg->size = ((struct reg_property32 *)ui_ptr)->size;
- } else {
- *reg = *((struct reg_property64 *)ui_ptr);
- }
-
- return 0;
-}
-
-static void python_countermeasures(struct device_node *dev,
- unsigned int addr_size_words)
-{
- struct reg_property64 reg_struct;
+ struct resource registers;
void __iomem *chip_regs;
volatile u32 val;
- if (get_phb_reg_prop(dev, addr_size_words, &reg_struct))
+ if (of_address_to_resource(dev, 0, &registers)) {
+ printk(KERN_ERR "Can't get address for Python workarounds !\n");
return;
+ }
/* Python's register file is 1 MB in size. */
- chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000);
+ chip_regs = ioremap(registers.start & ~(0xfffffUL), 0x100000);
/*
* Firmware doesn't always clear this bit which is critical
@@ -301,11 +281,10 @@ static int phb_set_bus_ranges(struct device_node *dev,
}
static int __devinit setup_phb(struct device_node *dev,
- struct pci_controller *phb,
- unsigned int addr_size_words)
+ struct pci_controller *phb)
{
if (is_python(dev))
- python_countermeasures(dev, addr_size_words);
+ python_countermeasures(dev);
if (phb_set_bus_ranges(dev, phb))
return 1;
@@ -320,8 +299,8 @@ unsigned long __init find_and_init_phbs(void)
{
struct device_node *node;
struct pci_controller *phb;
- unsigned int root_size_cells = 0;
unsigned int index;
+ unsigned int root_size_cells = 0;
unsigned int *opprop = NULL;
struct device_node *root = of_find_node_by_path("/");
@@ -343,10 +322,11 @@ unsigned long __init find_and_init_phbs(void)
phb = pcibios_alloc_controller(node);
if (!phb)
continue;
- setup_phb(node, phb, root_size_cells);
+ setup_phb(node, phb);
pci_process_bridge_OF_ranges(phb, node, 0);
pci_setup_phb_io(phb, index == 0);
#ifdef CONFIG_PPC_PSERIES
+ /* XXX This code need serious fixing ... --BenH */
if (ppc64_interrupt_controller == IC_OPEN_PIC && pSeries_mpic) {
int addr = root_size_cells * (index + 2) - 1;
mpic_assign_isu(pSeries_mpic, index, opprop[addr]);
@@ -381,22 +361,17 @@ unsigned long __init find_and_init_phbs(void)
struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
{
- struct device_node *root = of_find_node_by_path("/");
- unsigned int root_size_cells = 0;
struct pci_controller *phb;
int primary;
- root_size_cells = prom_n_size_cells(root);
-
primary = list_empty(&hose_list);
phb = pcibios_alloc_controller(dn);
if (!phb)
return NULL;
- setup_phb(dn, phb, root_size_cells);
+ setup_phb(dn, phb);
pci_process_bridge_OF_ranges(phb, dn, primary);
pci_setup_phb_io_dynamic(phb, primary);
- of_node_put(root);
pci_devs_phb_init_dynamic(phb);
scan_phb(phb);
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index bd3eb4292b53..d5c52fae023a 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -93,8 +93,8 @@ EXPORT_SYMBOL(ppc_do_canonicalize_irqs);
/* also used by kexec */
void machine_shutdown(void)
{
- if (ppc_md.nvram_sync)
- ppc_md.nvram_sync();
+ if (ppc_md.machine_shutdown)
+ ppc_md.machine_shutdown();
}
void machine_restart(char *cmd)
@@ -294,129 +294,6 @@ struct seq_operations cpuinfo_op = {
.show = show_cpuinfo,
};
-#ifdef CONFIG_PPC_MULTIPLATFORM
-static int __init set_preferred_console(void)
-{
- struct device_node *prom_stdout = NULL;
- char *name;
- u32 *spd;
- int offset = 0;
-
- DBG(" -> set_preferred_console()\n");
-
- /* The user has requested a console so this is already set up. */
- if (strstr(saved_command_line, "console=")) {
- DBG(" console was specified !\n");
- return -EBUSY;
- }
-
- if (!of_chosen) {
- DBG(" of_chosen is NULL !\n");
- return -ENODEV;
- }
- /* We are getting a weird phandle from OF ... */
- /* ... So use the full path instead */
- name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
- if (name == NULL) {
- DBG(" no linux,stdout-path !\n");
- return -ENODEV;
- }
- prom_stdout = of_find_node_by_path(name);
- if (!prom_stdout) {
- DBG(" can't find stdout package %s !\n", name);
- return -ENODEV;
- }
- DBG("stdout is %s\n", prom_stdout->full_name);
-
- name = (char *)get_property(prom_stdout, "name", NULL);
- if (!name) {
- DBG(" stdout package has no name !\n");
- goto not_found;
- }
- spd = (u32 *)get_property(prom_stdout, "current-speed", NULL);
-
- if (0)
- ;
-#ifdef CONFIG_SERIAL_8250_CONSOLE
- else if (strcmp(name, "serial") == 0) {
- int i;
- u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i);
- if (i > 8) {
- switch (reg[1]) {
- case 0x3f8:
- offset = 0;
- break;
- case 0x2f8:
- offset = 1;
- break;
- case 0x898:
- offset = 2;
- break;
- case 0x890:
- offset = 3;
- break;
- default:
- /* We dont recognise the serial port */
- goto not_found;
- }
- }
- }
-#endif /* CONFIG_SERIAL_8250_CONSOLE */
-#ifdef CONFIG_PPC_PSERIES
- else if (strcmp(name, "vty") == 0) {
- u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL);
- char *compat = (char *)get_property(prom_stdout, "compatible", NULL);
-
- if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) {
- /* Host Virtual Serial Interface */
- switch (reg[0]) {
- case 0x30000000:
- offset = 0;
- break;
- case 0x30000001:
- offset = 1;
- break;
- default:
- goto not_found;
- }
- of_node_put(prom_stdout);
- DBG("Found hvsi console at offset %d\n", offset);
- return add_preferred_console("hvsi", offset, NULL);
- } else {
- /* pSeries LPAR virtual console */
- of_node_put(prom_stdout);
- DBG("Found hvc console\n");
- return add_preferred_console("hvc", 0, NULL);
- }
- }
-#endif /* CONFIG_PPC_PSERIES */
-#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
- else if (strcmp(name, "ch-a") == 0)
- offset = 0;
- else if (strcmp(name, "ch-b") == 0)
- offset = 1;
-#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
- else
- goto not_found;
- of_node_put(prom_stdout);
-
- DBG("Found serial console at ttyS%d\n", offset);
-
- if (spd) {
- static char __initdata opt[16];
- sprintf(opt, "%d", *spd);
- return add_preferred_console("ttyS", offset, opt);
- } else
- return add_preferred_console("ttyS", offset, NULL);
-
- not_found:
- DBG("No preferred console found !\n");
- of_node_put(prom_stdout);
- return -ENODEV;
-}
-console_initcall(set_preferred_console);
-#endif /* CONFIG_PPC_MULTIPLATFORM */
-
void __init check_for_initrd(void)
{
#ifdef CONFIG_BLK_DEV_INITRD
@@ -442,7 +319,7 @@ void __init check_for_initrd(void)
/* If we were passed an initrd, set the ROOT_DEV properly if the values
* look sensible. If not, clear initrd reference.
*/
- if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE &&
+ if (is_kernel_addr(initrd_start) && is_kernel_addr(initrd_end) &&
initrd_end > initrd_start)
ROOT_DEV = Root_RAM0;
else
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index e5694335bf10..e5d285adb496 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -39,6 +39,8 @@
#include <asm/nvram.h>
#include <asm/xmon.h>
#include <asm/time.h>
+#include <asm/serial.h>
+#include <asm/udbg.h>
#include "setup.h"
@@ -172,12 +174,23 @@ void __init platform_init(void)
*/
void __init machine_init(unsigned long dt_ptr, unsigned long phys)
{
+ /* If btext is enabled, we might have a BAT setup for early display,
+ * thus we do enable some very basic udbg output
+ */
+#ifdef CONFIG_BOOTX_TEXT
+ udbg_putc = btext_drawchar;
+#endif
+
+ /* Do some early initialization based on the flat device tree */
early_init_devtree(__va(dt_ptr));
+ /* Check default command line */
#ifdef CONFIG_CMDLINE
- strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line));
+ if (cmd_line[0] == 0)
+ strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line));
#endif /* CONFIG_CMDLINE */
+ /* Base init based on machine type */
platform_init();
#ifdef CONFIG_6xx
@@ -282,25 +295,22 @@ void __init setup_arch(char **cmdline_p)
unflatten_device_tree();
check_for_initrd();
- finish_device_tree();
- smp_setup_cpu_maps();
+ if (ppc_md.init_early)
+ ppc_md.init_early();
-#ifdef CONFIG_BOOTX_TEXT
- init_boot_display();
+#ifdef CONFIG_SERIAL_8250
+ find_legacy_serial_ports();
#endif
+ finish_device_tree();
-#ifdef CONFIG_PPC_PMAC
- /* This could be called "early setup arch", it must be done
- * now because xmon need it
- */
- if (_machine == _MACH_Pmac)
- pmac_feature_init(); /* New cool way */
-#endif
+ smp_setup_cpu_maps();
#ifdef CONFIG_XMON_DEFAULT
xmon_init(1);
#endif
+ /* Register early console */
+ register_early_udbg_console();
#if defined(CONFIG_KGDB)
if (ppc_md.kgdb_map_scc)
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index e3fb78397dc6..98e9f0595dd8 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -34,6 +34,7 @@
#include <linux/serial.h>
#include <linux/serial_8250.h>
#include <asm/io.h>
+#include <asm/kdump.h>
#include <asm/prom.h>
#include <asm/processor.h>
#include <asm/pgtable.h>
@@ -268,6 +269,10 @@ void __init early_setup(unsigned long dt_ptr)
}
ppc_md = **mach;
+#ifdef CONFIG_CRASH_DUMP
+ kdump_setup();
+#endif
+
DBG("Found, Initializing memory management...\n");
/*
@@ -317,6 +322,7 @@ void early_setup_secondary(void)
void smp_release_cpus(void)
{
extern unsigned long __secondary_hold_spinloop;
+ unsigned long *ptr;
DBG(" -> smp_release_cpus()\n");
@@ -327,7 +333,9 @@ void smp_release_cpus(void)
* This is useless but harmless on iSeries, secondaries are already
* waiting on their paca spinloops. */
- __secondary_hold_spinloop = 1;
+ ptr = (unsigned long *)((unsigned long)&__secondary_hold_spinloop
+ - PHYSICAL_START);
+ *ptr = 1;
mb();
DBG(" <- smp_release_cpus()\n");
@@ -459,16 +467,21 @@ void __init setup_system(void)
*/
ppc_md.init_early();
+ /*
+ * We can discover serial ports now since the above did setup the
+ * hash table management for us, thus ioremap works. We do that early
+ * so that further code can be debugged
+ */
+#ifdef CONFIG_SERIAL_8250
+ find_legacy_serial_ports();
+#endif
+
/*
* "Finish" the device-tree, that is do the actual parsing of
* some of the properties like the interrupt map
*/
finish_device_tree();
-#ifdef CONFIG_BOOTX_TEXT
- init_boot_display();
-#endif
-
/*
* Initialize xmon
*/
@@ -507,6 +520,9 @@ void __init setup_system(void)
ppc64_caches.iline_size);
printk("htab_address = 0x%p\n", htab_address);
printk("htab_hash_mask = 0x%lx\n", htab_hash_mask);
+#if PHYSICAL_START > 0
+ printk("physical_start = 0x%x\n", PHYSICAL_START);
+#endif
printk("-----------------------------------------------------\n");
mm_init_ppc64();
@@ -657,187 +673,6 @@ void ppc64_terminate_msg(unsigned int src, const char *msg)
printk("[terminate]%04x %s\n", src, msg);
}
-#ifndef CONFIG_PPC_ISERIES
-/*
- * This function can be used by platforms to "find" legacy serial ports.
- * It works for "serial" nodes under an "isa" node, and will try to
- * respect the "ibm,aix-loc" property if any. It works with up to 8
- * ports.
- */
-
-#define MAX_LEGACY_SERIAL_PORTS 8
-static struct plat_serial8250_port serial_ports[MAX_LEGACY_SERIAL_PORTS+1];
-static unsigned int old_serial_count;
-
-void __init generic_find_legacy_serial_ports(u64 *physport,
- unsigned int *default_speed)
-{
- struct device_node *np;
- u32 *sizeprop;
-
- struct isa_reg_property {
- u32 space;
- u32 address;
- u32 size;
- };
- struct pci_reg_property {
- struct pci_address addr;
- u32 size_hi;
- u32 size_lo;
- };
-
- DBG(" -> generic_find_legacy_serial_port()\n");
-
- *physport = 0;
- if (default_speed)
- *default_speed = 0;
-
- np = of_find_node_by_path("/");
- if (!np)
- return;
-
- /* First fill our array */
- for (np = NULL; (np = of_find_node_by_type(np, "serial"));) {
- struct device_node *isa, *pci;
- struct isa_reg_property *reg;
- unsigned long phys_size, addr_size, io_base;
- u32 *rangesp;
- u32 *interrupts, *clk, *spd;
- char *typep;
- int index, rlen, rentsize;
-
- /* Ok, first check if it's under an "isa" parent */
- isa = of_get_parent(np);
- if (!isa || strcmp(isa->name, "isa")) {
- DBG("%s: no isa parent found\n", np->full_name);
- continue;
- }
-
- /* Now look for an "ibm,aix-loc" property that gives us ordering
- * if any...
- */
- typep = (char *)get_property(np, "ibm,aix-loc", NULL);
-
- /* Get the ISA port number */
- reg = (struct isa_reg_property *)get_property(np, "reg", NULL);
- if (reg == NULL)
- goto next_port;
- /* We assume the interrupt number isn't translated ... */
- interrupts = (u32 *)get_property(np, "interrupts", NULL);
- /* get clock freq. if present */
- clk = (u32 *)get_property(np, "clock-frequency", NULL);
- /* get default speed if present */
- spd = (u32 *)get_property(np, "current-speed", NULL);
- /* Default to locate at end of array */
- index = old_serial_count; /* end of the array by default */
-
- /* If we have a location index, then use it */
- if (typep && *typep == 'S') {
- index = simple_strtol(typep+1, NULL, 0) - 1;
- /* if index is out of range, use end of array instead */
- if (index >= MAX_LEGACY_SERIAL_PORTS)
- index = old_serial_count;
- /* if our index is still out of range, that mean that
- * array is full, we could scan for a free slot but that
- * make little sense to bother, just skip the port
- */
- if (index >= MAX_LEGACY_SERIAL_PORTS)
- goto next_port;
- if (index >= old_serial_count)
- old_serial_count = index + 1;
- /* Check if there is a port who already claimed our slot */
- if (serial_ports[index].iobase != 0) {
- /* if we still have some room, move it, else override */
- if (old_serial_count < MAX_LEGACY_SERIAL_PORTS) {
- DBG("Moved legacy port %d -> %d\n", index,
- old_serial_count);
- serial_ports[old_serial_count++] =
- serial_ports[index];
- } else {
- DBG("Replacing legacy port %d\n", index);
- }
- }
- }
- if (index >= MAX_LEGACY_SERIAL_PORTS)
- goto next_port;
- if (index >= old_serial_count)
- old_serial_count = index + 1;
-
- /* Now fill the entry */
- memset(&serial_ports[index], 0, sizeof(struct plat_serial8250_port));
- serial_ports[index].uartclk = clk ? *clk : BASE_BAUD * 16;
- serial_ports[index].iobase = reg->address;
- serial_ports[index].irq = interrupts ? interrupts[0] : 0;
- serial_ports[index].flags = ASYNC_BOOT_AUTOCONF;
-
- DBG("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n",
- index,
- serial_ports[index].iobase,
- serial_ports[index].irq,
- serial_ports[index].uartclk);
-
- /* Get phys address of IO reg for port 1 */
- if (index != 0)
- goto next_port;
-
- pci = of_get_parent(isa);
- if (!pci) {
- DBG("%s: no pci parent found\n", np->full_name);
- goto next_port;
- }
-
- rangesp = (u32 *)get_property(pci, "ranges", &rlen);
- if (rangesp == NULL) {
- of_node_put(pci);
- goto next_port;
- }
- rlen /= 4;
-
- /* we need the #size-cells of the PCI bridge node itself */
- phys_size = 1;
- sizeprop = (u32 *)get_property(pci, "#size-cells", NULL);
- if (sizeprop != NULL)
- phys_size = *sizeprop;
- /* we need the parent #addr-cells */
- addr_size = prom_n_addr_cells(pci);
- rentsize = 3 + addr_size + phys_size;
- io_base = 0;
- for (;rlen >= rentsize; rlen -= rentsize,rangesp += rentsize) {
- if (((rangesp[0] >> 24) & 0x3) != 1)
- continue; /* not IO space */
- io_base = rangesp[3];
- if (addr_size == 2)
- io_base = (io_base << 32) | rangesp[4];
- }
- if (io_base != 0) {
- *physport = io_base + reg->address;
- if (default_speed && spd)
- *default_speed = *spd;
- }
- of_node_put(pci);
- next_port:
- of_node_put(isa);
- }
-
- DBG(" <- generic_find_legacy_serial_port()\n");
-}
-
-static struct platform_device serial_device = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM,
- .dev = {
- .platform_data = serial_ports,
- },
-};
-
-static int __init serial_dev_init(void)
-{
- return platform_device_register(&serial_device);
-}
-arch_initcall(serial_dev_init);
-
-#endif /* CONFIG_PPC_ISERIES */
-
int check_legacy_ioport(unsigned long base_port)
{
if (ppc_md.check_legacy_ioport == NULL)
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 5a2eba60dd39..d3f0b6d452fb 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -76,7 +76,6 @@
* registers from *regs. This is what we need
* to do when a signal has been delivered.
*/
-#define sigreturn_exit(regs) return 0
#define GP_REGS_SIZE min(sizeof(elf_gregset_t32), sizeof(struct pt_regs32))
#undef __SIGNAL_FRAMESIZE
@@ -156,9 +155,17 @@ static inline int save_general_regs(struct pt_regs *regs,
elf_greg_t64 *gregs = (elf_greg_t64 *)regs;
int i;
- for (i = 0; i <= PT_RESULT; i ++)
+ if (!FULL_REGS(regs)) {
+ set_thread_flag(TIF_SAVE_NVGPRS);
+ current_thread_info()->nvgprs_frame = frame->mc_gregs;
+ }
+
+ for (i = 0; i <= PT_RESULT; i ++) {
+ if (i == 14 && !FULL_REGS(regs))
+ i = 32;
if (__put_user((unsigned int)gregs[i], &frame->mc_gregs[i]))
return -EFAULT;
+ }
return 0;
}
@@ -179,8 +186,6 @@ static inline int restore_general_regs(struct pt_regs *regs,
#else /* CONFIG_PPC64 */
-extern void sigreturn_exit(struct pt_regs *);
-
#define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs))
static inline int put_sigset_t(sigset_t __user *uset, sigset_t *set)
@@ -214,6 +219,15 @@ static inline int get_old_sigaction(struct k_sigaction *new_ka,
static inline int save_general_regs(struct pt_regs *regs,
struct mcontext __user *frame)
{
+ if (!FULL_REGS(regs)) {
+ /* Zero out the unsaved GPRs to avoid information
+ leak, and set TIF_SAVE_NVGPRS to ensure that the
+ registers do actually get saved later. */
+ memset(&regs->gpr[14], 0, 18 * sizeof(unsigned long));
+ current_thread_info()->nvgprs_frame = &frame->mc_gregs;
+ set_thread_flag(TIF_SAVE_NVGPRS);
+ }
+
return __copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE);
}
@@ -256,8 +270,10 @@ long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(&saveset, regs))
- sigreturn_exit(regs);
+ if (do_signal(&saveset, regs)) {
+ set_thread_flag(TIF_RESTOREALL);
+ return 0;
+ }
}
}
@@ -292,8 +308,10 @@ long sys_rt_sigsuspend(
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(&saveset, regs))
- sigreturn_exit(regs);
+ if (do_signal(&saveset, regs)) {
+ set_thread_flag(TIF_RESTOREALL);
+ return 0;
+ }
}
}
@@ -391,9 +409,6 @@ struct rt_sigframe {
static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
int sigret)
{
-#ifdef CONFIG_PPC32
- CHECK_FULL_REGS(regs);
-#endif
/* Make sure floating point registers are stored in regs */
flush_fp_to_thread(current);
@@ -828,12 +843,6 @@ static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka,
regs->gpr[6] = (unsigned long) rt_sf;
regs->nip = (unsigned long) ka->sa.sa_handler;
regs->trap = 0;
-#ifdef CONFIG_PPC64
- regs->result = 0;
-
- if (test_thread_flag(TIF_SINGLESTEP))
- ptrace_notify(SIGTRAP);
-#endif
return 1;
badframe:
@@ -911,8 +920,8 @@ long sys_swapcontext(struct ucontext __user *old_ctx,
*/
if (do_setcontext(new_ctx, regs, 0))
do_exit(SIGSEGV);
- sigreturn_exit(regs);
- /* doesn't actually return back to here */
+
+ set_thread_flag(TIF_RESTOREALL);
return 0;
}
@@ -945,12 +954,11 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
* nobody does any...
*/
compat_sys_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs);
- return (int)regs->result;
#else
do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]);
- sigreturn_exit(regs); /* doesn't return here */
- return 0;
#endif
+ set_thread_flag(TIF_RESTOREALL);
+ return 0;
bad:
force_sig(SIGSEGV, current);
@@ -1041,9 +1049,7 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
*/
do_sigaltstack(&ctx->uc_stack, NULL, regs->gpr[1]);
- sigreturn_exit(regs);
- /* doesn't actually return back to here */
-
+ set_thread_flag(TIF_RESTOREALL);
out:
return 0;
}
@@ -1107,12 +1113,6 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
regs->gpr[4] = (unsigned long) sc;
regs->nip = (unsigned long) ka->sa.sa_handler;
regs->trap = 0;
-#ifdef CONFIG_PPC64
- regs->result = 0;
-
- if (test_thread_flag(TIF_SINGLESTEP))
- ptrace_notify(SIGTRAP);
-#endif
return 1;
@@ -1160,12 +1160,8 @@ long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
|| restore_user_regs(regs, sr, 1))
goto badframe;
-#ifdef CONFIG_PPC64
- return (int)regs->result;
-#else
- sigreturn_exit(regs); /* doesn't return */
+ set_thread_flag(TIF_RESTOREALL);
return 0;
-#endif
badframe:
force_sig(SIGSEGV, current);
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 1decf2785530..5462bef898f6 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -96,8 +96,10 @@ long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, int p3, int
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(&saveset, regs))
+ if (do_signal(&saveset, regs)) {
+ set_thread_flag(TIF_RESTOREALL);
return 0;
+ }
}
}
@@ -152,6 +154,14 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
err |= __put_user(0, &sc->v_regs);
#endif /* CONFIG_ALTIVEC */
err |= __put_user(&sc->gp_regs, &sc->regs);
+ if (!FULL_REGS(regs)) {
+ /* Zero out the unsaved GPRs to avoid information
+ leak, and set TIF_SAVE_NVGPRS to ensure that the
+ registers do actually get saved later. */
+ memset(&regs->gpr[14], 0, 18 * sizeof(unsigned long));
+ set_thread_flag(TIF_SAVE_NVGPRS);
+ current_thread_info()->nvgprs_frame = &sc->gp_regs;
+ }
err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE);
err |= __copy_to_user(&sc->fp_regs, &current->thread.fpr, FP_REGS_SIZE);
err |= __put_user(signr, &sc->signal);
@@ -340,6 +350,7 @@ int sys_swapcontext(struct ucontext __user *old_ctx,
do_exit(SIGSEGV);
/* This returns like rt_sigreturn */
+ set_thread_flag(TIF_RESTOREALL);
return 0;
}
@@ -372,7 +383,8 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
*/
do_sigaltstack(&uc->uc_stack, NULL, regs->gpr[1]);
- return regs->result;
+ set_thread_flag(TIF_RESTOREALL);
+ return 0;
badframe:
#if DEBUG_SIG
@@ -454,9 +466,6 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
if (err)
goto badframe;
- if (test_thread_flag(TIF_SINGLESTEP))
- ptrace_notify(SIGTRAP);
-
return 1;
badframe:
@@ -502,6 +511,8 @@ static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
* we only get here if there is a handler, we dont restart.
*/
regs->result = -EINTR;
+ regs->gpr[3] = EINTR;
+ regs->ccr |= 0x10000000;
break;
case -ERESTARTSYS:
/* ERESTARTSYS means to restart the syscall if there is no
@@ -509,6 +520,8 @@ static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
*/
if (!(ka->sa.sa_flags & SA_RESTART)) {
regs->result = -EINTR;
+ regs->gpr[3] = EINTR;
+ regs->ccr |= 0x10000000;
break;
}
/* fallthrough */
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 30374d2f88e5..d381ec90b759 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -31,6 +31,7 @@
#include <linux/sysdev.h>
#include <linux/cpu.h>
#include <linux/notifier.h>
+#include <linux/topology.h>
#include <asm/ptrace.h>
#include <asm/atomic.h>
@@ -75,6 +76,8 @@ void smp_call_function_interrupt(void);
int smt_enabled_at_boot = 1;
+static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL;
+
#ifdef CONFIG_MPIC
int __init smp_mpic_probe(void)
{
@@ -123,11 +126,16 @@ void smp_message_recv(int msg, struct pt_regs *regs)
/* XXX Do we have to do this? */
set_need_resched();
break;
-#ifdef CONFIG_DEBUGGER
case PPC_MSG_DEBUGGER_BREAK:
+ if (crash_ipi_function_ptr) {
+ crash_ipi_function_ptr(regs);
+ break;
+ }
+#ifdef CONFIG_DEBUGGER
debugger_ipi(regs);
break;
-#endif
+#endif /* CONFIG_DEBUGGER */
+ /* FALLTHROUGH */
default:
printk("SMP %d: smp_message_recv(): unknown msg %d\n",
smp_processor_id(), msg);
@@ -147,6 +155,17 @@ void smp_send_debugger_break(int cpu)
}
#endif
+#ifdef CONFIG_KEXEC
+void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))
+{
+ crash_ipi_function_ptr = crash_ipi_callback;
+ if (crash_ipi_callback) {
+ mb();
+ smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_DEBUGGER_BREAK);
+ }
+}
+#endif
+
static void stop_this_cpu(void *dummy)
{
local_irq_disable();
@@ -452,10 +471,6 @@ int __devinit __cpu_up(unsigned int cpu)
if (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu))
return -EINVAL;
-#ifdef CONFIG_PPC64
- paca[cpu].default_decr = tb_ticks_per_jiffy;
-#endif
-
/* Make sure callin-map entry is 0 (can be leftover a CPU
* hotplug
*/
@@ -554,6 +569,8 @@ void __init smp_cpus_done(unsigned int max_cpus)
smp_ops->setup_cpu(boot_cpuid);
set_cpus_allowed(current, old_mask);
+
+ dump_numa_cpu_topology();
}
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c
index 91b93d917b64..ad895c99813b 100644
--- a/arch/powerpc/kernel/syscalls.c
+++ b/arch/powerpc/kernel/syscalls.c
@@ -43,9 +43,6 @@
#include <asm/time.h>
#include <asm/unistd.h>
-extern unsigned long wall_jiffies;
-
-
/*
* sys_ipc() is the de-multiplexer for the SysV IPC calls..
*
@@ -311,31 +308,6 @@ int sys_olduname(struct oldold_utsname __user *name)
return error? -EFAULT: 0;
}
-#ifdef CONFIG_PPC64
-time_t sys64_time(time_t __user * tloc)
-{
- time_t secs;
- time_t usecs;
-
- long tb_delta = tb_ticks_since(tb_last_stamp);
- tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy;
-
- secs = xtime.tv_sec;
- usecs = (xtime.tv_nsec/1000) + tb_delta / tb_ticks_per_usec;
- while (usecs >= USEC_PER_SEC) {
- ++secs;
- usecs -= USEC_PER_SEC;
- }
-
- if (tloc) {
- if (put_user(secs,tloc))
- secs = -EFAULT;
- }
-
- return secs;
-}
-#endif
-
long ppc_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low,
u32 len_high, u32 len_low)
{
diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S
index 65eaea91b499..65463a1076e8 100644
--- a/arch/powerpc/kernel/systbl.S
+++ b/arch/powerpc/kernel/systbl.S
@@ -54,7 +54,7 @@ SYSCALL(link)
SYSCALL(unlink)
COMPAT_SYS(execve)
SYSCALL(chdir)
-SYSX(sys64_time,compat_sys_time,sys_time)
+COMPAT_SYS(time)
SYSCALL(mknod)
SYSCALL(chmod)
SYSCALL(lchown)
@@ -113,7 +113,7 @@ SYSCALL(sgetmask)
COMPAT_SYS(ssetmask)
SYSCALL(setreuid)
SYSCALL(setregid)
-SYSX(sys_ni_syscall,ppc32_sigsuspend,ppc_sigsuspend)
+SYS32ONLY(sigsuspend)
COMPAT_SYS(sigpending)
COMPAT_SYS(sethostname)
COMPAT_SYS(setrlimit)
@@ -160,7 +160,7 @@ SYSCALL(swapoff)
COMPAT_SYS(sysinfo)
COMPAT_SYS(ipc)
SYSCALL(fsync)
-SYSX(sys_ni_syscall,ppc32_sigreturn,sys_sigreturn)
+SYS32ONLY(sigreturn)
PPC_SYS(clone)
COMPAT_SYS(setdomainname)
PPC_SYS(newuname)
@@ -213,13 +213,13 @@ COMPAT_SYS(nfsservctl)
SYSCALL(setresgid)
SYSCALL(getresgid)
COMPAT_SYS(prctl)
-SYSX(ppc64_rt_sigreturn,ppc32_rt_sigreturn,sys_rt_sigreturn)
+COMPAT_SYS(rt_sigreturn)
COMPAT_SYS(rt_sigaction)
COMPAT_SYS(rt_sigprocmask)
COMPAT_SYS(rt_sigpending)
COMPAT_SYS(rt_sigtimedwait)
COMPAT_SYS(rt_sigqueueinfo)
-SYSX(ppc64_rt_sigsuspend,ppc32_rt_sigsuspend,ppc_rt_sigsuspend)
+COMPAT_SYS(rt_sigsuspend)
COMPAT_SYS(pread64)
COMPAT_SYS(pwrite64)
SYSCALL(chown)
@@ -290,7 +290,7 @@ COMPAT_SYS(clock_settime)
COMPAT_SYS(clock_gettime)
COMPAT_SYS(clock_getres)
COMPAT_SYS(clock_nanosleep)
-SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext)
+COMPAT_SYS(swapcontext)
COMPAT_SYS(tgkill)
COMPAT_SYS(utimes)
COMPAT_SYS(statfs64)
@@ -319,3 +319,5 @@ COMPAT_SYS(ioprio_get)
SYSCALL(inotify_init)
SYSCALL(inotify_add_watch)
SYSCALL(inotify_rm_watch)
+SYSCALL(spu_run)
+SYSCALL(spu_create)
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index de8479769bb7..56f50e91bddb 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -699,10 +699,6 @@ void __init time_init(void)
div128_by_32(1024*1024, 0, tb_ticks_per_sec, &res);
tb_to_xs = res.result_low;
-#ifdef CONFIG_PPC64
- get_paca()->default_decr = tb_ticks_per_jiffy;
-#endif
-
/*
* Compute scale factor for sched_clock.
* The calibrate_decr() function has set tb_ticks_per_sec,
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 1511454c4690..7509aa6474f2 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -31,6 +31,7 @@
#include <linux/prctl.h>
#include <linux/delay.h>
#include <linux/kprobes.h>
+#include <linux/kexec.h>
#include <asm/kdebug.h>
#include <asm/pgtable.h>
@@ -95,7 +96,7 @@ static DEFINE_SPINLOCK(die_lock);
int die(const char *str, struct pt_regs *regs, long err)
{
- static int die_counter;
+ static int die_counter, crash_dump_start = 0;
int nl = 0;
if (debugger(regs))
@@ -156,7 +157,21 @@ int die(const char *str, struct pt_regs *regs, long err)
print_modules();
show_regs(regs);
bust_spinlocks(0);
+
+ if (!crash_dump_start && kexec_should_crash(current)) {
+ crash_dump_start = 1;
+ spin_unlock_irq(&die_lock);
+ crash_kexec(regs);
+ /* NOTREACHED */
+ }
spin_unlock_irq(&die_lock);
+ if (crash_dump_start)
+ /*
+ * Only for soft-reset: Other CPUs will be responded to an IPI
+ * sent by first kexec CPU.
+ */
+ for(;;)
+ ;
if (in_interrupt())
panic("Fatal exception in interrupt");
@@ -215,8 +230,10 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
void system_reset_exception(struct pt_regs *regs)
{
/* See if any machine dependent calls */
- if (ppc_md.system_reset_exception)
- ppc_md.system_reset_exception(regs);
+ if (ppc_md.system_reset_exception) {
+ if (ppc_md.system_reset_exception(regs))
+ return;
+ }
die("System Reset", regs, SIGABRT);
@@ -886,12 +903,10 @@ void altivec_unavailable_exception(struct pt_regs *regs)
die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);
}
-#if defined(CONFIG_PPC64) || defined(CONFIG_E500)
void performance_monitor_exception(struct pt_regs *regs)
{
perf_irq(regs);
}
-#endif
#ifdef CONFIG_8xx
void SoftwareEmulation(struct pt_regs *regs)
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
index 0d878e72fc44..558c1ceb2b93 100644
--- a/arch/powerpc/kernel/udbg.c
+++ b/arch/powerpc/kernel/udbg.c
@@ -16,8 +16,8 @@
#include <linux/console.h>
#include <asm/processor.h>
-void (*udbg_putc)(unsigned char c);
-unsigned char (*udbg_getc)(void);
+void (*udbg_putc)(char c);
+int (*udbg_getc)(void);
int (*udbg_getc_poll)(void);
/* udbg library, used by xmon et al */
@@ -57,8 +57,8 @@ int udbg_write(const char *s, int n)
int udbg_read(char *buf, int buflen)
{
- char c, *p = buf;
- int i;
+ char *p = buf;
+ int i, c;
if (!udbg_getc)
return 0;
@@ -66,8 +66,11 @@ int udbg_read(char *buf, int buflen)
for (i = 0; i < buflen; ++i) {
do {
c = udbg_getc();
+ if (c == -1 && i == 0)
+ return -1;
+
} while (c == 0x11 || c == 0x13);
- if (c == 0)
+ if (c == 0 || c == -1)
break;
*p++ = c;
}
@@ -78,7 +81,7 @@ int udbg_read(char *buf, int buflen)
#define UDBG_BUFSIZE 256
void udbg_printf(const char *fmt, ...)
{
- unsigned char buf[UDBG_BUFSIZE];
+ char buf[UDBG_BUFSIZE];
va_list args;
va_start(args, fmt);
@@ -87,6 +90,12 @@ void udbg_printf(const char *fmt, ...)
va_end(args);
}
+void __init udbg_progress(char *s, unsigned short hex)
+{
+ udbg_puts(s);
+ udbg_puts("\n");
+}
+
/*
* Early boot console based on udbg
*/
@@ -99,7 +108,7 @@ static void udbg_console_write(struct console *con, const char *s,
static struct console udbg_console = {
.name = "udbg",
.write = udbg_console_write,
- .flags = CON_PRINTBUFFER,
+ .flags = CON_PRINTBUFFER | CON_ENABLED,
.index = -1,
};
@@ -107,15 +116,19 @@ static int early_console_initialized;
void __init disable_early_printk(void)
{
+#if 1
if (!early_console_initialized)
return;
unregister_console(&udbg_console);
early_console_initialized = 0;
+#endif
}
/* called by setup_system */
void register_early_udbg_console(void)
{
+ if (early_console_initialized)
+ return;
early_console_initialized = 1;
register_console(&udbg_console);
}
diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c
index 9313574ab935..7541bf44d2da 100644
--- a/arch/powerpc/kernel/udbg_16550.c
+++ b/arch/powerpc/kernel/udbg_16550.c
@@ -43,9 +43,11 @@ struct NS16550 {
#define LSR_TEMT 0x40 /* Xmitter empty */
#define LSR_ERR 0x80 /* Error */
+#define LCR_DLAB 0x80
+
static volatile struct NS16550 __iomem *udbg_comport;
-static void udbg_550_putc(unsigned char c)
+static void udbg_550_putc(char c)
{
if (udbg_comport) {
while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
@@ -67,39 +69,80 @@ static int udbg_550_getc_poll(void)
return -1;
}
-static unsigned char udbg_550_getc(void)
+static int udbg_550_getc(void)
{
if (udbg_comport) {
while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
/* wait for char */;
return in_8(&udbg_comport->rbr);
}
- return 0;
+ return -1;
}
-void udbg_init_uart(void __iomem *comport, unsigned int speed)
+void udbg_init_uart(void __iomem *comport, unsigned int speed,
+ unsigned int clock)
{
- u16 dll = speed ? (115200 / speed) : 12;
+ unsigned int dll, base_bauds = clock / 16;
+
+ if (speed == 0)
+ speed = 9600;
+ dll = base_bauds / speed;
if (comport) {
udbg_comport = (struct NS16550 __iomem *)comport;
out_8(&udbg_comport->lcr, 0x00);
out_8(&udbg_comport->ier, 0xff);
out_8(&udbg_comport->ier, 0x00);
- out_8(&udbg_comport->lcr, 0x80); /* Access baud rate */
- out_8(&udbg_comport->dll, dll & 0xff); /* 1 = 115200, 2 = 57600,
- 3 = 38400, 12 = 9600 baud */
- out_8(&udbg_comport->dlm, dll >> 8); /* dll >> 8 which should be zero
- for fast rates; */
- out_8(&udbg_comport->lcr, 0x03); /* 8 data, 1 stop, no parity */
- out_8(&udbg_comport->mcr, 0x03); /* RTS/DTR */
- out_8(&udbg_comport->fcr ,0x07); /* Clear & enable FIFOs */
+ out_8(&udbg_comport->lcr, LCR_DLAB);
+ out_8(&udbg_comport->dll, dll & 0xff);
+ out_8(&udbg_comport->dlm, dll >> 8);
+ /* 8 data, 1 stop, no parity */
+ out_8(&udbg_comport->lcr, 0x03);
+ /* RTS/DTR */
+ out_8(&udbg_comport->mcr, 0x03);
+ /* Clear & enable FIFOs */
+ out_8(&udbg_comport->fcr ,0x07);
udbg_putc = udbg_550_putc;
udbg_getc = udbg_550_getc;
udbg_getc_poll = udbg_550_getc_poll;
}
}
+unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock)
+{
+ unsigned int dll, dlm, divisor, prescaler, speed;
+ u8 old_lcr;
+ volatile struct NS16550 __iomem *port = comport;
+
+ old_lcr = in_8(&port->lcr);
+
+ /* select divisor latch registers. */
+ out_8(&port->lcr, LCR_DLAB);
+
+ /* now, read the divisor */
+ dll = in_8(&port->dll);
+ dlm = in_8(&port->dlm);
+ divisor = dlm << 8 | dll;
+
+ /* check prescaling */
+ if (in_8(&port->mcr) & 0x80)
+ prescaler = 4;
+ else
+ prescaler = 1;
+
+ /* restore the LCR */
+ out_8(&port->lcr, old_lcr);
+
+ /* calculate speed */
+ speed = (clock / prescaler) / (divisor * 16);
+
+ /* sanity check */
+ if (speed < 0 || speed > (clock / 16))
+ speed = 9600;
+
+ return speed;
+}
+
#ifdef CONFIG_PPC_MAPLE
void udbg_maple_real_putc(unsigned char c)
{
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 93d4fbfdb724..a4815d316722 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -81,7 +81,8 @@ static int store_updates_sp(struct pt_regs *regs)
}
#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
-static void do_dabr(struct pt_regs *regs, unsigned long error_code)
+static void do_dabr(struct pt_regs *regs, unsigned long address,
+ unsigned long error_code)
{
siginfo_t info;
@@ -99,7 +100,7 @@ static void do_dabr(struct pt_regs *regs, unsigned long error_code)
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_HWBKPT;
- info.si_addr = (void __user *)regs->nip;
+ info.si_addr = (void __user *)address;
force_sig_info(SIGTRAP, &info, current);
}
#endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/
@@ -159,7 +160,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
if (error_code & DSISR_DABRMATCH) {
/* DABR match */
- do_dabr(regs, error_code);
+ do_dabr(regs, address, error_code);
return 0;
}
#endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index a606504678bd..5bb433cbe41b 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -456,7 +456,7 @@ void __init htab_initialize(void)
/* create bolted the linear mapping in the hash table */
for (i=0; i < lmb.memory.cnt; i++) {
- base = lmb.memory.region[i].base + KERNELBASE;
+ base = (unsigned long)__va(lmb.memory.region[i].base);
size = lmb.memory.region[i].size;
DBG("creating mapping for region: %lx : %lx\n", base, size);
@@ -498,8 +498,8 @@ void __init htab_initialize(void)
* for either 4K or 16MB pages.
*/
if (tce_alloc_start) {
- tce_alloc_start += KERNELBASE;
- tce_alloc_end += KERNELBASE;
+ tce_alloc_start = (unsigned long)__va(tce_alloc_start);
+ tce_alloc_end = (unsigned long)__va(tce_alloc_end);
if (base + size >= tce_alloc_start)
tce_alloc_start = base + size + 1;
@@ -644,6 +644,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
DBG_LOW(" -> rc=%d\n", rc);
return rc;
}
+EXPORT_SYMBOL_GPL(hash_page);
void hash_preload(struct mm_struct *mm, unsigned long ea,
unsigned long access, unsigned long trap)
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 54131b877da3..b51bb28c054b 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -549,6 +549,17 @@ fail:
return addr;
}
+static int htlb_check_hinted_area(unsigned long addr, unsigned long len)
+{
+ struct vm_area_struct *vma;
+
+ vma = find_vma(current->mm, addr);
+ if (!vma || ((addr + len) <= vma->vm_start))
+ return 0;
+
+ return -ENOMEM;
+}
+
static unsigned long htlb_get_low_area(unsigned long len, u16 segmask)
{
unsigned long addr = 0;
@@ -618,15 +629,28 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
if (!cpu_has_feature(CPU_FTR_16M_PAGE))
return -EINVAL;
+ /* Paranoia, caller should have dealt with this */
+ BUG_ON((addr + len) < addr);
+
if (test_thread_flag(TIF_32BIT)) {
+ /* Paranoia, caller should have dealt with this */
+ BUG_ON((addr + len) > 0x100000000UL);
+
curareas = current->mm->context.low_htlb_areas;
- /* First see if we can do the mapping in the existing
- * low areas */
+ /* First see if we can use the hint address */
+ if (addr && (htlb_check_hinted_area(addr, len) == 0)) {
+ areamask = LOW_ESID_MASK(addr, len);
+ if (open_low_hpage_areas(current->mm, areamask) == 0)
+ return addr;
+ }
+
+ /* Next see if we can map in the existing low areas */
addr = htlb_get_low_area(len, curareas);
if (addr != -ENOMEM)
return addr;
+ /* Finally go looking for areas to open */
lastshift = 0;
for (areamask = LOW_ESID_MASK(0x100000000UL-len, len);
! lastshift; areamask >>=1) {
@@ -641,12 +665,22 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
} else {
curareas = current->mm->context.high_htlb_areas;
- /* First see if we can do the mapping in the existing
- * high areas */
+ /* First see if we can use the hint address */
+ /* We discourage 64-bit processes from doing hugepage
+ * mappings below 4GB (must use MAP_FIXED) */
+ if ((addr >= 0x100000000UL)
+ && (htlb_check_hinted_area(addr, len) == 0)) {
+ areamask = HTLB_AREA_MASK(addr, len);
+ if (open_high_hpage_areas(current->mm, areamask) == 0)
+ return addr;
+ }
+
+ /* Next see if we can map in the existing high areas */
addr = htlb_get_high_area(len, curareas);
if (addr != -ENOMEM)
return addr;
+ /* Finally go looking for areas to open */
lastshift = 0;
for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len);
! lastshift; areamask >>=1) {
diff --git a/arch/powerpc/mm/imalloc.c b/arch/powerpc/mm/imalloc.c
index f9587bcc6a48..8b0c132bc163 100644
--- a/arch/powerpc/mm/imalloc.c
+++ b/arch/powerpc/mm/imalloc.c
@@ -107,6 +107,7 @@ static int im_region_status(unsigned long v_addr, unsigned long size,
if (v_addr < (unsigned long) tmp->addr + tmp->size)
break;
+ *vm = NULL;
if (tmp) {
if (im_region_overlaps(v_addr, size, tmp))
return IM_REGION_OVERLAP;
@@ -127,7 +128,6 @@ static int im_region_status(unsigned long v_addr, unsigned long size,
}
}
- *vm = NULL;
return IM_REGION_UNUSED;
}
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index 7d4b8b5f0606..7d0d75c11848 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -188,6 +188,11 @@ void __init MMU_init(void)
if (ppc_md.progress)
ppc_md.progress("MMU:exit", 0x211);
+
+ /* From now on, btext is no longer BAT mapped if it was at all */
+#ifdef CONFIG_BOOTX_TEXT
+ btext_unmap();
+#endif
}
/* This is only called until mem_init is done. */
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index ed6ed2e30dac..15aac0d78dfa 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -114,19 +114,18 @@ void online_page(struct page *page)
num_physpages++;
}
-/*
- * This works only for the non-NUMA case. Later, we'll need a lookup
- * to convert from real physical addresses to nid, that doesn't use
- * pfn_to_nid().
- */
int __devinit add_memory(u64 start, u64 size)
{
- struct pglist_data *pgdata = NODE_DATA(0);
+ struct pglist_data *pgdata;
struct zone *zone;
+ int nid;
unsigned long start_pfn = start >> PAGE_SHIFT;
unsigned long nr_pages = size >> PAGE_SHIFT;
- start += KERNELBASE;
+ nid = hot_add_scn_to_nid(start);
+ pgdata = NODE_DATA(nid);
+
+ start = __va(start);
create_section_mapping(start, start + size);
/* this should work for most non-highmem platforms */
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index ba7a3055a9fc..2863a912bcd0 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -37,6 +37,7 @@ EXPORT_SYMBOL(node_data);
static bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES];
static int min_common_depth;
+static int n_mem_addr_cells, n_mem_size_cells;
/*
* We need somewhere to store start/end/node for each region until we have
@@ -254,32 +255,20 @@ static int __init find_min_common_depth(void)
return depth;
}
-static int __init get_mem_addr_cells(void)
+static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells)
{
struct device_node *memory = NULL;
- int rc;
memory = of_find_node_by_type(memory, "memory");
if (!memory)
- return 0; /* it won't matter */
+ panic("numa.c: No memory nodes found!");
- rc = prom_n_addr_cells(memory);
- return rc;
+ *n_addr_cells = prom_n_addr_cells(memory);
+ *n_size_cells = prom_n_size_cells(memory);
+ of_node_put(memory);
}
-static int __init get_mem_size_cells(void)
-{
- struct device_node *memory = NULL;
- int rc;
-
- memory = of_find_node_by_type(memory, "memory");
- if (!memory)
- return 0; /* it won't matter */
- rc = prom_n_size_cells(memory);
- return rc;
-}
-
-static unsigned long __init read_n_cells(int n, unsigned int **buf)
+static unsigned long __devinit read_n_cells(int n, unsigned int **buf)
{
unsigned long result = 0;
@@ -386,7 +375,6 @@ static int __init parse_numa_properties(void)
{
struct device_node *cpu = NULL;
struct device_node *memory = NULL;
- int addr_cells, size_cells;
int max_domain;
unsigned long i;
@@ -425,8 +413,7 @@ static int __init parse_numa_properties(void)
}
}
- addr_cells = get_mem_addr_cells();
- size_cells = get_mem_size_cells();
+ get_n_mem_cells(&n_mem_addr_cells, &n_mem_size_cells);
memory = NULL;
while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
unsigned long start;
@@ -436,15 +423,21 @@ static int __init parse_numa_properties(void)
unsigned int *memcell_buf;
unsigned int len;
- memcell_buf = (unsigned int *)get_property(memory, "reg", &len);
+ memcell_buf = (unsigned int *)get_property(memory,
+ "linux,usable-memory", &len);
+ if (!memcell_buf || len <= 0)
+ memcell_buf =
+ (unsigned int *)get_property(memory, "reg",
+ &len);
if (!memcell_buf || len <= 0)
continue;
- ranges = memory->n_addrs;
+ /* ranges in cell */
+ ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells);
new_range:
/* these are order-sensitive, and modify the buffer pointer */
- start = read_n_cells(addr_cells, &memcell_buf);
- size = read_n_cells(size_cells, &memcell_buf);
+ start = read_n_cells(n_mem_addr_cells, &memcell_buf);
+ size = read_n_cells(n_mem_size_cells, &memcell_buf);
numa_domain = of_node_numa_domain(memory);
@@ -497,7 +490,41 @@ static void __init setup_nonnuma(void)
node_set_online(0);
}
-static void __init dump_numa_topology(void)
+void __init dump_numa_cpu_topology(void)
+{
+ unsigned int node;
+ unsigned int cpu, count;
+
+ if (min_common_depth == -1 || !numa_enabled)
+ return;
+
+ for_each_online_node(node) {
+ printk(KERN_INFO "Node %d CPUs:", node);
+
+ count = 0;
+ /*
+ * If we used a CPU iterator here we would miss printing
+ * the holes in the cpumap.
+ */
+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
+ if (cpu_isset(cpu, numa_cpumask_lookup_table[node])) {
+ if (count == 0)
+ printk(" %u", cpu);
+ ++count;
+ } else {
+ if (count > 1)
+ printk("-%u", cpu - 1);
+ count = 0;
+ }
+ }
+
+ if (count > 1)
+ printk("-%u", NR_CPUS - 1);
+ printk("\n");
+ }
+}
+
+static void __init dump_numa_memory_topology(void)
{
unsigned int node;
unsigned int count;
@@ -529,7 +556,6 @@ static void __init dump_numa_topology(void)
printk("-0x%lx", i);
printk("\n");
}
- return;
}
/*
@@ -591,7 +617,7 @@ void __init do_init_bootmem(void)
if (parse_numa_properties())
setup_nonnuma();
else
- dump_numa_topology();
+ dump_numa_memory_topology();
register_cpu_notifier(&ppc64_numa_nb);
@@ -730,3 +756,60 @@ static int __init early_numa(char *p)
return 0;
}
early_param("numa", early_numa);
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+/*
+ * Find the node associated with a hot added memory section. Section
+ * corresponds to a SPARSEMEM section, not an LMB. It is assumed that
+ * sections are fully contained within a single LMB.
+ */
+int hot_add_scn_to_nid(unsigned long scn_addr)
+{
+ struct device_node *memory = NULL;
+ nodemask_t nodes;
+ int numa_domain = 0;
+
+ if (!numa_enabled || (min_common_depth < 0))
+ return numa_domain;
+
+ while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
+ unsigned long start, size;
+ int ranges;
+ unsigned int *memcell_buf;
+ unsigned int len;
+
+ memcell_buf = (unsigned int *)get_property(memory, "reg", &len);
+ if (!memcell_buf || len <= 0)
+ continue;
+
+ /* ranges in cell */
+ ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells);
+ha_new_range:
+ start = read_n_cells(n_mem_addr_cells, &memcell_buf);
+ size = read_n_cells(n_mem_size_cells, &memcell_buf);
+ numa_domain = of_node_numa_domain(memory);
+
+ /* Domains not present at boot default to 0 */
+ if (!node_online(numa_domain))
+ numa_domain = any_online_node(NODE_MASK_ALL);
+
+ if ((scn_addr >= start) && (scn_addr < (start + size))) {
+ of_node_put(memory);
+ goto got_numa_domain;
+ }
+
+ if (--ranges) /* process all ranges in cell */
+ goto ha_new_range;
+ }
+ BUG(); /* section address should be found above */
+
+ /* Temporary code to ensure that returned node is not empty */
+got_numa_domain:
+ nodes_setall(nodes);
+ while (NODE_DATA(numa_domain)->node_spanned_pages == 0) {
+ node_clear(numa_domain, nodes);
+ numa_domain = any_online_node(nodes);
+ }
+ return numa_domain;
+}
+#endif /* CONFIG_MEMORY_HOTPLUG */
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
index 60e852f2f8e5..ffc8ed4de62d 100644
--- a/arch/powerpc/mm/slb.c
+++ b/arch/powerpc/mm/slb.c
@@ -75,7 +75,7 @@ static void slb_flush_and_rebolt(void)
vflags = SLB_VSID_KERNEL | virtual_llp;
ksp_esid_data = mk_esid_data(get_paca()->kstack, 2);
- if ((ksp_esid_data & ESID_MASK) == KERNELBASE)
+ if ((ksp_esid_data & ESID_MASK) == PAGE_OFFSET)
ksp_esid_data &= ~SLB_ESID_V;
/* We need to do this all in asm, so we're sure we don't touch
@@ -87,8 +87,8 @@ static void slb_flush_and_rebolt(void)
/* Slot 2 - kernel stack */
"slbmte %2,%3\n"
"isync"
- :: "r"(mk_vsid_data(VMALLOCBASE, vflags)),
- "r"(mk_esid_data(VMALLOCBASE, 1)),
+ :: "r"(mk_vsid_data(VMALLOC_START, vflags)),
+ "r"(mk_esid_data(VMALLOC_START, 1)),
"r"(mk_vsid_data(ksp_esid_data, lflags)),
"r"(ksp_esid_data)
: "memory");
@@ -134,14 +134,14 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
else
unmapped_base = TASK_UNMAPPED_BASE_USER64;
- if (pc >= KERNELBASE)
+ if (is_kernel_addr(pc))
return;
slb_allocate(pc);
if (GET_ESID(pc) == GET_ESID(stack))
return;
- if (stack >= KERNELBASE)
+ if (is_kernel_addr(stack))
return;
slb_allocate(stack);
@@ -149,7 +149,7 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
|| (GET_ESID(stack) == GET_ESID(unmapped_base)))
return;
- if (unmapped_base >= KERNELBASE)
+ if (is_kernel_addr(unmapped_base))
return;
slb_allocate(unmapped_base);
}
@@ -213,10 +213,10 @@ void slb_initialize(void)
asm volatile("isync":::"memory");
asm volatile("slbmte %0,%0"::"r" (0) : "memory");
asm volatile("isync; slbia; isync":::"memory");
- create_slbe(KERNELBASE, lflags, 0);
+ create_slbe(PAGE_OFFSET, lflags, 0);
/* VMALLOC space has 4K pages always for now */
- create_slbe(VMALLOCBASE, vflags, 1);
+ create_slbe(VMALLOC_START, vflags, 1);
/* We don't bolt the stack for the time being - we're in boot,
* so the stack is in the bolted segment. By the time it goes
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
index 950ffc5848c7..d1acee38f163 100644
--- a/arch/powerpc/mm/slb_low.S
+++ b/arch/powerpc/mm/slb_low.S
@@ -37,9 +37,9 @@ _GLOBAL(slb_allocate_realmode)
srdi r9,r3,60 /* get region */
srdi r10,r3,28 /* get esid */
- cmpldi cr7,r9,0xc /* cmp KERNELBASE for later use */
+ cmpldi cr7,r9,0xc /* cmp PAGE_OFFSET for later use */
- /* r3 = address, r10 = esid, cr7 = <>KERNELBASE */
+ /* r3 = address, r10 = esid, cr7 = <> PAGE_OFFSET */
blt cr7,0f /* user or kernel? */
/* kernel address: proto-VSID = ESID */
@@ -166,7 +166,7 @@ _GLOBAL(slb_allocate_user)
/*
* Finish loading of an SLB entry and return
*
- * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9, cr7 = <>KERNELBASE
+ * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9, cr7 = <> PAGE_OFFSET
*/
slb_finish_load:
ASM_VSID_SCRAMBLE(r10,r9)
diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c
index 51e7951414e5..82e4951826bc 100644
--- a/arch/powerpc/mm/stab.c
+++ b/arch/powerpc/mm/stab.c
@@ -40,7 +40,7 @@ static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid)
unsigned long entry, group, old_esid, castout_entry, i;
unsigned int global_entry;
struct stab_entry *ste, *castout_ste;
- unsigned long kernel_segment = (esid << SID_SHIFT) >= KERNELBASE;
+ unsigned long kernel_segment = (esid << SID_SHIFT) >= PAGE_OFFSET;
vsid_data = vsid << STE_VSID_SHIFT;
esid_data = esid << SID_SHIFT | STE_ESID_KP | STE_ESID_V;
@@ -83,7 +83,7 @@ static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid)
}
/* Dont cast out the first kernel segment */
- if ((castout_ste->esid_data & ESID_MASK) != KERNELBASE)
+ if ((castout_ste->esid_data & ESID_MASK) != PAGE_OFFSET)
break;
castout_entry = (castout_entry + 1) & 0xf;
@@ -122,7 +122,7 @@ static int __ste_allocate(unsigned long ea, struct mm_struct *mm)
unsigned long offset;
/* Kernel or user address? */
- if (ea >= KERNELBASE) {
+ if (is_kernel_addr(ea)) {
vsid = get_kernel_vsid(ea);
} else {
if ((ea >= TASK_SIZE_USER64) || (! mm))
@@ -133,7 +133,7 @@ static int __ste_allocate(unsigned long ea, struct mm_struct *mm)
stab_entry = make_ste(get_paca()->stab_addr, GET_ESID(ea), vsid);
- if (ea < KERNELBASE) {
+ if (!is_kernel_addr(ea)) {
offset = __get_cpu_var(stab_cache_ptr);
if (offset < NR_STAB_CACHE_ENTRIES)
__get_cpu_var(stab_cache[offset++]) = stab_entry;
@@ -190,7 +190,7 @@ void switch_stab(struct task_struct *tsk, struct mm_struct *mm)
entry++, ste++) {
unsigned long ea;
ea = ste->esid_data & ESID_MASK;
- if (ea < KERNELBASE) {
+ if (!is_kernel_addr(ea)) {
ste->esid_data = 0;
}
}
@@ -251,7 +251,7 @@ void stabs_alloc(void)
panic("Unable to allocate segment table for CPU %d.\n",
cpu);
- newstab += KERNELBASE;
+ newstab = (unsigned long)__va(newstab);
memset((void *)newstab, 0, HW_PAGE_SIZE);
@@ -270,11 +270,11 @@ void stabs_alloc(void)
*/
void stab_initialize(unsigned long stab)
{
- unsigned long vsid = get_kernel_vsid(KERNELBASE);
+ unsigned long vsid = get_kernel_vsid(PAGE_OFFSET);
unsigned long stabreal;
asm volatile("isync; slbia; isync":::"memory");
- make_ste(stab, GET_ESID(KERNELBASE), vsid);
+ make_ste(stab, GET_ESID(PAGE_OFFSET), vsid);
/* Order update */
asm volatile("sync":::"memory");
diff --git a/arch/powerpc/mm/tlb_64.c b/arch/powerpc/mm/tlb_64.c
index 859d29a0cac5..bb3afb6e6317 100644
--- a/arch/powerpc/mm/tlb_64.c
+++ b/arch/powerpc/mm/tlb_64.c
@@ -168,7 +168,7 @@ void hpte_update(struct mm_struct *mm, unsigned long addr,
batch->mm = mm;
batch->psize = psize;
}
- if (addr < KERNELBASE) {
+ if (!is_kernel_addr(addr)) {
vsid = get_vsid(mm->context.id, addr);
WARN_ON(vsid == 0);
} else
diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile
index 0782d0cca89c..554cd7c75321 100644
--- a/arch/powerpc/oprofile/Makefile
+++ b/arch/powerpc/oprofile/Makefile
@@ -9,3 +9,4 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
oprofile-y := $(DRIVER_OBJS) common.o
oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o
oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
+oprofile-$(CONFIG_PPC32) += op_model_7450.o
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index af2c05d20ba5..71615eb70b2b 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -14,9 +14,6 @@
*/
#include <linux/oprofile.h>
-#ifndef __powerpc64__
-#include <linux/slab.h>
-#endif /* ! __powerpc64__ */
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/errno.h>
@@ -31,10 +28,6 @@ static struct op_powerpc_model *model;
static struct op_counter_config ctr[OP_MAX_COUNTER];
static struct op_system_config sys;
-#ifndef __powerpc64__
-static char *cpu_type;
-#endif /* ! __powerpc64__ */
-
static void op_handle_interrupt(struct pt_regs *regs)
{
model->handle_interrupt(regs, ctr);
@@ -53,14 +46,7 @@ static int op_powerpc_setup(void)
model->reg_setup(ctr, &sys, model->num_counters);
/* Configure the registers on all cpus. */
-#ifdef __powerpc64__
on_each_cpu(model->cpu_setup, NULL, 0, 1);
-#else /* __powerpc64__ */
-#if 0
- /* FIXME: Make multi-cpu work */
- on_each_cpu(model->reg_setup, NULL, 0, 1);
-#endif
-#endif /* __powerpc64__ */
return 0;
}
@@ -95,7 +81,7 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root)
{
int i;
-#ifdef __powerpc64__
+#ifdef CONFIG_PPC64
/*
* There is one mmcr0, mmcr1 and mmcra for setting the events for
* all of the counters.
@@ -103,7 +89,7 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root)
oprofilefs_create_ulong(sb, root, "mmcr0", &sys.mmcr0);
oprofilefs_create_ulong(sb, root, "mmcr1", &sys.mmcr1);
oprofilefs_create_ulong(sb, root, "mmcra", &sys.mmcra);
-#endif /* __powerpc64__ */
+#endif
for (i = 0; i < model->num_counters; ++i) {
struct dentry *dir;
@@ -115,65 +101,68 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root)
oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
-#ifdef __powerpc64__
+
/*
- * We dont support per counter user/kernel selection, but
- * we leave the entries because userspace expects them
+ * Classic PowerPC doesn't support per-counter
+ * control like this, but the options are
+ * expected, so they remain. For Freescale
+ * Book-E style performance monitors, we do
+ * support them.
*/
-#endif /* __powerpc64__ */
oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
-#ifndef __powerpc64__
- /* FIXME: Not sure if this is used */
-#endif /* ! __powerpc64__ */
oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
}
oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel);
oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user);
-#ifdef __powerpc64__
+#ifdef CONFIG_PPC64
oprofilefs_create_ulong(sb, root, "backtrace_spinlocks",
&sys.backtrace_spinlocks);
-#endif /* __powerpc64__ */
+#endif
/* Default to tracing both kernel and user */
sys.enable_kernel = 1;
sys.enable_user = 1;
-#ifdef __powerpc64__
+#ifdef CONFIG_PPC64
/* Turn on backtracing through spinlocks by default */
sys.backtrace_spinlocks = 1;
-#endif /* __powerpc64__ */
+#endif
return 0;
}
int __init oprofile_arch_init(struct oprofile_operations *ops)
{
-#ifndef __powerpc64__
-#ifdef CONFIG_FSL_BOOKE
- model = &op_model_fsl_booke;
+ if (!cur_cpu_spec->oprofile_cpu_type)
+ return -ENODEV;
+
+ switch (cur_cpu_spec->oprofile_type) {
+#ifdef CONFIG_PPC64
+ case RS64:
+ model = &op_model_rs64;
+ break;
+ case POWER4:
+ model = &op_model_power4;
+ break;
#else
- return -ENODEV;
+ case G4:
+ model = &op_model_7450;
+ break;
#endif
+#ifdef CONFIG_FSL_BOOKE
+ case BOOKE:
+ model = &op_model_fsl_booke;
+ break;
+#endif
+ default:
+ return -ENODEV;
+ }
- cpu_type = kmalloc(32, GFP_KERNEL);
- if (NULL == cpu_type)
- return -ENOMEM;
-
- sprintf(cpu_type, "ppc/%s", cur_cpu_spec->cpu_name);
-
- model->num_counters = cur_cpu_spec->num_pmcs;
-
- ops->cpu_type = cpu_type;
-#else /* __powerpc64__ */
- if (!cur_cpu_spec->oprofile_model || !cur_cpu_spec->oprofile_cpu_type)
- return -ENODEV;
- model = cur_cpu_spec->oprofile_model;
model->num_counters = cur_cpu_spec->num_pmcs;
ops->cpu_type = cur_cpu_spec->oprofile_cpu_type;
-#endif /* __powerpc64__ */
ops->create_files = op_powerpc_create_files;
ops->setup = op_powerpc_setup;
ops->shutdown = op_powerpc_shutdown;
@@ -188,8 +177,4 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
void oprofile_arch_exit(void)
{
-#ifndef __powerpc64__
- kfree(cpu_type);
- cpu_type = NULL;
-#endif /* ! __powerpc64__ */
}
diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c
new file mode 100644
index 000000000000..32abfdbb0eb1
--- /dev/null
+++ b/arch/powerpc/oprofile/op_model_7450.c
@@ -0,0 +1,206 @@
+/*
+ * oprofile/op_model_7450.c
+ *
+ * Freescale 745x/744x oprofile support, based on fsl_booke support
+ * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc
+ *
+ * Author: Andy Fleming
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/oprofile.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/cputable.h>
+#include <asm/page.h>
+#include <asm/pmc.h>
+#include <asm/oprofile_impl.h>
+
+static unsigned long reset_value[OP_MAX_COUNTER];
+
+static int oprofile_running;
+static u32 mmcr0_val, mmcr1_val, mmcr2_val;
+
+#define MMCR0_PMC1_SHIFT 6
+#define MMCR0_PMC2_SHIFT 0
+#define MMCR1_PMC3_SHIFT 27
+#define MMCR1_PMC4_SHIFT 22
+#define MMCR1_PMC5_SHIFT 17
+#define MMCR1_PMC6_SHIFT 11
+
+#define mmcr0_event1(event) \
+ ((event << MMCR0_PMC1_SHIFT) & MMCR0_PMC1SEL)
+#define mmcr0_event2(event) \
+ ((event << MMCR0_PMC2_SHIFT) & MMCR0_PMC2SEL)
+
+#define mmcr1_event3(event) \
+ ((event << MMCR1_PMC3_SHIFT) & MMCR1_PMC3SEL)
+#define mmcr1_event4(event) \
+ ((event << MMCR1_PMC4_SHIFT) & MMCR1_PMC4SEL)
+#define mmcr1_event5(event) \
+ ((event << MMCR1_PMC5_SHIFT) & MMCR1_PMC5SEL)
+#define mmcr1_event6(event) \
+ ((event << MMCR1_PMC6_SHIFT) & MMCR1_PMC6SEL)
+
+#define MMCR0_INIT (MMCR0_FC | MMCR0_FCS | MMCR0_FCP | MMCR0_FCM1 | MMCR0_FCM0)
+
+/* Unfreezes the counters on this CPU, enables the interrupt,
+ * enables the counters to trigger the interrupt, and sets the
+ * counters to only count when the mark bit is not set.
+ */
+static void pmc_start_ctrs(void)
+{
+ u32 mmcr0 = mfspr(SPRN_MMCR0);
+
+ mmcr0 &= ~(MMCR0_FC | MMCR0_FCM0);
+ mmcr0 |= (MMCR0_FCECE | MMCR0_PMC1CE | MMCR0_PMCnCE | MMCR0_PMXE);
+
+ mtspr(SPRN_MMCR0, mmcr0);
+}
+
+/* Disables the counters on this CPU, and freezes them */
+static void pmc_stop_ctrs(void)
+{
+ u32 mmcr0 = mfspr(SPRN_MMCR0);
+
+ mmcr0 |= MMCR0_FC;
+ mmcr0 &= ~(MMCR0_FCECE | MMCR0_PMC1CE | MMCR0_PMCnCE | MMCR0_PMXE);
+
+ mtspr(SPRN_MMCR0, mmcr0);
+}
+
+/* Configures the counters on this CPU based on the global
+ * settings */
+static void fsl7450_cpu_setup(void *unused)
+{
+ /* freeze all counters */
+ pmc_stop_ctrs();
+
+ mtspr(SPRN_MMCR0, mmcr0_val);
+ mtspr(SPRN_MMCR1, mmcr1_val);
+ mtspr(SPRN_MMCR2, mmcr2_val);
+}
+
+#define NUM_CTRS 6
+
+/* Configures the global settings for the countes on all CPUs. */
+static void fsl7450_reg_setup(struct op_counter_config *ctr,
+ struct op_system_config *sys,
+ int num_ctrs)
+{
+ int i;
+
+ /* Our counters count up, and "count" refers to
+ * how much before the next interrupt, and we interrupt
+ * on overflow. So we calculate the starting value
+ * which will give us "count" until overflow.
+ * Then we set the events on the enabled counters */
+ for (i = 0; i < NUM_CTRS; ++i)
+ reset_value[i] = 0x80000000UL - ctr[i].count;
+
+ /* Set events for Counters 1 & 2 */
+ mmcr0_val = MMCR0_INIT | mmcr0_event1(ctr[0].event)
+ | mmcr0_event2(ctr[1].event);
+
+ /* Setup user/kernel bits */
+ if (sys->enable_kernel)
+ mmcr0_val &= ~(MMCR0_FCS);
+
+ if (sys->enable_user)
+ mmcr0_val &= ~(MMCR0_FCP);
+
+ /* Set events for Counters 3-6 */
+ mmcr1_val = mmcr1_event3(ctr[2].event)
+ | mmcr1_event4(ctr[3].event)
+ | mmcr1_event5(ctr[4].event)
+ | mmcr1_event6(ctr[5].event);
+
+ mmcr2_val = 0;
+}
+
+/* Sets the counters on this CPU to the chosen values, and starts them */
+static void fsl7450_start(struct op_counter_config *ctr)
+{
+ int i;
+
+ mtmsr(mfmsr() | MSR_PMM);
+
+ for (i = 0; i < NUM_CTRS; ++i) {
+ if (ctr[i].enabled)
+ ctr_write(i, reset_value[i]);
+ else
+ ctr_write(i, 0);
+ }
+
+ /* Clear the freeze bit, and enable the interrupt.
+ * The counters won't actually start until the rfi clears
+ * the PMM bit */
+ pmc_start_ctrs();
+
+ oprofile_running = 1;
+}
+
+/* Stop the counters on this CPU */
+static void fsl7450_stop(void)
+{
+ /* freeze counters */
+ pmc_stop_ctrs();
+
+ oprofile_running = 0;
+
+ mb();
+}
+
+
+/* Handle the interrupt on this CPU, and log a sample for each
+ * event that triggered the interrupt */
+static void fsl7450_handle_interrupt(struct pt_regs *regs,
+ struct op_counter_config *ctr)
+{
+ unsigned long pc;
+ int is_kernel;
+ int val;
+ int i;
+
+ /* set the PMM bit (see comment below) */
+ mtmsr(mfmsr() | MSR_PMM);
+
+ pc = mfspr(SPRN_SIAR);
+ is_kernel = (pc >= KERNELBASE);
+
+ for (i = 0; i < NUM_CTRS; ++i) {
+ val = ctr_read(i);
+ if (val < 0) {
+ if (oprofile_running && ctr[i].enabled) {
+ oprofile_add_pc(pc, is_kernel, i);
+ ctr_write(i, reset_value[i]);
+ } else {
+ ctr_write(i, 0);
+ }
+ }
+ }
+
+ /* The freeze bit was set by the interrupt. */
+ /* Clear the freeze bit, and reenable the interrupt.
+ * The counters won't actually start until the rfi clears
+ * the PMM bit */
+ pmc_start_ctrs();
+}
+
+struct op_powerpc_model op_model_7450= {
+ .reg_setup = fsl7450_reg_setup,
+ .cpu_setup = fsl7450_cpu_setup,
+ .start = fsl7450_start,
+ .stop = fsl7450_stop,
+ .handle_interrupt = fsl7450_handle_interrupt,
+};
diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c
index a3401b46f3ba..659a021da0c7 100644
--- a/arch/powerpc/oprofile/op_model_power4.c
+++ b/arch/powerpc/oprofile/op_model_power4.c
@@ -252,7 +252,7 @@ static unsigned long get_pc(struct pt_regs *regs)
return (unsigned long)__va(pc);
/* Not sure where we were */
- if (pc < KERNELBASE)
+ if (!is_kernel_addr(pc))
/* function descriptor madness */
return *((unsigned long *)kernel_unknown_bucket);
@@ -264,7 +264,7 @@ static int get_kernel(unsigned long pc)
int is_kernel;
if (!mmcra_has_sihv) {
- is_kernel = (pc >= KERNELBASE);
+ is_kernel = is_kernel_addr(pc);
} else {
unsigned long mmcra = mfspr(SPRN_MMCRA);
is_kernel = ((mmcra & MMCRA_SIPR) == 0);
diff --git a/arch/powerpc/oprofile/op_model_rs64.c b/arch/powerpc/oprofile/op_model_rs64.c
index e010b85996e8..5c909ee609fe 100644
--- a/arch/powerpc/oprofile/op_model_rs64.c
+++ b/arch/powerpc/oprofile/op_model_rs64.c
@@ -178,7 +178,6 @@ static void rs64_handle_interrupt(struct pt_regs *regs,
int val;
int i;
unsigned long pc = mfspr(SPRN_SIAR);
- int is_kernel = (pc >= KERNELBASE);
/* set the PMM bit (see comment below) */
mtmsrd(mfmsr() | MSR_PMM);
@@ -187,7 +186,7 @@ static void rs64_handle_interrupt(struct pt_regs *regs,
val = ctr_read(i);
if (val < 0) {
if (ctr[i].enabled) {
- oprofile_add_pc(pc, is_kernel, i);
+ oprofile_add_pc(pc, is_kernel_addr(pc), i);
ctr_write(i, reset_value[i]);
} else {
ctr_write(i, 0);
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
new file mode 100644
index 000000000000..3157071e241c
--- /dev/null
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -0,0 +1,13 @@
+menu "Cell Broadband Engine options"
+ depends on PPC_CELL
+
+config SPU_FS
+ tristate "SPU file system"
+ default m
+ depends on PPC_CELL
+ help
+ The SPU file system is used to access Synergistic Processing
+ Units on machines implementing the Broadband Processor
+ Architecture.
+
+endmenu
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index 55e094b96bc0..16031b565be4 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -1,2 +1,10 @@
obj-y += interrupt.o iommu.o setup.o spider-pic.o
+obj-y += pervasive.o
+
obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_SPU_FS) += spufs/ spu-base.o
+
+spu-base-y += spu_base.o spu_priv1.o
+
+builtin-spufs-$(CONFIG_SPU_FS) += spu_syscalls.o
+obj-y += $(builtin-spufs-m)
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 7fbe78a9327d..63aa52acf441 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -23,6 +23,7 @@
#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/module.h>
#include <linux/percpu.h>
#include <linux/types.h>
@@ -55,6 +56,7 @@ struct iic_regs {
struct iic {
struct iic_regs __iomem *regs;
+ u8 target_id;
};
static DEFINE_PER_CPU(struct iic, iic);
@@ -172,12 +174,11 @@ int iic_get_irq(struct pt_regs *regs)
return irq;
}
-static struct iic_regs __iomem *find_iic(int cpu)
+static int setup_iic(int cpu, struct iic *iic)
{
struct device_node *np;
int nodeid = cpu / 2;
unsigned long regs;
- struct iic_regs __iomem *iic_regs;
for (np = of_find_node_by_type(NULL, "cpu");
np;
@@ -188,20 +189,23 @@ static struct iic_regs __iomem *find_iic(int cpu)
if (!np) {
printk(KERN_WARNING "IIC: CPU %d not found\n", cpu);
- iic_regs = NULL;
- } else {
- regs = *(long *)get_property(np, "iic", NULL);
-
- /* hack until we have decided on the devtree info */
- regs += 0x400;
- if (cpu & 1)
- regs += 0x20;
-
- printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs);
- iic_regs = __ioremap(regs, sizeof(struct iic_regs),
- _PAGE_NO_CACHE);
+ iic->regs = NULL;
+ iic->target_id = 0xff;
+ return -ENODEV;
}
- return iic_regs;
+
+ regs = *(long *)get_property(np, "iic", NULL);
+
+ /* hack until we have decided on the devtree info */
+ regs += 0x400;
+ if (cpu & 1)
+ regs += 0x20;
+
+ printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs);
+ iic->regs = __ioremap(regs, sizeof(struct iic_regs),
+ _PAGE_NO_CACHE);
+ iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
+ return 0;
}
#ifdef CONFIG_SMP
@@ -227,6 +231,12 @@ void iic_cause_IPI(int cpu, int mesg)
out_be64(&per_cpu(iic, cpu).regs->generate, (IIC_NUM_IPIS - 1 - mesg) << 4);
}
+u8 iic_get_target_id(int cpu)
+{
+ return per_cpu(iic, cpu).target_id;
+}
+EXPORT_SYMBOL_GPL(iic_get_target_id);
+
static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
{
smp_message_recv(iic_irq_to_ipi(irq), regs);
@@ -276,7 +286,7 @@ void iic_init_IRQ(void)
irq_offset = 0;
for_each_cpu(cpu) {
iic = &per_cpu(iic, cpu);
- iic->regs = find_iic(cpu);
+ setup_iic(cpu, iic);
if (iic->regs)
out_be64(&iic->regs->prio, 0xff);
}
diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h
index 37d58e6fd0c6..a14bd38791c0 100644
--- a/arch/powerpc/platforms/cell/interrupt.h
+++ b/arch/powerpc/platforms/cell/interrupt.h
@@ -54,6 +54,7 @@ extern void iic_setup_cpu(void);
extern void iic_local_enable(void);
extern void iic_local_disable(void);
+extern u8 iic_get_target_id(int cpu);
extern void spider_init_IRQ(void);
extern int spider_get_irq(unsigned long int_pending);
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 74f999b4ac9e..46e7cb9c3e64 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -29,6 +29,8 @@
#include <linux/bootmem.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
#include <asm/sections.h>
#include <asm/iommu.h>
@@ -40,6 +42,7 @@
#include <asm/abs_addr.h>
#include <asm/system.h>
#include <asm/ppc-pci.h>
+#include <asm/udbg.h>
#include "iommu.h"
@@ -220,8 +223,6 @@ set_iopt_cache(void __iomem *base, unsigned long index,
{
unsigned long __iomem *tags = base + IOC_PT_CACHE_DIR;
unsigned long __iomem *p = base + IOC_PT_CACHE_REG;
- pr_debug("iopt %02lx was v%016lx/t%016lx, store v%016lx/t%016lx\n",
- index, get_iopt_cache(base, index, &oldtag), oldtag, val, tag);
out_be64(p, val);
out_be64(&tags[index], tag);
@@ -248,67 +249,176 @@ set_iocmd_config(void __iomem *base)
out_be64(p, conf | IOCMD_CONF_TE);
}
-/* FIXME: get these from the device tree */
-#define ioc_base 0x20000511000ull
-#define ioc_mmio_base 0x20000510000ull
-#define ioid 0x48a
-#define iopt_phys_offset (- 0x20000000) /* We have a 512MB offset from the SB */
-#define io_page_size 0x1000000
-
-static unsigned long map_iopt_entry(unsigned long address)
+static void enable_mapping(void __iomem *base, void __iomem *mmio_base)
{
- switch (address >> 20) {
- case 0x600:
- address = 0x24020000000ull; /* spider i/o */
- break;
- default:
- address += iopt_phys_offset;
- break;
- }
-
- return get_iopt_entry(address, ioid, IOPT_PROT_RW);
+ set_iocmd_config(base);
+ set_iost_origin(mmio_base);
}
-static void iommu_bus_setup_null(struct pci_bus *b) { }
static void iommu_dev_setup_null(struct pci_dev *d) { }
+static void iommu_bus_setup_null(struct pci_bus *b) { }
+
+struct cell_iommu {
+ unsigned long base;
+ unsigned long mmio_base;
+ void __iomem *mapped_base;
+ void __iomem *mapped_mmio_base;
+};
+
+static struct cell_iommu cell_iommus[NR_CPUS];
/* initialize the iommu to support a simple linear mapping
* for each DMA window used by any device. For now, we
* happen to know that there is only one DMA window in use,
* starting at iopt_phys_offset. */
-static void cell_map_iommu(void)
+static void cell_do_map_iommu(struct cell_iommu *iommu,
+ unsigned int ioid,
+ unsigned long map_start,
+ unsigned long map_size)
{
- unsigned long address;
- void __iomem *base;
+ unsigned long io_address, real_address;
+ void __iomem *ioc_base, *ioc_mmio_base;
ioste ioste;
unsigned long index;
- base = __ioremap(ioc_base, 0x1000, _PAGE_NO_CACHE);
- pr_debug("%lx mapped to %p\n", ioc_base, base);
- set_iocmd_config(base);
- iounmap(base);
+ /* we pretend the io page table was at a very high address */
+ const unsigned long fake_iopt = 0x10000000000ul;
+ const unsigned long io_page_size = 0x1000000; /* use 16M pages */
+ const unsigned long io_segment_size = 0x10000000; /* 256M */
+
+ ioc_base = iommu->mapped_base;
+ ioc_mmio_base = iommu->mapped_mmio_base;
+
+ for (real_address = 0, io_address = 0;
+ io_address <= map_start + map_size;
+ real_address += io_page_size, io_address += io_page_size) {
+ ioste = get_iost_entry(fake_iopt, io_address, io_page_size);
+ if ((real_address % io_segment_size) == 0) /* segment start */
+ set_iost_cache(ioc_mmio_base,
+ io_address >> 28, ioste);
+ index = get_ioc_hash_1way(ioste, io_address);
+ pr_debug("addr %08lx, index %02lx, ioste %016lx\n",
+ io_address, index, ioste.val);
+ set_iopt_cache(ioc_mmio_base,
+ get_ioc_hash_1way(ioste, io_address),
+ get_ioc_tag(ioste, io_address),
+ get_iopt_entry(real_address-map_start, ioid, IOPT_PROT_RW));
+ }
+}
- base = __ioremap(ioc_mmio_base, 0x1000, _PAGE_NO_CACHE);
- pr_debug("%lx mapped to %p\n", ioc_mmio_base, base);
+static void iommu_devnode_setup(struct device_node *d)
+{
+ unsigned int *ioid;
+ unsigned long *dma_window, map_start, map_size, token;
+ struct cell_iommu *iommu;
- set_iost_origin(base);
+ ioid = (unsigned int *)get_property(d, "ioid", NULL);
+ if (!ioid)
+ pr_debug("No ioid entry found !\n");
- for (address = 0; address < 0x100000000ul; address += io_page_size) {
- ioste = get_iost_entry(0x10000000000ul, address, io_page_size);
- if ((address & 0xfffffff) == 0) /* segment start */
- set_iost_cache(base, address >> 28, ioste);
- index = get_ioc_hash_1way(ioste, address);
- pr_debug("addr %08lx, index %02lx, ioste %016lx\n",
- address, index, ioste.val);
- set_iopt_cache(base,
- get_ioc_hash_1way(ioste, address),
- get_ioc_tag(ioste, address),
- map_iopt_entry(address));
- }
- iounmap(base);
+ dma_window = (unsigned long *)get_property(d, "ibm,dma-window", NULL);
+ if (!dma_window)
+ pr_debug("No ibm,dma-window entry found !\n");
+
+ map_start = dma_window[1];
+ map_size = dma_window[2];
+ token = dma_window[0] >> 32;
+
+ iommu = &cell_iommus[token];
+
+ cell_do_map_iommu(iommu, *ioid, map_start, map_size);
+}
+
+static void iommu_bus_setup(struct pci_bus *b)
+{
+ struct device_node *d = (struct device_node *)b->sysdata;
+ iommu_devnode_setup(d);
+}
+
+
+static int cell_map_iommu_hardcoded(int num_nodes)
+{
+ struct cell_iommu *iommu = NULL;
+
+ pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__);
+
+ /* node 0 */
+ iommu = &cell_iommus[0];
+ iommu->mapped_base = __ioremap(0x20000511000, 0x1000, _PAGE_NO_CACHE);
+ iommu->mapped_mmio_base = __ioremap(0x20000510000, 0x1000, _PAGE_NO_CACHE);
+
+ enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
+
+ cell_do_map_iommu(iommu, 0x048a,
+ 0x20000000ul,0x20000000ul);
+
+ if (num_nodes < 2)
+ return 0;
+
+ /* node 1 */
+ iommu = &cell_iommus[1];
+ iommu->mapped_base = __ioremap(0x30000511000, 0x1000, _PAGE_NO_CACHE);
+ iommu->mapped_mmio_base = __ioremap(0x30000510000, 0x1000, _PAGE_NO_CACHE);
+
+ enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
+
+ cell_do_map_iommu(iommu, 0x048a,
+ 0x20000000,0x20000000ul);
+
+ return 0;
}
+static int cell_map_iommu(void)
+{
+ unsigned int num_nodes = 0, *node_id;
+ unsigned long *base, *mmio_base;
+ struct device_node *dn;
+ struct cell_iommu *iommu = NULL;
+
+ /* determine number of nodes (=iommus) */
+ pr_debug("%s(%d): determining number of nodes...", __FUNCTION__, __LINE__);
+ for(dn = of_find_node_by_type(NULL, "cpu");
+ dn;
+ dn = of_find_node_by_type(dn, "cpu")) {
+ node_id = (unsigned int *)get_property(dn, "node-id", NULL);
+
+ if (num_nodes < *node_id)
+ num_nodes = *node_id;
+ }
+
+ num_nodes++;
+ pr_debug("%i found.\n", num_nodes);
+
+ /* map the iommu registers for each node */
+ pr_debug("%s(%d): Looping through nodes\n", __FUNCTION__, __LINE__);
+ for(dn = of_find_node_by_type(NULL, "cpu");
+ dn;
+ dn = of_find_node_by_type(dn, "cpu")) {
+
+ node_id = (unsigned int *)get_property(dn, "node-id", NULL);
+ base = (unsigned long *)get_property(dn, "ioc-cache", NULL);
+ mmio_base = (unsigned long *)get_property(dn, "ioc-translation", NULL);
+
+ if (!base || !mmio_base || !node_id)
+ return cell_map_iommu_hardcoded(num_nodes);
+
+ iommu = &cell_iommus[*node_id];
+ iommu->base = *base;
+ iommu->mmio_base = *mmio_base;
+
+ iommu->mapped_base = __ioremap(*base, 0x1000, _PAGE_NO_CACHE);
+ iommu->mapped_mmio_base = __ioremap(*mmio_base, 0x1000, _PAGE_NO_CACHE);
+
+ enable_mapping(iommu->mapped_base,
+ iommu->mapped_mmio_base);
+
+ /* everything else will be done in iommu_bus_setup */
+ }
+
+ return 1;
+}
+
static void *cell_alloc_coherent(struct device *hwdev, size_t size,
dma_addr_t *dma_handle, gfp_t flag)
{
@@ -365,11 +475,28 @@ static int cell_dma_supported(struct device *dev, u64 mask)
void cell_init_iommu(void)
{
- cell_map_iommu();
-
- /* Direct I/O, IOMMU off */
- ppc_md.iommu_dev_setup = iommu_dev_setup_null;
- ppc_md.iommu_bus_setup = iommu_bus_setup_null;
+ int setup_bus = 0;
+
+ if (of_find_node_by_path("/mambo")) {
+ pr_info("Not using iommu on systemsim\n");
+ } else {
+
+ if (!(of_chosen &&
+ get_property(of_chosen, "linux,iommu-off", NULL)))
+ setup_bus = cell_map_iommu();
+
+ if (setup_bus) {
+ pr_debug("%s: IOMMU mapping activated\n", __FUNCTION__);
+ ppc_md.iommu_dev_setup = iommu_dev_setup_null;
+ ppc_md.iommu_bus_setup = iommu_bus_setup;
+ } else {
+ pr_debug("%s: IOMMU mapping activated, "
+ "no device action necessary\n", __FUNCTION__);
+ /* Direct I/O, IOMMU off */
+ ppc_md.iommu_dev_setup = iommu_dev_setup_null;
+ ppc_md.iommu_bus_setup = iommu_bus_setup_null;
+ }
+ }
pci_dma_ops.alloc_coherent = cell_alloc_coherent;
pci_dma_ops.free_coherent = cell_free_coherent;
diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c
new file mode 100644
index 000000000000..85152544c153
--- /dev/null
+++ b/arch/powerpc/platforms/cell/pervasive.c
@@ -0,0 +1,229 @@
+/*
+ * CBE Pervasive Monitor and Debug
+ *
+ * (C) Copyright IBM Corporation 2005
+ *
+ * Authors: Maximino Aguilar (maguilar@us.ibm.com)
+ * Michael N. Day (mnday@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, 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.
+ */
+
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/percpu.h>
+#include <linux/types.h>
+#include <linux/kallsyms.h>
+
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/pgtable.h>
+#include <asm/reg.h>
+
+#include "pervasive.h"
+
+static DEFINE_SPINLOCK(cbe_pervasive_lock);
+struct cbe_pervasive {
+ struct pmd_regs __iomem *regs;
+ unsigned int thread;
+};
+
+/* can't use per_cpu from setup_arch */
+static struct cbe_pervasive cbe_pervasive[NR_CPUS];
+
+static void __init cbe_enable_pause_zero(void)
+{
+ unsigned long thread_switch_control;
+ unsigned long temp_register;
+ struct cbe_pervasive *p;
+ int thread;
+
+ spin_lock_irq(&cbe_pervasive_lock);
+ p = &cbe_pervasive[smp_processor_id()];
+
+ if (!cbe_pervasive->regs)
+ goto out;
+
+ pr_debug("Power Management: CPU %d\n", smp_processor_id());
+
+ /* Enable Pause(0) control bit */
+ temp_register = in_be64(&p->regs->pm_control);
+
+ out_be64(&p->regs->pm_control,
+ temp_register|PMD_PAUSE_ZERO_CONTROL);
+
+ /* Enable DEC and EE interrupt request */
+ thread_switch_control = mfspr(SPRN_TSC_CELL);
+ thread_switch_control |= TSC_CELL_EE_ENABLE | TSC_CELL_EE_BOOST;
+
+ switch ((mfspr(SPRN_CTRLF) & CTRL_CT)) {
+ case CTRL_CT0:
+ thread_switch_control |= TSC_CELL_DEC_ENABLE_0;
+ thread = 0;
+ break;
+ case CTRL_CT1:
+ thread_switch_control |= TSC_CELL_DEC_ENABLE_1;
+ thread = 1;
+ break;
+ default:
+ printk(KERN_WARNING "%s: unknown configuration\n",
+ __FUNCTION__);
+ thread = -1;
+ break;
+ }
+
+ if (p->thread != thread)
+ printk(KERN_WARNING "%s: device tree inconsistant, "
+ "cpu %i: %d/%d\n", __FUNCTION__,
+ smp_processor_id(),
+ p->thread, thread);
+
+ mtspr(SPRN_TSC_CELL, thread_switch_control);
+
+out:
+ spin_unlock_irq(&cbe_pervasive_lock);
+}
+
+static void cbe_idle(void)
+{
+ unsigned long ctrl;
+
+ cbe_enable_pause_zero();
+
+ while (1) {
+ if (!need_resched()) {
+ local_irq_disable();
+ while (!need_resched()) {
+ /* go into low thread priority */
+ HMT_low();
+
+ /*
+ * atomically disable thread execution
+ * and runlatch.
+ * External and Decrementer exceptions
+ * are still handled when the thread
+ * is disabled but now enter in
+ * cbe_system_reset_exception()
+ */
+ ctrl = mfspr(SPRN_CTRLF);
+ ctrl &= ~(CTRL_RUNLATCH | CTRL_TE);
+ mtspr(SPRN_CTRLT, ctrl);
+ }
+ /* restore thread prio */
+ HMT_medium();
+ local_irq_enable();
+ }
+
+ /*
+ * turn runlatch on again before scheduling the
+ * process we just woke up
+ */
+ ppc64_runlatch_on();
+
+ preempt_enable_no_resched();
+ schedule();
+ preempt_disable();
+ }
+}
+
+int cbe_system_reset_exception(struct pt_regs *regs)
+{
+ switch (regs->msr & SRR1_WAKEMASK) {
+ case SRR1_WAKEEE:
+ do_IRQ(regs);
+ break;
+ case SRR1_WAKEDEC:
+ timer_interrupt(regs);
+ break;
+ case SRR1_WAKEMT:
+ /* no action required */
+ break;
+ default:
+ /* do system reset */
+ return 0;
+ }
+ /* everything handled */
+ return 1;
+}
+
+static int __init cbe_find_pmd_mmio(int cpu, struct cbe_pervasive *p)
+{
+ struct device_node *node;
+ unsigned int *int_servers;
+ char *addr;
+ unsigned long real_address;
+ unsigned int size;
+
+ struct pmd_regs __iomem *pmd_mmio_area;
+ int hardid, thread;
+ int proplen;
+
+ pmd_mmio_area = NULL;
+ hardid = get_hard_smp_processor_id(cpu);
+ for (node = NULL; (node = of_find_node_by_type(node, "cpu"));) {
+ int_servers = (void *) get_property(node,
+ "ibm,ppc-interrupt-server#s", &proplen);
+ if (!int_servers) {
+ printk(KERN_WARNING "%s misses "
+ "ibm,ppc-interrupt-server#s property",
+ node->full_name);
+ continue;
+ }
+ for (thread = 0; thread < proplen / sizeof (int); thread++) {
+ if (hardid == int_servers[thread]) {
+ addr = get_property(node, "pervasive", NULL);
+ goto found;
+ }
+ }
+ }
+
+ printk(KERN_WARNING "%s: CPU %d not found\n", __FUNCTION__, cpu);
+ return -EINVAL;
+
+found:
+ real_address = *(unsigned long*) addr;
+ addr += sizeof (unsigned long);
+ size = *(unsigned int*) addr;
+
+ pr_debug("pervasive area for CPU %d at %lx, size %x\n",
+ cpu, real_address, size);
+ p->regs = __ioremap(real_address, size, _PAGE_NO_CACHE);
+ p->thread = thread;
+ return 0;
+}
+
+void __init cell_pervasive_init(void)
+{
+ struct cbe_pervasive *p;
+ int cpu;
+ int ret;
+
+ if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO))
+ return;
+
+ for_each_cpu(cpu) {
+ p = &cbe_pervasive[cpu];
+ ret = cbe_find_pmd_mmio(cpu, p);
+ if (ret)
+ return;
+ }
+
+ ppc_md.idle_loop = cbe_idle;
+ ppc_md.system_reset_exception = cbe_system_reset_exception;
+}
diff --git a/arch/powerpc/platforms/cell/pervasive.h b/arch/powerpc/platforms/cell/pervasive.h
new file mode 100644
index 000000000000..da1fb85ca3e8
--- /dev/null
+++ b/arch/powerpc/platforms/cell/pervasive.h
@@ -0,0 +1,62 @@
+/*
+ * Cell Pervasive Monitor and Debug interface and HW structures
+ *
+ * (C) Copyright IBM Corporation 2005
+ *
+ * Authors: Maximino Aguilar (maguilar@us.ibm.com)
+ * David J. Erb (djerb@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, 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 PERVASIVE_H
+#define PERVASIVE_H
+
+struct pmd_regs {
+ u8 pad_0x0000_0x0800[0x0800 - 0x0000]; /* 0x0000 */
+
+ /* Thermal Sensor Registers */
+ u64 ts_ctsr1; /* 0x0800 */
+ u64 ts_ctsr2; /* 0x0808 */
+ u64 ts_mtsr1; /* 0x0810 */
+ u64 ts_mtsr2; /* 0x0818 */
+ u64 ts_itr1; /* 0x0820 */
+ u64 ts_itr2; /* 0x0828 */
+ u64 ts_gitr; /* 0x0830 */
+ u64 ts_isr; /* 0x0838 */
+ u64 ts_imr; /* 0x0840 */
+ u64 tm_cr1; /* 0x0848 */
+ u64 tm_cr2; /* 0x0850 */
+ u64 tm_simr; /* 0x0858 */
+ u64 tm_tpr; /* 0x0860 */
+ u64 tm_str1; /* 0x0868 */
+ u64 tm_str2; /* 0x0870 */
+ u64 tm_tsr; /* 0x0878 */
+
+ /* Power Management */
+ u64 pm_control; /* 0x0880 */
+#define PMD_PAUSE_ZERO_CONTROL 0x10000
+ u64 pm_status; /* 0x0888 */
+
+ /* Time Base Register */
+ u64 tbr; /* 0x0890 */
+
+ u8 pad_0x0898_0x1000 [0x1000 - 0x0898]; /* 0x0898 */
+};
+
+void __init cell_pervasive_init(void);
+
+#endif
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index 9a495634d0c2..18e25e65c04b 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -33,6 +33,7 @@
#include <asm/mmu.h>
#include <asm/processor.h>
#include <asm/io.h>
+#include <asm/kexec.h>
#include <asm/pgtable.h>
#include <asm/prom.h>
#include <asm/rtas.h>
@@ -48,6 +49,7 @@
#include "interrupt.h"
#include "iommu.h"
+#include "pervasive.h"
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
@@ -67,6 +69,77 @@ void cell_show_cpuinfo(struct seq_file *m)
of_node_put(root);
}
+#ifdef CONFIG_SPARSEMEM
+static int __init find_spu_node_id(struct device_node *spe)
+{
+ unsigned int *id;
+#ifdef CONFIG_NUMA
+ struct device_node *cpu;
+ cpu = spe->parent->parent;
+ id = (unsigned int *)get_property(cpu, "node-id", NULL);
+#else
+ id = NULL;
+#endif
+ return id ? *id : 0;
+}
+
+static void __init cell_spuprop_present(struct device_node *spe,
+ const char *prop, int early)
+{
+ struct address_prop {
+ unsigned long address;
+ unsigned int len;
+ } __attribute__((packed)) *p;
+ int proplen;
+
+ unsigned long start_pfn, end_pfn, pfn;
+ int node_id;
+
+ p = (void*)get_property(spe, prop, &proplen);
+ WARN_ON(proplen != sizeof (*p));
+
+ node_id = find_spu_node_id(spe);
+
+ start_pfn = p->address >> PAGE_SHIFT;
+ end_pfn = (p->address + p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ /* We need to call memory_present *before* the call to sparse_init,
+ but we can initialize the page structs only *after* that call.
+ Thus, we're being called twice. */
+ if (early)
+ memory_present(node_id, start_pfn, end_pfn);
+ else {
+ /* As the pages backing SPU LS and I/O are outside the range
+ of regular memory, their page structs were not initialized
+ by free_area_init. Do it here instead. */
+ for (pfn = start_pfn; pfn < end_pfn; pfn++) {
+ struct page *page = pfn_to_page(pfn);
+ set_page_links(page, ZONE_DMA, node_id, pfn);
+ set_page_count(page, 1);
+ reset_page_mapcount(page);
+ SetPageReserved(page);
+ INIT_LIST_HEAD(&page->lru);
+ }
+ }
+}
+
+static void __init cell_spumem_init(int early)
+{
+ struct device_node *node;
+ for (node = of_find_node_by_type(NULL, "spe");
+ node; node = of_find_node_by_type(node, "spe")) {
+ cell_spuprop_present(node, "local-store", early);
+ cell_spuprop_present(node, "problem", early);
+ cell_spuprop_present(node, "priv1", early);
+ cell_spuprop_present(node, "priv2", early);
+ }
+}
+#else
+static void __init cell_spumem_init(int early)
+{
+}
+#endif
+
static void cell_progress(char *s, unsigned short hex)
{
printk("*** %04x : %s\n", hex, s ? s : "");
@@ -93,11 +166,14 @@ static void __init cell_setup_arch(void)
init_pci_config_tokens();
find_and_init_phbs();
spider_init_IRQ();
+ cell_pervasive_init();
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
#endif
mmio_nvram_init();
+
+ cell_spumem_init(0);
}
/*
@@ -113,6 +189,8 @@ static void __init cell_init_early(void)
ppc64_interrupt_controller = IC_CELL_PIC;
+ cell_spumem_init(1);
+
DBG(" <- cell_init_early()\n");
}
@@ -125,6 +203,15 @@ static int __init cell_probe(int platform)
return 1;
}
+/*
+ * Cell has no legacy IO; anything calling this function has to
+ * fail or bad things will happen
+ */
+static int cell_check_legacy_ioport(unsigned int baseport)
+{
+ return -ENODEV;
+}
+
struct machdep_calls __initdata cell_md = {
.probe = cell_probe,
.setup_arch = cell_setup_arch,
@@ -137,5 +224,11 @@ struct machdep_calls __initdata cell_md = {
.get_rtc_time = rtas_get_rtc_time,
.set_rtc_time = rtas_set_rtc_time,
.calibrate_decr = generic_calibrate_decr,
+ .check_legacy_ioport = cell_check_legacy_ioport,
.progress = cell_progress,
+#ifdef CONFIG_KEXEC
+ .machine_kexec = default_machine_kexec,
+ .machine_kexec_prepare = default_machine_kexec_prepare,
+ .machine_crash_shutdown = default_machine_crash_shutdown,
+#endif
};
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
new file mode 100644
index 000000000000..d75ae03df686
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -0,0 +1,711 @@
+/*
+ * Low-level SPU handling
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.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, 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.
+ */
+
+#undef DEBUG
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/semaphore.h>
+#include <asm/spu.h>
+#include <asm/mmu_context.h>
+
+#include "interrupt.h"
+
+static int __spu_trap_invalid_dma(struct spu *spu)
+{
+ pr_debug("%s\n", __FUNCTION__);
+ force_sig(SIGBUS, /* info, */ current);
+ return 0;
+}
+
+static int __spu_trap_dma_align(struct spu *spu)
+{
+ pr_debug("%s\n", __FUNCTION__);
+ force_sig(SIGBUS, /* info, */ current);
+ return 0;
+}
+
+static int __spu_trap_error(struct spu *spu)
+{
+ pr_debug("%s\n", __FUNCTION__);
+ force_sig(SIGILL, /* info, */ current);
+ return 0;
+}
+
+static void spu_restart_dma(struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags))
+ out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
+}
+
+static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+ struct mm_struct *mm = spu->mm;
+ u64 esid, vsid;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) {
+ /* SLBs are pre-loaded for context switch, so
+ * we should never get here!
+ */
+ printk("%s: invalid access during switch!\n", __func__);
+ return 1;
+ }
+ if (!mm || (REGION_ID(ea) != USER_REGION_ID)) {
+ /* Future: support kernel segments so that drivers
+ * can use SPUs.
+ */
+ pr_debug("invalid region access at %016lx\n", ea);
+ return 1;
+ }
+
+ esid = (ea & ESID_MASK) | SLB_ESID_V;
+ vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) | SLB_VSID_USER;
+ if (in_hugepage_area(mm->context, ea))
+ vsid |= SLB_VSID_L;
+
+ out_be64(&priv2->slb_index_W, spu->slb_replace);
+ out_be64(&priv2->slb_vsid_RW, vsid);
+ out_be64(&priv2->slb_esid_RW, esid);
+
+ spu->slb_replace++;
+ if (spu->slb_replace >= 8)
+ spu->slb_replace = 0;
+
+ spu_restart_dma(spu);
+
+ return 0;
+}
+
+extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX
+static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
+{
+ pr_debug("%s\n", __FUNCTION__);
+
+ /* Handle kernel space hash faults immediately.
+ User hash faults need to be deferred to process context. */
+ if ((dsisr & MFC_DSISR_PTE_NOT_FOUND)
+ && REGION_ID(ea) != USER_REGION_ID
+ && hash_page(ea, _PAGE_PRESENT, 0x300) == 0) {
+ spu_restart_dma(spu);
+ return 0;
+ }
+
+ if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) {
+ printk("%s: invalid access during switch!\n", __func__);
+ return 1;
+ }
+
+ spu->dar = ea;
+ spu->dsisr = dsisr;
+ mb();
+ if (spu->stop_callback)
+ spu->stop_callback(spu);
+ return 0;
+}
+
+static int __spu_trap_mailbox(struct spu *spu)
+{
+ if (spu->ibox_callback)
+ spu->ibox_callback(spu);
+
+ /* atomically disable SPU mailbox interrupts */
+ spin_lock(&spu->register_lock);
+ spu_int_mask_and(spu, 2, ~0x1);
+ spin_unlock(&spu->register_lock);
+ return 0;
+}
+
+static int __spu_trap_stop(struct spu *spu)
+{
+ pr_debug("%s\n", __FUNCTION__);
+ spu->stop_code = in_be32(&spu->problem->spu_status_R);
+ if (spu->stop_callback)
+ spu->stop_callback(spu);
+ return 0;
+}
+
+static int __spu_trap_halt(struct spu *spu)
+{
+ pr_debug("%s\n", __FUNCTION__);
+ spu->stop_code = in_be32(&spu->problem->spu_status_R);
+ if (spu->stop_callback)
+ spu->stop_callback(spu);
+ return 0;
+}
+
+static int __spu_trap_tag_group(struct spu *spu)
+{
+ pr_debug("%s\n", __FUNCTION__);
+ /* wake_up(&spu->dma_wq); */
+ return 0;
+}
+
+static int __spu_trap_spubox(struct spu *spu)
+{
+ if (spu->wbox_callback)
+ spu->wbox_callback(spu);
+
+ /* atomically disable SPU mailbox interrupts */
+ spin_lock(&spu->register_lock);
+ spu_int_mask_and(spu, 2, ~0x10);
+ spin_unlock(&spu->register_lock);
+ return 0;
+}
+
+static irqreturn_t
+spu_irq_class_0(int irq, void *data, struct pt_regs *regs)
+{
+ struct spu *spu;
+
+ spu = data;
+ spu->class_0_pending = 1;
+ if (spu->stop_callback)
+ spu->stop_callback(spu);
+
+ return IRQ_HANDLED;
+}
+
+int
+spu_irq_class_0_bottom(struct spu *spu)
+{
+ unsigned long stat, mask;
+
+ spu->class_0_pending = 0;
+
+ mask = spu_int_mask_get(spu, 0);
+ stat = spu_int_stat_get(spu, 0);
+
+ stat &= mask;
+
+ if (stat & 1) /* invalid MFC DMA */
+ __spu_trap_invalid_dma(spu);
+
+ if (stat & 2) /* invalid DMA alignment */
+ __spu_trap_dma_align(spu);
+
+ if (stat & 4) /* error on SPU */
+ __spu_trap_error(spu);
+
+ spu_int_stat_clear(spu, 0, stat);
+
+ return (stat & 0x7) ? -EIO : 0;
+}
+EXPORT_SYMBOL_GPL(spu_irq_class_0_bottom);
+
+static irqreturn_t
+spu_irq_class_1(int irq, void *data, struct pt_regs *regs)
+{
+ struct spu *spu;
+ unsigned long stat, mask, dar, dsisr;
+
+ spu = data;
+
+ /* atomically read & clear class1 status. */
+ spin_lock(&spu->register_lock);
+ mask = spu_int_mask_get(spu, 1);
+ stat = spu_int_stat_get(spu, 1) & mask;
+ dar = spu_mfc_dar_get(spu);
+ dsisr = spu_mfc_dsisr_get(spu);
+ if (stat & 2) /* mapping fault */
+ spu_mfc_dsisr_set(spu, 0ul);
+ spu_int_stat_clear(spu, 1, stat);
+ spin_unlock(&spu->register_lock);
+
+ if (stat & 1) /* segment fault */
+ __spu_trap_data_seg(spu, dar);
+
+ if (stat & 2) { /* mapping fault */
+ __spu_trap_data_map(spu, dar, dsisr);
+ }
+
+ if (stat & 4) /* ls compare & suspend on get */
+ ;
+
+ if (stat & 8) /* ls compare & suspend on put */
+ ;
+
+ return stat ? IRQ_HANDLED : IRQ_NONE;
+}
+EXPORT_SYMBOL_GPL(spu_irq_class_1_bottom);
+
+static irqreturn_t
+spu_irq_class_2(int irq, void *data, struct pt_regs *regs)
+{
+ struct spu *spu;
+ unsigned long stat;
+ unsigned long mask;
+
+ spu = data;
+ stat = spu_int_stat_get(spu, 2);
+ mask = spu_int_mask_get(spu, 2);
+
+ pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask);
+
+ stat &= mask;
+
+ if (stat & 1) /* PPC core mailbox */
+ __spu_trap_mailbox(spu);
+
+ if (stat & 2) /* SPU stop-and-signal */
+ __spu_trap_stop(spu);
+
+ if (stat & 4) /* SPU halted */
+ __spu_trap_halt(spu);
+
+ if (stat & 8) /* DMA tag group complete */
+ __spu_trap_tag_group(spu);
+
+ if (stat & 0x10) /* SPU mailbox threshold */
+ __spu_trap_spubox(spu);
+
+ spu_int_stat_clear(spu, 2, stat);
+ return stat ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int
+spu_request_irqs(struct spu *spu)
+{
+ int ret;
+ int irq_base;
+
+ irq_base = IIC_NODE_STRIDE * spu->node + IIC_SPE_OFFSET;
+
+ snprintf(spu->irq_c0, sizeof (spu->irq_c0), "spe%02d.0", spu->number);
+ ret = request_irq(irq_base + spu->isrc,
+ spu_irq_class_0, 0, spu->irq_c0, spu);
+ if (ret)
+ goto out;
+
+ snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1", spu->number);
+ ret = request_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc,
+ spu_irq_class_1, 0, spu->irq_c1, spu);
+ if (ret)
+ goto out1;
+
+ snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2", spu->number);
+ ret = request_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc,
+ spu_irq_class_2, 0, spu->irq_c2, spu);
+ if (ret)
+ goto out2;
+ goto out;
+
+out2:
+ free_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, spu);
+out1:
+ free_irq(irq_base + spu->isrc, spu);
+out:
+ return ret;
+}
+
+static void
+spu_free_irqs(struct spu *spu)
+{
+ int irq_base;
+
+ irq_base = IIC_NODE_STRIDE * spu->node + IIC_SPE_OFFSET;
+
+ free_irq(irq_base + spu->isrc, spu);
+ free_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, spu);
+ free_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc, spu);
+}
+
+static LIST_HEAD(spu_list);
+static DECLARE_MUTEX(spu_mutex);
+
+static void spu_init_channels(struct spu *spu)
+{
+ static const struct {
+ unsigned channel;
+ unsigned count;
+ } zero_list[] = {
+ { 0x00, 1, }, { 0x01, 1, }, { 0x03, 1, }, { 0x04, 1, },
+ { 0x18, 1, }, { 0x19, 1, }, { 0x1b, 1, }, { 0x1d, 1, },
+ }, count_list[] = {
+ { 0x00, 0, }, { 0x03, 0, }, { 0x04, 0, }, { 0x15, 16, },
+ { 0x17, 1, }, { 0x18, 0, }, { 0x19, 0, }, { 0x1b, 0, },
+ { 0x1c, 1, }, { 0x1d, 0, }, { 0x1e, 1, },
+ };
+ struct spu_priv2 __iomem *priv2;
+ int i;
+
+ priv2 = spu->priv2;
+
+ /* initialize all channel data to zero */
+ for (i = 0; i < ARRAY_SIZE(zero_list); i++) {
+ int count;
+
+ out_be64(&priv2->spu_chnlcntptr_RW, zero_list[i].channel);
+ for (count = 0; count < zero_list[i].count; count++)
+ out_be64(&priv2->spu_chnldata_RW, 0);
+ }
+
+ /* initialize channel counts to meaningful values */
+ for (i = 0; i < ARRAY_SIZE(count_list); i++) {
+ out_be64(&priv2->spu_chnlcntptr_RW, count_list[i].channel);
+ out_be64(&priv2->spu_chnlcnt_RW, count_list[i].count);
+ }
+}
+
+struct spu *spu_alloc(void)
+{
+ struct spu *spu;
+
+ down(&spu_mutex);
+ if (!list_empty(&spu_list)) {
+ spu = list_entry(spu_list.next, struct spu, list);
+ list_del_init(&spu->list);
+ pr_debug("Got SPU %x %d\n", spu->isrc, spu->number);
+ } else {
+ pr_debug("No SPU left\n");
+ spu = NULL;
+ }
+ up(&spu_mutex);
+
+ if (spu)
+ spu_init_channels(spu);
+
+ return spu;
+}
+EXPORT_SYMBOL_GPL(spu_alloc);
+
+void spu_free(struct spu *spu)
+{
+ down(&spu_mutex);
+ list_add_tail(&spu->list, &spu_list);
+ up(&spu_mutex);
+}
+EXPORT_SYMBOL_GPL(spu_free);
+
+static int spu_handle_mm_fault(struct spu *spu)
+{
+ struct mm_struct *mm = spu->mm;
+ struct vm_area_struct *vma;
+ u64 ea, dsisr, is_write;
+ int ret;
+
+ ea = spu->dar;
+ dsisr = spu->dsisr;
+#if 0
+ if (!IS_VALID_EA(ea)) {
+ return -EFAULT;
+ }
+#endif /* XXX */
+ if (mm == NULL) {
+ return -EFAULT;
+ }
+ if (mm->pgd == NULL) {
+ return -EFAULT;
+ }
+
+ down_read(&mm->mmap_sem);
+ vma = find_vma(mm, ea);
+ if (!vma)
+ goto bad_area;
+ if (vma->vm_start <= ea)
+ goto good_area;
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto bad_area;
+#if 0
+ if (expand_stack(vma, ea))
+ goto bad_area;
+#endif /* XXX */
+good_area:
+ is_write = dsisr & MFC_DSISR_ACCESS_PUT;
+ if (is_write) {
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ } else {
+ if (dsisr & MFC_DSISR_ACCESS_DENIED)
+ goto bad_area;
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ goto bad_area;
+ }
+ ret = 0;
+ switch (handle_mm_fault(mm, vma, ea, is_write)) {
+ case VM_FAULT_MINOR:
+ current->min_flt++;
+ break;
+ case VM_FAULT_MAJOR:
+ current->maj_flt++;
+ break;
+ case VM_FAULT_SIGBUS:
+ ret = -EFAULT;
+ goto bad_area;
+ case VM_FAULT_OOM:
+ ret = -ENOMEM;
+ goto bad_area;
+ default:
+ BUG();
+ }
+ up_read(&mm->mmap_sem);
+ return ret;
+
+bad_area:
+ up_read(&mm->mmap_sem);
+ return -EFAULT;
+}
+
+int spu_irq_class_1_bottom(struct spu *spu)
+{
+ u64 ea, dsisr, access, error = 0UL;
+ int ret = 0;
+
+ ea = spu->dar;
+ dsisr = spu->dsisr;
+ if (dsisr & MFC_DSISR_PTE_NOT_FOUND) {
+ access = (_PAGE_PRESENT | _PAGE_USER);
+ access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
+ if (hash_page(ea, access, 0x300) != 0)
+ error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
+ }
+ if ((error & CLASS1_ENABLE_STORAGE_FAULT_INTR) ||
+ (dsisr & MFC_DSISR_ACCESS_DENIED)) {
+ if ((ret = spu_handle_mm_fault(spu)) != 0)
+ error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
+ else
+ error &= ~CLASS1_ENABLE_STORAGE_FAULT_INTR;
+ }
+ spu->dar = 0UL;
+ spu->dsisr = 0UL;
+ if (!error) {
+ spu_restart_dma(spu);
+ } else {
+ __spu_trap_invalid_dma(spu);
+ }
+ return ret;
+}
+
+void spu_irq_setaffinity(struct spu *spu, int cpu)
+{
+ u64 target = iic_get_target_id(cpu);
+ u64 route = target << 48 | target << 32 | target << 16;
+ spu_int_route_set(spu, route);
+}
+EXPORT_SYMBOL_GPL(spu_irq_setaffinity);
+
+static void __iomem * __init map_spe_prop(struct device_node *n,
+ const char *name)
+{
+ struct address_prop {
+ unsigned long address;
+ unsigned int len;
+ } __attribute__((packed)) *prop;
+
+ void *p;
+ int proplen;
+
+ p = get_property(n, name, &proplen);
+ if (proplen != sizeof (struct address_prop))
+ return NULL;
+
+ prop = p;
+
+ return ioremap(prop->address, prop->len);
+}
+
+static void spu_unmap(struct spu *spu)
+{
+ iounmap(spu->priv2);
+ iounmap(spu->priv1);
+ iounmap(spu->problem);
+ iounmap((u8 __iomem *)spu->local_store);
+}
+
+static int __init spu_map_device(struct spu *spu, struct device_node *spe)
+{
+ char *prop;
+ int ret;
+
+ ret = -ENODEV;
+ prop = get_property(spe, "isrc", NULL);
+ if (!prop)
+ goto out;
+ spu->isrc = *(unsigned int *)prop;
+
+ spu->name = get_property(spe, "name", NULL);
+ if (!spu->name)
+ goto out;
+
+ prop = get_property(spe, "local-store", NULL);
+ if (!prop)
+ goto out;
+ spu->local_store_phys = *(unsigned long *)prop;
+
+ /* we use local store as ram, not io memory */
+ spu->local_store = (void __force *)map_spe_prop(spe, "local-store");
+ if (!spu->local_store)
+ goto out;
+
+ spu->problem= map_spe_prop(spe, "problem");
+ if (!spu->problem)
+ goto out_unmap;
+
+ spu->priv1= map_spe_prop(spe, "priv1");
+ /* priv1 is not available on a hypervisor */
+
+ spu->priv2= map_spe_prop(spe, "priv2");
+ if (!spu->priv2)
+ goto out_unmap;
+ ret = 0;
+ goto out;
+
+out_unmap:
+ spu_unmap(spu);
+out:
+ return ret;
+}
+
+static int __init find_spu_node_id(struct device_node *spe)
+{
+ unsigned int *id;
+ struct device_node *cpu;
+
+ cpu = spe->parent->parent;
+ id = (unsigned int *)get_property(cpu, "node-id", NULL);
+
+ return id ? *id : 0;
+}
+
+static int __init create_spu(struct device_node *spe)
+{
+ struct spu *spu;
+ int ret;
+ static int number;
+
+ ret = -ENOMEM;
+ spu = kmalloc(sizeof (*spu), GFP_KERNEL);
+ if (!spu)
+ goto out;
+
+ ret = spu_map_device(spu, spe);
+ if (ret)
+ goto out_free;
+
+ spu->node = find_spu_node_id(spe);
+ spu->stop_code = 0;
+ spu->slb_replace = 0;
+ spu->mm = NULL;
+ spu->ctx = NULL;
+ spu->rq = NULL;
+ spu->pid = 0;
+ spu->class_0_pending = 0;
+ spu->flags = 0UL;
+ spu->dar = 0UL;
+ spu->dsisr = 0UL;
+ spin_lock_init(&spu->register_lock);
+
+ spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1));
+ spu_mfc_sr1_set(spu, 0x33);
+
+ spu->ibox_callback = NULL;
+ spu->wbox_callback = NULL;
+ spu->stop_callback = NULL;
+
+ down(&spu_mutex);
+ spu->number = number++;
+ ret = spu_request_irqs(spu);
+ if (ret)
+ goto out_unmap;
+
+ list_add(&spu->list, &spu_list);
+ up(&spu_mutex);
+
+ pr_debug(KERN_DEBUG "Using SPE %s %02x %p %p %p %p %d\n",
+ spu->name, spu->isrc, spu->local_store,
+ spu->problem, spu->priv1, spu->priv2, spu->number);
+ goto out;
+
+out_unmap:
+ up(&spu_mutex);
+ spu_unmap(spu);
+out_free:
+ kfree(spu);
+out:
+ return ret;
+}
+
+static void destroy_spu(struct spu *spu)
+{
+ list_del_init(&spu->list);
+
+ spu_free_irqs(spu);
+ spu_unmap(spu);
+ kfree(spu);
+}
+
+static void cleanup_spu_base(void)
+{
+ struct spu *spu, *tmp;
+ down(&spu_mutex);
+ list_for_each_entry_safe(spu, tmp, &spu_list, list)
+ destroy_spu(spu);
+ up(&spu_mutex);
+}
+module_exit(cleanup_spu_base);
+
+static int __init init_spu_base(void)
+{
+ struct device_node *node;
+ int ret;
+
+ ret = -ENODEV;
+ for (node = of_find_node_by_type(NULL, "spe");
+ node; node = of_find_node_by_type(node, "spe")) {
+ ret = create_spu(node);
+ if (ret) {
+ printk(KERN_WARNING "%s: Error initializing %s\n",
+ __FUNCTION__, node->name);
+ cleanup_spu_base();
+ break;
+ }
+ }
+ /* in some old firmware versions, the spe is called 'spc', so we
+ look for that as well */
+ for (node = of_find_node_by_type(NULL, "spc");
+ node; node = of_find_node_by_type(node, "spc")) {
+ ret = create_spu(node);
+ if (ret) {
+ printk(KERN_WARNING "%s: Error initializing %s\n",
+ __FUNCTION__, node->name);
+ cleanup_spu_base();
+ break;
+ }
+ }
+ return ret;
+}
+module_init(init_spu_base);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
diff --git a/arch/powerpc/platforms/cell/spu_priv1.c b/arch/powerpc/platforms/cell/spu_priv1.c
new file mode 100644
index 000000000000..b2656421c7b5
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spu_priv1.c
@@ -0,0 +1,133 @@
+/*
+ * access to SPU privileged registers
+ */
+#include <linux/module.h>
+
+#include <asm/io.h>
+#include <asm/spu.h>
+
+void spu_int_mask_and(struct spu *spu, int class, u64 mask)
+{
+ u64 old_mask;
+
+ old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
+ out_be64(&spu->priv1->int_mask_RW[class], old_mask & mask);
+}
+EXPORT_SYMBOL_GPL(spu_int_mask_and);
+
+void spu_int_mask_or(struct spu *spu, int class, u64 mask)
+{
+ u64 old_mask;
+
+ old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
+ out_be64(&spu->priv1->int_mask_RW[class], old_mask | mask);
+}
+EXPORT_SYMBOL_GPL(spu_int_mask_or);
+
+void spu_int_mask_set(struct spu *spu, int class, u64 mask)
+{
+ out_be64(&spu->priv1->int_mask_RW[class], mask);
+}
+EXPORT_SYMBOL_GPL(spu_int_mask_set);
+
+u64 spu_int_mask_get(struct spu *spu, int class)
+{
+ return in_be64(&spu->priv1->int_mask_RW[class]);
+}
+EXPORT_SYMBOL_GPL(spu_int_mask_get);
+
+void spu_int_stat_clear(struct spu *spu, int class, u64 stat)
+{
+ out_be64(&spu->priv1->int_stat_RW[class], stat);
+}
+EXPORT_SYMBOL_GPL(spu_int_stat_clear);
+
+u64 spu_int_stat_get(struct spu *spu, int class)
+{
+ return in_be64(&spu->priv1->int_stat_RW[class]);
+}
+EXPORT_SYMBOL_GPL(spu_int_stat_get);
+
+void spu_int_route_set(struct spu *spu, u64 route)
+{
+ out_be64(&spu->priv1->int_route_RW, route);
+}
+EXPORT_SYMBOL_GPL(spu_int_route_set);
+
+u64 spu_mfc_dar_get(struct spu *spu)
+{
+ return in_be64(&spu->priv1->mfc_dar_RW);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_dar_get);
+
+u64 spu_mfc_dsisr_get(struct spu *spu)
+{
+ return in_be64(&spu->priv1->mfc_dsisr_RW);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_dsisr_get);
+
+void spu_mfc_dsisr_set(struct spu *spu, u64 dsisr)
+{
+ out_be64(&spu->priv1->mfc_dsisr_RW, dsisr);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_dsisr_set);
+
+void spu_mfc_sdr_set(struct spu *spu, u64 sdr)
+{
+ out_be64(&spu->priv1->mfc_sdr_RW, sdr);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_sdr_set);
+
+void spu_mfc_sr1_set(struct spu *spu, u64 sr1)
+{
+ out_be64(&spu->priv1->mfc_sr1_RW, sr1);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_sr1_set);
+
+u64 spu_mfc_sr1_get(struct spu *spu)
+{
+ return in_be64(&spu->priv1->mfc_sr1_RW);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_sr1_get);
+
+void spu_mfc_tclass_id_set(struct spu *spu, u64 tclass_id)
+{
+ out_be64(&spu->priv1->mfc_tclass_id_RW, tclass_id);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_tclass_id_set);
+
+u64 spu_mfc_tclass_id_get(struct spu *spu)
+{
+ return in_be64(&spu->priv1->mfc_tclass_id_RW);
+}
+EXPORT_SYMBOL_GPL(spu_mfc_tclass_id_get);
+
+void spu_tlb_invalidate(struct spu *spu)
+{
+ out_be64(&spu->priv1->tlb_invalidate_entry_W, 0ul);
+}
+EXPORT_SYMBOL_GPL(spu_tlb_invalidate);
+
+void spu_resource_allocation_groupID_set(struct spu *spu, u64 id)
+{
+ out_be64(&spu->priv1->resource_allocation_groupID_RW, id);
+}
+EXPORT_SYMBOL_GPL(spu_resource_allocation_groupID_set);
+
+u64 spu_resource_allocation_groupID_get(struct spu *spu)
+{
+ return in_be64(&spu->priv1->resource_allocation_groupID_RW);
+}
+EXPORT_SYMBOL_GPL(spu_resource_allocation_groupID_get);
+
+void spu_resource_allocation_enable_set(struct spu *spu, u64 enable)
+{
+ out_be64(&spu->priv1->resource_allocation_enable_RW, enable);
+}
+EXPORT_SYMBOL_GPL(spu_resource_allocation_enable_set);
+
+u64 spu_resource_allocation_enable_get(struct spu *spu)
+{
+ return in_be64(&spu->priv1->resource_allocation_enable_RW);
+}
+EXPORT_SYMBOL_GPL(spu_resource_allocation_enable_get);
diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c
new file mode 100644
index 000000000000..261b507a901a
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spu_syscalls.c
@@ -0,0 +1,88 @@
+/*
+ * SPU file system -- system call stubs
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.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, 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/file.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+
+#include <asm/spu.h>
+
+struct spufs_calls spufs_calls = {
+ .owner = NULL,
+};
+
+/* These stub syscalls are needed to have the actual implementation
+ * within a loadable module. When spufs is built into the kernel,
+ * this file is not used and the syscalls directly enter the fs code */
+
+asmlinkage long sys_spu_create(const char __user *name,
+ unsigned int flags, mode_t mode)
+{
+ long ret;
+ struct module *owner = spufs_calls.owner;
+
+ ret = -ENOSYS;
+ if (owner && try_module_get(owner)) {
+ ret = spufs_calls.create_thread(name, flags, mode);
+ module_put(owner);
+ }
+ return ret;
+}
+
+asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
+{
+ long ret;
+ struct file *filp;
+ int fput_needed;
+ struct module *owner = spufs_calls.owner;
+
+ ret = -ENOSYS;
+ if (owner && try_module_get(owner)) {
+ ret = -EBADF;
+ filp = fget_light(fd, &fput_needed);
+ if (filp) {
+ ret = spufs_calls.spu_run(filp, unpc, ustatus);
+ fput_light(filp, fput_needed);
+ }
+ module_put(owner);
+ }
+ return ret;
+}
+
+int register_spu_syscalls(struct spufs_calls *calls)
+{
+ if (spufs_calls.owner)
+ return -EBUSY;
+
+ spufs_calls.create_thread = calls->create_thread;
+ spufs_calls.spu_run = calls->spu_run;
+ smp_mb();
+ spufs_calls.owner = calls->owner;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(register_spu_syscalls);
+
+void unregister_spu_syscalls(struct spufs_calls *calls)
+{
+ BUG_ON(spufs_calls.owner != calls->owner);
+ spufs_calls.owner = NULL;
+}
+EXPORT_SYMBOL_GPL(unregister_spu_syscalls);
diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile
new file mode 100644
index 000000000000..a7cddf40e3d9
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/Makefile
@@ -0,0 +1,54 @@
+obj-$(CONFIG_SPU_FS) += spufs.o
+spufs-y += inode.o file.o context.o switch.o syscalls.o
+spufs-y += sched.o backing_ops.o hw_ops.o run.o
+
+# Rules to build switch.o with the help of SPU tool chain
+SPU_CROSS := spu-
+SPU_CC := $(SPU_CROSS)gcc
+SPU_AS := $(SPU_CROSS)gcc
+SPU_LD := $(SPU_CROSS)ld
+SPU_OBJCOPY := $(SPU_CROSS)objcopy
+SPU_CFLAGS := -O2 -Wall -I$(srctree)/include -I$(objtree)/include2
+SPU_AFLAGS := -c -D__ASSEMBLY__ -I$(srctree)/include -I$(objtree)/include2
+SPU_LDFLAGS := -N -Ttext=0x0
+
+$(obj)/switch.o: $(obj)/spu_save_dump.h $(obj)/spu_restore_dump.h
+
+# Compile SPU files
+ cmd_spu_cc = $(SPU_CC) $(SPU_CFLAGS) -c -o $@ $<
+quiet_cmd_spu_cc = SPU_CC $@
+$(obj)/spu_%.o: $(src)/spu_%.c
+ $(call if_changed,spu_cc)
+
+# Assemble SPU files
+ cmd_spu_as = $(SPU_AS) $(SPU_AFLAGS) -o $@ $<
+quiet_cmd_spu_as = SPU_AS $@
+$(obj)/spu_%.o: $(src)/spu_%.S
+ $(call if_changed,spu_as)
+
+# Link SPU Executables
+ cmd_spu_ld = $(SPU_LD) $(SPU_LDFLAGS) -o $@ $^
+quiet_cmd_spu_ld = SPU_LD $@
+$(obj)/spu_%: $(obj)/spu_%_crt0.o $(obj)/spu_%.o
+ $(call if_changed,spu_ld)
+
+# Copy into binary format
+ cmd_spu_objcopy = $(SPU_OBJCOPY) -O binary $< $@
+quiet_cmd_spu_objcopy = OBJCOPY $@
+$(obj)/spu_%.bin: $(src)/spu_%
+ $(call if_changed,spu_objcopy)
+
+# create C code from ELF executable
+cmd_hexdump = ( \
+ echo "/*" ; \
+ echo " * $*_dump.h: Copyright (C) 2005 IBM." ; \
+ echo " * Hex-dump auto generated from $*.c." ; \
+ echo " * Do not edit!" ; \
+ echo " */" ; \
+ echo "static unsigned int $*_code[] __page_aligned = {" ; \
+ hexdump -v -e '"0x" 4/1 "%02x" "," "\n"' $< ; \
+ echo "};" ; \
+ ) > $@
+quiet_cmd_hexdump = HEXDUMP $@
+$(obj)/%_dump.h: $(obj)/%.bin
+ $(call if_changed,hexdump)
diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c
new file mode 100644
index 000000000000..a5c489a53c61
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c
@@ -0,0 +1,308 @@
+/* backing_ops.c - query/set operations on saved SPU context.
+ *
+ * Copyright (C) IBM 2005
+ * Author: Mark Nutter <mnutter@us.ibm.com>
+ *
+ * These register operations allow SPUFS to operate on saved
+ * SPU contexts rather than hardware.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/poll.h>
+
+#include <asm/io.h>
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include <asm/mmu_context.h>
+#include "spufs.h"
+
+/*
+ * Reads/writes to various problem and priv2 registers require
+ * state changes, i.e. generate SPU events, modify channel
+ * counts, etc.
+ */
+
+static void gen_spu_event(struct spu_context *ctx, u32 event)
+{
+ u64 ch0_cnt;
+ u64 ch0_data;
+ u64 ch1_data;
+
+ ch0_cnt = ctx->csa.spu_chnlcnt_RW[0];
+ ch0_data = ctx->csa.spu_chnldata_RW[0];
+ ch1_data = ctx->csa.spu_chnldata_RW[1];
+ ctx->csa.spu_chnldata_RW[0] |= event;
+ if ((ch0_cnt == 0) && !(ch0_data & event) && (ch1_data & event)) {
+ ctx->csa.spu_chnlcnt_RW[0] = 1;
+ }
+}
+
+static int spu_backing_mbox_read(struct spu_context *ctx, u32 * data)
+{
+ u32 mbox_stat;
+ int ret = 0;
+
+ spin_lock(&ctx->csa.register_lock);
+ mbox_stat = ctx->csa.prob.mb_stat_R;
+ if (mbox_stat & 0x0000ff) {
+ /* Read the first available word.
+ * Implementation note: the depth
+ * of pu_mb_R is currently 1.
+ */
+ *data = ctx->csa.prob.pu_mb_R;
+ ctx->csa.prob.mb_stat_R &= ~(0x0000ff);
+ ctx->csa.spu_chnlcnt_RW[28] = 1;
+ gen_spu_event(ctx, MFC_PU_MAILBOX_AVAILABLE_EVENT);
+ ret = 4;
+ }
+ spin_unlock(&ctx->csa.register_lock);
+ return ret;
+}
+
+static u32 spu_backing_mbox_stat_read(struct spu_context *ctx)
+{
+ return ctx->csa.prob.mb_stat_R;
+}
+
+static unsigned int spu_backing_mbox_stat_poll(struct spu_context *ctx,
+ unsigned int events)
+{
+ int ret;
+ u32 stat;
+
+ ret = 0;
+ spin_lock_irq(&ctx->csa.register_lock);
+ stat = ctx->csa.prob.mb_stat_R;
+
+ /* if the requested event is there, return the poll
+ mask, otherwise enable the interrupt to get notified,
+ but first mark any pending interrupts as done so
+ we don't get woken up unnecessarily */
+
+ if (events & (POLLIN | POLLRDNORM)) {
+ if (stat & 0xff0000)
+ ret |= POLLIN | POLLRDNORM;
+ else {
+ ctx->csa.priv1.int_stat_class0_RW &= ~0x1;
+ ctx->csa.priv1.int_mask_class2_RW |= 0x1;
+ }
+ }
+ if (events & (POLLOUT | POLLWRNORM)) {
+ if (stat & 0x00ff00)
+ ret = POLLOUT | POLLWRNORM;
+ else {
+ ctx->csa.priv1.int_stat_class0_RW &= ~0x10;
+ ctx->csa.priv1.int_mask_class2_RW |= 0x10;
+ }
+ }
+ spin_unlock_irq(&ctx->csa.register_lock);
+ return ret;
+}
+
+static int spu_backing_ibox_read(struct spu_context *ctx, u32 * data)
+{
+ int ret;
+
+ spin_lock(&ctx->csa.register_lock);
+ if (ctx->csa.prob.mb_stat_R & 0xff0000) {
+ /* Read the first available word.
+ * Implementation note: the depth
+ * of puint_mb_R is currently 1.
+ */
+ *data = ctx->csa.priv2.puint_mb_R;
+ ctx->csa.prob.mb_stat_R &= ~(0xff0000);
+ ctx->csa.spu_chnlcnt_RW[30] = 1;
+ gen_spu_event(ctx, MFC_PU_INT_MAILBOX_AVAILABLE_EVENT);
+ ret = 4;
+ } else {
+ /* make sure we get woken up by the interrupt */
+ ctx->csa.priv1.int_mask_class2_RW |= 0x1UL;
+ ret = 0;
+ }
+ spin_unlock(&ctx->csa.register_lock);
+ return ret;
+}
+
+static int spu_backing_wbox_write(struct spu_context *ctx, u32 data)
+{
+ int ret;
+
+ spin_lock(&ctx->csa.register_lock);
+ if ((ctx->csa.prob.mb_stat_R) & 0x00ff00) {
+ int slot = ctx->csa.spu_chnlcnt_RW[29];
+ int avail = (ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8;
+
+ /* We have space to write wbox_data.
+ * Implementation note: the depth
+ * of spu_mb_W is currently 4.
+ */
+ BUG_ON(avail != (4 - slot));
+ ctx->csa.spu_mailbox_data[slot] = data;
+ ctx->csa.spu_chnlcnt_RW[29] = ++slot;
+ ctx->csa.prob.mb_stat_R = (((4 - slot) & 0xff) << 8);
+ gen_spu_event(ctx, MFC_SPU_MAILBOX_WRITTEN_EVENT);
+ ret = 4;
+ } else {
+ /* make sure we get woken up by the interrupt when space
+ becomes available */
+ ctx->csa.priv1.int_mask_class2_RW |= 0x10;
+ ret = 0;
+ }
+ spin_unlock(&ctx->csa.register_lock);
+ return ret;
+}
+
+static u32 spu_backing_signal1_read(struct spu_context *ctx)
+{
+ return ctx->csa.spu_chnldata_RW[3];
+}
+
+static void spu_backing_signal1_write(struct spu_context *ctx, u32 data)
+{
+ spin_lock(&ctx->csa.register_lock);
+ if (ctx->csa.priv2.spu_cfg_RW & 0x1)
+ ctx->csa.spu_chnldata_RW[3] |= data;
+ else
+ ctx->csa.spu_chnldata_RW[3] = data;
+ ctx->csa.spu_chnlcnt_RW[3] = 1;
+ gen_spu_event(ctx, MFC_SIGNAL_1_EVENT);
+ spin_unlock(&ctx->csa.register_lock);
+}
+
+static u32 spu_backing_signal2_read(struct spu_context *ctx)
+{
+ return ctx->csa.spu_chnldata_RW[4];
+}
+
+static void spu_backing_signal2_write(struct spu_context *ctx, u32 data)
+{
+ spin_lock(&ctx->csa.register_lock);
+ if (ctx->csa.priv2.spu_cfg_RW & 0x2)
+ ctx->csa.spu_chnldata_RW[4] |= data;
+ else
+ ctx->csa.spu_chnldata_RW[4] = data;
+ ctx->csa.spu_chnlcnt_RW[4] = 1;
+ gen_spu_event(ctx, MFC_SIGNAL_2_EVENT);
+ spin_unlock(&ctx->csa.register_lock);
+}
+
+static void spu_backing_signal1_type_set(struct spu_context *ctx, u64 val)
+{
+ u64 tmp;
+
+ spin_lock(&ctx->csa.register_lock);
+ tmp = ctx->csa.priv2.spu_cfg_RW;
+ if (val)
+ tmp |= 1;
+ else
+ tmp &= ~1;
+ ctx->csa.priv2.spu_cfg_RW = tmp;
+ spin_unlock(&ctx->csa.register_lock);
+}
+
+static u64 spu_backing_signal1_type_get(struct spu_context *ctx)
+{
+ return ((ctx->csa.priv2.spu_cfg_RW & 1) != 0);
+}
+
+static void spu_backing_signal2_type_set(struct spu_context *ctx, u64 val)
+{
+ u64 tmp;
+
+ spin_lock(&ctx->csa.register_lock);
+ tmp = ctx->csa.priv2.spu_cfg_RW;
+ if (val)
+ tmp |= 2;
+ else
+ tmp &= ~2;
+ ctx->csa.priv2.spu_cfg_RW = tmp;
+ spin_unlock(&ctx->csa.register_lock);
+}
+
+static u64 spu_backing_signal2_type_get(struct spu_context *ctx)
+{
+ return ((ctx->csa.priv2.spu_cfg_RW & 2) != 0);
+}
+
+static u32 spu_backing_npc_read(struct spu_context *ctx)
+{
+ return ctx->csa.prob.spu_npc_RW;
+}
+
+static void spu_backing_npc_write(struct spu_context *ctx, u32 val)
+{
+ ctx->csa.prob.spu_npc_RW = val;
+}
+
+static u32 spu_backing_status_read(struct spu_context *ctx)
+{
+ return ctx->csa.prob.spu_status_R;
+}
+
+static char *spu_backing_get_ls(struct spu_context *ctx)
+{
+ return ctx->csa.lscsa->ls;
+}
+
+static void spu_backing_runcntl_write(struct spu_context *ctx, u32 val)
+{
+ spin_lock(&ctx->csa.register_lock);
+ ctx->csa.prob.spu_runcntl_RW = val;
+ if (val & SPU_RUNCNTL_RUNNABLE) {
+ ctx->csa.prob.spu_status_R |= SPU_STATUS_RUNNING;
+ } else {
+ ctx->csa.prob.spu_status_R &= ~SPU_STATUS_RUNNING;
+ }
+ spin_unlock(&ctx->csa.register_lock);
+}
+
+static void spu_backing_runcntl_stop(struct spu_context *ctx)
+{
+ spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP);
+}
+
+struct spu_context_ops spu_backing_ops = {
+ .mbox_read = spu_backing_mbox_read,
+ .mbox_stat_read = spu_backing_mbox_stat_read,
+ .mbox_stat_poll = spu_backing_mbox_stat_poll,
+ .ibox_read = spu_backing_ibox_read,
+ .wbox_write = spu_backing_wbox_write,
+ .signal1_read = spu_backing_signal1_read,
+ .signal1_write = spu_backing_signal1_write,
+ .signal2_read = spu_backing_signal2_read,
+ .signal2_write = spu_backing_signal2_write,
+ .signal1_type_set = spu_backing_signal1_type_set,
+ .signal1_type_get = spu_backing_signal1_type_get,
+ .signal2_type_set = spu_backing_signal2_type_set,
+ .signal2_type_get = spu_backing_signal2_type_get,
+ .npc_read = spu_backing_npc_read,
+ .npc_write = spu_backing_npc_write,
+ .status_read = spu_backing_status_read,
+ .get_ls = spu_backing_get_ls,
+ .runcntl_write = spu_backing_runcntl_write,
+ .runcntl_stop = spu_backing_runcntl_stop,
+};
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
new file mode 100644
index 000000000000..336f238102fd
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -0,0 +1,167 @@
+/*
+ * SPU file system -- SPU context management
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.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, 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/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include "spufs.h"
+
+struct spu_context *alloc_spu_context(struct address_space *local_store)
+{
+ struct spu_context *ctx;
+ ctx = kmalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx)
+ goto out;
+ /* Binding to physical processor deferred
+ * until spu_activate().
+ */
+ spu_init_csa(&ctx->csa);
+ if (!ctx->csa.lscsa) {
+ goto out_free;
+ }
+ spin_lock_init(&ctx->mmio_lock);
+ kref_init(&ctx->kref);
+ init_rwsem(&ctx->state_sema);
+ init_MUTEX(&ctx->run_sema);
+ init_waitqueue_head(&ctx->ibox_wq);
+ init_waitqueue_head(&ctx->wbox_wq);
+ init_waitqueue_head(&ctx->stop_wq);
+ ctx->ibox_fasync = NULL;
+ ctx->wbox_fasync = NULL;
+ ctx->state = SPU_STATE_SAVED;
+ ctx->local_store = local_store;
+ ctx->spu = NULL;
+ ctx->ops = &spu_backing_ops;
+ ctx->owner = get_task_mm(current);
+ goto out;
+out_free:
+ kfree(ctx);
+ ctx = NULL;
+out:
+ return ctx;
+}
+
+void destroy_spu_context(struct kref *kref)
+{
+ struct spu_context *ctx;
+ ctx = container_of(kref, struct spu_context, kref);
+ down_write(&ctx->state_sema);
+ spu_deactivate(ctx);
+ ctx->ibox_fasync = NULL;
+ ctx->wbox_fasync = NULL;
+ up_write(&ctx->state_sema);
+ spu_fini_csa(&ctx->csa);
+ kfree(ctx);
+}
+
+struct spu_context * get_spu_context(struct spu_context *ctx)
+{
+ kref_get(&ctx->kref);
+ return ctx;
+}
+
+int put_spu_context(struct spu_context *ctx)
+{
+ return kref_put(&ctx->kref, &destroy_spu_context);
+}
+
+/* give up the mm reference when the context is about to be destroyed */
+void spu_forget(struct spu_context *ctx)
+{
+ struct mm_struct *mm;
+ spu_acquire_saved(ctx);
+ mm = ctx->owner;
+ ctx->owner = NULL;
+ mmput(mm);
+ spu_release(ctx);
+}
+
+void spu_acquire(struct spu_context *ctx)
+{
+ down_read(&ctx->state_sema);
+}
+
+void spu_release(struct spu_context *ctx)
+{
+ up_read(&ctx->state_sema);
+}
+
+void spu_unmap_mappings(struct spu_context *ctx)
+{
+ unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1);
+}
+
+int spu_acquire_runnable(struct spu_context *ctx)
+{
+ int ret = 0;
+
+ down_read(&ctx->state_sema);
+ if (ctx->state == SPU_STATE_RUNNABLE) {
+ ctx->spu->prio = current->prio;
+ return 0;
+ }
+ up_read(&ctx->state_sema);
+
+ down_write(&ctx->state_sema);
+ /* ctx is about to be freed, can't acquire any more */
+ if (!ctx->owner) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (ctx->state == SPU_STATE_SAVED) {
+ ret = spu_activate(ctx, 0);
+ if (ret)
+ goto out;
+ ctx->state = SPU_STATE_RUNNABLE;
+ }
+
+ downgrade_write(&ctx->state_sema);
+ /* On success, we return holding the lock */
+
+ return ret;
+out:
+ /* Release here, to simplify calling code. */
+ up_write(&ctx->state_sema);
+
+ return ret;
+}
+
+void spu_acquire_saved(struct spu_context *ctx)
+{
+ down_read(&ctx->state_sema);
+
+ if (ctx->state == SPU_STATE_SAVED)
+ return;
+
+ up_read(&ctx->state_sema);
+ down_write(&ctx->state_sema);
+
+ if (ctx->state == SPU_STATE_RUNNABLE) {
+ spu_deactivate(ctx);
+ ctx->state = SPU_STATE_SAVED;
+ }
+
+ downgrade_write(&ctx->state_sema);
+}
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
new file mode 100644
index 000000000000..dfa649c9b956
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -0,0 +1,794 @@
+/*
+ * SPU file system -- file contents
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.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, 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/fs.h>
+#include <linux/ioctl.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/poll.h>
+#include <linux/ptrace.h>
+
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <asm/spu.h>
+#include <asm/uaccess.h>
+
+#include "spufs.h"
+
+
+static int
+spufs_mem_open(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ file->private_data = i->i_ctx;
+ file->f_mapping = i->i_ctx->local_store;
+ return 0;
+}
+
+static ssize_t
+spufs_mem_read(struct file *file, char __user *buffer,
+ size_t size, loff_t *pos)
+{
+ struct spu_context *ctx = file->private_data;
+ char *local_store;
+ int ret;
+
+ spu_acquire(ctx);
+
+ local_store = ctx->ops->get_ls(ctx);
+ ret = simple_read_from_buffer(buffer, size, pos, local_store, LS_SIZE);
+
+ spu_release(ctx);
+ return ret;
+}
+
+static ssize_t
+spufs_mem_write(struct file *file, const char __user *buffer,
+ size_t size, loff_t *pos)
+{
+ struct spu_context *ctx = file->private_data;
+ char *local_store;
+ int ret;
+
+ size = min_t(ssize_t, LS_SIZE - *pos, size);
+ if (size <= 0)
+ return -EFBIG;
+ *pos += size;
+
+ spu_acquire(ctx);
+
+ local_store = ctx->ops->get_ls(ctx);
+ ret = copy_from_user(local_store + *pos - size,
+ buffer, size) ? -EFAULT : size;
+
+ spu_release(ctx);
+ return ret;
+}
+
+#ifdef CONFIG_SPARSEMEM
+static struct page *
+spufs_mem_mmap_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ struct page *page = NOPAGE_SIGBUS;
+
+ struct spu_context *ctx = vma->vm_file->private_data;
+ unsigned long offset = address - vma->vm_start;
+ offset += vma->vm_pgoff << PAGE_SHIFT;
+
+ spu_acquire(ctx);
+
+ if (ctx->state == SPU_STATE_SAVED)
+ page = vmalloc_to_page(ctx->csa.lscsa->ls + offset);
+ else
+ page = pfn_to_page((ctx->spu->local_store_phys + offset)
+ >> PAGE_SHIFT);
+
+ spu_release(ctx);
+
+ if (type)
+ *type = VM_FAULT_MINOR;
+
+ page_cache_get(page);
+ return page;
+}
+
+static struct vm_operations_struct spufs_mem_mmap_vmops = {
+ .nopage = spufs_mem_mmap_nopage,
+};
+
+static int
+spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ if (!(vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+
+ /* FIXME: */
+ vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+ | _PAGE_NO_CACHE);
+
+ vma->vm_ops = &spufs_mem_mmap_vmops;
+ return 0;
+}
+#endif
+
+static struct file_operations spufs_mem_fops = {
+ .open = spufs_mem_open,
+ .read = spufs_mem_read,
+ .write = spufs_mem_write,
+ .llseek = generic_file_llseek,
+#ifdef CONFIG_SPARSEMEM
+ .mmap = spufs_mem_mmap,
+#endif
+};
+
+static int
+spufs_regs_open(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ file->private_data = i->i_ctx;
+ return 0;
+}
+
+static ssize_t
+spufs_regs_read(struct file *file, char __user *buffer,
+ size_t size, loff_t *pos)
+{
+ struct spu_context *ctx = file->private_data;
+ struct spu_lscsa *lscsa = ctx->csa.lscsa;
+ int ret;
+
+ spu_acquire_saved(ctx);
+
+ ret = simple_read_from_buffer(buffer, size, pos,
+ lscsa->gprs, sizeof lscsa->gprs);
+
+ spu_release(ctx);
+ return ret;
+}
+
+static ssize_t
+spufs_regs_write(struct file *file, const char __user *buffer,
+ size_t size, loff_t *pos)
+{
+ struct spu_context *ctx = file->private_data;
+ struct spu_lscsa *lscsa = ctx->csa.lscsa;
+ int ret;
+
+ size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size);
+ if (size <= 0)
+ return -EFBIG;
+ *pos += size;
+
+ spu_acquire_saved(ctx);
+
+ ret = copy_from_user(lscsa->gprs + *pos - size,
+ buffer, size) ? -EFAULT : size;
+
+ spu_release(ctx);
+ return ret;
+}
+
+static struct file_operations spufs_regs_fops = {
+ .open = spufs_regs_open,
+ .read = spufs_regs_read,
+ .write = spufs_regs_write,
+ .llseek = generic_file_llseek,
+};
+
+static ssize_t
+spufs_fpcr_read(struct file *file, char __user * buffer,
+ size_t size, loff_t * pos)
+{
+ struct spu_context *ctx = file->private_data;
+ struct spu_lscsa *lscsa = ctx->csa.lscsa;
+ int ret;
+
+ spu_acquire_saved(ctx);
+
+ ret = simple_read_from_buffer(buffer, size, pos,
+ &lscsa->fpcr, sizeof(lscsa->fpcr));
+
+ spu_release(ctx);
+ return ret;
+}
+
+static ssize_t
+spufs_fpcr_write(struct file *file, const char __user * buffer,
+ size_t size, loff_t * pos)
+{
+ struct spu_context *ctx = file->private_data;
+ struct spu_lscsa *lscsa = ctx->csa.lscsa;
+ int ret;
+
+ size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size);
+ if (size <= 0)
+ return -EFBIG;
+ *pos += size;
+
+ spu_acquire_saved(ctx);
+
+ ret = copy_from_user((char *)&lscsa->fpcr + *pos - size,
+ buffer, size) ? -EFAULT : size;
+
+ spu_release(ctx);
+ return ret;
+}
+
+static struct file_operations spufs_fpcr_fops = {
+ .open = spufs_regs_open,
+ .read = spufs_fpcr_read,
+ .write = spufs_fpcr_write,
+ .llseek = generic_file_llseek,
+};
+
+/* generic open function for all pipe-like files */
+static int spufs_pipe_open(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ file->private_data = i->i_ctx;
+
+ return nonseekable_open(inode, file);
+}
+
+static ssize_t spufs_mbox_read(struct file *file, char __user *buf,
+ size_t len, loff_t *pos)
+{
+ struct spu_context *ctx = file->private_data;
+ u32 mbox_data;
+ int ret;
+
+ if (len < 4)
+ return -EINVAL;
+
+ spu_acquire(ctx);
+ ret = ctx->ops->mbox_read(ctx, &mbox_data);
+ spu_release(ctx);
+
+ if (!ret)
+ return -EAGAIN;
+
+ if (copy_to_user(buf, &mbox_data, sizeof mbox_data))
+ return -EFAULT;
+
+ return 4;
+}
+
+static struct file_operations spufs_mbox_fops = {
+ .open = spufs_pipe_open,
+ .read = spufs_mbox_read,
+};
+
+static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf,
+ size_t len, loff_t *pos)
+{
+ struct spu_context *ctx = file->private_data;
+ u32 mbox_stat;
+
+ if (len < 4)
+ return -EINVAL;
+
+ spu_acquire(ctx);
+
+ mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff;
+
+ spu_release(ctx);
+
+ if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat))
+ return -EFAULT;
+
+ return 4;
+}
+
+static struct file_operations spufs_mbox_stat_fops = {
+ .open = spufs_pipe_open,
+ .read = spufs_mbox_stat_read,
+};
+
+/* low-level ibox access function */
+size_t spu_ibox_read(struct spu_context *ctx, u32 *data)
+{
+ return ctx->ops->ibox_read(ctx, data);
+}
+
+static int spufs_ibox_fasync(int fd, struct file *file, int on)
+{
+ struct spu_context *ctx = file->private_data;
+
+ return fasync_helper(fd, file, on, &ctx->ibox_fasync);
+}
+
+/* interrupt-level ibox callback function. */
+void spufs_ibox_callback(struct spu *spu)
+{
+ struct spu_context *ctx = spu->ctx;
+
+ wake_up_all(&ctx->ibox_wq);
+ kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN);
+}
+
+static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
+ size_t len, loff_t *pos)
+{
+ struct spu_context *ctx = file->private_data;
+ u32 ibox_data;
+ ssize_t ret;
+
+ if (len < 4)
+ return -EINVAL;
+
+ spu_acquire(ctx);
+
+ ret = 0;
+ if (file->f_flags & O_NONBLOCK) {
+ if (!spu_ibox_read(ctx, &ibox_data))
+ ret = -EAGAIN;
+ } else {
+ ret = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data));
+ }
+
+ spu_release(ctx);
+
+ if (ret)
+ return ret;
+
+ ret = 4;
+ if (copy_to_user(buf, &ibox_data, sizeof ibox_data))
+ ret = -EFAULT;
+
+ return ret;
+}
+
+static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait)
+{
+ struct spu_context *ctx = file->private_data;
+ unsigned int mask;
+
+ poll_wait(file, &ctx->ibox_wq, wait);
+
+ spu_acquire(ctx);
+ mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM);
+ spu_release(ctx);
+
+ return mask;
+}
+
+static struct file_operations spufs_ibox_fops = {
+ .open = spufs_pipe_open,
+ .read = spufs_ibox_read,
+ .poll = spufs_ibox_poll,
+ .fasync = spufs_ibox_fasync,
+};
+
+static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf,
+ size_t len, loff_t *pos)
+{
+ struct spu_context *ctx = file->private_data;
+ u32 ibox_stat;
+
+ if (len < 4)
+ return -EINVAL;
+
+ spu_acquire(ctx);
+ ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff;
+ spu_release(ctx);
+
+ if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat))
+ return -EFAULT;
+
+ return 4;
+}
+
+static struct file_operations spufs_ibox_stat_fops = {
+ .open = spufs_pipe_open,
+ .read = spufs_ibox_stat_read,
+};
+
+/* low-level mailbox write */
+size_t spu_wbox_write(struct spu_context *ctx, u32 data)
+{
+ return ctx->ops->wbox_write(ctx, data);
+}
+
+static int spufs_wbox_fasync(int fd, struct file *file, int on)
+{
+ struct spu_context *ctx = file->private_data;
+ int ret;
+
+ ret = fasync_helper(fd, file, on, &ctx->wbox_fasync);
+
+ return ret;
+}
+
+/* interrupt-level wbox callback function. */
+void spufs_wbox_callback(struct spu *spu)
+{
+ struct spu_context *ctx = spu->ctx;
+
+ wake_up_all(&ctx->wbox_wq);
+ kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT);
+}
+
+static ssize_t spufs_wbox_write(struct file *file, const char __user *buf,
+ size_t len, loff_t *pos)
+{
+ struct spu_context *ctx = file->private_data;
+ u32 wbox_data;
+ int ret;
+
+ if (len < 4)
+ return -EINVAL;
+
+ if (copy_from_user(&wbox_data, buf, sizeof wbox_data))
+ return -EFAULT;
+
+ spu_acquire(ctx);
+
+ ret = 0;
+ if (file->f_flags & O_NONBLOCK) {
+ if (!spu_wbox_write(ctx, wbox_data))
+ ret = -EAGAIN;
+ } else {
+ ret = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data));
+ }
+
+ spu_release(ctx);
+
+ return ret ? ret : sizeof wbox_data;
+}
+
+static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait)
+{
+ struct spu_context *ctx = file->private_data;
+ unsigned int mask;
+
+ poll_wait(file, &ctx->wbox_wq, wait);
+
+ spu_acquire(ctx);
+ mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM);
+ spu_release(ctx);
+
+ return mask;
+}
+
+static struct file_operations spufs_wbox_fops = {
+ .open = spufs_pipe_open,
+ .write = spufs_wbox_write,
+ .poll = spufs_wbox_poll,
+ .fasync = spufs_wbox_fasync,
+};
+
+static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf,
+ size_t len, loff_t *pos)
+{
+ struct spu_context *ctx = file->private_data;
+ u32 wbox_stat;
+
+ if (len < 4)
+ return -EINVAL;
+
+ spu_acquire(ctx);
+ wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff;
+ spu_release(ctx);
+
+ if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat))
+ return -EFAULT;
+
+ return 4;
+}
+
+static struct file_operations spufs_wbox_stat_fops = {
+ .open = spufs_pipe_open,
+ .read = spufs_wbox_stat_read,
+};
+
+static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
+ size_t len, loff_t *pos)
+{
+ struct spu_context *ctx = file->private_data;
+ u32 data;
+
+ if (len < 4)
+ return -EINVAL;
+
+ spu_acquire(ctx);
+ data = ctx->ops->signal1_read(ctx);
+ spu_release(ctx);
+
+ if (copy_to_user(buf, &data, 4))
+ return -EFAULT;
+
+ return 4;
+}
+
+static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
+ size_t len, loff_t *pos)
+{
+ struct spu_context *ctx;
+ u32 data;
+
+ ctx = file->private_data;
+
+ if (len < 4)
+ return -EINVAL;
+
+ if (copy_from_user(&data, buf, 4))
+ return -EFAULT;
+
+ spu_acquire(ctx);
+ ctx->ops->signal1_write(ctx, data);
+ spu_release(ctx);
+
+ return 4;
+}
+
+static struct file_operations spufs_signal1_fops = {
+ .open = spufs_pipe_open,
+ .read = spufs_signal1_read,
+ .write = spufs_signal1_write,
+};
+
+static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
+ size_t len, loff_t *pos)
+{
+ struct spu_context *ctx;
+ u32 data;
+
+ ctx = file->private_data;
+
+ if (len < 4)
+ return -EINVAL;
+
+ spu_acquire(ctx);
+ data = ctx->ops->signal2_read(ctx);
+ spu_release(ctx);
+
+ if (copy_to_user(buf, &data, 4))
+ return -EFAULT;
+
+ return 4;
+}
+
+static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
+ size_t len, loff_t *pos)
+{
+ struct spu_context *ctx;
+ u32 data;
+
+ ctx = file->private_data;
+
+ if (len < 4)
+ return -EINVAL;
+
+ if (copy_from_user(&data, buf, 4))
+ return -EFAULT;
+
+ spu_acquire(ctx);
+ ctx->ops->signal2_write(ctx, data);
+ spu_release(ctx);
+
+ return 4;
+}
+
+static struct file_operations spufs_signal2_fops = {
+ .open = spufs_pipe_open,
+ .read = spufs_signal2_read,
+ .write = spufs_signal2_write,
+};
+
+static void spufs_signal1_type_set(void *data, u64 val)
+{
+ struct spu_context *ctx = data;
+
+ spu_acquire(ctx);
+ ctx->ops->signal1_type_set(ctx, val);
+ spu_release(ctx);
+}
+
+static u64 spufs_signal1_type_get(void *data)
+{
+ struct spu_context *ctx = data;
+ u64 ret;
+
+ spu_acquire(ctx);
+ ret = ctx->ops->signal1_type_get(ctx);
+ spu_release(ctx);
+
+ return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get,
+ spufs_signal1_type_set, "%llu");
+
+static void spufs_signal2_type_set(void *data, u64 val)
+{
+ struct spu_context *ctx = data;
+
+ spu_acquire(ctx);
+ ctx->ops->signal2_type_set(ctx, val);
+ spu_release(ctx);
+}
+
+static u64 spufs_signal2_type_get(void *data)
+{
+ struct spu_context *ctx = data;
+ u64 ret;
+
+ spu_acquire(ctx);
+ ret = ctx->ops->signal2_type_get(ctx);
+ spu_release(ctx);
+
+ return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
+ spufs_signal2_type_set, "%llu");
+
+static void spufs_npc_set(void *data, u64 val)
+{
+ struct spu_context *ctx = data;
+ spu_acquire(ctx);
+ ctx->ops->npc_write(ctx, val);
+ spu_release(ctx);
+}
+
+static u64 spufs_npc_get(void *data)
+{
+ struct spu_context *ctx = data;
+ u64 ret;
+ spu_acquire(ctx);
+ ret = ctx->ops->npc_read(ctx);
+ spu_release(ctx);
+ return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n")
+
+static void spufs_decr_set(void *data, u64 val)
+{
+ struct spu_context *ctx = data;
+ struct spu_lscsa *lscsa = ctx->csa.lscsa;
+ spu_acquire_saved(ctx);
+ lscsa->decr.slot[0] = (u32) val;
+ spu_release(ctx);
+}
+
+static u64 spufs_decr_get(void *data)
+{
+ struct spu_context *ctx = data;
+ struct spu_lscsa *lscsa = ctx->csa.lscsa;
+ u64 ret;
+ spu_acquire_saved(ctx);
+ ret = lscsa->decr.slot[0];
+ spu_release(ctx);
+ return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
+ "%llx\n")
+
+static void spufs_decr_status_set(void *data, u64 val)
+{
+ struct spu_context *ctx = data;
+ struct spu_lscsa *lscsa = ctx->csa.lscsa;
+ spu_acquire_saved(ctx);
+ lscsa->decr_status.slot[0] = (u32) val;
+ spu_release(ctx);
+}
+
+static u64 spufs_decr_status_get(void *data)
+{
+ struct spu_context *ctx = data;
+ struct spu_lscsa *lscsa = ctx->csa.lscsa;
+ u64 ret;
+ spu_acquire_saved(ctx);
+ ret = lscsa->decr_status.slot[0];
+ spu_release(ctx);
+ return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
+ spufs_decr_status_set, "%llx\n")
+
+static void spufs_spu_tag_mask_set(void *data, u64 val)
+{
+ struct spu_context *ctx = data;
+ struct spu_lscsa *lscsa = ctx->csa.lscsa;
+ spu_acquire_saved(ctx);
+ lscsa->tag_mask.slot[0] = (u32) val;
+ spu_release(ctx);
+}
+
+static u64 spufs_spu_tag_mask_get(void *data)
+{
+ struct spu_context *ctx = data;
+ struct spu_lscsa *lscsa = ctx->csa.lscsa;
+ u64 ret;
+ spu_acquire_saved(ctx);
+ ret = lscsa->tag_mask.slot[0];
+ spu_release(ctx);
+ return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_spu_tag_mask_ops, spufs_spu_tag_mask_get,
+ spufs_spu_tag_mask_set, "%llx\n")
+
+static void spufs_event_mask_set(void *data, u64 val)
+{
+ struct spu_context *ctx = data;
+ struct spu_lscsa *lscsa = ctx->csa.lscsa;
+ spu_acquire_saved(ctx);
+ lscsa->event_mask.slot[0] = (u32) val;
+ spu_release(ctx);
+}
+
+static u64 spufs_event_mask_get(void *data)
+{
+ struct spu_context *ctx = data;
+ struct spu_lscsa *lscsa = ctx->csa.lscsa;
+ u64 ret;
+ spu_acquire_saved(ctx);
+ ret = lscsa->event_mask.slot[0];
+ spu_release(ctx);
+ return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
+ spufs_event_mask_set, "%llx\n")
+
+static void spufs_srr0_set(void *data, u64 val)
+{
+ struct spu_context *ctx = data;
+ struct spu_lscsa *lscsa = ctx->csa.lscsa;
+ spu_acquire_saved(ctx);
+ lscsa->srr0.slot[0] = (u32) val;
+ spu_release(ctx);
+}
+
+static u64 spufs_srr0_get(void *data)
+{
+ struct spu_context *ctx = data;
+ struct spu_lscsa *lscsa = ctx->csa.lscsa;
+ u64 ret;
+ spu_acquire_saved(ctx);
+ ret = lscsa->srr0.slot[0];
+ spu_release(ctx);
+ return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
+ "%llx\n")
+
+struct tree_descr spufs_dir_contents[] = {
+ { "mem", &spufs_mem_fops, 0666, },
+ { "regs", &spufs_regs_fops, 0666, },
+ { "mbox", &spufs_mbox_fops, 0444, },
+ { "ibox", &spufs_ibox_fops, 0444, },
+ { "wbox", &spufs_wbox_fops, 0222, },
+ { "mbox_stat", &spufs_mbox_stat_fops, 0444, },
+ { "ibox_stat", &spufs_ibox_stat_fops, 0444, },
+ { "wbox_stat", &spufs_wbox_stat_fops, 0444, },
+ { "signal1", &spufs_signal1_fops, 0666, },
+ { "signal2", &spufs_signal2_fops, 0666, },
+ { "signal1_type", &spufs_signal1_type, 0666, },
+ { "signal2_type", &spufs_signal2_type, 0666, },
+ { "npc", &spufs_npc_ops, 0666, },
+ { "fpcr", &spufs_fpcr_fops, 0666, },
+ { "decr", &spufs_decr_ops, 0666, },
+ { "decr_status", &spufs_decr_status_ops, 0666, },
+ { "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, },
+ { "event_mask", &spufs_event_mask_ops, 0666, },
+ { "srr0", &spufs_srr0_ops, 0666, },
+ {},
+};
diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c
new file mode 100644
index 000000000000..5445719bff79
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c
@@ -0,0 +1,255 @@
+/* hw_ops.c - query/set operations on active SPU context.
+ *
+ * Copyright (C) IBM 2005
+ * Author: Mark Nutter <mnutter@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, 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/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+
+#include <asm/io.h>
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include <asm/mmu_context.h>
+#include "spufs.h"
+
+static int spu_hw_mbox_read(struct spu_context *ctx, u32 * data)
+{
+ struct spu *spu = ctx->spu;
+ struct spu_problem __iomem *prob = spu->problem;
+ u32 mbox_stat;
+ int ret = 0;
+
+ spin_lock_irq(&spu->register_lock);
+ mbox_stat = in_be32(&prob->mb_stat_R);
+ if (mbox_stat & 0x0000ff) {
+ *data = in_be32(&prob->pu_mb_R);
+ ret = 4;
+ }
+ spin_unlock_irq(&spu->register_lock);
+ return ret;
+}
+
+static u32 spu_hw_mbox_stat_read(struct spu_context *ctx)
+{
+ return in_be32(&ctx->spu->problem->mb_stat_R);
+}
+
+static unsigned int spu_hw_mbox_stat_poll(struct spu_context *ctx,
+ unsigned int events)
+{
+ struct spu *spu = ctx->spu;
+ int ret = 0;
+ u32 stat;
+
+ spin_lock_irq(&spu->register_lock);
+ stat = in_be32(&spu->problem->mb_stat_R);
+
+ /* if the requested event is there, return the poll
+ mask, otherwise enable the interrupt to get notified,
+ but first mark any pending interrupts as done so
+ we don't get woken up unnecessarily */
+
+ if (events & (POLLIN | POLLRDNORM)) {
+ if (stat & 0xff0000)
+ ret |= POLLIN | POLLRDNORM;
+ else {
+ spu_int_stat_clear(spu, 2, 0x1);
+ spu_int_mask_or(spu, 2, 0x1);
+ }
+ }
+ if (events & (POLLOUT | POLLWRNORM)) {
+ if (stat & 0x00ff00)
+ ret = POLLOUT | POLLWRNORM;
+ else {
+ spu_int_stat_clear(spu, 2, 0x10);
+ spu_int_mask_or(spu, 2, 0x10);
+ }
+ }
+ spin_unlock_irq(&spu->register_lock);
+ return ret;
+}
+
+static int spu_hw_ibox_read(struct spu_context *ctx, u32 * data)
+{
+ struct spu *spu = ctx->spu;
+ struct spu_problem __iomem *prob = spu->problem;
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+ int ret;
+
+ spin_lock_irq(&spu->register_lock);
+ if (in_be32(&prob->mb_stat_R) & 0xff0000) {
+ /* read the first available word */
+ *data = in_be64(&priv2->puint_mb_R);
+ ret = 4;
+ } else {
+ /* make sure we get woken up by the interrupt */
+ spu_int_mask_or(spu, 2, 0x1);
+ ret = 0;
+ }
+ spin_unlock_irq(&spu->register_lock);
+ return ret;
+}
+
+static int spu_hw_wbox_write(struct spu_context *ctx, u32 data)
+{
+ struct spu *spu = ctx->spu;
+ struct spu_problem __iomem *prob = spu->problem;
+ int ret;
+
+ spin_lock_irq(&spu->register_lock);
+ if (in_be32(&prob->mb_stat_R) & 0x00ff00) {
+ /* we have space to write wbox_data to */
+ out_be32(&prob->spu_mb_W, data);
+ ret = 4;
+ } else {
+ /* make sure we get woken up by the interrupt when space
+ becomes available */
+ spu_int_mask_or(spu, 2, 0x10);
+ ret = 0;
+ }
+ spin_unlock_irq(&spu->register_lock);
+ return ret;
+}
+
+static u32 spu_hw_signal1_read(struct spu_context *ctx)
+{
+ return in_be32(&ctx->spu->problem->signal_notify1);
+}
+
+static void spu_hw_signal1_write(struct spu_context *ctx, u32 data)
+{
+ out_be32(&ctx->spu->problem->signal_notify1, data);
+}
+
+static u32 spu_hw_signal2_read(struct spu_context *ctx)
+{
+ return in_be32(&ctx->spu->problem->signal_notify1);
+}
+
+static void spu_hw_signal2_write(struct spu_context *ctx, u32 data)
+{
+ out_be32(&ctx->spu->problem->signal_notify2, data);
+}
+
+static void spu_hw_signal1_type_set(struct spu_context *ctx, u64 val)
+{
+ struct spu *spu = ctx->spu;
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+ u64 tmp;
+
+ spin_lock_irq(&spu->register_lock);
+ tmp = in_be64(&priv2->spu_cfg_RW);
+ if (val)
+ tmp |= 1;
+ else
+ tmp &= ~1;
+ out_be64(&priv2->spu_cfg_RW, tmp);
+ spin_unlock_irq(&spu->register_lock);
+}
+
+static u64 spu_hw_signal1_type_get(struct spu_context *ctx)
+{
+ return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0);
+}
+
+static void spu_hw_signal2_type_set(struct spu_context *ctx, u64 val)
+{
+ struct spu *spu = ctx->spu;
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+ u64 tmp;
+
+ spin_lock_irq(&spu->register_lock);
+ tmp = in_be64(&priv2->spu_cfg_RW);
+ if (val)
+ tmp |= 2;
+ else
+ tmp &= ~2;
+ out_be64(&priv2->spu_cfg_RW, tmp);
+ spin_unlock_irq(&spu->register_lock);
+}
+
+static u64 spu_hw_signal2_type_get(struct spu_context *ctx)
+{
+ return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0);
+}
+
+static u32 spu_hw_npc_read(struct spu_context *ctx)
+{
+ return in_be32(&ctx->spu->problem->spu_npc_RW);
+}
+
+static void spu_hw_npc_write(struct spu_context *ctx, u32 val)
+{
+ out_be32(&ctx->spu->problem->spu_npc_RW, val);
+}
+
+static u32 spu_hw_status_read(struct spu_context *ctx)
+{
+ return in_be32(&ctx->spu->problem->spu_status_R);
+}
+
+static char *spu_hw_get_ls(struct spu_context *ctx)
+{
+ return ctx->spu->local_store;
+}
+
+static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val)
+{
+ eieio();
+ out_be32(&ctx->spu->problem->spu_runcntl_RW, val);
+}
+
+static void spu_hw_runcntl_stop(struct spu_context *ctx)
+{
+ spin_lock_irq(&ctx->spu->register_lock);
+ out_be32(&ctx->spu->problem->spu_runcntl_RW, SPU_RUNCNTL_STOP);
+ while (in_be32(&ctx->spu->problem->spu_status_R) & SPU_STATUS_RUNNING)
+ cpu_relax();
+ spin_unlock_irq(&ctx->spu->register_lock);
+}
+
+struct spu_context_ops spu_hw_ops = {
+ .mbox_read = spu_hw_mbox_read,
+ .mbox_stat_read = spu_hw_mbox_stat_read,
+ .mbox_stat_poll = spu_hw_mbox_stat_poll,
+ .ibox_read = spu_hw_ibox_read,
+ .wbox_write = spu_hw_wbox_write,
+ .signal1_read = spu_hw_signal1_read,
+ .signal1_write = spu_hw_signal1_write,
+ .signal2_read = spu_hw_signal2_read,
+ .signal2_write = spu_hw_signal2_write,
+ .signal1_type_set = spu_hw_signal1_type_set,
+ .signal1_type_get = spu_hw_signal1_type_get,
+ .signal2_type_set = spu_hw_signal2_type_set,
+ .signal2_type_get = spu_hw_signal2_type_get,
+ .npc_read = spu_hw_npc_read,
+ .npc_write = spu_hw_npc_write,
+ .status_read = spu_hw_status_read,
+ .get_ls = spu_hw_get_ls,
+ .runcntl_write = spu_hw_runcntl_write,
+ .runcntl_stop = spu_hw_runcntl_stop,
+};
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
new file mode 100644
index 000000000000..1f3507c75e90
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -0,0 +1,486 @@
+/*
+ * SPU file system
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.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, 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/file.h>
+#include <linux/fs.h>
+#include <linux/backing-dev.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/module.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/pagemap.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/parser.h>
+
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <asm/spu.h>
+#include <asm/uaccess.h>
+
+#include "spufs.h"
+
+static kmem_cache_t *spufs_inode_cache;
+
+static struct inode *
+spufs_alloc_inode(struct super_block *sb)
+{
+ struct spufs_inode_info *ei;
+
+ ei = kmem_cache_alloc(spufs_inode_cache, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void
+spufs_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(spufs_inode_cache, SPUFS_I(inode));
+}
+
+static void
+spufs_init_once(void *p, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct spufs_inode_info *ei = p;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR) {
+ inode_init_once(&ei->vfs_inode);
+ }
+}
+
+static struct inode *
+spufs_new_inode(struct super_block *sb, int mode)
+{
+ struct inode *inode;
+
+ inode = new_inode(sb);
+ if (!inode)
+ goto out;
+
+ inode->i_mode = mode;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+ inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+out:
+ return inode;
+}
+
+static int
+spufs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct inode *inode = dentry->d_inode;
+
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ (attr->ia_size != inode->i_size))
+ return -EINVAL;
+ return inode_setattr(inode, attr);
+}
+
+
+static int
+spufs_new_file(struct super_block *sb, struct dentry *dentry,
+ struct file_operations *fops, int mode,
+ struct spu_context *ctx)
+{
+ static struct inode_operations spufs_file_iops = {
+ .setattr = spufs_setattr,
+ };
+ struct inode *inode;
+ int ret;
+
+ ret = -ENOSPC;
+ inode = spufs_new_inode(sb, S_IFREG | mode);
+ if (!inode)
+ goto out;
+
+ ret = 0;
+ inode->i_op = &spufs_file_iops;
+ inode->i_fop = fops;
+ inode->u.generic_ip = SPUFS_I(inode)->i_ctx = get_spu_context(ctx);
+ d_add(dentry, inode);
+out:
+ return ret;
+}
+
+static void
+spufs_delete_inode(struct inode *inode)
+{
+ if (SPUFS_I(inode)->i_ctx)
+ put_spu_context(SPUFS_I(inode)->i_ctx);
+ clear_inode(inode);
+}
+
+static void spufs_prune_dir(struct dentry *dir)
+{
+ struct dentry *dentry, *tmp;
+ down(&dir->d_inode->i_sem);
+ list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) {
+ spin_lock(&dcache_lock);
+ spin_lock(&dentry->d_lock);
+ if (!(d_unhashed(dentry)) && dentry->d_inode) {
+ dget_locked(dentry);
+ __d_drop(dentry);
+ spin_unlock(&dentry->d_lock);
+ simple_unlink(dir->d_inode, dentry);
+ spin_unlock(&dcache_lock);
+ dput(dentry);
+ } else {
+ spin_unlock(&dentry->d_lock);
+ spin_unlock(&dcache_lock);
+ }
+ }
+ shrink_dcache_parent(dir);
+ up(&dir->d_inode->i_sem);
+}
+
+static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
+{
+ struct spu_context *ctx;
+
+ /* remove all entries */
+ down(&root->i_sem);
+ spufs_prune_dir(dir_dentry);
+ up(&root->i_sem);
+
+ /* We have to give up the mm_struct */
+ ctx = SPUFS_I(dir_dentry->d_inode)->i_ctx;
+ spu_forget(ctx);
+
+ /* XXX Do we need to hold i_sem here ? */
+ return simple_rmdir(root, dir_dentry);
+}
+
+static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files,
+ int mode, struct spu_context *ctx)
+{
+ struct dentry *dentry;
+ int ret;
+
+ while (files->name && files->name[0]) {
+ ret = -ENOMEM;
+ dentry = d_alloc_name(dir, files->name);
+ if (!dentry)
+ goto out;
+ ret = spufs_new_file(dir->d_sb, dentry, files->ops,
+ files->mode & mode, ctx);
+ if (ret)
+ goto out;
+ files++;
+ }
+ return 0;
+out:
+ spufs_prune_dir(dir);
+ return ret;
+}
+
+static int spufs_dir_close(struct inode *inode, struct file *file)
+{
+ struct inode *dir;
+ struct dentry *dentry;
+ int ret;
+
+ dentry = file->f_dentry;
+ dir = dentry->d_parent->d_inode;
+
+ ret = spufs_rmdir(dir, dentry);
+ WARN_ON(ret);
+
+ return dcache_dir_close(inode, file);
+}
+
+struct inode_operations spufs_dir_inode_operations = {
+ .lookup = simple_lookup,
+};
+
+struct file_operations spufs_context_fops = {
+ .open = dcache_dir_open,
+ .release = spufs_dir_close,
+ .llseek = dcache_dir_lseek,
+ .read = generic_read_dir,
+ .readdir = dcache_readdir,
+ .fsync = simple_sync_file,
+};
+
+static int
+spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+ int ret;
+ struct inode *inode;
+ struct spu_context *ctx;
+
+ ret = -ENOSPC;
+ inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
+ if (!inode)
+ goto out;
+
+ if (dir->i_mode & S_ISGID) {
+ inode->i_gid = dir->i_gid;
+ inode->i_mode &= S_ISGID;
+ }
+ ctx = alloc_spu_context(inode->i_mapping);
+ SPUFS_I(inode)->i_ctx = ctx;
+ if (!ctx)
+ goto out_iput;
+
+ inode->i_op = &spufs_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+ ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);
+ if (ret)
+ goto out_free_ctx;
+
+ d_instantiate(dentry, inode);
+ dget(dentry);
+ dir->i_nlink++;
+ dentry->d_inode->i_nlink++;
+ goto out;
+
+out_free_ctx:
+ put_spu_context(ctx);
+out_iput:
+ iput(inode);
+out:
+ return ret;
+}
+
+static int spufs_context_open(struct dentry *dentry, struct vfsmount *mnt)
+{
+ int ret;
+ struct file *filp;
+
+ ret = get_unused_fd();
+ if (ret < 0) {
+ dput(dentry);
+ mntput(mnt);
+ goto out;
+ }
+
+ filp = dentry_open(dentry, mnt, O_RDONLY);
+ if (IS_ERR(filp)) {
+ put_unused_fd(ret);
+ ret = PTR_ERR(filp);
+ goto out;
+ }
+
+ filp->f_op = &spufs_context_fops;
+ fd_install(ret, filp);
+out:
+ return ret;
+}
+
+static struct file_system_type spufs_type;
+
+long spufs_create_thread(struct nameidata *nd,
+ unsigned int flags, mode_t mode)
+{
+ struct dentry *dentry;
+ int ret;
+
+ /* need to be at the root of spufs */
+ ret = -EINVAL;
+ if (nd->dentry->d_sb->s_type != &spufs_type ||
+ nd->dentry != nd->dentry->d_sb->s_root)
+ goto out;
+
+ dentry = lookup_create(nd, 1);
+ ret = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ goto out_dir;
+
+ ret = -EEXIST;
+ if (dentry->d_inode)
+ goto out_dput;
+
+ mode &= ~current->fs->umask;
+ ret = spufs_mkdir(nd->dentry->d_inode, dentry, mode & S_IRWXUGO);
+ if (ret)
+ goto out_dput;
+
+ /*
+ * get references for dget and mntget, will be released
+ * in error path of *_open().
+ */
+ ret = spufs_context_open(dget(dentry), mntget(nd->mnt));
+ if (ret < 0)
+ spufs_rmdir(nd->dentry->d_inode, dentry);
+
+out_dput:
+ dput(dentry);
+out_dir:
+ up(&nd->dentry->d_inode->i_sem);
+out:
+ return ret;
+}
+
+/* File system initialization */
+enum {
+ Opt_uid, Opt_gid, Opt_err,
+};
+
+static match_table_t spufs_tokens = {
+ { Opt_uid, "uid=%d" },
+ { Opt_gid, "gid=%d" },
+ { Opt_err, NULL },
+};
+
+static int
+spufs_parse_options(char *options, struct inode *root)
+{
+ char *p;
+ substring_t args[MAX_OPT_ARGS];
+
+ while ((p = strsep(&options, ",")) != NULL) {
+ int token, option;
+
+ if (!*p)
+ continue;
+
+ token = match_token(p, spufs_tokens, args);
+ switch (token) {
+ case Opt_uid:
+ if (match_int(&args[0], &option))
+ return 0;
+ root->i_uid = option;
+ break;
+ case Opt_gid:
+ if (match_int(&args[0], &option))
+ return 0;
+ root->i_gid = option;
+ break;
+ default:
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+spufs_create_root(struct super_block *sb, void *data)
+{
+ struct inode *inode;
+ int ret;
+
+ ret = -ENOMEM;
+ inode = spufs_new_inode(sb, S_IFDIR | 0775);
+ if (!inode)
+ goto out;
+
+ inode->i_op = &spufs_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+ SPUFS_I(inode)->i_ctx = NULL;
+
+ ret = -EINVAL;
+ if (!spufs_parse_options(data, inode))
+ goto out_iput;
+
+ ret = -ENOMEM;
+ sb->s_root = d_alloc_root(inode);
+ if (!sb->s_root)
+ goto out_iput;
+
+ return 0;
+out_iput:
+ iput(inode);
+out:
+ return ret;
+}
+
+static int
+spufs_fill_super(struct super_block *sb, void *data, int silent)
+{
+ static struct super_operations s_ops = {
+ .alloc_inode = spufs_alloc_inode,
+ .destroy_inode = spufs_destroy_inode,
+ .statfs = simple_statfs,
+ .delete_inode = spufs_delete_inode,
+ .drop_inode = generic_delete_inode,
+ };
+
+ sb->s_maxbytes = MAX_LFS_FILESIZE;
+ sb->s_blocksize = PAGE_CACHE_SIZE;
+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+ sb->s_magic = SPUFS_MAGIC;
+ sb->s_op = &s_ops;
+
+ return spufs_create_root(sb, data);
+}
+
+static struct super_block *
+spufs_get_sb(struct file_system_type *fstype, int flags,
+ const char *name, void *data)
+{
+ return get_sb_single(fstype, flags, data, spufs_fill_super);
+}
+
+static struct file_system_type spufs_type = {
+ .owner = THIS_MODULE,
+ .name = "spufs",
+ .get_sb = spufs_get_sb,
+ .kill_sb = kill_litter_super,
+};
+
+static int spufs_init(void)
+{
+ int ret;
+ ret = -ENOMEM;
+ spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
+ sizeof(struct spufs_inode_info), 0,
+ SLAB_HWCACHE_ALIGN, spufs_init_once, NULL);
+
+ if (!spufs_inode_cache)
+ goto out;
+ if (spu_sched_init() != 0) {
+ kmem_cache_destroy(spufs_inode_cache);
+ goto out;
+ }
+ ret = register_filesystem(&spufs_type);
+ if (ret)
+ goto out_cache;
+ ret = register_spu_syscalls(&spufs_calls);
+ if (ret)
+ goto out_fs;
+ return 0;
+out_fs:
+ unregister_filesystem(&spufs_type);
+out_cache:
+ kmem_cache_destroy(spufs_inode_cache);
+out:
+ return ret;
+}
+module_init(spufs_init);
+
+static void spufs_exit(void)
+{
+ spu_sched_exit();
+ unregister_spu_syscalls(&spufs_calls);
+ unregister_filesystem(&spufs_type);
+ kmem_cache_destroy(spufs_inode_cache);
+}
+module_exit(spufs_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
+
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
new file mode 100644
index 000000000000..18ea8866c61a
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -0,0 +1,131 @@
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+
+#include <asm/spu.h>
+
+#include "spufs.h"
+
+/* interrupt-level stop callback function. */
+void spufs_stop_callback(struct spu *spu)
+{
+ struct spu_context *ctx = spu->ctx;
+
+ wake_up_all(&ctx->stop_wq);
+}
+
+static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
+{
+ struct spu *spu;
+ u64 pte_fault;
+
+ *stat = ctx->ops->status_read(ctx);
+ if (ctx->state != SPU_STATE_RUNNABLE)
+ return 1;
+ spu = ctx->spu;
+ pte_fault = spu->dsisr &
+ (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
+ return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
+}
+
+static inline int spu_run_init(struct spu_context *ctx, u32 * npc,
+ u32 * status)
+{
+ int ret;
+
+ if ((ret = spu_acquire_runnable(ctx)) != 0)
+ return ret;
+ ctx->ops->npc_write(ctx, *npc);
+ ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
+ return 0;
+}
+
+static inline int spu_run_fini(struct spu_context *ctx, u32 * npc,
+ u32 * status)
+{
+ int ret = 0;
+
+ *status = ctx->ops->status_read(ctx);
+ *npc = ctx->ops->npc_read(ctx);
+ spu_release(ctx);
+
+ if (signal_pending(current))
+ ret = -ERESTARTSYS;
+ if (unlikely(current->ptrace & PT_PTRACED)) {
+ if ((*status & SPU_STATUS_STOPPED_BY_STOP)
+ && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
+ force_sig(SIGTRAP, current);
+ ret = -ERESTARTSYS;
+ }
+ }
+ return ret;
+}
+
+static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
+ u32 *status)
+{
+ int ret;
+
+ if ((ret = spu_run_fini(ctx, npc, status)) != 0)
+ return ret;
+ if (*status & (SPU_STATUS_STOPPED_BY_STOP |
+ SPU_STATUS_STOPPED_BY_HALT)) {
+ return *status;
+ }
+ if ((ret = spu_run_init(ctx, npc, status)) != 0)
+ return ret;
+ return 0;
+}
+
+static inline int spu_process_events(struct spu_context *ctx)
+{
+ struct spu *spu = ctx->spu;
+ u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED;
+ int ret = 0;
+
+ if (spu->dsisr & pte_fault)
+ ret = spu_irq_class_1_bottom(spu);
+ if (spu->class_0_pending)
+ ret = spu_irq_class_0_bottom(spu);
+ if (!ret && signal_pending(current))
+ ret = -ERESTARTSYS;
+ return ret;
+}
+
+long spufs_run_spu(struct file *file, struct spu_context *ctx,
+ u32 * npc, u32 * status)
+{
+ int ret;
+
+ if (down_interruptible(&ctx->run_sema))
+ return -ERESTARTSYS;
+
+ ret = spu_run_init(ctx, npc, status);
+ if (ret)
+ goto out;
+
+ do {
+ ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status));
+ if (unlikely(ret))
+ break;
+ if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
+ ret = spu_reacquire_runnable(ctx, npc, status);
+ if (ret)
+ goto out;
+ continue;
+ }
+ ret = spu_process_events(ctx);
+
+ } while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP |
+ SPU_STATUS_STOPPED_BY_HALT)));
+
+ ctx->ops->runcntl_stop(ctx);
+ ret = spu_run_fini(ctx, npc, status);
+ if (!ret)
+ ret = *status;
+ spu_yield(ctx);
+
+out:
+ up(&ctx->run_sema);
+ return ret;
+}
+
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
new file mode 100644
index 000000000000..963182fbd1aa
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -0,0 +1,461 @@
+/* sched.c - SPU scheduler.
+ *
+ * Copyright (C) IBM 2005
+ * Author: Mark Nutter <mnutter@us.ibm.com>
+ *
+ * SPU scheduler, based on Linux thread priority. For now use
+ * a simple "cooperative" yield model with no preemption. SPU
+ * scheduling will eventually be preemptive: When a thread with
+ * a higher static priority gets ready to run, then an active SPU
+ * context will be preempted and returned to the waitq.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/completion.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include "spufs.h"
+
+#define SPU_MIN_TIMESLICE (100 * HZ / 1000)
+
+#define SPU_BITMAP_SIZE (((MAX_PRIO+BITS_PER_LONG)/BITS_PER_LONG)+1)
+struct spu_prio_array {
+ atomic_t nr_blocked;
+ unsigned long bitmap[SPU_BITMAP_SIZE];
+ wait_queue_head_t waitq[MAX_PRIO];
+};
+
+/* spu_runqueue - This is the main runqueue data structure for SPUs. */
+struct spu_runqueue {
+ struct semaphore sem;
+ unsigned long nr_active;
+ unsigned long nr_idle;
+ unsigned long nr_switches;
+ struct list_head active_list;
+ struct list_head idle_list;
+ struct spu_prio_array prio;
+};
+
+static struct spu_runqueue *spu_runqueues = NULL;
+
+static inline struct spu_runqueue *spu_rq(void)
+{
+ /* Future: make this a per-NODE array,
+ * and use cpu_to_node(smp_processor_id())
+ */
+ return spu_runqueues;
+}
+
+static inline struct spu *del_idle(struct spu_runqueue *rq)
+{
+ struct spu *spu;
+
+ BUG_ON(rq->nr_idle <= 0);
+ BUG_ON(list_empty(&rq->idle_list));
+ /* Future: Move SPU out of low-power SRI state. */
+ spu = list_entry(rq->idle_list.next, struct spu, sched_list);
+ list_del_init(&spu->sched_list);
+ rq->nr_idle--;
+ return spu;
+}
+
+static inline void del_active(struct spu_runqueue *rq, struct spu *spu)
+{
+ BUG_ON(rq->nr_active <= 0);
+ BUG_ON(list_empty(&rq->active_list));
+ list_del_init(&spu->sched_list);
+ rq->nr_active--;
+}
+
+static inline void add_idle(struct spu_runqueue *rq, struct spu *spu)
+{
+ /* Future: Put SPU into low-power SRI state. */
+ list_add_tail(&spu->sched_list, &rq->idle_list);
+ rq->nr_idle++;
+}
+
+static inline void add_active(struct spu_runqueue *rq, struct spu *spu)
+{
+ rq->nr_active++;
+ rq->nr_switches++;
+ list_add_tail(&spu->sched_list, &rq->active_list);
+}
+
+static void prio_wakeup(struct spu_runqueue *rq)
+{
+ if (atomic_read(&rq->prio.nr_blocked) && rq->nr_idle) {
+ int best = sched_find_first_bit(rq->prio.bitmap);
+ if (best < MAX_PRIO) {
+ wait_queue_head_t *wq = &rq->prio.waitq[best];
+ wake_up_interruptible_nr(wq, 1);
+ }
+ }
+}
+
+static void prio_wait(struct spu_runqueue *rq, struct spu_context *ctx,
+ u64 flags)
+{
+ int prio = current->prio;
+ wait_queue_head_t *wq = &rq->prio.waitq[prio];
+ DEFINE_WAIT(wait);
+
+ __set_bit(prio, rq->prio.bitmap);
+ atomic_inc(&rq->prio.nr_blocked);
+ prepare_to_wait_exclusive(wq, &wait, TASK_INTERRUPTIBLE);
+ if (!signal_pending(current)) {
+ up(&rq->sem);
+ up_write(&ctx->state_sema);
+ pr_debug("%s: pid=%d prio=%d\n", __FUNCTION__,
+ current->pid, current->prio);
+ schedule();
+ down_write(&ctx->state_sema);
+ down(&rq->sem);
+ }
+ finish_wait(wq, &wait);
+ atomic_dec(&rq->prio.nr_blocked);
+ if (!waitqueue_active(wq))
+ __clear_bit(prio, rq->prio.bitmap);
+}
+
+static inline int is_best_prio(struct spu_runqueue *rq)
+{
+ int best_prio;
+
+ best_prio = sched_find_first_bit(rq->prio.bitmap);
+ return (current->prio < best_prio) ? 1 : 0;
+}
+
+static inline void mm_needs_global_tlbie(struct mm_struct *mm)
+{
+ /* Global TLBIE broadcast required with SPEs. */
+#if (NR_CPUS > 1)
+ __cpus_setall(&mm->cpu_vm_mask, NR_CPUS);
+#else
+ __cpus_setall(&mm->cpu_vm_mask, NR_CPUS+1); /* is this ok? */
+#endif
+}
+
+static inline void bind_context(struct spu *spu, struct spu_context *ctx)
+{
+ pr_debug("%s: pid=%d SPU=%d\n", __FUNCTION__, current->pid,
+ spu->number);
+ spu->ctx = ctx;
+ spu->flags = 0;
+ ctx->flags = 0;
+ ctx->spu = spu;
+ ctx->ops = &spu_hw_ops;
+ spu->pid = current->pid;
+ spu->prio = current->prio;
+ spu->mm = ctx->owner;
+ mm_needs_global_tlbie(spu->mm);
+ spu->ibox_callback = spufs_ibox_callback;
+ spu->wbox_callback = spufs_wbox_callback;
+ spu->stop_callback = spufs_stop_callback;
+ mb();
+ spu_unmap_mappings(ctx);
+ spu_restore(&ctx->csa, spu);
+ spu->timestamp = jiffies;
+}
+
+static inline void unbind_context(struct spu *spu, struct spu_context *ctx)
+{
+ pr_debug("%s: unbind pid=%d SPU=%d\n", __FUNCTION__,
+ spu->pid, spu->number);
+ spu_unmap_mappings(ctx);
+ spu_save(&ctx->csa, spu);
+ spu->timestamp = jiffies;
+ ctx->state = SPU_STATE_SAVED;
+ spu->ibox_callback = NULL;
+ spu->wbox_callback = NULL;
+ spu->stop_callback = NULL;
+ spu->mm = NULL;
+ spu->pid = 0;
+ spu->prio = MAX_PRIO;
+ ctx->ops = &spu_backing_ops;
+ ctx->spu = NULL;
+ ctx->flags = 0;
+ spu->flags = 0;
+ spu->ctx = NULL;
+}
+
+static void spu_reaper(void *data)
+{
+ struct spu_context *ctx = data;
+ struct spu *spu;
+
+ down_write(&ctx->state_sema);
+ spu = ctx->spu;
+ if (spu && test_bit(SPU_CONTEXT_PREEMPT, &ctx->flags)) {
+ if (atomic_read(&spu->rq->prio.nr_blocked)) {
+ pr_debug("%s: spu=%d\n", __func__, spu->number);
+ ctx->ops->runcntl_stop(ctx);
+ spu_deactivate(ctx);
+ wake_up_all(&ctx->stop_wq);
+ } else {
+ clear_bit(SPU_CONTEXT_PREEMPT, &ctx->flags);
+ }
+ }
+ up_write(&ctx->state_sema);
+ put_spu_context(ctx);
+}
+
+static void schedule_spu_reaper(struct spu_runqueue *rq, struct spu *spu)
+{
+ struct spu_context *ctx = get_spu_context(spu->ctx);
+ unsigned long now = jiffies;
+ unsigned long expire = spu->timestamp + SPU_MIN_TIMESLICE;
+
+ set_bit(SPU_CONTEXT_PREEMPT, &ctx->flags);
+ INIT_WORK(&ctx->reap_work, spu_reaper, ctx);
+ if (time_after(now, expire))
+ schedule_work(&ctx->reap_work);
+ else
+ schedule_delayed_work(&ctx->reap_work, expire - now);
+}
+
+static void check_preempt_active(struct spu_runqueue *rq)
+{
+ struct list_head *p;
+ struct spu *worst = NULL;
+
+ list_for_each(p, &rq->active_list) {
+ struct spu *spu = list_entry(p, struct spu, sched_list);
+ struct spu_context *ctx = spu->ctx;
+ if (!test_bit(SPU_CONTEXT_PREEMPT, &ctx->flags)) {
+ if (!worst || (spu->prio > worst->prio)) {
+ worst = spu;
+ }
+ }
+ }
+ if (worst && (current->prio < worst->prio))
+ schedule_spu_reaper(rq, worst);
+}
+
+static struct spu *get_idle_spu(struct spu_context *ctx, u64 flags)
+{
+ struct spu_runqueue *rq;
+ struct spu *spu = NULL;
+
+ rq = spu_rq();
+ down(&rq->sem);
+ for (;;) {
+ if (rq->nr_idle > 0) {
+ if (is_best_prio(rq)) {
+ /* Fall through. */
+ spu = del_idle(rq);
+ break;
+ } else {
+ prio_wakeup(rq);
+ up(&rq->sem);
+ yield();
+ if (signal_pending(current)) {
+ return NULL;
+ }
+ rq = spu_rq();
+ down(&rq->sem);
+ continue;
+ }
+ } else {
+ check_preempt_active(rq);
+ prio_wait(rq, ctx, flags);
+ if (signal_pending(current)) {
+ prio_wakeup(rq);
+ spu = NULL;
+ break;
+ }
+ continue;
+ }
+ }
+ up(&rq->sem);
+ return spu;
+}
+
+static void put_idle_spu(struct spu *spu)
+{
+ struct spu_runqueue *rq = spu->rq;
+
+ down(&rq->sem);
+ add_idle(rq, spu);
+ prio_wakeup(rq);
+ up(&rq->sem);
+}
+
+static int get_active_spu(struct spu *spu)
+{
+ struct spu_runqueue *rq = spu->rq;
+ struct list_head *p;
+ struct spu *tmp;
+ int rc = 0;
+
+ down(&rq->sem);
+ list_for_each(p, &rq->active_list) {
+ tmp = list_entry(p, struct spu, sched_list);
+ if (tmp == spu) {
+ del_active(rq, spu);
+ rc = 1;
+ break;
+ }
+ }
+ up(&rq->sem);
+ return rc;
+}
+
+static void put_active_spu(struct spu *spu)
+{
+ struct spu_runqueue *rq = spu->rq;
+
+ down(&rq->sem);
+ add_active(rq, spu);
+ up(&rq->sem);
+}
+
+/* Lock order:
+ * spu_activate() & spu_deactivate() require the
+ * caller to have down_write(&ctx->state_sema).
+ *
+ * The rq->sem is breifly held (inside or outside a
+ * given ctx lock) for list management, but is never
+ * held during save/restore.
+ */
+
+int spu_activate(struct spu_context *ctx, u64 flags)
+{
+ struct spu *spu;
+
+ if (ctx->spu)
+ return 0;
+ spu = get_idle_spu(ctx, flags);
+ if (!spu)
+ return (signal_pending(current)) ? -ERESTARTSYS : -EAGAIN;
+ bind_context(spu, ctx);
+ /*
+ * We're likely to wait for interrupts on the same
+ * CPU that we are now on, so send them here.
+ */
+ spu_irq_setaffinity(spu, raw_smp_processor_id());
+ put_active_spu(spu);
+ return 0;
+}
+
+void spu_deactivate(struct spu_context *ctx)
+{
+ struct spu *spu;
+ int needs_idle;
+
+ spu = ctx->spu;
+ if (!spu)
+ return;
+ needs_idle = get_active_spu(spu);
+ unbind_context(spu, ctx);
+ if (needs_idle)
+ put_idle_spu(spu);
+}
+
+void spu_yield(struct spu_context *ctx)
+{
+ struct spu *spu;
+ int need_yield = 0;
+
+ down_write(&ctx->state_sema);
+ spu = ctx->spu;
+ if (spu && (sched_find_first_bit(spu->rq->prio.bitmap) < MAX_PRIO)) {
+ pr_debug("%s: yielding SPU %d\n", __FUNCTION__, spu->number);
+ spu_deactivate(ctx);
+ ctx->state = SPU_STATE_SAVED;
+ need_yield = 1;
+ } else if (spu) {
+ spu->prio = MAX_PRIO;
+ }
+ up_write(&ctx->state_sema);
+ if (unlikely(need_yield))
+ yield();
+}
+
+int __init spu_sched_init(void)
+{
+ struct spu_runqueue *rq;
+ struct spu *spu;
+ int i;
+
+ rq = spu_runqueues = kmalloc(sizeof(struct spu_runqueue), GFP_KERNEL);
+ if (!rq) {
+ printk(KERN_WARNING "%s: Unable to allocate runqueues.\n",
+ __FUNCTION__);
+ return 1;
+ }
+ memset(rq, 0, sizeof(struct spu_runqueue));
+ init_MUTEX(&rq->sem);
+ INIT_LIST_HEAD(&rq->active_list);
+ INIT_LIST_HEAD(&rq->idle_list);
+ rq->nr_active = 0;
+ rq->nr_idle = 0;
+ rq->nr_switches = 0;
+ atomic_set(&rq->prio.nr_blocked, 0);
+ for (i = 0; i < MAX_PRIO; i++) {
+ init_waitqueue_head(&rq->prio.waitq[i]);
+ __clear_bit(i, rq->prio.bitmap);
+ }
+ __set_bit(MAX_PRIO, rq->prio.bitmap);
+ for (;;) {
+ spu = spu_alloc();
+ if (!spu)
+ break;
+ pr_debug("%s: adding SPU[%d]\n", __FUNCTION__, spu->number);
+ add_idle(rq, spu);
+ spu->rq = rq;
+ spu->timestamp = jiffies;
+ }
+ if (!rq->nr_idle) {
+ printk(KERN_WARNING "%s: No available SPUs.\n", __FUNCTION__);
+ kfree(rq);
+ return 1;
+ }
+ return 0;
+}
+
+void __exit spu_sched_exit(void)
+{
+ struct spu_runqueue *rq = spu_rq();
+ struct spu *spu;
+
+ if (!rq) {
+ printk(KERN_WARNING "%s: no runqueues!\n", __FUNCTION__);
+ return;
+ }
+ while (rq->nr_idle > 0) {
+ spu = del_idle(rq);
+ if (!spu)
+ break;
+ spu_free(spu);
+ }
+ kfree(rq);
+}
diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore.c b/arch/powerpc/platforms/cell/spufs/spu_restore.c
new file mode 100644
index 000000000000..0bf723dcd677
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/spu_restore.c
@@ -0,0 +1,336 @@
+/*
+ * spu_restore.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * SPU-side context restore sequence outlined in
+ * Synergistic Processor Element Book IV
+ *
+ * Author: Mark Nutter <mnutter@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, 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 LS_SIZE
+#define LS_SIZE 0x40000 /* 256K (in bytes) */
+#endif
+
+typedef unsigned int u32;
+typedef unsigned long long u64;
+
+#include <spu_intrinsics.h>
+#include <asm/spu_csa.h>
+#include "spu_utils.h"
+
+#define BR_INSTR 0x327fff80 /* br -4 */
+#define NOP_INSTR 0x40200000 /* nop */
+#define HEQ_INSTR 0x7b000000 /* heq $0, $0 */
+#define STOP_INSTR 0x00000000 /* stop 0x0 */
+#define ILLEGAL_INSTR 0x00800000 /* illegal instr */
+#define RESTORE_COMPLETE 0x00003ffc /* stop 0x3ffc */
+
+static inline void fetch_regs_from_mem(addr64 lscsa_ea)
+{
+ unsigned int ls = (unsigned int)&regs_spill[0];
+ unsigned int size = sizeof(regs_spill);
+ unsigned int tag_id = 0;
+ unsigned int cmd = 0x40; /* GET */
+
+ spu_writech(MFC_LSA, ls);
+ spu_writech(MFC_EAH, lscsa_ea.ui[0]);
+ spu_writech(MFC_EAL, lscsa_ea.ui[1]);
+ spu_writech(MFC_Size, size);
+ spu_writech(MFC_TagID, tag_id);
+ spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void restore_upper_240kb(addr64 lscsa_ea)
+{
+ unsigned int ls = 16384;
+ unsigned int list = (unsigned int)&dma_list[0];
+ unsigned int size = sizeof(dma_list);
+ unsigned int tag_id = 0;
+ unsigned int cmd = 0x44; /* GETL */
+
+ /* Restore, Step 4:
+ * Enqueue the GETL command (tag 0) to the MFC SPU command
+ * queue to transfer the upper 240 kb of LS from CSA.
+ */
+ spu_writech(MFC_LSA, ls);
+ spu_writech(MFC_EAH, lscsa_ea.ui[0]);
+ spu_writech(MFC_EAL, list);
+ spu_writech(MFC_Size, size);
+ spu_writech(MFC_TagID, tag_id);
+ spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void restore_decr(void)
+{
+ unsigned int offset;
+ unsigned int decr_running;
+ unsigned int decr;
+
+ /* Restore, Step 6:
+ * If the LSCSA "decrementer running" flag is set
+ * then write the SPU_WrDec channel with the
+ * decrementer value from LSCSA.
+ */
+ offset = LSCSA_QW_OFFSET(decr_status);
+ decr_running = regs_spill[offset].slot[0];
+ if (decr_running) {
+ offset = LSCSA_QW_OFFSET(decr);
+ decr = regs_spill[offset].slot[0];
+ spu_writech(SPU_WrDec, decr);
+ }
+}
+
+static inline void write_ppu_mb(void)
+{
+ unsigned int offset;
+ unsigned int data;
+
+ /* Restore, Step 11:
+ * Write the MFC_WrOut_MB channel with the PPU_MB
+ * data from LSCSA.
+ */
+ offset = LSCSA_QW_OFFSET(ppu_mb);
+ data = regs_spill[offset].slot[0];
+ spu_writech(SPU_WrOutMbox, data);
+}
+
+static inline void write_ppuint_mb(void)
+{
+ unsigned int offset;
+ unsigned int data;
+
+ /* Restore, Step 12:
+ * Write the MFC_WrInt_MB channel with the PPUINT_MB
+ * data from LSCSA.
+ */
+ offset = LSCSA_QW_OFFSET(ppuint_mb);
+ data = regs_spill[offset].slot[0];
+ spu_writech(SPU_WrOutIntrMbox, data);
+}
+
+static inline void restore_fpcr(void)
+{
+ unsigned int offset;
+ vector unsigned int fpcr;
+
+ /* Restore, Step 13:
+ * Restore the floating-point status and control
+ * register from the LSCSA.
+ */
+ offset = LSCSA_QW_OFFSET(fpcr);
+ fpcr = regs_spill[offset].v;
+ spu_mtfpscr(fpcr);
+}
+
+static inline void restore_srr0(void)
+{
+ unsigned int offset;
+ unsigned int srr0;
+
+ /* Restore, Step 14:
+ * Restore the SPU SRR0 data from the LSCSA.
+ */
+ offset = LSCSA_QW_OFFSET(srr0);
+ srr0 = regs_spill[offset].slot[0];
+ spu_writech(SPU_WrSRR0, srr0);
+}
+
+static inline void restore_event_mask(void)
+{
+ unsigned int offset;
+ unsigned int event_mask;
+
+ /* Restore, Step 15:
+ * Restore the SPU_RdEventMsk data from the LSCSA.
+ */
+ offset = LSCSA_QW_OFFSET(event_mask);
+ event_mask = regs_spill[offset].slot[0];
+ spu_writech(SPU_WrEventMask, event_mask);
+}
+
+static inline void restore_tag_mask(void)
+{
+ unsigned int offset;
+ unsigned int tag_mask;
+
+ /* Restore, Step 16:
+ * Restore the SPU_RdTagMsk data from the LSCSA.
+ */
+ offset = LSCSA_QW_OFFSET(tag_mask);
+ tag_mask = regs_spill[offset].slot[0];
+ spu_writech(MFC_WrTagMask, tag_mask);
+}
+
+static inline void restore_complete(void)
+{
+ extern void exit_fini(void);
+ unsigned int *exit_instrs = (unsigned int *)exit_fini;
+ unsigned int offset;
+ unsigned int stopped_status;
+ unsigned int stopped_code;
+
+ /* Restore, Step 18:
+ * Issue a stop-and-signal instruction with
+ * "good context restore" signal value.
+ *
+ * Restore, Step 19:
+ * There may be additional instructions placed
+ * here by the PPE Sequence for SPU Context
+ * Restore in order to restore the correct
+ * "stopped state".
+ *
+ * This step is handled here by analyzing the
+ * LSCSA.stopped_status and then modifying the
+ * exit() function to behave appropriately.
+ */
+
+ offset = LSCSA_QW_OFFSET(stopped_status);
+ stopped_status = regs_spill[offset].slot[0];
+ stopped_code = regs_spill[offset].slot[1];
+
+ switch (stopped_status) {
+ case SPU_STOPPED_STATUS_P_I:
+ /* SPU_Status[P,I]=1. Add illegal instruction
+ * followed by stop-and-signal instruction after
+ * end of restore code.
+ */
+ exit_instrs[0] = RESTORE_COMPLETE;
+ exit_instrs[1] = ILLEGAL_INSTR;
+ exit_instrs[2] = STOP_INSTR | stopped_code;
+ break;
+ case SPU_STOPPED_STATUS_P_H:
+ /* SPU_Status[P,H]=1. Add 'heq $0, $0' followed
+ * by stop-and-signal instruction after end of
+ * restore code.
+ */
+ exit_instrs[0] = RESTORE_COMPLETE;
+ exit_instrs[1] = HEQ_INSTR;
+ exit_instrs[2] = STOP_INSTR | stopped_code;
+ break;
+ case SPU_STOPPED_STATUS_S_P:
+ /* SPU_Status[S,P]=1. Add nop instruction
+ * followed by 'br -4' after end of restore
+ * code.
+ */
+ exit_instrs[0] = RESTORE_COMPLETE;
+ exit_instrs[1] = STOP_INSTR | stopped_code;
+ exit_instrs[2] = NOP_INSTR;
+ exit_instrs[3] = BR_INSTR;
+ break;
+ case SPU_STOPPED_STATUS_S_I:
+ /* SPU_Status[S,I]=1. Add illegal instruction
+ * followed by 'br -4' after end of restore code.
+ */
+ exit_instrs[0] = RESTORE_COMPLETE;
+ exit_instrs[1] = ILLEGAL_INSTR;
+ exit_instrs[2] = NOP_INSTR;
+ exit_instrs[3] = BR_INSTR;
+ break;
+ case SPU_STOPPED_STATUS_I:
+ /* SPU_Status[I]=1. Add illegal instruction followed
+ * by infinite loop after end of restore sequence.
+ */
+ exit_instrs[0] = RESTORE_COMPLETE;
+ exit_instrs[1] = ILLEGAL_INSTR;
+ exit_instrs[2] = NOP_INSTR;
+ exit_instrs[3] = BR_INSTR;
+ break;
+ case SPU_STOPPED_STATUS_S:
+ /* SPU_Status[S]=1. Add two 'nop' instructions. */
+ exit_instrs[0] = RESTORE_COMPLETE;
+ exit_instrs[1] = NOP_INSTR;
+ exit_instrs[2] = NOP_INSTR;
+ exit_instrs[3] = BR_INSTR;
+ break;
+ case SPU_STOPPED_STATUS_H:
+ /* SPU_Status[H]=1. Add 'heq $0, $0' instruction
+ * after end of restore code.
+ */
+ exit_instrs[0] = RESTORE_COMPLETE;
+ exit_instrs[1] = HEQ_INSTR;
+ exit_instrs[2] = NOP_INSTR;
+ exit_instrs[3] = BR_INSTR;
+ break;
+ case SPU_STOPPED_STATUS_P:
+ /* SPU_Status[P]=1. Add stop-and-signal instruction
+ * after end of restore code.
+ */
+ exit_instrs[0] = RESTORE_COMPLETE;
+ exit_instrs[1] = STOP_INSTR | stopped_code;
+ break;
+ case SPU_STOPPED_STATUS_R:
+ /* SPU_Status[I,S,H,P,R]=0. Add infinite loop. */
+ exit_instrs[0] = RESTORE_COMPLETE;
+ exit_instrs[1] = NOP_INSTR;
+ exit_instrs[2] = NOP_INSTR;
+ exit_instrs[3] = BR_INSTR;
+ break;
+ default:
+ /* SPU_Status[R]=1. No additonal instructions. */
+ break;
+ }
+ spu_sync();
+}
+
+/**
+ * main - entry point for SPU-side context restore.
+ *
+ * This code deviates from the documented sequence in the
+ * following aspects:
+ *
+ * 1. The EA for LSCSA is passed from PPE in the
+ * signal notification channels.
+ * 2. The register spill area is pulled by SPU
+ * into LS, rather than pushed by PPE.
+ * 3. All 128 registers are restored by exit().
+ * 4. The exit() function is modified at run
+ * time in order to properly restore the
+ * SPU_Status register.
+ */
+int main()
+{
+ addr64 lscsa_ea;
+
+ lscsa_ea.ui[0] = spu_readch(SPU_RdSigNotify1);
+ lscsa_ea.ui[1] = spu_readch(SPU_RdSigNotify2);
+ fetch_regs_from_mem(lscsa_ea);
+
+ set_event_mask(); /* Step 1. */
+ set_tag_mask(); /* Step 2. */
+ build_dma_list(lscsa_ea); /* Step 3. */
+ restore_upper_240kb(lscsa_ea); /* Step 4. */
+ /* Step 5: done by 'exit'. */
+ restore_decr(); /* Step 6. */
+ enqueue_putllc(lscsa_ea); /* Step 7. */
+ set_tag_update(); /* Step 8. */
+ read_tag_status(); /* Step 9. */
+ read_llar_status(); /* Step 10. */
+ write_ppu_mb(); /* Step 11. */
+ write_ppuint_mb(); /* Step 12. */
+ restore_fpcr(); /* Step 13. */
+ restore_srr0(); /* Step 14. */
+ restore_event_mask(); /* Step 15. */
+ restore_tag_mask(); /* Step 16. */
+ /* Step 17. done by 'exit'. */
+ restore_complete(); /* Step 18. */
+
+ return 0;
+}
diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore_crt0.S b/arch/powerpc/platforms/cell/spufs/spu_restore_crt0.S
new file mode 100644
index 000000000000..2905949debe1
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/spu_restore_crt0.S
@@ -0,0 +1,116 @@
+/*
+ * crt0_r.S: Entry function for SPU-side context restore.
+ *
+ * Copyright (C) 2005 IBM
+ *
+ * Entry and exit function for SPU-side of the context restore
+ * sequence. Sets up an initial stack frame, then branches to
+ * 'main'. On return, restores all 128 registers from the LSCSA
+ * and exits.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <asm/spu_csa.h>
+
+.data
+.align 7
+.globl regs_spill
+regs_spill:
+.space SIZEOF_SPU_SPILL_REGS, 0x0
+
+.text
+.global _start
+_start:
+ /* Initialize the stack pointer to point to 16368
+ * (16kb-16). The back chain pointer is initialized
+ * to NULL.
+ */
+ il $0, 0
+ il $SP, 16368
+ stqd $0, 0($SP)
+
+ /* Allocate a minimum stack frame for the called main.
+ * This is needed so that main has a place to save the
+ * link register when it calls another function.
+ */
+ stqd $SP, -160($SP)
+ ai $SP, $SP, -160
+
+ /* Call the program's main function. */
+ brsl $0, main
+
+.global exit
+.global _exit
+exit:
+_exit:
+ /* SPU Context Restore, Step 5: Restore the remaining 112 GPRs. */
+ ila $3, regs_spill + 256
+restore_regs:
+ lqr $4, restore_reg_insts
+restore_reg_loop:
+ ai $4, $4, 4
+ .balignl 16, 0x40200000
+restore_reg_insts: /* must be quad-word aligned. */
+ lqd $16, 0($3)
+ lqd $17, 16($3)
+ lqd $18, 32($3)
+ lqd $19, 48($3)
+ andi $5, $4, 0x7F
+ stqr $4, restore_reg_insts
+ ai $3, $3, 64
+ brnz $5, restore_reg_loop
+
+ /* SPU Context Restore Step 17: Restore the first 16 GPRs. */
+ lqa $0, regs_spill + 0
+ lqa $1, regs_spill + 16
+ lqa $2, regs_spill + 32
+ lqa $3, regs_spill + 48
+ lqa $4, regs_spill + 64
+ lqa $5, regs_spill + 80
+ lqa $6, regs_spill + 96
+ lqa $7, regs_spill + 112
+ lqa $8, regs_spill + 128
+ lqa $9, regs_spill + 144
+ lqa $10, regs_spill + 160
+ lqa $11, regs_spill + 176
+ lqa $12, regs_spill + 192
+ lqa $13, regs_spill + 208
+ lqa $14, regs_spill + 224
+ lqa $15, regs_spill + 240
+
+ /* Under normal circumstances, the 'exit' function
+ * terminates with 'stop SPU_RESTORE_COMPLETE',
+ * indicating that the SPU-side restore code has
+ * completed.
+ *
+ * However it is possible that instructions immediately
+ * following the 'stop 0x3ffc' have been modified at run
+ * time so as to recreate the exact SPU_Status settings
+ * from the application, e.g. illegal instruciton, halt,
+ * etc.
+ */
+.global exit_fini
+.global _exit_fini
+exit_fini:
+_exit_fini:
+ stop SPU_RESTORE_COMPLETE
+ stop 0
+ stop 0
+ stop 0
+
+ /* Pad the size of this crt0.o to be multiple of 16 bytes. */
+.balignl 16, 0x0
diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped b/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped
new file mode 100644
index 000000000000..1b2355ff7036
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped
@@ -0,0 +1,231 @@
+/*
+ * spu_restore_dump.h: Copyright (C) 2005 IBM.
+ * Hex-dump auto generated from spu_restore.c.
+ * Do not edit!
+ */
+static unsigned int spu_restore_code[] __page_aligned = {
+0x40800000, 0x409ff801, 0x24000080, 0x24fd8081,
+0x1cd80081, 0x33001180, 0x42030003, 0x33800284,
+0x1c010204, 0x40200000, 0x40200000, 0x40200000,
+0x34000190, 0x34004191, 0x34008192, 0x3400c193,
+0x141fc205, 0x23fffd84, 0x1c100183, 0x217ffa85,
+0x3080a000, 0x3080a201, 0x3080a402, 0x3080a603,
+0x3080a804, 0x3080aa05, 0x3080ac06, 0x3080ae07,
+0x3080b008, 0x3080b209, 0x3080b40a, 0x3080b60b,
+0x3080b80c, 0x3080ba0d, 0x3080bc0e, 0x3080be0f,
+0x00003ffc, 0x00000000, 0x00000000, 0x00000000,
+0x01a00182, 0x3ec00083, 0xb0a14103, 0x01a00204,
+0x3ec10082, 0x4202800e, 0x04000703, 0xb0a14202,
+0x21a00803, 0x3fbf028d, 0x3f20068d, 0x3fbe0682,
+0x3fe30102, 0x21a00882, 0x3f82028f, 0x3fe3078f,
+0x3fbf0784, 0x3f200204, 0x3fbe0204, 0x3fe30204,
+0x04000203, 0x21a00903, 0x40848002, 0x21a00982,
+0x40800003, 0x21a00a03, 0x40802002, 0x21a00a82,
+0x21a00083, 0x40800082, 0x21a00b02, 0x10002818,
+0x40a80002, 0x32800007, 0x4207000c, 0x18008208,
+0x40a0000b, 0x4080020a, 0x40800709, 0x00200000,
+0x42070002, 0x3ac30384, 0x1cffc489, 0x00200000,
+0x18008383, 0x38830382, 0x4cffc486, 0x3ac28185,
+0xb0408584, 0x28830382, 0x1c020387, 0x38828182,
+0xb0408405, 0x1802c408, 0x28828182, 0x217ff886,
+0x04000583, 0x21a00803, 0x3fbe0682, 0x3fe30102,
+0x04000106, 0x21a00886, 0x04000603, 0x21a00903,
+0x40803c02, 0x21a00982, 0x40800003, 0x04000184,
+0x21a00a04, 0x40802202, 0x21a00a82, 0x42028005,
+0x34208702, 0x21002282, 0x21a00804, 0x21a00886,
+0x3fbf0782, 0x3f200102, 0x3fbe0102, 0x3fe30102,
+0x21a00902, 0x40804003, 0x21a00983, 0x21a00a04,
+0x40805a02, 0x21a00a82, 0x40800083, 0x21a00b83,
+0x01a00c02, 0x01a00d83, 0x3420c282, 0x21a00e02,
+0x34210283, 0x21a00f03, 0x34200284, 0x77400200,
+0x3421c282, 0x21a00702, 0x34218283, 0x21a00083,
+0x34214282, 0x21a00b02, 0x4200480c, 0x00200000,
+0x1c010286, 0x34220284, 0x34220302, 0x0f608203,
+0x5c024204, 0x3b81810b, 0x42013c02, 0x00200000,
+0x18008185, 0x38808183, 0x3b814182, 0x21004e84,
+0x4020007f, 0x35000100, 0x000004e0, 0x000002a0,
+0x000002e8, 0x00000428, 0x00000360, 0x000002e8,
+0x000004a0, 0x00000468, 0x000003c8, 0x00000360,
+0x409ffe02, 0x30801203, 0x40800204, 0x3ec40085,
+0x10009c09, 0x3ac10606, 0xb060c105, 0x4020007f,
+0x4020007f, 0x20801203, 0x38810602, 0xb0408586,
+0x28810602, 0x32004180, 0x34204702, 0x21a00382,
+0x4020007f, 0x327fdc80, 0x409ffe02, 0x30801203,
+0x40800204, 0x3ec40087, 0x40800405, 0x00200000,
+0x40800606, 0x3ac10608, 0x3ac14609, 0x3ac1860a,
+0xb060c107, 0x20801203, 0x41004003, 0x38810602,
+0x4020007f, 0xb0408188, 0x4020007f, 0x28810602,
+0x41201002, 0x38814603, 0x10009c09, 0xb060c109,
+0x4020007f, 0x28814603, 0x41193f83, 0x38818602,
+0x60ffc003, 0xb040818a, 0x28818602, 0x32003080,
+0x409ffe02, 0x30801203, 0x40800204, 0x3ec40087,
+0x41201008, 0x10009c14, 0x40800405, 0x3ac10609,
+0x40800606, 0x3ac1460a, 0xb060c107, 0x3ac1860b,
+0x20801203, 0x38810602, 0xb0408409, 0x28810602,
+0x38814603, 0xb060c40a, 0x4020007f, 0x28814603,
+0x41193f83, 0x38818602, 0x60ffc003, 0xb040818b,
+0x28818602, 0x32002380, 0x409ffe02, 0x30801204,
+0x40800205, 0x3ec40083, 0x40800406, 0x3ac14607,
+0x3ac18608, 0xb0810103, 0x41004002, 0x20801204,
+0x4020007f, 0x38814603, 0x10009c0b, 0xb060c107,
+0x4020007f, 0x4020007f, 0x28814603, 0x38818602,
+0x4020007f, 0x4020007f, 0xb0408588, 0x28818602,
+0x4020007f, 0x32001780, 0x409ffe02, 0x1000640e,
+0x40800204, 0x30801203, 0x40800405, 0x3ec40087,
+0x40800606, 0x3ac10608, 0x3ac14609, 0x3ac1860a,
+0xb060c107, 0x20801203, 0x413d8003, 0x38810602,
+0x4020007f, 0x327fd780, 0x409ffe02, 0x10007f0c,
+0x40800205, 0x30801204, 0x40800406, 0x3ec40083,
+0x3ac14607, 0x3ac18608, 0xb0810103, 0x413d8002,
+0x20801204, 0x38814603, 0x4020007f, 0x327feb80,
+0x409ffe02, 0x30801203, 0x40800204, 0x3ec40087,
+0x40800405, 0x1000650a, 0x40800606, 0x3ac10608,
+0x3ac14609, 0x3ac1860a, 0xb060c107, 0x20801203,
+0x38810602, 0xb0408588, 0x4020007f, 0x327fc980,
+0x00400000, 0x40800003, 0x4020007f, 0x35000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
diff --git a/arch/powerpc/platforms/cell/spufs/spu_save.c b/arch/powerpc/platforms/cell/spufs/spu_save.c
new file mode 100644
index 000000000000..196033b8a579
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/spu_save.c
@@ -0,0 +1,195 @@
+/*
+ * spu_save.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * SPU-side context save sequence outlined in
+ * Synergistic Processor Element Book IV
+ *
+ * Author: Mark Nutter <mnutter@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, 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 LS_SIZE
+#define LS_SIZE 0x40000 /* 256K (in bytes) */
+#endif
+
+typedef unsigned int u32;
+typedef unsigned long long u64;
+
+#include <spu_intrinsics.h>
+#include <asm/spu_csa.h>
+#include "spu_utils.h"
+
+static inline void save_event_mask(void)
+{
+ unsigned int offset;
+
+ /* Save, Step 2:
+ * Read the SPU_RdEventMsk channel and save to the LSCSA.
+ */
+ offset = LSCSA_QW_OFFSET(event_mask);
+ regs_spill[offset].slot[0] = spu_readch(SPU_RdEventStatMask);
+}
+
+static inline void save_tag_mask(void)
+{
+ unsigned int offset;
+
+ /* Save, Step 3:
+ * Read the SPU_RdTagMsk channel and save to the LSCSA.
+ */
+ offset = LSCSA_QW_OFFSET(tag_mask);
+ regs_spill[offset].slot[0] = spu_readch(MFC_RdTagMask);
+}
+
+static inline void save_upper_240kb(addr64 lscsa_ea)
+{
+ unsigned int ls = 16384;
+ unsigned int list = (unsigned int)&dma_list[0];
+ unsigned int size = sizeof(dma_list);
+ unsigned int tag_id = 0;
+ unsigned int cmd = 0x24; /* PUTL */
+
+ /* Save, Step 7:
+ * Enqueue the PUTL command (tag 0) to the MFC SPU command
+ * queue to transfer the remaining 240 kb of LS to CSA.
+ */
+ spu_writech(MFC_LSA, ls);
+ spu_writech(MFC_EAH, lscsa_ea.ui[0]);
+ spu_writech(MFC_EAL, list);
+ spu_writech(MFC_Size, size);
+ spu_writech(MFC_TagID, tag_id);
+ spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void save_fpcr(void)
+{
+ // vector unsigned int fpcr;
+ unsigned int offset;
+
+ /* Save, Step 9:
+ * Issue the floating-point status and control register
+ * read instruction, and save to the LSCSA.
+ */
+ offset = LSCSA_QW_OFFSET(fpcr);
+ regs_spill[offset].v = spu_mffpscr();
+}
+
+static inline void save_decr(void)
+{
+ unsigned int offset;
+
+ /* Save, Step 10:
+ * Read and save the SPU_RdDec channel data to
+ * the LSCSA.
+ */
+ offset = LSCSA_QW_OFFSET(decr);
+ regs_spill[offset].slot[0] = spu_readch(SPU_RdDec);
+}
+
+static inline void save_srr0(void)
+{
+ unsigned int offset;
+
+ /* Save, Step 11:
+ * Read and save the SPU_WSRR0 channel data to
+ * the LSCSA.
+ */
+ offset = LSCSA_QW_OFFSET(srr0);
+ regs_spill[offset].slot[0] = spu_readch(SPU_RdSRR0);
+}
+
+static inline void spill_regs_to_mem(addr64 lscsa_ea)
+{
+ unsigned int ls = (unsigned int)&regs_spill[0];
+ unsigned int size = sizeof(regs_spill);
+ unsigned int tag_id = 0;
+ unsigned int cmd = 0x20; /* PUT */
+
+ /* Save, Step 13:
+ * Enqueue a PUT command (tag 0) to send the LSCSA
+ * to the CSA.
+ */
+ spu_writech(MFC_LSA, ls);
+ spu_writech(MFC_EAH, lscsa_ea.ui[0]);
+ spu_writech(MFC_EAL, lscsa_ea.ui[1]);
+ spu_writech(MFC_Size, size);
+ spu_writech(MFC_TagID, tag_id);
+ spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void enqueue_sync(addr64 lscsa_ea)
+{
+ unsigned int tag_id = 0;
+ unsigned int cmd = 0xCC;
+
+ /* Save, Step 14:
+ * Enqueue an MFC_SYNC command (tag 0).
+ */
+ spu_writech(MFC_TagID, tag_id);
+ spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void save_complete(void)
+{
+ /* Save, Step 18:
+ * Issue a stop-and-signal instruction indicating
+ * "save complete". Note: This function will not
+ * return!!
+ */
+ spu_stop(SPU_SAVE_COMPLETE);
+}
+
+/**
+ * main - entry point for SPU-side context save.
+ *
+ * This code deviates from the documented sequence as follows:
+ *
+ * 1. The EA for LSCSA is passed from PPE in the
+ * signal notification channels.
+ * 2. All 128 registers are saved by crt0.o.
+ */
+int main()
+{
+ addr64 lscsa_ea;
+
+ lscsa_ea.ui[0] = spu_readch(SPU_RdSigNotify1);
+ lscsa_ea.ui[1] = spu_readch(SPU_RdSigNotify2);
+
+ /* Step 1: done by exit(). */
+ save_event_mask(); /* Step 2. */
+ save_tag_mask(); /* Step 3. */
+ set_event_mask(); /* Step 4. */
+ set_tag_mask(); /* Step 5. */
+ build_dma_list(lscsa_ea); /* Step 6. */
+ save_upper_240kb(lscsa_ea); /* Step 7. */
+ /* Step 8: done by exit(). */
+ save_fpcr(); /* Step 9. */
+ save_decr(); /* Step 10. */
+ save_srr0(); /* Step 11. */
+ enqueue_putllc(lscsa_ea); /* Step 12. */
+ spill_regs_to_mem(lscsa_ea); /* Step 13. */
+ enqueue_sync(lscsa_ea); /* Step 14. */
+ set_tag_update(); /* Step 15. */
+ read_tag_status(); /* Step 16. */
+ read_llar_status(); /* Step 17. */
+ save_complete(); /* Step 18. */
+
+ return 0;
+}
diff --git a/arch/powerpc/platforms/cell/spufs/spu_save_crt0.S b/arch/powerpc/platforms/cell/spufs/spu_save_crt0.S
new file mode 100644
index 000000000000..6659d6a66faa
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/spu_save_crt0.S
@@ -0,0 +1,102 @@
+/*
+ * crt0_s.S: Entry function for SPU-side context save.
+ *
+ * Copyright (C) 2005 IBM
+ *
+ * Entry function for SPU-side of the context save sequence.
+ * Saves all 128 GPRs, sets up an initial stack frame, then
+ * branches to 'main'.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <asm/spu_csa.h>
+
+.data
+.align 7
+.globl regs_spill
+regs_spill:
+.space SIZEOF_SPU_SPILL_REGS, 0x0
+
+.text
+.global _start
+_start:
+ /* SPU Context Save Step 1: Save the first 16 GPRs. */
+ stqa $0, regs_spill + 0
+ stqa $1, regs_spill + 16
+ stqa $2, regs_spill + 32
+ stqa $3, regs_spill + 48
+ stqa $4, regs_spill + 64
+ stqa $5, regs_spill + 80
+ stqa $6, regs_spill + 96
+ stqa $7, regs_spill + 112
+ stqa $8, regs_spill + 128
+ stqa $9, regs_spill + 144
+ stqa $10, regs_spill + 160
+ stqa $11, regs_spill + 176
+ stqa $12, regs_spill + 192
+ stqa $13, regs_spill + 208
+ stqa $14, regs_spill + 224
+ stqa $15, regs_spill + 240
+
+ /* SPU Context Save, Step 8: Save the remaining 112 GPRs. */
+ ila $3, regs_spill + 256
+save_regs:
+ lqr $4, save_reg_insts
+save_reg_loop:
+ ai $4, $4, 4
+ .balignl 16, 0x40200000
+save_reg_insts: /* must be quad-word aligned. */
+ stqd $16, 0($3)
+ stqd $17, 16($3)
+ stqd $18, 32($3)
+ stqd $19, 48($3)
+ andi $5, $4, 0x7F
+ stqr $4, save_reg_insts
+ ai $3, $3, 64
+ brnz $5, save_reg_loop
+
+ /* Initialize the stack pointer to point to 16368
+ * (16kb-16). The back chain pointer is initialized
+ * to NULL.
+ */
+ il $0, 0
+ il $SP, 16368
+ stqd $0, 0($SP)
+
+ /* Allocate a minimum stack frame for the called main.
+ * This is needed so that main has a place to save the
+ * link register when it calls another function.
+ */
+ stqd $SP, -160($SP)
+ ai $SP, $SP, -160
+
+ /* Call the program's main function. */
+ brsl $0, main
+
+ /* In this case main should not return; if it does
+ * there has been an error in the sequence. Execute
+ * stop-and-signal with code=0.
+ */
+.global exit
+.global _exit
+exit:
+_exit:
+ stop 0x0
+
+ /* Pad the size of this crt0.o to be multiple of 16 bytes. */
+.balignl 16, 0x0
+
diff --git a/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped b/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped
new file mode 100644
index 000000000000..39e54003f1df
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped
@@ -0,0 +1,191 @@
+/*
+ * spu_save_dump.h: Copyright (C) 2005 IBM.
+ * Hex-dump auto generated from spu_save.c.
+ * Do not edit!
+ */
+static unsigned int spu_save_code[] __page_aligned = {
+0x20805000, 0x20805201, 0x20805402, 0x20805603,
+0x20805804, 0x20805a05, 0x20805c06, 0x20805e07,
+0x20806008, 0x20806209, 0x2080640a, 0x2080660b,
+0x2080680c, 0x20806a0d, 0x20806c0e, 0x20806e0f,
+0x4201c003, 0x33800184, 0x1c010204, 0x40200000,
+0x24000190, 0x24004191, 0x24008192, 0x2400c193,
+0x141fc205, 0x23fffd84, 0x1c100183, 0x217ffb85,
+0x40800000, 0x409ff801, 0x24000080, 0x24fd8081,
+0x1cd80081, 0x33000180, 0x00000000, 0x00000000,
+0x01a00182, 0x3ec00083, 0xb1c38103, 0x01a00204,
+0x3ec10082, 0x4201400d, 0xb1c38202, 0x01a00583,
+0x34218682, 0x3ed80684, 0xb0408184, 0x24218682,
+0x01a00603, 0x00200000, 0x34214682, 0x3ed40684,
+0xb0408184, 0x40800003, 0x24214682, 0x21a00083,
+0x40800082, 0x21a00b02, 0x4020007f, 0x1000251e,
+0x40a80002, 0x32800008, 0x4205c00c, 0x00200000,
+0x40a0000b, 0x3f82070f, 0x4080020a, 0x40800709,
+0x3fe3078f, 0x3fbf0783, 0x3f200183, 0x3fbe0183,
+0x3fe30187, 0x18008387, 0x4205c002, 0x3ac30404,
+0x1cffc489, 0x00200000, 0x18008403, 0x38830402,
+0x4cffc486, 0x3ac28185, 0xb0408584, 0x28830402,
+0x1c020408, 0x38828182, 0xb0408385, 0x1802c387,
+0x28828182, 0x217ff886, 0x04000582, 0x32800007,
+0x21a00802, 0x3fbf0705, 0x3f200285, 0x3fbe0285,
+0x3fe30285, 0x21a00885, 0x04000603, 0x21a00903,
+0x40803c02, 0x21a00982, 0x04000386, 0x21a00a06,
+0x40801202, 0x21a00a82, 0x73000003, 0x24200683,
+0x01a00404, 0x00200000, 0x34204682, 0x3ec40683,
+0xb0408203, 0x24204682, 0x01a00783, 0x00200000,
+0x3421c682, 0x3edc0684, 0xb0408184, 0x2421c682,
+0x21a00806, 0x21a00885, 0x3fbf0784, 0x3f200204,
+0x3fbe0204, 0x3fe30204, 0x21a00904, 0x40804002,
+0x21a00982, 0x21a00a06, 0x40805a02, 0x21a00a82,
+0x04000683, 0x21a00803, 0x21a00885, 0x21a00904,
+0x40848002, 0x21a00982, 0x21a00a06, 0x40801002,
+0x21a00a82, 0x21a00a06, 0x40806602, 0x00200000,
+0x35800009, 0x21a00a82, 0x40800083, 0x21a00b83,
+0x01a00c02, 0x01a00d83, 0x00003ffb, 0x40800003,
+0x4020007f, 0x35000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
diff --git a/arch/powerpc/platforms/cell/spufs/spu_utils.h b/arch/powerpc/platforms/cell/spufs/spu_utils.h
new file mode 100644
index 000000000000..58359feb6c95
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/spu_utils.h
@@ -0,0 +1,160 @@
+/*
+ * utils.h: Utilities for SPU-side of the context switch operation.
+ *
+ * (C) Copyright IBM 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, 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 _SPU_CONTEXT_UTILS_H_
+#define _SPU_CONTEXT_UTILS_H_
+
+/*
+ * 64-bit safe EA.
+ */
+typedef union {
+ unsigned long long ull;
+ unsigned int ui[2];
+} addr64;
+
+/*
+ * 128-bit register template.
+ */
+typedef union {
+ unsigned int slot[4];
+ vector unsigned int v;
+} spu_reg128v;
+
+/*
+ * DMA list structure.
+ */
+struct dma_list_elem {
+ unsigned int size;
+ unsigned int ea_low;
+};
+
+/*
+ * Declare storage for 8-byte aligned DMA list.
+ */
+struct dma_list_elem dma_list[15] __attribute__ ((aligned(8)));
+
+/*
+ * External definition for storage
+ * declared in crt0.
+ */
+extern spu_reg128v regs_spill[NR_SPU_SPILL_REGS];
+
+/*
+ * Compute LSCSA byte offset for a given field.
+ */
+static struct spu_lscsa *dummy = (struct spu_lscsa *)0;
+#define LSCSA_BYTE_OFFSET(_field) \
+ ((char *)(&(dummy->_field)) - (char *)(&(dummy->gprs[0].slot[0])))
+#define LSCSA_QW_OFFSET(_field) (LSCSA_BYTE_OFFSET(_field) >> 4)
+
+static inline void set_event_mask(void)
+{
+ unsigned int event_mask = 0;
+
+ /* Save, Step 4:
+ * Restore, Step 1:
+ * Set the SPU_RdEventMsk channel to zero to mask
+ * all events.
+ */
+ spu_writech(SPU_WrEventMask, event_mask);
+}
+
+static inline void set_tag_mask(void)
+{
+ unsigned int tag_mask = 1;
+
+ /* Save, Step 5:
+ * Restore, Step 2:
+ * Set the SPU_WrTagMsk channel to '01' to unmask
+ * only tag group 0.
+ */
+ spu_writech(MFC_WrTagMask, tag_mask);
+}
+
+static inline void build_dma_list(addr64 lscsa_ea)
+{
+ unsigned int ea_low;
+ int i;
+
+ /* Save, Step 6:
+ * Restore, Step 3:
+ * Update the effective address for the CSA in the
+ * pre-canned DMA-list in local storage.
+ */
+ ea_low = lscsa_ea.ui[1];
+ ea_low += LSCSA_BYTE_OFFSET(ls[16384]);
+
+ for (i = 0; i < 15; i++, ea_low += 16384) {
+ dma_list[i].size = 16384;
+ dma_list[i].ea_low = ea_low;
+ }
+}
+
+static inline void enqueue_putllc(addr64 lscsa_ea)
+{
+ unsigned int ls = 0;
+ unsigned int size = 128;
+ unsigned int tag_id = 0;
+ unsigned int cmd = 0xB4; /* PUTLLC */
+
+ /* Save, Step 12:
+ * Restore, Step 7:
+ * Send a PUTLLC (tag 0) command to the MFC using
+ * an effective address in the CSA in order to
+ * remove any possible lock-line reservation.
+ */
+ spu_writech(MFC_LSA, ls);
+ spu_writech(MFC_EAH, lscsa_ea.ui[0]);
+ spu_writech(MFC_EAL, lscsa_ea.ui[1]);
+ spu_writech(MFC_Size, size);
+ spu_writech(MFC_TagID, tag_id);
+ spu_writech(MFC_Cmd, cmd);
+}
+
+static inline void set_tag_update(void)
+{
+ unsigned int update_any = 1;
+
+ /* Save, Step 15:
+ * Restore, Step 8:
+ * Write the MFC_TagUpdate channel with '01'.
+ */
+ spu_writech(MFC_WrTagUpdate, update_any);
+}
+
+static inline void read_tag_status(void)
+{
+ /* Save, Step 16:
+ * Restore, Step 9:
+ * Read the MFC_TagStat channel data.
+ */
+ spu_readch(MFC_RdTagStat);
+}
+
+static inline void read_llar_status(void)
+{
+ /* Save, Step 17:
+ * Restore, Step 10:
+ * Read the MFC_AtomicStat channel data.
+ */
+ spu_readch(MFC_RdAtomicStat);
+}
+
+#endif /* _SPU_CONTEXT_UTILS_H_ */
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
new file mode 100644
index 000000000000..db2601f0abd5
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -0,0 +1,163 @@
+/*
+ * SPU file system
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.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, 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 SPUFS_H
+#define SPUFS_H
+
+#include <linux/kref.h>
+#include <linux/rwsem.h>
+#include <linux/spinlock.h>
+#include <linux/fs.h>
+
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+
+/* The magic number for our file system */
+enum {
+ SPUFS_MAGIC = 0x23c9b64e,
+};
+
+struct spu_context_ops;
+
+#define SPU_CONTEXT_PREEMPT 0UL
+
+struct spu_context {
+ struct spu *spu; /* pointer to a physical SPU */
+ struct spu_state csa; /* SPU context save area. */
+ spinlock_t mmio_lock; /* protects mmio access */
+ struct address_space *local_store;/* local store backing store */
+
+ enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state;
+ struct rw_semaphore state_sema;
+ struct semaphore run_sema;
+
+ struct mm_struct *owner;
+
+ struct kref kref;
+ wait_queue_head_t ibox_wq;
+ wait_queue_head_t wbox_wq;
+ wait_queue_head_t stop_wq;
+ struct fasync_struct *ibox_fasync;
+ struct fasync_struct *wbox_fasync;
+ struct spu_context_ops *ops;
+ struct work_struct reap_work;
+ u64 flags;
+};
+
+/* SPU context query/set operations. */
+struct spu_context_ops {
+ int (*mbox_read) (struct spu_context * ctx, u32 * data);
+ u32(*mbox_stat_read) (struct spu_context * ctx);
+ unsigned int (*mbox_stat_poll)(struct spu_context *ctx,
+ unsigned int events);
+ int (*ibox_read) (struct spu_context * ctx, u32 * data);
+ int (*wbox_write) (struct spu_context * ctx, u32 data);
+ u32(*signal1_read) (struct spu_context * ctx);
+ void (*signal1_write) (struct spu_context * ctx, u32 data);
+ u32(*signal2_read) (struct spu_context * ctx);
+ void (*signal2_write) (struct spu_context * ctx, u32 data);
+ void (*signal1_type_set) (struct spu_context * ctx, u64 val);
+ u64(*signal1_type_get) (struct spu_context * ctx);
+ void (*signal2_type_set) (struct spu_context * ctx, u64 val);
+ u64(*signal2_type_get) (struct spu_context * ctx);
+ u32(*npc_read) (struct spu_context * ctx);
+ void (*npc_write) (struct spu_context * ctx, u32 data);
+ u32(*status_read) (struct spu_context * ctx);
+ char*(*get_ls) (struct spu_context * ctx);
+ void (*runcntl_write) (struct spu_context * ctx, u32 data);
+ void (*runcntl_stop) (struct spu_context * ctx);
+};
+
+extern struct spu_context_ops spu_hw_ops;
+extern struct spu_context_ops spu_backing_ops;
+
+struct spufs_inode_info {
+ struct spu_context *i_ctx;
+ struct inode vfs_inode;
+};
+#define SPUFS_I(inode) \
+ container_of(inode, struct spufs_inode_info, vfs_inode)
+
+extern struct tree_descr spufs_dir_contents[];
+
+/* system call implementation */
+long spufs_run_spu(struct file *file,
+ struct spu_context *ctx, u32 *npc, u32 *status);
+long spufs_create_thread(struct nameidata *nd,
+ unsigned int flags, mode_t mode);
+extern struct file_operations spufs_context_fops;
+
+/* context management */
+struct spu_context * alloc_spu_context(struct address_space *local_store);
+void destroy_spu_context(struct kref *kref);
+struct spu_context * get_spu_context(struct spu_context *ctx);
+int put_spu_context(struct spu_context *ctx);
+void spu_unmap_mappings(struct spu_context *ctx);
+
+void spu_forget(struct spu_context *ctx);
+void spu_acquire(struct spu_context *ctx);
+void spu_release(struct spu_context *ctx);
+int spu_acquire_runnable(struct spu_context *ctx);
+void spu_acquire_saved(struct spu_context *ctx);
+
+int spu_activate(struct spu_context *ctx, u64 flags);
+void spu_deactivate(struct spu_context *ctx);
+void spu_yield(struct spu_context *ctx);
+int __init spu_sched_init(void);
+void __exit spu_sched_exit(void);
+
+/*
+ * spufs_wait
+ * Same as wait_event_interruptible(), except that here
+ * we need to call spu_release(ctx) before sleeping, and
+ * then spu_acquire(ctx) when awoken.
+ */
+
+#define spufs_wait(wq, condition) \
+({ \
+ int __ret = 0; \
+ DEFINE_WAIT(__wait); \
+ for (;;) { \
+ prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE); \
+ if (condition) \
+ break; \
+ if (!signal_pending(current)) { \
+ spu_release(ctx); \
+ schedule(); \
+ spu_acquire(ctx); \
+ continue; \
+ } \
+ __ret = -ERESTARTSYS; \
+ break; \
+ } \
+ finish_wait(&(wq), &__wait); \
+ __ret; \
+})
+
+size_t spu_wbox_write(struct spu_context *ctx, u32 data);
+size_t spu_ibox_read(struct spu_context *ctx, u32 *data);
+
+/* irq callback funcs. */
+void spufs_ibox_callback(struct spu *spu);
+void spufs_wbox_callback(struct spu *spu);
+void spufs_stop_callback(struct spu *spu);
+
+#endif
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
new file mode 100644
index 000000000000..1061c12b2edb
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -0,0 +1,2180 @@
+/*
+ * spu_switch.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author: Mark Nutter <mnutter@us.ibm.com>
+ *
+ * Host-side part of SPU context switch sequence outlined in
+ * Synergistic Processor Element, Book IV.
+ *
+ * A fully premptive switch of an SPE is very expensive in terms
+ * of time and system resources. SPE Book IV indicates that SPE
+ * allocation should follow a "serially reusable device" model,
+ * in which the SPE is assigned a task until it completes. When
+ * this is not possible, this sequence may be used to premptively
+ * save, and then later (optionally) restore the context of a
+ * program executing on an SPE.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+
+#include <asm/io.h>
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include <asm/mmu_context.h>
+
+#include "spu_save_dump.h"
+#include "spu_restore_dump.h"
+
+#if 0
+#define POLL_WHILE_TRUE(_c) { \
+ do { \
+ } while (_c); \
+ }
+#else
+#define RELAX_SPIN_COUNT 1000
+#define POLL_WHILE_TRUE(_c) { \
+ do { \
+ int _i; \
+ for (_i=0; _i<RELAX_SPIN_COUNT && (_c); _i++) { \
+ cpu_relax(); \
+ } \
+ if (unlikely(_c)) yield(); \
+ else break; \
+ } while (_c); \
+ }
+#endif /* debug */
+
+#define POLL_WHILE_FALSE(_c) POLL_WHILE_TRUE(!(_c))
+
+static inline void acquire_spu_lock(struct spu *spu)
+{
+ /* Save, Step 1:
+ * Restore, Step 1:
+ * Acquire SPU-specific mutual exclusion lock.
+ * TBD.
+ */
+}
+
+static inline void release_spu_lock(struct spu *spu)
+{
+ /* Restore, Step 76:
+ * Release SPU-specific mutual exclusion lock.
+ * TBD.
+ */
+}
+
+static inline int check_spu_isolate(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+ u32 isolate_state;
+
+ /* Save, Step 2:
+ * Save, Step 6:
+ * If SPU_Status[E,L,IS] any field is '1', this
+ * SPU is in isolate state and cannot be context
+ * saved at this time.
+ */
+ isolate_state = SPU_STATUS_ISOLATED_STATE |
+ SPU_STATUS_ISOLATED_LOAD_STAUTUS | SPU_STATUS_ISOLATED_EXIT_STAUTUS;
+ return (in_be32(&prob->spu_status_R) & isolate_state) ? 1 : 0;
+}
+
+static inline void disable_interrupts(struct spu_state *csa, struct spu *spu)
+{
+ /* Save, Step 3:
+ * Restore, Step 2:
+ * Save INT_Mask_class0 in CSA.
+ * Write INT_MASK_class0 with value of 0.
+ * Save INT_Mask_class1 in CSA.
+ * Write INT_MASK_class1 with value of 0.
+ * Save INT_Mask_class2 in CSA.
+ * Write INT_MASK_class2 with value of 0.
+ */
+ spin_lock_irq(&spu->register_lock);
+ if (csa) {
+ csa->priv1.int_mask_class0_RW = spu_int_mask_get(spu, 0);
+ csa->priv1.int_mask_class1_RW = spu_int_mask_get(spu, 1);
+ csa->priv1.int_mask_class2_RW = spu_int_mask_get(spu, 2);
+ }
+ spu_int_mask_set(spu, 0, 0ul);
+ spu_int_mask_set(spu, 1, 0ul);
+ spu_int_mask_set(spu, 2, 0ul);
+ eieio();
+ spin_unlock_irq(&spu->register_lock);
+}
+
+static inline void set_watchdog_timer(struct spu_state *csa, struct spu *spu)
+{
+ /* Save, Step 4:
+ * Restore, Step 25.
+ * Set a software watchdog timer, which specifies the
+ * maximum allowable time for a context save sequence.
+ *
+ * For present, this implementation will not set a global
+ * watchdog timer, as virtualization & variable system load
+ * may cause unpredictable execution times.
+ */
+}
+
+static inline void inhibit_user_access(struct spu_state *csa, struct spu *spu)
+{
+ /* Save, Step 5:
+ * Restore, Step 3:
+ * Inhibit user-space access (if provided) to this
+ * SPU by unmapping the virtual pages assigned to
+ * the SPU memory-mapped I/O (MMIO) for problem
+ * state. TBD.
+ */
+}
+
+static inline void set_switch_pending(struct spu_state *csa, struct spu *spu)
+{
+ /* Save, Step 7:
+ * Restore, Step 5:
+ * Set a software context switch pending flag.
+ */
+ set_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags);
+ mb();
+}
+
+static inline void save_mfc_cntl(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Save, Step 8:
+ * Read and save MFC_CNTL[Ss].
+ */
+ if (csa) {
+ csa->priv2.mfc_control_RW = in_be64(&priv2->mfc_control_RW) &
+ MFC_CNTL_SUSPEND_DMA_STATUS_MASK;
+ }
+}
+
+static inline void save_spu_runcntl(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+
+ /* Save, Step 9:
+ * Save SPU_Runcntl in the CSA. This value contains
+ * the "Application Desired State".
+ */
+ csa->prob.spu_runcntl_RW = in_be32(&prob->spu_runcntl_RW);
+}
+
+static inline void save_mfc_sr1(struct spu_state *csa, struct spu *spu)
+{
+ /* Save, Step 10:
+ * Save MFC_SR1 in the CSA.
+ */
+ csa->priv1.mfc_sr1_RW = spu_mfc_sr1_get(spu);
+}
+
+static inline void save_spu_status(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+
+ /* Save, Step 11:
+ * Read SPU_Status[R], and save to CSA.
+ */
+ if ((in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) == 0) {
+ csa->prob.spu_status_R = in_be32(&prob->spu_status_R);
+ } else {
+ u32 stopped;
+
+ out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
+ eieio();
+ POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+ SPU_STATUS_RUNNING);
+ stopped =
+ SPU_STATUS_INVALID_INSTR | SPU_STATUS_SINGLE_STEP |
+ SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP;
+ if ((in_be32(&prob->spu_status_R) & stopped) == 0)
+ csa->prob.spu_status_R = SPU_STATUS_RUNNING;
+ else
+ csa->prob.spu_status_R = in_be32(&prob->spu_status_R);
+ }
+}
+
+static inline void save_mfc_decr(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Save, Step 12:
+ * Read MFC_CNTL[Ds]. Update saved copy of
+ * CSA.MFC_CNTL[Ds].
+ */
+ if (in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DECREMENTER_RUNNING) {
+ csa->priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING;
+ csa->suspend_time = get_cycles();
+ out_be64(&priv2->spu_chnlcntptr_RW, 7ULL);
+ eieio();
+ csa->spu_chnldata_RW[7] = in_be64(&priv2->spu_chnldata_RW);
+ eieio();
+ }
+}
+
+static inline void halt_mfc_decr(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Save, Step 13:
+ * Write MFC_CNTL[Dh] set to a '1' to halt
+ * the decrementer.
+ */
+ out_be64(&priv2->mfc_control_RW, MFC_CNTL_DECREMENTER_HALTED);
+ eieio();
+}
+
+static inline void save_timebase(struct spu_state *csa, struct spu *spu)
+{
+ /* Save, Step 14:
+ * Read PPE Timebase High and Timebase low registers
+ * and save in CSA. TBD.
+ */
+ csa->suspend_time = get_cycles();
+}
+
+static inline void remove_other_spu_access(struct spu_state *csa,
+ struct spu *spu)
+{
+ /* Save, Step 15:
+ * Remove other SPU access to this SPU by unmapping
+ * this SPU's pages from their address space. TBD.
+ */
+}
+
+static inline void do_mfc_mssync(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+
+ /* Save, Step 16:
+ * Restore, Step 11.
+ * Write SPU_MSSync register. Poll SPU_MSSync[P]
+ * for a value of 0.
+ */
+ out_be64(&prob->spc_mssync_RW, 1UL);
+ POLL_WHILE_TRUE(in_be64(&prob->spc_mssync_RW) & MS_SYNC_PENDING);
+}
+
+static inline void issue_mfc_tlbie(struct spu_state *csa, struct spu *spu)
+{
+ /* Save, Step 17:
+ * Restore, Step 12.
+ * Restore, Step 48.
+ * Write TLB_Invalidate_Entry[IS,VPN,L,Lp]=0 register.
+ * Then issue a PPE sync instruction.
+ */
+ spu_tlb_invalidate(spu);
+ mb();
+}
+
+static inline void handle_pending_interrupts(struct spu_state *csa,
+ struct spu *spu)
+{
+ /* Save, Step 18:
+ * Handle any pending interrupts from this SPU
+ * here. This is OS or hypervisor specific. One
+ * option is to re-enable interrupts to handle any
+ * pending interrupts, with the interrupt handlers
+ * recognizing the software Context Switch Pending
+ * flag, to ensure the SPU execution or MFC command
+ * queue is not restarted. TBD.
+ */
+}
+
+static inline void save_mfc_queues(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+ int i;
+
+ /* Save, Step 19:
+ * If MFC_Cntl[Se]=0 then save
+ * MFC command queues.
+ */
+ if ((in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DMA_QUEUES_EMPTY) == 0) {
+ for (i = 0; i < 8; i++) {
+ csa->priv2.puq[i].mfc_cq_data0_RW =
+ in_be64(&priv2->puq[i].mfc_cq_data0_RW);
+ csa->priv2.puq[i].mfc_cq_data1_RW =
+ in_be64(&priv2->puq[i].mfc_cq_data1_RW);
+ csa->priv2.puq[i].mfc_cq_data2_RW =
+ in_be64(&priv2->puq[i].mfc_cq_data2_RW);
+ csa->priv2.puq[i].mfc_cq_data3_RW =
+ in_be64(&priv2->puq[i].mfc_cq_data3_RW);
+ }
+ for (i = 0; i < 16; i++) {
+ csa->priv2.spuq[i].mfc_cq_data0_RW =
+ in_be64(&priv2->spuq[i].mfc_cq_data0_RW);
+ csa->priv2.spuq[i].mfc_cq_data1_RW =
+ in_be64(&priv2->spuq[i].mfc_cq_data1_RW);
+ csa->priv2.spuq[i].mfc_cq_data2_RW =
+ in_be64(&priv2->spuq[i].mfc_cq_data2_RW);
+ csa->priv2.spuq[i].mfc_cq_data3_RW =
+ in_be64(&priv2->spuq[i].mfc_cq_data3_RW);
+ }
+ }
+}
+
+static inline void save_ppu_querymask(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+
+ /* Save, Step 20:
+ * Save the PPU_QueryMask register
+ * in the CSA.
+ */
+ csa->prob.dma_querymask_RW = in_be32(&prob->dma_querymask_RW);
+}
+
+static inline void save_ppu_querytype(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+
+ /* Save, Step 21:
+ * Save the PPU_QueryType register
+ * in the CSA.
+ */
+ csa->prob.dma_querytype_RW = in_be32(&prob->dma_querytype_RW);
+}
+
+static inline void save_mfc_csr_tsq(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Save, Step 22:
+ * Save the MFC_CSR_TSQ register
+ * in the LSCSA.
+ */
+ csa->priv2.spu_tag_status_query_RW =
+ in_be64(&priv2->spu_tag_status_query_RW);
+}
+
+static inline void save_mfc_csr_cmd(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Save, Step 23:
+ * Save the MFC_CSR_CMD1 and MFC_CSR_CMD2
+ * registers in the CSA.
+ */
+ csa->priv2.spu_cmd_buf1_RW = in_be64(&priv2->spu_cmd_buf1_RW);
+ csa->priv2.spu_cmd_buf2_RW = in_be64(&priv2->spu_cmd_buf2_RW);
+}
+
+static inline void save_mfc_csr_ato(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Save, Step 24:
+ * Save the MFC_CSR_ATO register in
+ * the CSA.
+ */
+ csa->priv2.spu_atomic_status_RW = in_be64(&priv2->spu_atomic_status_RW);
+}
+
+static inline void save_mfc_tclass_id(struct spu_state *csa, struct spu *spu)
+{
+ /* Save, Step 25:
+ * Save the MFC_TCLASS_ID register in
+ * the CSA.
+ */
+ csa->priv1.mfc_tclass_id_RW = spu_mfc_tclass_id_get(spu);
+}
+
+static inline void set_mfc_tclass_id(struct spu_state *csa, struct spu *spu)
+{
+ /* Save, Step 26:
+ * Restore, Step 23.
+ * Write the MFC_TCLASS_ID register with
+ * the value 0x10000000.
+ */
+ spu_mfc_tclass_id_set(spu, 0x10000000);
+ eieio();
+}
+
+static inline void purge_mfc_queue(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Save, Step 27:
+ * Restore, Step 14.
+ * Write MFC_CNTL[Pc]=1 (purge queue).
+ */
+ out_be64(&priv2->mfc_control_RW, MFC_CNTL_PURGE_DMA_REQUEST);
+ eieio();
+}
+
+static inline void wait_purge_complete(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Save, Step 28:
+ * Poll MFC_CNTL[Ps] until value '11' is read
+ * (purge complete).
+ */
+ POLL_WHILE_FALSE(in_be64(&priv2->mfc_control_RW) &
+ MFC_CNTL_PURGE_DMA_COMPLETE);
+}
+
+static inline void save_mfc_slbs(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+ int i;
+
+ /* Save, Step 29:
+ * If MFC_SR1[R]='1', save SLBs in CSA.
+ */
+ if (spu_mfc_sr1_get(spu) & MFC_STATE1_RELOCATE_MASK) {
+ csa->priv2.slb_index_W = in_be64(&priv2->slb_index_W);
+ for (i = 0; i < 8; i++) {
+ out_be64(&priv2->slb_index_W, i);
+ eieio();
+ csa->slb_esid_RW[i] = in_be64(&priv2->slb_esid_RW);
+ csa->slb_vsid_RW[i] = in_be64(&priv2->slb_vsid_RW);
+ eieio();
+ }
+ }
+}
+
+static inline void setup_mfc_sr1(struct spu_state *csa, struct spu *spu)
+{
+ /* Save, Step 30:
+ * Restore, Step 18:
+ * Write MFC_SR1 with MFC_SR1[D=0,S=1] and
+ * MFC_SR1[TL,R,Pr,T] set correctly for the
+ * OS specific environment.
+ *
+ * Implementation note: The SPU-side code
+ * for save/restore is privileged, so the
+ * MFC_SR1[Pr] bit is not set.
+ *
+ */
+ spu_mfc_sr1_set(spu, (MFC_STATE1_MASTER_RUN_CONTROL_MASK |
+ MFC_STATE1_RELOCATE_MASK |
+ MFC_STATE1_BUS_TLBIE_MASK));
+}
+
+static inline void save_spu_npc(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+
+ /* Save, Step 31:
+ * Save SPU_NPC in the CSA.
+ */
+ csa->prob.spu_npc_RW = in_be32(&prob->spu_npc_RW);
+}
+
+static inline void save_spu_privcntl(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Save, Step 32:
+ * Save SPU_PrivCntl in the CSA.
+ */
+ csa->priv2.spu_privcntl_RW = in_be64(&priv2->spu_privcntl_RW);
+}
+
+static inline void reset_spu_privcntl(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Save, Step 33:
+ * Restore, Step 16:
+ * Write SPU_PrivCntl[S,Le,A] fields reset to 0.
+ */
+ out_be64(&priv2->spu_privcntl_RW, 0UL);
+ eieio();
+}
+
+static inline void save_spu_lslr(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Save, Step 34:
+ * Save SPU_LSLR in the CSA.
+ */
+ csa->priv2.spu_lslr_RW = in_be64(&priv2->spu_lslr_RW);
+}
+
+static inline void reset_spu_lslr(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Save, Step 35:
+ * Restore, Step 17.
+ * Reset SPU_LSLR.
+ */
+ out_be64(&priv2->spu_lslr_RW, LS_ADDR_MASK);
+ eieio();
+}
+
+static inline void save_spu_cfg(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Save, Step 36:
+ * Save SPU_Cfg in the CSA.
+ */
+ csa->priv2.spu_cfg_RW = in_be64(&priv2->spu_cfg_RW);
+}
+
+static inline void save_pm_trace(struct spu_state *csa, struct spu *spu)
+{
+ /* Save, Step 37:
+ * Save PM_Trace_Tag_Wait_Mask in the CSA.
+ * Not performed by this implementation.
+ */
+}
+
+static inline void save_mfc_rag(struct spu_state *csa, struct spu *spu)
+{
+ /* Save, Step 38:
+ * Save RA_GROUP_ID register and the
+ * RA_ENABLE reigster in the CSA.
+ */
+ csa->priv1.resource_allocation_groupID_RW =
+ spu_resource_allocation_groupID_get(spu);
+ csa->priv1.resource_allocation_enable_RW =
+ spu_resource_allocation_enable_get(spu);
+}
+
+static inline void save_ppu_mb_stat(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+
+ /* Save, Step 39:
+ * Save MB_Stat register in the CSA.
+ */
+ csa->prob.mb_stat_R = in_be32(&prob->mb_stat_R);
+}
+
+static inline void save_ppu_mb(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+
+ /* Save, Step 40:
+ * Save the PPU_MB register in the CSA.
+ */
+ csa->prob.pu_mb_R = in_be32(&prob->pu_mb_R);
+}
+
+static inline void save_ppuint_mb(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Save, Step 41:
+ * Save the PPUINT_MB register in the CSA.
+ */
+ csa->priv2.puint_mb_R = in_be64(&priv2->puint_mb_R);
+}
+
+static inline void save_ch_part1(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+ u64 idx, ch_indices[7] = { 0UL, 1UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+ int i;
+
+ /* Save, Step 42:
+ * Save the following CH: [0,1,3,4,24,25,27]
+ */
+ for (i = 0; i < 7; i++) {
+ idx = ch_indices[i];
+ out_be64(&priv2->spu_chnlcntptr_RW, idx);
+ eieio();
+ csa->spu_chnldata_RW[idx] = in_be64(&priv2->spu_chnldata_RW);
+ csa->spu_chnlcnt_RW[idx] = in_be64(&priv2->spu_chnlcnt_RW);
+ out_be64(&priv2->spu_chnldata_RW, 0UL);
+ out_be64(&priv2->spu_chnlcnt_RW, 0UL);
+ eieio();
+ }
+}
+
+static inline void save_spu_mb(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+ int i;
+
+ /* Save, Step 43:
+ * Save SPU Read Mailbox Channel.
+ */
+ out_be64(&priv2->spu_chnlcntptr_RW, 29UL);
+ eieio();
+ csa->spu_chnlcnt_RW[29] = in_be64(&priv2->spu_chnlcnt_RW);
+ for (i = 0; i < 4; i++) {
+ csa->spu_mailbox_data[i] = in_be64(&priv2->spu_chnldata_RW);
+ }
+ out_be64(&priv2->spu_chnlcnt_RW, 0UL);
+ eieio();
+}
+
+static inline void save_mfc_cmd(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Save, Step 44:
+ * Save MFC_CMD Channel.
+ */
+ out_be64(&priv2->spu_chnlcntptr_RW, 21UL);
+ eieio();
+ csa->spu_chnlcnt_RW[21] = in_be64(&priv2->spu_chnlcnt_RW);
+ eieio();
+}
+
+static inline void reset_ch(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+ u64 ch_indices[4] = { 21UL, 23UL, 28UL, 30UL };
+ u64 ch_counts[4] = { 16UL, 1UL, 1UL, 1UL };
+ u64 idx;
+ int i;
+
+ /* Save, Step 45:
+ * Reset the following CH: [21, 23, 28, 30]
+ */
+ for (i = 0; i < 4; i++) {
+ idx = ch_indices[i];
+ out_be64(&priv2->spu_chnlcntptr_RW, idx);
+ eieio();
+ out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]);
+ eieio();
+ }
+}
+
+static inline void resume_mfc_queue(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Save, Step 46:
+ * Restore, Step 25.
+ * Write MFC_CNTL[Sc]=0 (resume queue processing).
+ */
+ out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESUME_DMA_QUEUE);
+}
+
+static inline void invalidate_slbs(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Save, Step 45:
+ * Restore, Step 19:
+ * If MFC_SR1[R]=1, write 0 to SLB_Invalidate_All.
+ */
+ if (spu_mfc_sr1_get(spu) & MFC_STATE1_RELOCATE_MASK) {
+ out_be64(&priv2->slb_invalidate_all_W, 0UL);
+ eieio();
+ }
+}
+
+static inline void get_kernel_slb(u64 ea, u64 slb[2])
+{
+ slb[0] = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | SLB_VSID_KERNEL;
+ slb[1] = (ea & ESID_MASK) | SLB_ESID_V;
+
+ /* Large pages are used for kernel text/data, but not vmalloc. */
+ if (cpu_has_feature(CPU_FTR_16M_PAGE)
+ && REGION_ID(ea) == KERNEL_REGION_ID)
+ slb[0] |= SLB_VSID_L;
+}
+
+static inline void load_mfc_slb(struct spu *spu, u64 slb[2], int slbe)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ out_be64(&priv2->slb_index_W, slbe);
+ eieio();
+ out_be64(&priv2->slb_vsid_RW, slb[0]);
+ out_be64(&priv2->slb_esid_RW, slb[1]);
+ eieio();
+}
+
+static inline void setup_mfc_slbs(struct spu_state *csa, struct spu *spu)
+{
+ u64 code_slb[2];
+ u64 lscsa_slb[2];
+
+ /* Save, Step 47:
+ * Restore, Step 30.
+ * If MFC_SR1[R]=1, write 0 to SLB_Invalidate_All
+ * register, then initialize SLB_VSID and SLB_ESID
+ * to provide access to SPU context save code and
+ * LSCSA.
+ *
+ * This implementation places both the context
+ * switch code and LSCSA in kernel address space.
+ *
+ * Further this implementation assumes that the
+ * MFC_SR1[R]=1 (in other words, assume that
+ * translation is desired by OS environment).
+ */
+ invalidate_slbs(csa, spu);
+ get_kernel_slb((unsigned long)&spu_save_code[0], code_slb);
+ get_kernel_slb((unsigned long)csa->lscsa, lscsa_slb);
+ load_mfc_slb(spu, code_slb, 0);
+ if ((lscsa_slb[0] != code_slb[0]) || (lscsa_slb[1] != code_slb[1]))
+ load_mfc_slb(spu, lscsa_slb, 1);
+}
+
+static inline void set_switch_active(struct spu_state *csa, struct spu *spu)
+{
+ /* Save, Step 48:
+ * Restore, Step 23.
+ * Change the software context switch pending flag
+ * to context switch active.
+ */
+ set_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags);
+ clear_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags);
+ mb();
+}
+
+static inline void enable_interrupts(struct spu_state *csa, struct spu *spu)
+{
+ unsigned long class1_mask = CLASS1_ENABLE_SEGMENT_FAULT_INTR |
+ CLASS1_ENABLE_STORAGE_FAULT_INTR;
+
+ /* Save, Step 49:
+ * Restore, Step 22:
+ * Reset and then enable interrupts, as
+ * needed by OS.
+ *
+ * This implementation enables only class1
+ * (translation) interrupts.
+ */
+ spin_lock_irq(&spu->register_lock);
+ spu_int_stat_clear(spu, 0, ~0ul);
+ spu_int_stat_clear(spu, 1, ~0ul);
+ spu_int_stat_clear(spu, 2, ~0ul);
+ spu_int_mask_set(spu, 0, 0ul);
+ spu_int_mask_set(spu, 1, class1_mask);
+ spu_int_mask_set(spu, 2, 0ul);
+ spin_unlock_irq(&spu->register_lock);
+}
+
+static inline int send_mfc_dma(struct spu *spu, unsigned long ea,
+ unsigned int ls_offset, unsigned int size,
+ unsigned int tag, unsigned int rclass,
+ unsigned int cmd)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+ union mfc_tag_size_class_cmd command;
+ unsigned int transfer_size;
+ volatile unsigned int status = 0x0;
+
+ while (size > 0) {
+ transfer_size =
+ (size > MFC_MAX_DMA_SIZE) ? MFC_MAX_DMA_SIZE : size;
+ command.u.mfc_size = transfer_size;
+ command.u.mfc_tag = tag;
+ command.u.mfc_rclassid = rclass;
+ command.u.mfc_cmd = cmd;
+ do {
+ out_be32(&prob->mfc_lsa_W, ls_offset);
+ out_be64(&prob->mfc_ea_W, ea);
+ out_be64(&prob->mfc_union_W.all64, command.all64);
+ status =
+ in_be32(&prob->mfc_union_W.by32.mfc_class_cmd32);
+ if (unlikely(status & 0x2)) {
+ cpu_relax();
+ }
+ } while (status & 0x3);
+ size -= transfer_size;
+ ea += transfer_size;
+ ls_offset += transfer_size;
+ }
+ return 0;
+}
+
+static inline void save_ls_16kb(struct spu_state *csa, struct spu *spu)
+{
+ unsigned long addr = (unsigned long)&csa->lscsa->ls[0];
+ unsigned int ls_offset = 0x0;
+ unsigned int size = 16384;
+ unsigned int tag = 0;
+ unsigned int rclass = 0;
+ unsigned int cmd = MFC_PUT_CMD;
+
+ /* Save, Step 50:
+ * Issue a DMA command to copy the first 16K bytes
+ * of local storage to the CSA.
+ */
+ send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
+}
+
+static inline void set_spu_npc(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+
+ /* Save, Step 51:
+ * Restore, Step 31.
+ * Write SPU_NPC[IE]=0 and SPU_NPC[LSA] to entry
+ * point address of context save code in local
+ * storage.
+ *
+ * This implementation uses SPU-side save/restore
+ * programs with entry points at LSA of 0.
+ */
+ out_be32(&prob->spu_npc_RW, 0);
+ eieio();
+}
+
+static inline void set_signot1(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+ union {
+ u64 ull;
+ u32 ui[2];
+ } addr64;
+
+ /* Save, Step 52:
+ * Restore, Step 32:
+ * Write SPU_Sig_Notify_1 register with upper 32-bits
+ * of the CSA.LSCSA effective address.
+ */
+ addr64.ull = (u64) csa->lscsa;
+ out_be32(&prob->signal_notify1, addr64.ui[0]);
+ eieio();
+}
+
+static inline void set_signot2(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+ union {
+ u64 ull;
+ u32 ui[2];
+ } addr64;
+
+ /* Save, Step 53:
+ * Restore, Step 33:
+ * Write SPU_Sig_Notify_2 register with lower 32-bits
+ * of the CSA.LSCSA effective address.
+ */
+ addr64.ull = (u64) csa->lscsa;
+ out_be32(&prob->signal_notify2, addr64.ui[1]);
+ eieio();
+}
+
+static inline void send_save_code(struct spu_state *csa, struct spu *spu)
+{
+ unsigned long addr = (unsigned long)&spu_save_code[0];
+ unsigned int ls_offset = 0x0;
+ unsigned int size = sizeof(spu_save_code);
+ unsigned int tag = 0;
+ unsigned int rclass = 0;
+ unsigned int cmd = MFC_GETFS_CMD;
+
+ /* Save, Step 54:
+ * Issue a DMA command to copy context save code
+ * to local storage and start SPU.
+ */
+ send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
+}
+
+static inline void set_ppu_querymask(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+
+ /* Save, Step 55:
+ * Restore, Step 38.
+ * Write PPU_QueryMask=1 (enable Tag Group 0)
+ * and issue eieio instruction.
+ */
+ out_be32(&prob->dma_querymask_RW, MFC_TAGID_TO_TAGMASK(0));
+ eieio();
+}
+
+static inline void wait_tag_complete(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+ u32 mask = MFC_TAGID_TO_TAGMASK(0);
+ unsigned long flags;
+
+ /* Save, Step 56:
+ * Restore, Step 39.
+ * Restore, Step 39.
+ * Restore, Step 46.
+ * Poll PPU_TagStatus[gn] until 01 (Tag group 0 complete)
+ * or write PPU_QueryType[TS]=01 and wait for Tag Group
+ * Complete Interrupt. Write INT_Stat_Class0 or
+ * INT_Stat_Class2 with value of 'handled'.
+ */
+ POLL_WHILE_FALSE(in_be32(&prob->dma_tagstatus_R) & mask);
+
+ local_irq_save(flags);
+ spu_int_stat_clear(spu, 0, ~(0ul));
+ spu_int_stat_clear(spu, 2, ~(0ul));
+ local_irq_restore(flags);
+}
+
+static inline void wait_spu_stopped(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+ unsigned long flags;
+
+ /* Save, Step 57:
+ * Restore, Step 40.
+ * Poll until SPU_Status[R]=0 or wait for SPU Class 0
+ * or SPU Class 2 interrupt. Write INT_Stat_class0
+ * or INT_Stat_class2 with value of handled.
+ */
+ POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING);
+
+ local_irq_save(flags);
+ spu_int_stat_clear(spu, 0, ~(0ul));
+ spu_int_stat_clear(spu, 2, ~(0ul));
+ local_irq_restore(flags);
+}
+
+static inline int check_save_status(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+ u32 complete;
+
+ /* Save, Step 54:
+ * If SPU_Status[P]=1 and SPU_Status[SC] = "success",
+ * context save succeeded, otherwise context save
+ * failed.
+ */
+ complete = ((SPU_SAVE_COMPLETE << SPU_STOP_STATUS_SHIFT) |
+ SPU_STATUS_STOPPED_BY_STOP);
+ return (in_be32(&prob->spu_status_R) != complete) ? 1 : 0;
+}
+
+static inline void terminate_spu_app(struct spu_state *csa, struct spu *spu)
+{
+ /* Restore, Step 4:
+ * If required, notify the "using application" that
+ * the SPU task has been terminated. TBD.
+ */
+}
+
+static inline void suspend_mfc(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Restore, Step 7:
+ * Restore, Step 47.
+ * Write MFC_Cntl[Dh,Sc]='1','1' to suspend
+ * the queue and halt the decrementer.
+ */
+ out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE |
+ MFC_CNTL_DECREMENTER_HALTED);
+ eieio();
+}
+
+static inline void wait_suspend_mfc_complete(struct spu_state *csa,
+ struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Restore, Step 8:
+ * Restore, Step 47.
+ * Poll MFC_CNTL[Ss] until 11 is returned.
+ */
+ POLL_WHILE_FALSE(in_be64(&priv2->mfc_control_RW) &
+ MFC_CNTL_SUSPEND_COMPLETE);
+}
+
+static inline int suspend_spe(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+
+ /* Restore, Step 9:
+ * If SPU_Status[R]=1, stop SPU execution
+ * and wait for stop to complete.
+ *
+ * Returns 1 if SPU_Status[R]=1 on entry.
+ * 0 otherwise
+ */
+ if (in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) {
+ if (in_be32(&prob->spu_status_R) &
+ SPU_STATUS_ISOLATED_EXIT_STAUTUS) {
+ POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+ SPU_STATUS_RUNNING);
+ }
+ if ((in_be32(&prob->spu_status_R) &
+ SPU_STATUS_ISOLATED_LOAD_STAUTUS)
+ || (in_be32(&prob->spu_status_R) &
+ SPU_STATUS_ISOLATED_STATE)) {
+ out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
+ eieio();
+ POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+ SPU_STATUS_RUNNING);
+ out_be32(&prob->spu_runcntl_RW, 0x2);
+ eieio();
+ POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+ SPU_STATUS_RUNNING);
+ }
+ if (in_be32(&prob->spu_status_R) &
+ SPU_STATUS_WAITING_FOR_CHANNEL) {
+ out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
+ eieio();
+ POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+ SPU_STATUS_RUNNING);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static inline void clear_spu_status(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+
+ /* Restore, Step 10:
+ * If SPU_Status[R]=0 and SPU_Status[E,L,IS]=1,
+ * release SPU from isolate state.
+ */
+ if (!(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING)) {
+ if (in_be32(&prob->spu_status_R) &
+ SPU_STATUS_ISOLATED_EXIT_STAUTUS) {
+ spu_mfc_sr1_set(spu,
+ MFC_STATE1_MASTER_RUN_CONTROL_MASK);
+ eieio();
+ out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
+ eieio();
+ POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+ SPU_STATUS_RUNNING);
+ }
+ if ((in_be32(&prob->spu_status_R) &
+ SPU_STATUS_ISOLATED_LOAD_STAUTUS)
+ || (in_be32(&prob->spu_status_R) &
+ SPU_STATUS_ISOLATED_STATE)) {
+ spu_mfc_sr1_set(spu,
+ MFC_STATE1_MASTER_RUN_CONTROL_MASK);
+ eieio();
+ out_be32(&prob->spu_runcntl_RW, 0x2);
+ eieio();
+ POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+ SPU_STATUS_RUNNING);
+ }
+ }
+}
+
+static inline void reset_ch_part1(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+ u64 ch_indices[7] = { 0UL, 1UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+ u64 idx;
+ int i;
+
+ /* Restore, Step 20:
+ * Reset the following CH: [0,1,3,4,24,25,27]
+ */
+ for (i = 0; i < 7; i++) {
+ idx = ch_indices[i];
+ out_be64(&priv2->spu_chnlcntptr_RW, idx);
+ eieio();
+ out_be64(&priv2->spu_chnldata_RW, 0UL);
+ out_be64(&priv2->spu_chnlcnt_RW, 0UL);
+ eieio();
+ }
+}
+
+static inline void reset_ch_part2(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+ u64 ch_indices[5] = { 21UL, 23UL, 28UL, 29UL, 30UL };
+ u64 ch_counts[5] = { 16UL, 1UL, 1UL, 0UL, 1UL };
+ u64 idx;
+ int i;
+
+ /* Restore, Step 21:
+ * Reset the following CH: [21, 23, 28, 29, 30]
+ */
+ for (i = 0; i < 5; i++) {
+ idx = ch_indices[i];
+ out_be64(&priv2->spu_chnlcntptr_RW, idx);
+ eieio();
+ out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]);
+ eieio();
+ }
+}
+
+static inline void setup_spu_status_part1(struct spu_state *csa,
+ struct spu *spu)
+{
+ u32 status_P = SPU_STATUS_STOPPED_BY_STOP;
+ u32 status_I = SPU_STATUS_INVALID_INSTR;
+ u32 status_H = SPU_STATUS_STOPPED_BY_HALT;
+ u32 status_S = SPU_STATUS_SINGLE_STEP;
+ u32 status_S_I = SPU_STATUS_SINGLE_STEP | SPU_STATUS_INVALID_INSTR;
+ u32 status_S_P = SPU_STATUS_SINGLE_STEP | SPU_STATUS_STOPPED_BY_STOP;
+ u32 status_P_H = SPU_STATUS_STOPPED_BY_HALT |SPU_STATUS_STOPPED_BY_STOP;
+ u32 status_P_I = SPU_STATUS_STOPPED_BY_STOP |SPU_STATUS_INVALID_INSTR;
+ u32 status_code;
+
+ /* Restore, Step 27:
+ * If the CSA.SPU_Status[I,S,H,P]=1 then add the correct
+ * instruction sequence to the end of the SPU based restore
+ * code (after the "context restored" stop and signal) to
+ * restore the correct SPU status.
+ *
+ * NOTE: Rather than modifying the SPU executable, we
+ * instead add a new 'stopped_status' field to the
+ * LSCSA. The SPU-side restore reads this field and
+ * takes the appropriate action when exiting.
+ */
+
+ status_code =
+ (csa->prob.spu_status_R >> SPU_STOP_STATUS_SHIFT) & 0xFFFF;
+ if ((csa->prob.spu_status_R & status_P_I) == status_P_I) {
+
+ /* SPU_Status[P,I]=1 - Illegal Instruction followed
+ * by Stop and Signal instruction, followed by 'br -4'.
+ *
+ */
+ csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P_I;
+ csa->lscsa->stopped_status.slot[1] = status_code;
+
+ } else if ((csa->prob.spu_status_R & status_P_H) == status_P_H) {
+
+ /* SPU_Status[P,H]=1 - Halt Conditional, followed
+ * by Stop and Signal instruction, followed by
+ * 'br -4'.
+ */
+ csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P_H;
+ csa->lscsa->stopped_status.slot[1] = status_code;
+
+ } else if ((csa->prob.spu_status_R & status_S_P) == status_S_P) {
+
+ /* SPU_Status[S,P]=1 - Stop and Signal instruction
+ * followed by 'br -4'.
+ */
+ csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S_P;
+ csa->lscsa->stopped_status.slot[1] = status_code;
+
+ } else if ((csa->prob.spu_status_R & status_S_I) == status_S_I) {
+
+ /* SPU_Status[S,I]=1 - Illegal instruction followed
+ * by 'br -4'.
+ */
+ csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S_I;
+ csa->lscsa->stopped_status.slot[1] = status_code;
+
+ } else if ((csa->prob.spu_status_R & status_P) == status_P) {
+
+ /* SPU_Status[P]=1 - Stop and Signal instruction
+ * followed by 'br -4'.
+ */
+ csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P;
+ csa->lscsa->stopped_status.slot[1] = status_code;
+
+ } else if ((csa->prob.spu_status_R & status_H) == status_H) {
+
+ /* SPU_Status[H]=1 - Halt Conditional, followed
+ * by 'br -4'.
+ */
+ csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_H;
+
+ } else if ((csa->prob.spu_status_R & status_S) == status_S) {
+
+ /* SPU_Status[S]=1 - Two nop instructions.
+ */
+ csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S;
+
+ } else if ((csa->prob.spu_status_R & status_I) == status_I) {
+
+ /* SPU_Status[I]=1 - Illegal instruction followed
+ * by 'br -4'.
+ */
+ csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_I;
+
+ }
+}
+
+static inline void setup_spu_status_part2(struct spu_state *csa,
+ struct spu *spu)
+{
+ u32 mask;
+
+ /* Restore, Step 28:
+ * If the CSA.SPU_Status[I,S,H,P,R]=0 then
+ * add a 'br *' instruction to the end of
+ * the SPU based restore code.
+ *
+ * NOTE: Rather than modifying the SPU executable, we
+ * instead add a new 'stopped_status' field to the
+ * LSCSA. The SPU-side restore reads this field and
+ * takes the appropriate action when exiting.
+ */
+ mask = SPU_STATUS_INVALID_INSTR |
+ SPU_STATUS_SINGLE_STEP |
+ SPU_STATUS_STOPPED_BY_HALT |
+ SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_RUNNING;
+ if (!(csa->prob.spu_status_R & mask)) {
+ csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_R;
+ }
+}
+
+static inline void restore_mfc_rag(struct spu_state *csa, struct spu *spu)
+{
+ /* Restore, Step 29:
+ * Restore RA_GROUP_ID register and the
+ * RA_ENABLE reigster from the CSA.
+ */
+ spu_resource_allocation_groupID_set(spu,
+ csa->priv1.resource_allocation_groupID_RW);
+ spu_resource_allocation_enable_set(spu,
+ csa->priv1.resource_allocation_enable_RW);
+}
+
+static inline void send_restore_code(struct spu_state *csa, struct spu *spu)
+{
+ unsigned long addr = (unsigned long)&spu_restore_code[0];
+ unsigned int ls_offset = 0x0;
+ unsigned int size = sizeof(spu_restore_code);
+ unsigned int tag = 0;
+ unsigned int rclass = 0;
+ unsigned int cmd = MFC_GETFS_CMD;
+
+ /* Restore, Step 37:
+ * Issue MFC DMA command to copy context
+ * restore code to local storage.
+ */
+ send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
+}
+
+static inline void setup_decr(struct spu_state *csa, struct spu *spu)
+{
+ /* Restore, Step 34:
+ * If CSA.MFC_CNTL[Ds]=1 (decrementer was
+ * running) then adjust decrementer, set
+ * decrementer running status in LSCSA,
+ * and set decrementer "wrapped" status
+ * in LSCSA.
+ */
+ if (csa->priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) {
+ cycles_t resume_time = get_cycles();
+ cycles_t delta_time = resume_time - csa->suspend_time;
+
+ csa->lscsa->decr.slot[0] = delta_time;
+ }
+}
+
+static inline void setup_ppu_mb(struct spu_state *csa, struct spu *spu)
+{
+ /* Restore, Step 35:
+ * Copy the CSA.PU_MB data into the LSCSA.
+ */
+ csa->lscsa->ppu_mb.slot[0] = csa->prob.pu_mb_R;
+}
+
+static inline void setup_ppuint_mb(struct spu_state *csa, struct spu *spu)
+{
+ /* Restore, Step 36:
+ * Copy the CSA.PUINT_MB data into the LSCSA.
+ */
+ csa->lscsa->ppuint_mb.slot[0] = csa->priv2.puint_mb_R;
+}
+
+static inline int check_restore_status(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+ u32 complete;
+
+ /* Restore, Step 40:
+ * If SPU_Status[P]=1 and SPU_Status[SC] = "success",
+ * context restore succeeded, otherwise context restore
+ * failed.
+ */
+ complete = ((SPU_RESTORE_COMPLETE << SPU_STOP_STATUS_SHIFT) |
+ SPU_STATUS_STOPPED_BY_STOP);
+ return (in_be32(&prob->spu_status_R) != complete) ? 1 : 0;
+}
+
+static inline void restore_spu_privcntl(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Restore, Step 41:
+ * Restore SPU_PrivCntl from the CSA.
+ */
+ out_be64(&priv2->spu_privcntl_RW, csa->priv2.spu_privcntl_RW);
+ eieio();
+}
+
+static inline void restore_status_part1(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+ u32 mask;
+
+ /* Restore, Step 42:
+ * If any CSA.SPU_Status[I,S,H,P]=1, then
+ * restore the error or single step state.
+ */
+ mask = SPU_STATUS_INVALID_INSTR |
+ SPU_STATUS_SINGLE_STEP |
+ SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP;
+ if (csa->prob.spu_status_R & mask) {
+ out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
+ eieio();
+ POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+ SPU_STATUS_RUNNING);
+ }
+}
+
+static inline void restore_status_part2(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+ u32 mask;
+
+ /* Restore, Step 43:
+ * If all CSA.SPU_Status[I,S,H,P,R]=0 then write
+ * SPU_RunCntl[R0R1]='01', wait for SPU_Status[R]=1,
+ * then write '00' to SPU_RunCntl[R0R1] and wait
+ * for SPU_Status[R]=0.
+ */
+ mask = SPU_STATUS_INVALID_INSTR |
+ SPU_STATUS_SINGLE_STEP |
+ SPU_STATUS_STOPPED_BY_HALT |
+ SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_RUNNING;
+ if (!(csa->prob.spu_status_R & mask)) {
+ out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
+ eieio();
+ POLL_WHILE_FALSE(in_be32(&prob->spu_status_R) &
+ SPU_STATUS_RUNNING);
+ out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
+ eieio();
+ POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
+ SPU_STATUS_RUNNING);
+ }
+}
+
+static inline void restore_ls_16kb(struct spu_state *csa, struct spu *spu)
+{
+ unsigned long addr = (unsigned long)&csa->lscsa->ls[0];
+ unsigned int ls_offset = 0x0;
+ unsigned int size = 16384;
+ unsigned int tag = 0;
+ unsigned int rclass = 0;
+ unsigned int cmd = MFC_GET_CMD;
+
+ /* Restore, Step 44:
+ * Issue a DMA command to restore the first
+ * 16kb of local storage from CSA.
+ */
+ send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
+}
+
+static inline void clear_interrupts(struct spu_state *csa, struct spu *spu)
+{
+ /* Restore, Step 49:
+ * Write INT_MASK_class0 with value of 0.
+ * Write INT_MASK_class1 with value of 0.
+ * Write INT_MASK_class2 with value of 0.
+ * Write INT_STAT_class0 with value of -1.
+ * Write INT_STAT_class1 with value of -1.
+ * Write INT_STAT_class2 with value of -1.
+ */
+ spin_lock_irq(&spu->register_lock);
+ spu_int_mask_set(spu, 0, 0ul);
+ spu_int_mask_set(spu, 1, 0ul);
+ spu_int_mask_set(spu, 2, 0ul);
+ spu_int_stat_clear(spu, 0, ~0ul);
+ spu_int_stat_clear(spu, 1, ~0ul);
+ spu_int_stat_clear(spu, 2, ~0ul);
+ spin_unlock_irq(&spu->register_lock);
+}
+
+static inline void restore_mfc_queues(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+ int i;
+
+ /* Restore, Step 50:
+ * If MFC_Cntl[Se]!=0 then restore
+ * MFC command queues.
+ */
+ if ((csa->priv2.mfc_control_RW & MFC_CNTL_DMA_QUEUES_EMPTY_MASK) == 0) {
+ for (i = 0; i < 8; i++) {
+ out_be64(&priv2->puq[i].mfc_cq_data0_RW,
+ csa->priv2.puq[i].mfc_cq_data0_RW);
+ out_be64(&priv2->puq[i].mfc_cq_data1_RW,
+ csa->priv2.puq[i].mfc_cq_data1_RW);
+ out_be64(&priv2->puq[i].mfc_cq_data2_RW,
+ csa->priv2.puq[i].mfc_cq_data2_RW);
+ out_be64(&priv2->puq[i].mfc_cq_data3_RW,
+ csa->priv2.puq[i].mfc_cq_data3_RW);
+ }
+ for (i = 0; i < 16; i++) {
+ out_be64(&priv2->spuq[i].mfc_cq_data0_RW,
+ csa->priv2.spuq[i].mfc_cq_data0_RW);
+ out_be64(&priv2->spuq[i].mfc_cq_data1_RW,
+ csa->priv2.spuq[i].mfc_cq_data1_RW);
+ out_be64(&priv2->spuq[i].mfc_cq_data2_RW,
+ csa->priv2.spuq[i].mfc_cq_data2_RW);
+ out_be64(&priv2->spuq[i].mfc_cq_data3_RW,
+ csa->priv2.spuq[i].mfc_cq_data3_RW);
+ }
+ }
+ eieio();
+}
+
+static inline void restore_ppu_querymask(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+
+ /* Restore, Step 51:
+ * Restore the PPU_QueryMask register from CSA.
+ */
+ out_be32(&prob->dma_querymask_RW, csa->prob.dma_querymask_RW);
+ eieio();
+}
+
+static inline void restore_ppu_querytype(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+
+ /* Restore, Step 52:
+ * Restore the PPU_QueryType register from CSA.
+ */
+ out_be32(&prob->dma_querytype_RW, csa->prob.dma_querytype_RW);
+ eieio();
+}
+
+static inline void restore_mfc_csr_tsq(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Restore, Step 53:
+ * Restore the MFC_CSR_TSQ register from CSA.
+ */
+ out_be64(&priv2->spu_tag_status_query_RW,
+ csa->priv2.spu_tag_status_query_RW);
+ eieio();
+}
+
+static inline void restore_mfc_csr_cmd(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Restore, Step 54:
+ * Restore the MFC_CSR_CMD1 and MFC_CSR_CMD2
+ * registers from CSA.
+ */
+ out_be64(&priv2->spu_cmd_buf1_RW, csa->priv2.spu_cmd_buf1_RW);
+ out_be64(&priv2->spu_cmd_buf2_RW, csa->priv2.spu_cmd_buf2_RW);
+ eieio();
+}
+
+static inline void restore_mfc_csr_ato(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Restore, Step 55:
+ * Restore the MFC_CSR_ATO register from CSA.
+ */
+ out_be64(&priv2->spu_atomic_status_RW, csa->priv2.spu_atomic_status_RW);
+}
+
+static inline void restore_mfc_tclass_id(struct spu_state *csa, struct spu *spu)
+{
+ /* Restore, Step 56:
+ * Restore the MFC_TCLASS_ID register from CSA.
+ */
+ spu_mfc_tclass_id_set(spu, csa->priv1.mfc_tclass_id_RW);
+ eieio();
+}
+
+static inline void set_llr_event(struct spu_state *csa, struct spu *spu)
+{
+ u64 ch0_cnt, ch0_data;
+ u64 ch1_data;
+
+ /* Restore, Step 57:
+ * Set the Lock Line Reservation Lost Event by:
+ * 1. OR CSA.SPU_Event_Status with bit 21 (Lr) set to 1.
+ * 2. If CSA.SPU_Channel_0_Count=0 and
+ * CSA.SPU_Wr_Event_Mask[Lr]=1 and
+ * CSA.SPU_Event_Status[Lr]=0 then set
+ * CSA.SPU_Event_Status_Count=1.
+ */
+ ch0_cnt = csa->spu_chnlcnt_RW[0];
+ ch0_data = csa->spu_chnldata_RW[0];
+ ch1_data = csa->spu_chnldata_RW[1];
+ csa->spu_chnldata_RW[0] |= MFC_LLR_LOST_EVENT;
+ if ((ch0_cnt == 0) && !(ch0_data & MFC_LLR_LOST_EVENT) &&
+ (ch1_data & MFC_LLR_LOST_EVENT)) {
+ csa->spu_chnlcnt_RW[0] = 1;
+ }
+}
+
+static inline void restore_decr_wrapped(struct spu_state *csa, struct spu *spu)
+{
+ /* Restore, Step 58:
+ * If the status of the CSA software decrementer
+ * "wrapped" flag is set, OR in a '1' to
+ * CSA.SPU_Event_Status[Tm].
+ */
+ if (csa->lscsa->decr_status.slot[0] == 1) {
+ csa->spu_chnldata_RW[0] |= 0x20;
+ }
+ if ((csa->lscsa->decr_status.slot[0] == 1) &&
+ (csa->spu_chnlcnt_RW[0] == 0 &&
+ ((csa->spu_chnldata_RW[2] & 0x20) == 0x0) &&
+ ((csa->spu_chnldata_RW[0] & 0x20) != 0x1))) {
+ csa->spu_chnlcnt_RW[0] = 1;
+ }
+}
+
+static inline void restore_ch_part1(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+ u64 idx, ch_indices[7] = { 0UL, 1UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+ int i;
+
+ /* Restore, Step 59:
+ * Restore the following CH: [0,1,3,4,24,25,27]
+ */
+ for (i = 0; i < 7; i++) {
+ idx = ch_indices[i];
+ out_be64(&priv2->spu_chnlcntptr_RW, idx);
+ eieio();
+ out_be64(&priv2->spu_chnldata_RW, csa->spu_chnldata_RW[idx]);
+ out_be64(&priv2->spu_chnlcnt_RW, csa->spu_chnlcnt_RW[idx]);
+ eieio();
+ }
+}
+
+static inline void restore_ch_part2(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+ u64 ch_indices[3] = { 9UL, 21UL, 23UL };
+ u64 ch_counts[3] = { 1UL, 16UL, 1UL };
+ u64 idx;
+ int i;
+
+ /* Restore, Step 60:
+ * Restore the following CH: [9,21,23].
+ */
+ ch_counts[0] = 1UL;
+ ch_counts[1] = csa->spu_chnlcnt_RW[21];
+ ch_counts[2] = 1UL;
+ for (i = 0; i < 3; i++) {
+ idx = ch_indices[i];
+ out_be64(&priv2->spu_chnlcntptr_RW, idx);
+ eieio();
+ out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]);
+ eieio();
+ }
+}
+
+static inline void restore_spu_lslr(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Restore, Step 61:
+ * Restore the SPU_LSLR register from CSA.
+ */
+ out_be64(&priv2->spu_lslr_RW, csa->priv2.spu_lslr_RW);
+ eieio();
+}
+
+static inline void restore_spu_cfg(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Restore, Step 62:
+ * Restore the SPU_Cfg register from CSA.
+ */
+ out_be64(&priv2->spu_cfg_RW, csa->priv2.spu_cfg_RW);
+ eieio();
+}
+
+static inline void restore_pm_trace(struct spu_state *csa, struct spu *spu)
+{
+ /* Restore, Step 63:
+ * Restore PM_Trace_Tag_Wait_Mask from CSA.
+ * Not performed by this implementation.
+ */
+}
+
+static inline void restore_spu_npc(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+
+ /* Restore, Step 64:
+ * Restore SPU_NPC from CSA.
+ */
+ out_be32(&prob->spu_npc_RW, csa->prob.spu_npc_RW);
+ eieio();
+}
+
+static inline void restore_spu_mb(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+ int i;
+
+ /* Restore, Step 65:
+ * Restore MFC_RdSPU_MB from CSA.
+ */
+ out_be64(&priv2->spu_chnlcntptr_RW, 29UL);
+ eieio();
+ out_be64(&priv2->spu_chnlcnt_RW, csa->spu_chnlcnt_RW[29]);
+ for (i = 0; i < 4; i++) {
+ out_be64(&priv2->spu_chnldata_RW, csa->spu_mailbox_data[i]);
+ }
+ eieio();
+}
+
+static inline void check_ppu_mb_stat(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+ u32 dummy = 0;
+
+ /* Restore, Step 66:
+ * If CSA.MB_Stat[P]=0 (mailbox empty) then
+ * read from the PPU_MB register.
+ */
+ if ((csa->prob.mb_stat_R & 0xFF) == 0) {
+ dummy = in_be32(&prob->pu_mb_R);
+ eieio();
+ }
+}
+
+static inline void check_ppuint_mb_stat(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+ u64 dummy = 0UL;
+
+ /* Restore, Step 66:
+ * If CSA.MB_Stat[I]=0 (mailbox empty) then
+ * read from the PPUINT_MB register.
+ */
+ if ((csa->prob.mb_stat_R & 0xFF0000) == 0) {
+ dummy = in_be64(&priv2->puint_mb_R);
+ eieio();
+ spu_int_stat_clear(spu, 2, CLASS2_ENABLE_MAILBOX_INTR);
+ eieio();
+ }
+}
+
+static inline void restore_mfc_slbs(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+ int i;
+
+ /* Restore, Step 68:
+ * If MFC_SR1[R]='1', restore SLBs from CSA.
+ */
+ if (csa->priv1.mfc_sr1_RW & MFC_STATE1_RELOCATE_MASK) {
+ for (i = 0; i < 8; i++) {
+ out_be64(&priv2->slb_index_W, i);
+ eieio();
+ out_be64(&priv2->slb_esid_RW, csa->slb_esid_RW[i]);
+ out_be64(&priv2->slb_vsid_RW, csa->slb_vsid_RW[i]);
+ eieio();
+ }
+ out_be64(&priv2->slb_index_W, csa->priv2.slb_index_W);
+ eieio();
+ }
+}
+
+static inline void restore_mfc_sr1(struct spu_state *csa, struct spu *spu)
+{
+ /* Restore, Step 69:
+ * Restore the MFC_SR1 register from CSA.
+ */
+ spu_mfc_sr1_set(spu, csa->priv1.mfc_sr1_RW);
+ eieio();
+}
+
+static inline void restore_other_spu_access(struct spu_state *csa,
+ struct spu *spu)
+{
+ /* Restore, Step 70:
+ * Restore other SPU mappings to this SPU. TBD.
+ */
+}
+
+static inline void restore_spu_runcntl(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+
+ /* Restore, Step 71:
+ * If CSA.SPU_Status[R]=1 then write
+ * SPU_RunCntl[R0R1]='01'.
+ */
+ if (csa->prob.spu_status_R & SPU_STATUS_RUNNING) {
+ out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
+ eieio();
+ }
+}
+
+static inline void restore_mfc_cntl(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Restore, Step 72:
+ * Restore the MFC_CNTL register for the CSA.
+ */
+ out_be64(&priv2->mfc_control_RW, csa->priv2.mfc_control_RW);
+ eieio();
+}
+
+static inline void enable_user_access(struct spu_state *csa, struct spu *spu)
+{
+ /* Restore, Step 73:
+ * Enable user-space access (if provided) to this
+ * SPU by mapping the virtual pages assigned to
+ * the SPU memory-mapped I/O (MMIO) for problem
+ * state. TBD.
+ */
+}
+
+static inline void reset_switch_active(struct spu_state *csa, struct spu *spu)
+{
+ /* Restore, Step 74:
+ * Reset the "context switch active" flag.
+ */
+ clear_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags);
+ mb();
+}
+
+static inline void reenable_interrupts(struct spu_state *csa, struct spu *spu)
+{
+ /* Restore, Step 75:
+ * Re-enable SPU interrupts.
+ */
+ spin_lock_irq(&spu->register_lock);
+ spu_int_mask_set(spu, 0, csa->priv1.int_mask_class0_RW);
+ spu_int_mask_set(spu, 1, csa->priv1.int_mask_class1_RW);
+ spu_int_mask_set(spu, 2, csa->priv1.int_mask_class2_RW);
+ spin_unlock_irq(&spu->register_lock);
+}
+
+static int quiece_spu(struct spu_state *prev, struct spu *spu)
+{
+ /*
+ * Combined steps 2-18 of SPU context save sequence, which
+ * quiesce the SPU state (disable SPU execution, MFC command
+ * queues, decrementer, SPU interrupts, etc.).
+ *
+ * Returns 0 on success.
+ * 2 if failed step 2.
+ * 6 if failed step 6.
+ */
+
+ if (check_spu_isolate(prev, spu)) { /* Step 2. */
+ return 2;
+ }
+ disable_interrupts(prev, spu); /* Step 3. */
+ set_watchdog_timer(prev, spu); /* Step 4. */
+ inhibit_user_access(prev, spu); /* Step 5. */
+ if (check_spu_isolate(prev, spu)) { /* Step 6. */
+ return 6;
+ }
+ set_switch_pending(prev, spu); /* Step 7. */
+ save_mfc_cntl(prev, spu); /* Step 8. */
+ save_spu_runcntl(prev, spu); /* Step 9. */
+ save_mfc_sr1(prev, spu); /* Step 10. */
+ save_spu_status(prev, spu); /* Step 11. */
+ save_mfc_decr(prev, spu); /* Step 12. */
+ halt_mfc_decr(prev, spu); /* Step 13. */
+ save_timebase(prev, spu); /* Step 14. */
+ remove_other_spu_access(prev, spu); /* Step 15. */
+ do_mfc_mssync(prev, spu); /* Step 16. */
+ issue_mfc_tlbie(prev, spu); /* Step 17. */
+ handle_pending_interrupts(prev, spu); /* Step 18. */
+
+ return 0;
+}
+
+static void save_csa(struct spu_state *prev, struct spu *spu)
+{
+ /*
+ * Combine steps 19-44 of SPU context save sequence, which
+ * save regions of the privileged & problem state areas.
+ */
+
+ save_mfc_queues(prev, spu); /* Step 19. */
+ save_ppu_querymask(prev, spu); /* Step 20. */
+ save_ppu_querytype(prev, spu); /* Step 21. */
+ save_mfc_csr_tsq(prev, spu); /* Step 22. */
+ save_mfc_csr_cmd(prev, spu); /* Step 23. */
+ save_mfc_csr_ato(prev, spu); /* Step 24. */
+ save_mfc_tclass_id(prev, spu); /* Step 25. */
+ set_mfc_tclass_id(prev, spu); /* Step 26. */
+ purge_mfc_queue(prev, spu); /* Step 27. */
+ wait_purge_complete(prev, spu); /* Step 28. */
+ save_mfc_slbs(prev, spu); /* Step 29. */
+ setup_mfc_sr1(prev, spu); /* Step 30. */
+ save_spu_npc(prev, spu); /* Step 31. */
+ save_spu_privcntl(prev, spu); /* Step 32. */
+ reset_spu_privcntl(prev, spu); /* Step 33. */
+ save_spu_lslr(prev, spu); /* Step 34. */
+ reset_spu_lslr(prev, spu); /* Step 35. */
+ save_spu_cfg(prev, spu); /* Step 36. */
+ save_pm_trace(prev, spu); /* Step 37. */
+ save_mfc_rag(prev, spu); /* Step 38. */
+ save_ppu_mb_stat(prev, spu); /* Step 39. */
+ save_ppu_mb(prev, spu); /* Step 40. */
+ save_ppuint_mb(prev, spu); /* Step 41. */
+ save_ch_part1(prev, spu); /* Step 42. */
+ save_spu_mb(prev, spu); /* Step 43. */
+ save_mfc_cmd(prev, spu); /* Step 44. */
+ reset_ch(prev, spu); /* Step 45. */
+}
+
+static void save_lscsa(struct spu_state *prev, struct spu *spu)
+{
+ /*
+ * Perform steps 46-57 of SPU context save sequence,
+ * which save regions of the local store and register
+ * file.
+ */
+
+ resume_mfc_queue(prev, spu); /* Step 46. */
+ setup_mfc_slbs(prev, spu); /* Step 47. */
+ set_switch_active(prev, spu); /* Step 48. */
+ enable_interrupts(prev, spu); /* Step 49. */
+ save_ls_16kb(prev, spu); /* Step 50. */
+ set_spu_npc(prev, spu); /* Step 51. */
+ set_signot1(prev, spu); /* Step 52. */
+ set_signot2(prev, spu); /* Step 53. */
+ send_save_code(prev, spu); /* Step 54. */
+ set_ppu_querymask(prev, spu); /* Step 55. */
+ wait_tag_complete(prev, spu); /* Step 56. */
+ wait_spu_stopped(prev, spu); /* Step 57. */
+}
+
+static void harvest(struct spu_state *prev, struct spu *spu)
+{
+ /*
+ * Perform steps 2-25 of SPU context restore sequence,
+ * which resets an SPU either after a failed save, or
+ * when using SPU for first time.
+ */
+
+ disable_interrupts(prev, spu); /* Step 2. */
+ inhibit_user_access(prev, spu); /* Step 3. */
+ terminate_spu_app(prev, spu); /* Step 4. */
+ set_switch_pending(prev, spu); /* Step 5. */
+ remove_other_spu_access(prev, spu); /* Step 6. */
+ suspend_mfc(prev, spu); /* Step 7. */
+ wait_suspend_mfc_complete(prev, spu); /* Step 8. */
+ if (!suspend_spe(prev, spu)) /* Step 9. */
+ clear_spu_status(prev, spu); /* Step 10. */
+ do_mfc_mssync(prev, spu); /* Step 11. */
+ issue_mfc_tlbie(prev, spu); /* Step 12. */
+ handle_pending_interrupts(prev, spu); /* Step 13. */
+ purge_mfc_queue(prev, spu); /* Step 14. */
+ wait_purge_complete(prev, spu); /* Step 15. */
+ reset_spu_privcntl(prev, spu); /* Step 16. */
+ reset_spu_lslr(prev, spu); /* Step 17. */
+ setup_mfc_sr1(prev, spu); /* Step 18. */
+ invalidate_slbs(prev, spu); /* Step 19. */
+ reset_ch_part1(prev, spu); /* Step 20. */
+ reset_ch_part2(prev, spu); /* Step 21. */
+ enable_interrupts(prev, spu); /* Step 22. */
+ set_switch_active(prev, spu); /* Step 23. */
+ set_mfc_tclass_id(prev, spu); /* Step 24. */
+ resume_mfc_queue(prev, spu); /* Step 25. */
+}
+
+static void restore_lscsa(struct spu_state *next, struct spu *spu)
+{
+ /*
+ * Perform steps 26-40 of SPU context restore sequence,
+ * which restores regions of the local store and register
+ * file.
+ */
+
+ set_watchdog_timer(next, spu); /* Step 26. */
+ setup_spu_status_part1(next, spu); /* Step 27. */
+ setup_spu_status_part2(next, spu); /* Step 28. */
+ restore_mfc_rag(next, spu); /* Step 29. */
+ setup_mfc_slbs(next, spu); /* Step 30. */
+ set_spu_npc(next, spu); /* Step 31. */
+ set_signot1(next, spu); /* Step 32. */
+ set_signot2(next, spu); /* Step 33. */
+ setup_decr(next, spu); /* Step 34. */
+ setup_ppu_mb(next, spu); /* Step 35. */
+ setup_ppuint_mb(next, spu); /* Step 36. */
+ send_restore_code(next, spu); /* Step 37. */
+ set_ppu_querymask(next, spu); /* Step 38. */
+ wait_tag_complete(next, spu); /* Step 39. */
+ wait_spu_stopped(next, spu); /* Step 40. */
+}
+
+static void restore_csa(struct spu_state *next, struct spu *spu)
+{
+ /*
+ * Combine steps 41-76 of SPU context restore sequence, which
+ * restore regions of the privileged & problem state areas.
+ */
+
+ restore_spu_privcntl(next, spu); /* Step 41. */
+ restore_status_part1(next, spu); /* Step 42. */
+ restore_status_part2(next, spu); /* Step 43. */
+ restore_ls_16kb(next, spu); /* Step 44. */
+ wait_tag_complete(next, spu); /* Step 45. */
+ suspend_mfc(next, spu); /* Step 46. */
+ wait_suspend_mfc_complete(next, spu); /* Step 47. */
+ issue_mfc_tlbie(next, spu); /* Step 48. */
+ clear_interrupts(next, spu); /* Step 49. */
+ restore_mfc_queues(next, spu); /* Step 50. */
+ restore_ppu_querymask(next, spu); /* Step 51. */
+ restore_ppu_querytype(next, spu); /* Step 52. */
+ restore_mfc_csr_tsq(next, spu); /* Step 53. */
+ restore_mfc_csr_cmd(next, spu); /* Step 54. */
+ restore_mfc_csr_ato(next, spu); /* Step 55. */
+ restore_mfc_tclass_id(next, spu); /* Step 56. */
+ set_llr_event(next, spu); /* Step 57. */
+ restore_decr_wrapped(next, spu); /* Step 58. */
+ restore_ch_part1(next, spu); /* Step 59. */
+ restore_ch_part2(next, spu); /* Step 60. */
+ restore_spu_lslr(next, spu); /* Step 61. */
+ restore_spu_cfg(next, spu); /* Step 62. */
+ restore_pm_trace(next, spu); /* Step 63. */
+ restore_spu_npc(next, spu); /* Step 64. */
+ restore_spu_mb(next, spu); /* Step 65. */
+ check_ppu_mb_stat(next, spu); /* Step 66. */
+ check_ppuint_mb_stat(next, spu); /* Step 67. */
+ restore_mfc_slbs(next, spu); /* Step 68. */
+ restore_mfc_sr1(next, spu); /* Step 69. */
+ restore_other_spu_access(next, spu); /* Step 70. */
+ restore_spu_runcntl(next, spu); /* Step 71. */
+ restore_mfc_cntl(next, spu); /* Step 72. */
+ enable_user_access(next, spu); /* Step 73. */
+ reset_switch_active(next, spu); /* Step 74. */
+ reenable_interrupts(next, spu); /* Step 75. */
+}
+
+static int __do_spu_save(struct spu_state *prev, struct spu *spu)
+{
+ int rc;
+
+ /*
+ * SPU context save can be broken into three phases:
+ *
+ * (a) quiesce [steps 2-16].
+ * (b) save of CSA, performed by PPE [steps 17-42]
+ * (c) save of LSCSA, mostly performed by SPU [steps 43-52].
+ *
+ * Returns 0 on success.
+ * 2,6 if failed to quiece SPU
+ * 53 if SPU-side of save failed.
+ */
+
+ rc = quiece_spu(prev, spu); /* Steps 2-16. */
+ switch (rc) {
+ default:
+ case 2:
+ case 6:
+ harvest(prev, spu);
+ return rc;
+ break;
+ case 0:
+ break;
+ }
+ save_csa(prev, spu); /* Steps 17-43. */
+ save_lscsa(prev, spu); /* Steps 44-53. */
+ return check_save_status(prev, spu); /* Step 54. */
+}
+
+static int __do_spu_restore(struct spu_state *next, struct spu *spu)
+{
+ int rc;
+
+ /*
+ * SPU context restore can be broken into three phases:
+ *
+ * (a) harvest (or reset) SPU [steps 2-24].
+ * (b) restore LSCSA [steps 25-40], mostly performed by SPU.
+ * (c) restore CSA [steps 41-76], performed by PPE.
+ *
+ * The 'harvest' step is not performed here, but rather
+ * as needed below.
+ */
+
+ restore_lscsa(next, spu); /* Steps 24-39. */
+ rc = check_restore_status(next, spu); /* Step 40. */
+ switch (rc) {
+ default:
+ /* Failed. Return now. */
+ return rc;
+ break;
+ case 0:
+ /* Fall through to next step. */
+ break;
+ }
+ restore_csa(next, spu);
+
+ return 0;
+}
+
+/**
+ * spu_save - SPU context save, with locking.
+ * @prev: pointer to SPU context save area, to be saved.
+ * @spu: pointer to SPU iomem structure.
+ *
+ * Acquire locks, perform the save operation then return.
+ */
+int spu_save(struct spu_state *prev, struct spu *spu)
+{
+ int rc;
+
+ acquire_spu_lock(spu); /* Step 1. */
+ rc = __do_spu_save(prev, spu); /* Steps 2-53. */
+ release_spu_lock(spu);
+ if (rc) {
+ panic("%s failed on SPU[%d], rc=%d.\n",
+ __func__, spu->number, rc);
+ }
+ return rc;
+}
+
+/**
+ * spu_restore - SPU context restore, with harvest and locking.
+ * @new: pointer to SPU context save area, to be restored.
+ * @spu: pointer to SPU iomem structure.
+ *
+ * Perform harvest + restore, as we may not be coming
+ * from a previous succesful save operation, and the
+ * hardware state is unknown.
+ */
+int spu_restore(struct spu_state *new, struct spu *spu)
+{
+ int rc;
+
+ acquire_spu_lock(spu);
+ harvest(NULL, spu);
+ spu->stop_code = 0;
+ spu->dar = 0;
+ spu->dsisr = 0;
+ spu->slb_replace = 0;
+ spu->class_0_pending = 0;
+ rc = __do_spu_restore(new, spu);
+ release_spu_lock(spu);
+ if (rc) {
+ panic("%s failed on SPU[%d] rc=%d.\n",
+ __func__, spu->number, rc);
+ }
+ return rc;
+}
+
+/**
+ * spu_harvest - SPU harvest (reset) operation
+ * @spu: pointer to SPU iomem structure.
+ *
+ * Perform SPU harvest (reset) operation.
+ */
+void spu_harvest(struct spu *spu)
+{
+ acquire_spu_lock(spu);
+ harvest(NULL, spu);
+ release_spu_lock(spu);
+}
+
+static void init_prob(struct spu_state *csa)
+{
+ csa->spu_chnlcnt_RW[9] = 1;
+ csa->spu_chnlcnt_RW[21] = 16;
+ csa->spu_chnlcnt_RW[23] = 1;
+ csa->spu_chnlcnt_RW[28] = 1;
+ csa->spu_chnlcnt_RW[30] = 1;
+ csa->prob.spu_runcntl_RW = SPU_RUNCNTL_STOP;
+}
+
+static void init_priv1(struct spu_state *csa)
+{
+ /* Enable decode, relocate, tlbie response, master runcntl. */
+ csa->priv1.mfc_sr1_RW = MFC_STATE1_LOCAL_STORAGE_DECODE_MASK |
+ MFC_STATE1_MASTER_RUN_CONTROL_MASK |
+ MFC_STATE1_PROBLEM_STATE_MASK |
+ MFC_STATE1_RELOCATE_MASK | MFC_STATE1_BUS_TLBIE_MASK;
+
+ /* Set storage description. */
+ csa->priv1.mfc_sdr_RW = mfspr(SPRN_SDR1);
+
+ /* Enable OS-specific set of interrupts. */
+ csa->priv1.int_mask_class0_RW = CLASS0_ENABLE_DMA_ALIGNMENT_INTR |
+ CLASS0_ENABLE_INVALID_DMA_COMMAND_INTR |
+ CLASS0_ENABLE_SPU_ERROR_INTR;
+ csa->priv1.int_mask_class1_RW = CLASS1_ENABLE_SEGMENT_FAULT_INTR |
+ CLASS1_ENABLE_STORAGE_FAULT_INTR;
+ csa->priv1.int_mask_class2_RW = CLASS2_ENABLE_SPU_STOP_INTR |
+ CLASS2_ENABLE_SPU_HALT_INTR;
+}
+
+static void init_priv2(struct spu_state *csa)
+{
+ csa->priv2.spu_lslr_RW = LS_ADDR_MASK;
+ csa->priv2.mfc_control_RW = MFC_CNTL_RESUME_DMA_QUEUE |
+ MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION |
+ MFC_CNTL_DMA_QUEUES_EMPTY_MASK;
+}
+
+/**
+ * spu_alloc_csa - allocate and initialize an SPU context save area.
+ *
+ * Allocate and initialize the contents of an SPU context save area.
+ * This includes enabling address translation, interrupt masks, etc.,
+ * as appropriate for the given OS environment.
+ *
+ * Note that storage for the 'lscsa' is allocated separately,
+ * as it is by far the largest of the context save regions,
+ * and may need to be pinned or otherwise specially aligned.
+ */
+void spu_init_csa(struct spu_state *csa)
+{
+ struct spu_lscsa *lscsa;
+ unsigned char *p;
+
+ if (!csa)
+ return;
+ memset(csa, 0, sizeof(struct spu_state));
+
+ lscsa = vmalloc(sizeof(struct spu_lscsa));
+ if (!lscsa)
+ return;
+
+ memset(lscsa, 0, sizeof(struct spu_lscsa));
+ csa->lscsa = lscsa;
+ csa->register_lock = SPIN_LOCK_UNLOCKED;
+
+ /* Set LS pages reserved to allow for user-space mapping. */
+ for (p = lscsa->ls; p < lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+ SetPageReserved(vmalloc_to_page(p));
+
+ init_prob(csa);
+ init_priv1(csa);
+ init_priv2(csa);
+}
+
+void spu_fini_csa(struct spu_state *csa)
+{
+ /* Clear reserved bit before vfree. */
+ unsigned char *p;
+ for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+ ClearPageReserved(vmalloc_to_page(p));
+
+ vfree(csa->lscsa);
+}
diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c
new file mode 100644
index 000000000000..d549aa7ebea6
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/syscalls.c
@@ -0,0 +1,101 @@
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+
+#include <asm/uaccess.h>
+
+#include "spufs.h"
+
+/**
+ * sys_spu_run - run code loaded into an SPU
+ *
+ * @unpc: next program counter for the SPU
+ * @ustatus: status of the SPU
+ *
+ * This system call transfers the control of execution of a
+ * user space thread to an SPU. It will return when the
+ * SPU has finished executing or when it hits an error
+ * condition and it will be interrupted if a signal needs
+ * to be delivered to a handler in user space.
+ *
+ * The next program counter is set to the passed value
+ * before the SPU starts fetching code and the user space
+ * pointer gets updated with the new value when returning
+ * from kernel space.
+ *
+ * The status value returned from spu_run reflects the
+ * value of the spu_status register after the SPU has stopped.
+ *
+ */
+long do_spu_run(struct file *filp, __u32 __user *unpc, __u32 __user *ustatus)
+{
+ long ret;
+ struct spufs_inode_info *i;
+ u32 npc, status;
+
+ ret = -EFAULT;
+ if (get_user(npc, unpc) || get_user(status, ustatus))
+ goto out;
+
+ /* check if this file was created by spu_create */
+ ret = -EINVAL;
+ if (filp->f_op != &spufs_context_fops)
+ goto out;
+
+ i = SPUFS_I(filp->f_dentry->d_inode);
+ ret = spufs_run_spu(filp, i->i_ctx, &npc, &status);
+
+ if (put_user(npc, unpc) || put_user(status, ustatus))
+ ret = -EFAULT;
+out:
+ return ret;
+}
+
+#ifndef MODULE
+asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
+{
+ int fput_needed;
+ struct file *filp;
+ long ret;
+
+ ret = -EBADF;
+ filp = fget_light(fd, &fput_needed);
+ if (filp) {
+ ret = do_spu_run(filp, unpc, ustatus);
+ fput_light(filp, fput_needed);
+ }
+
+ return ret;
+}
+#endif
+
+asmlinkage long sys_spu_create(const char __user *pathname,
+ unsigned int flags, mode_t mode)
+{
+ char *tmp;
+ int ret;
+
+ tmp = getname(pathname);
+ ret = PTR_ERR(tmp);
+ if (!IS_ERR(tmp)) {
+ struct nameidata nd;
+
+ ret = path_lookup(tmp, LOOKUP_PARENT|
+ LOOKUP_OPEN|LOOKUP_CREATE, &nd);
+ if (!ret) {
+ ret = spufs_create_thread(&nd, flags, mode);
+ path_release(&nd);
+ }
+ putname(tmp);
+ }
+
+ return ret;
+}
+
+struct spufs_calls spufs_calls = {
+ .create_thread = sys_spu_create,
+ .spu_run = do_spu_run,
+ .owner = THIS_MODULE,
+};
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index dda5f2c72c25..4ec8ba737e7d 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -49,7 +49,6 @@
#include <asm/hydra.h>
#include <asm/sections.h>
#include <asm/time.h>
-#include <asm/btext.h>
#include <asm/i8259.h>
#include <asm/mpic.h>
#include <asm/rtas.h>
@@ -58,7 +57,6 @@
#include "chrp.h"
void rtas_indicator_progress(char *, unsigned short);
-void btext_progress(char *, unsigned short);
int _chrp_type;
EXPORT_SYMBOL(_chrp_type);
@@ -264,11 +262,6 @@ void __init chrp_setup_arch(void)
ppc_md.set_rtc_time = rtas_set_rtc_time;
}
-#ifdef CONFIG_BOOTX_TEXT
- if (ppc_md.progress == NULL && boot_text_mapped)
- ppc_md.progress = btext_progress;
-#endif
-
#ifdef CONFIG_BLK_DEV_INITRD
/* this is fine for chrp */
initrd_below_start_ok = 1;
@@ -522,12 +515,3 @@ void __init chrp_init(void)
smp_ops = &chrp_smp_ops;
#endif /* CONFIG_SMP */
}
-
-#ifdef CONFIG_BOOTX_TEXT
-void
-btext_progress(char *s, unsigned short hex)
-{
- btext_drawstring(s);
- btext_drawstring("\n");
-}
-#endif /* CONFIG_BOOTX_TEXT */
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index a58daa153686..42e978e4897a 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -35,161 +35,138 @@
#include <linux/irq.h>
#include <linux/spinlock.h>
+#include <asm/paca.h>
#include <asm/iseries/hv_types.h>
#include <asm/iseries/hv_lp_event.h>
#include <asm/iseries/hv_call_xm.h>
+#include <asm/iseries/it_lp_queue.h>
#include "irq.h"
#include "call_pci.h"
-static long Pci_Interrupt_Count;
-static long Pci_Event_Count;
-
-enum XmPciLpEvent_Subtype {
- XmPciLpEvent_BusCreated = 0, // PHB has been created
- XmPciLpEvent_BusError = 1, // PHB has failed
- XmPciLpEvent_BusFailed = 2, // Msg to Secondary, Primary failed bus
- XmPciLpEvent_NodeFailed = 4, // Multi-adapter bridge has failed
- XmPciLpEvent_NodeRecovered = 5, // Multi-adapter bridge has recovered
- XmPciLpEvent_BusRecovered = 12, // PHB has been recovered
- XmPciLpEvent_UnQuiesceBus = 18, // Secondary bus unqiescing
- XmPciLpEvent_BridgeError = 21, // Bridge Error
- XmPciLpEvent_SlotInterrupt = 22 // Slot interrupt
-};
-
-struct XmPciLpEvent_BusInterrupt {
- HvBusNumber busNumber;
- HvSubBusNumber subBusNumber;
-};
+#if defined(CONFIG_SMP)
+extern void iSeries_smp_message_recv(struct pt_regs *);
+#endif
-struct XmPciLpEvent_NodeInterrupt {
- HvBusNumber busNumber;
- HvSubBusNumber subBusNumber;
- HvAgentId deviceId;
+enum pci_event_type {
+ pe_bus_created = 0, /* PHB has been created */
+ pe_bus_error = 1, /* PHB has failed */
+ pe_bus_failed = 2, /* Msg to Secondary, Primary failed bus */
+ pe_node_failed = 4, /* Multi-adapter bridge has failed */
+ pe_node_recovered = 5, /* Multi-adapter bridge has recovered */
+ pe_bus_recovered = 12, /* PHB has been recovered */
+ pe_unquiese_bus = 18, /* Secondary bus unqiescing */
+ pe_bridge_error = 21, /* Bridge Error */
+ pe_slot_interrupt = 22 /* Slot interrupt */
};
-struct XmPciLpEvent {
- struct HvLpEvent hvLpEvent;
-
+struct pci_event {
+ struct HvLpEvent event;
union {
- u64 alignData; // Align on an 8-byte boundary
-
+ u64 __align; /* Align on an 8-byte boundary */
struct {
u32 fisr;
- HvBusNumber busNumber;
- HvSubBusNumber subBusNumber;
- HvAgentId deviceId;
- } slotInterrupt;
-
- struct XmPciLpEvent_BusInterrupt busFailed;
- struct XmPciLpEvent_BusInterrupt busRecovered;
- struct XmPciLpEvent_BusInterrupt busCreated;
-
- struct XmPciLpEvent_NodeInterrupt nodeFailed;
- struct XmPciLpEvent_NodeInterrupt nodeRecovered;
-
- } eventData;
-
+ HvBusNumber bus_number;
+ HvSubBusNumber sub_bus_number;
+ HvAgentId dev_id;
+ } slot;
+ struct {
+ HvBusNumber bus_number;
+ HvSubBusNumber sub_bus_number;
+ } bus;
+ struct {
+ HvBusNumber bus_number;
+ HvSubBusNumber sub_bus_number;
+ HvAgentId dev_id;
+ } node;
+ } data;
};
-static void intReceived(struct XmPciLpEvent *eventParm,
- struct pt_regs *regsParm)
+static DEFINE_SPINLOCK(pending_irqs_lock);
+static int num_pending_irqs;
+static int pending_irqs[NR_IRQS];
+
+static void int_received(struct pci_event *event, struct pt_regs *regs)
{
int irq;
-#ifdef CONFIG_IRQSTACKS
- struct thread_info *curtp, *irqtp;
-#endif
- ++Pci_Interrupt_Count;
-
- switch (eventParm->hvLpEvent.xSubtype) {
- case XmPciLpEvent_SlotInterrupt:
- irq = eventParm->hvLpEvent.xCorrelationToken;
- /* Dispatch the interrupt handlers for this irq */
-#ifdef CONFIG_IRQSTACKS
- /* Switch to the irq stack to handle this */
- curtp = current_thread_info();
- irqtp = hardirq_ctx[smp_processor_id()];
- if (curtp != irqtp) {
- irqtp->task = curtp->task;
- irqtp->flags = 0;
- call___do_IRQ(irq, regsParm, irqtp);
- irqtp->task = NULL;
- if (irqtp->flags)
- set_bits(irqtp->flags, &curtp->flags);
- } else
-#endif
- __do_IRQ(irq, regsParm);
- HvCallPci_eoi(eventParm->eventData.slotInterrupt.busNumber,
- eventParm->eventData.slotInterrupt.subBusNumber,
- eventParm->eventData.slotInterrupt.deviceId);
+ switch (event->event.xSubtype) {
+ case pe_slot_interrupt:
+ irq = event->event.xCorrelationToken;
+ if (irq < NR_IRQS) {
+ spin_lock(&pending_irqs_lock);
+ pending_irqs[irq]++;
+ num_pending_irqs++;
+ spin_unlock(&pending_irqs_lock);
+ } else {
+ printk(KERN_WARNING "int_received: bad irq number %d\n",
+ irq);
+ HvCallPci_eoi(event->data.slot.bus_number,
+ event->data.slot.sub_bus_number,
+ event->data.slot.dev_id);
+ }
break;
/* Ignore error recovery events for now */
- case XmPciLpEvent_BusCreated:
- printk(KERN_INFO "intReceived: system bus %d created\n",
- eventParm->eventData.busCreated.busNumber);
+ case pe_bus_created:
+ printk(KERN_INFO "int_received: system bus %d created\n",
+ event->data.bus.bus_number);
break;
- case XmPciLpEvent_BusError:
- case XmPciLpEvent_BusFailed:
- printk(KERN_INFO "intReceived: system bus %d failed\n",
- eventParm->eventData.busFailed.busNumber);
+ case pe_bus_error:
+ case pe_bus_failed:
+ printk(KERN_INFO "int_received: system bus %d failed\n",
+ event->data.bus.bus_number);
break;
- case XmPciLpEvent_BusRecovered:
- case XmPciLpEvent_UnQuiesceBus:
- printk(KERN_INFO "intReceived: system bus %d recovered\n",
- eventParm->eventData.busRecovered.busNumber);
+ case pe_bus_recovered:
+ case pe_unquiese_bus:
+ printk(KERN_INFO "int_received: system bus %d recovered\n",
+ event->data.bus.bus_number);
break;
- case XmPciLpEvent_NodeFailed:
- case XmPciLpEvent_BridgeError:
+ case pe_node_failed:
+ case pe_bridge_error:
printk(KERN_INFO
- "intReceived: multi-adapter bridge %d/%d/%d failed\n",
- eventParm->eventData.nodeFailed.busNumber,
- eventParm->eventData.nodeFailed.subBusNumber,
- eventParm->eventData.nodeFailed.deviceId);
+ "int_received: multi-adapter bridge %d/%d/%d failed\n",
+ event->data.node.bus_number,
+ event->data.node.sub_bus_number,
+ event->data.node.dev_id);
break;
- case XmPciLpEvent_NodeRecovered:
+ case pe_node_recovered:
printk(KERN_INFO
- "intReceived: multi-adapter bridge %d/%d/%d recovered\n",
- eventParm->eventData.nodeRecovered.busNumber,
- eventParm->eventData.nodeRecovered.subBusNumber,
- eventParm->eventData.nodeRecovered.deviceId);
+ "int_received: multi-adapter bridge %d/%d/%d recovered\n",
+ event->data.node.bus_number,
+ event->data.node.sub_bus_number,
+ event->data.node.dev_id);
break;
default:
printk(KERN_ERR
- "intReceived: unrecognized event subtype 0x%x\n",
- eventParm->hvLpEvent.xSubtype);
+ "int_received: unrecognized event subtype 0x%x\n",
+ event->event.xSubtype);
break;
}
}
-static void XmPciLpEvent_handler(struct HvLpEvent *eventParm,
- struct pt_regs *regsParm)
+static void pci_event_handler(struct HvLpEvent *event, struct pt_regs *regs)
{
-#ifdef CONFIG_PCI
- ++Pci_Event_Count;
-
- if (eventParm && (eventParm->xType == HvLpEvent_Type_PciIo)) {
- switch (eventParm->xFlags.xFunction) {
+ if (event && (event->xType == HvLpEvent_Type_PciIo)) {
+ switch (event->xFlags.xFunction) {
case HvLpEvent_Function_Int:
- intReceived((struct XmPciLpEvent *)eventParm, regsParm);
+ int_received((struct pci_event *)event, regs);
break;
case HvLpEvent_Function_Ack:
printk(KERN_ERR
- "XmPciLpEvent_handler: unexpected ack received\n");
+ "pci_event_handler: unexpected ack received\n");
break;
default:
printk(KERN_ERR
- "XmPciLpEvent_handler: unexpected event function %d\n",
- (int)eventParm->xFlags.xFunction);
+ "pci_event_handler: unexpected event function %d\n",
+ (int)event->xFlags.xFunction);
break;
}
- } else if (eventParm)
+ } else if (event)
printk(KERN_ERR
- "XmPciLpEvent_handler: Unrecognized PCI event type 0x%x\n",
- (int)eventParm->xType);
+ "pci_event_handler: Unrecognized PCI event type 0x%x\n",
+ (int)event->xType);
else
- printk(KERN_ERR "XmPciLpEvent_handler: NULL event received\n");
-#endif
+ printk(KERN_ERR "pci_event_handler: NULL event received\n");
}
/*
@@ -199,20 +176,21 @@ static void XmPciLpEvent_handler(struct HvLpEvent *eventParm,
void __init iSeries_init_IRQ(void)
{
/* Register PCI event handler and open an event path */
- int xRc;
-
- xRc = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
- &XmPciLpEvent_handler);
- if (xRc == 0) {
- xRc = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
- if (xRc != 0)
- printk(KERN_ERR "iSeries_init_IRQ: open event path "
- "failed with rc 0x%x\n", xRc);
+ int ret;
+
+ ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
+ &pci_event_handler);
+ if (ret == 0) {
+ ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
+ if (ret != 0)
+ printk(KERN_ERR "iseries_init_IRQ: open event path "
+ "failed with rc 0x%x\n", ret);
} else
- printk(KERN_ERR "iSeries_init_IRQ: register handler "
- "failed with rc 0x%x\n", xRc);
+ printk(KERN_ERR "iseries_init_IRQ: register handler "
+ "failed with rc 0x%x\n", ret);
}
+#define REAL_IRQ_TO_SUBBUS(irq) (((irq) >> 14) & 0xff)
#define REAL_IRQ_TO_BUS(irq) ((((irq) >> 6) & 0xff) + 1)
#define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1)
#define REAL_IRQ_TO_FUNC(irq) ((irq) & 7)
@@ -221,40 +199,40 @@ void __init iSeries_init_IRQ(void)
* This will be called by device drivers (via enable_IRQ)
* to enable INTA in the bridge interrupt status register.
*/
-static void iSeries_enable_IRQ(unsigned int irq)
+static void iseries_enable_IRQ(unsigned int irq)
{
- u32 bus, deviceId, function, mask;
- const u32 subBus = 0;
+ u32 bus, dev_id, function, mask;
+ const u32 sub_bus = 0;
unsigned int rirq = virt_irq_to_real_map[irq];
/* The IRQ has already been locked by the caller */
bus = REAL_IRQ_TO_BUS(rirq);
function = REAL_IRQ_TO_FUNC(rirq);
- deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
+ dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
/* Unmask secondary INTA */
mask = 0x80000000;
- HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask);
+ HvCallPci_unmaskInterrupts(bus, sub_bus, dev_id, mask);
}
-/* This is called by iSeries_activate_IRQs */
-static unsigned int iSeries_startup_IRQ(unsigned int irq)
+/* This is called by iseries_activate_IRQs */
+static unsigned int iseries_startup_IRQ(unsigned int irq)
{
- u32 bus, deviceId, function, mask;
- const u32 subBus = 0;
+ u32 bus, dev_id, function, mask;
+ const u32 sub_bus = 0;
unsigned int rirq = virt_irq_to_real_map[irq];
bus = REAL_IRQ_TO_BUS(rirq);
function = REAL_IRQ_TO_FUNC(rirq);
- deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
+ dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
/* Link the IRQ number to the bridge */
- HvCallXm_connectBusUnit(bus, subBus, deviceId, irq);
+ HvCallXm_connectBusUnit(bus, sub_bus, dev_id, irq);
/* Unmask bridge interrupts in the FISR */
mask = 0x01010000 << function;
- HvCallPci_unmaskFisr(bus, subBus, deviceId, mask);
- iSeries_enable_IRQ(irq);
+ HvCallPci_unmaskFisr(bus, sub_bus, dev_id, mask);
+ iseries_enable_IRQ(irq);
return 0;
}
@@ -279,78 +257,115 @@ void __init iSeries_activate_IRQs()
}
/* this is not called anywhere currently */
-static void iSeries_shutdown_IRQ(unsigned int irq)
+static void iseries_shutdown_IRQ(unsigned int irq)
{
- u32 bus, deviceId, function, mask;
- const u32 subBus = 0;
+ u32 bus, dev_id, function, mask;
+ const u32 sub_bus = 0;
unsigned int rirq = virt_irq_to_real_map[irq];
/* irq should be locked by the caller */
bus = REAL_IRQ_TO_BUS(rirq);
function = REAL_IRQ_TO_FUNC(rirq);
- deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
+ dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
/* Invalidate the IRQ number in the bridge */
- HvCallXm_connectBusUnit(bus, subBus, deviceId, 0);
+ HvCallXm_connectBusUnit(bus, sub_bus, dev_id, 0);
/* Mask bridge interrupts in the FISR */
mask = 0x01010000 << function;
- HvCallPci_maskFisr(bus, subBus, deviceId, mask);
+ HvCallPci_maskFisr(bus, sub_bus, dev_id, mask);
}
/*
* This will be called by device drivers (via disable_IRQ)
* to disable INTA in the bridge interrupt status register.
*/
-static void iSeries_disable_IRQ(unsigned int irq)
+static void iseries_disable_IRQ(unsigned int irq)
{
- u32 bus, deviceId, function, mask;
- const u32 subBus = 0;
+ u32 bus, dev_id, function, mask;
+ const u32 sub_bus = 0;
unsigned int rirq = virt_irq_to_real_map[irq];
/* The IRQ has already been locked by the caller */
bus = REAL_IRQ_TO_BUS(rirq);
function = REAL_IRQ_TO_FUNC(rirq);
- deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
+ dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
/* Mask secondary INTA */
mask = 0x80000000;
- HvCallPci_maskInterrupts(bus, subBus, deviceId, mask);
+ HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask);
}
-/*
- * This does nothing because there is not enough information
- * provided to do the EOI HvCall. This is done by XmPciLpEvent.c
- */
-static void iSeries_end_IRQ(unsigned int irq)
+static void iseries_end_IRQ(unsigned int irq)
{
+ unsigned int rirq = virt_irq_to_real_map[irq];
+
+ HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq),
+ (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq));
}
static hw_irq_controller iSeries_IRQ_handler = {
.typename = "iSeries irq controller",
- .startup = iSeries_startup_IRQ,
- .shutdown = iSeries_shutdown_IRQ,
- .enable = iSeries_enable_IRQ,
- .disable = iSeries_disable_IRQ,
- .end = iSeries_end_IRQ
+ .startup = iseries_startup_IRQ,
+ .shutdown = iseries_shutdown_IRQ,
+ .enable = iseries_enable_IRQ,
+ .disable = iseries_disable_IRQ,
+ .end = iseries_end_IRQ
};
/*
* This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot
* It calculates the irq value for the slot.
- * Note that subBusNumber is always 0 (at the moment at least).
+ * Note that sub_bus is always 0 (at the moment at least).
*/
-int __init iSeries_allocate_IRQ(HvBusNumber busNumber,
- HvSubBusNumber subBusNumber, HvAgentId deviceId)
+int __init iSeries_allocate_IRQ(HvBusNumber bus,
+ HvSubBusNumber sub_bus, HvAgentId dev_id)
{
int virtirq;
unsigned int realirq;
- u8 idsel = (deviceId >> 4);
- u8 function = deviceId & 7;
+ u8 idsel = (dev_id >> 4);
+ u8 function = dev_id & 7;
- realirq = ((busNumber - 1) << 6) + ((idsel - 1) << 3) + function;
+ realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3)
+ + function;
virtirq = virt_irq_create_mapping(realirq);
irq_desc[virtirq].handler = &iSeries_IRQ_handler;
return virtirq;
}
+
+/*
+ * Get the next pending IRQ.
+ */
+int iSeries_get_irq(struct pt_regs *regs)
+{
+ struct paca_struct *lpaca;
+ /* -2 means ignore this interrupt */
+ int irq = -2;
+
+ lpaca = get_paca();
+#ifdef CONFIG_SMP
+ if (lpaca->lppaca.int_dword.fields.ipi_cnt) {
+ lpaca->lppaca.int_dword.fields.ipi_cnt = 0;
+ iSeries_smp_message_recv(regs);
+ }
+#endif /* CONFIG_SMP */
+ if (hvlpevent_is_pending())
+ process_hvlpevents(regs);
+
+ if (num_pending_irqs) {
+ spin_lock(&pending_irqs_lock);
+ for (irq = 0; irq < NR_IRQS; irq++) {
+ if (pending_irqs[irq]) {
+ pending_irqs[irq]--;
+ num_pending_irqs--;
+ break;
+ }
+ }
+ spin_unlock(&pending_irqs_lock);
+ if (irq >= NR_IRQS)
+ irq = -2;
+ }
+
+ return irq;
+}
diff --git a/arch/powerpc/platforms/iseries/irq.h b/arch/powerpc/platforms/iseries/irq.h
index 5f643f16ecc0..b9c801ba5a47 100644
--- a/arch/powerpc/platforms/iseries/irq.h
+++ b/arch/powerpc/platforms/iseries/irq.h
@@ -4,5 +4,6 @@
extern void iSeries_init_IRQ(void);
extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, HvAgentId);
extern void iSeries_activate_IRQs(void);
+extern int iSeries_get_irq(struct pt_regs *);
#endif /* _ISERIES_IRQ_H */
diff --git a/arch/powerpc/platforms/iseries/lpardata.c b/arch/powerpc/platforms/iseries/lpardata.c
index bb8c91537f35..ea72385aaf0a 100644
--- a/arch/powerpc/platforms/iseries/lpardata.c
+++ b/arch/powerpc/platforms/iseries/lpardata.c
@@ -225,3 +225,10 @@ struct ItVpdAreas itVpdAreas = {
0,0
}
};
+
+struct ItLpRegSave iseries_reg_save[] = {
+ [0 ... (NR_CPUS-1)] = {
+ .xDesc = 0xd397d9e2, /* "LpRS" */
+ .xSize = sizeof(struct ItLpRegSave),
+ },
+};
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index da26639190db..ad5ef80500ce 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -571,16 +571,6 @@ static void iSeries_show_cpuinfo(struct seq_file *m)
/*
* Document me.
- * and Implement me.
- */
-static int iSeries_get_irq(struct pt_regs *regs)
-{
- /* -2 means ignore this interrupt */
- return -2;
-}
-
-/*
- * Document me.
*/
static void iSeries_restart(char *cmd)
{
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index 7ece8983a105..dd73e38bfb7d 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -51,6 +51,7 @@
#include <asm/pgtable.h>
#include <asm/bitops.h>
#include <asm/io.h>
+#include <asm/kexec.h>
#include <asm/pci-bridge.h>
#include <asm/iommu.h>
#include <asm/machdep.h>
@@ -191,24 +192,10 @@ static void __init maple_init_early(void)
*/
hpte_init_native();
- /* Find the serial port */
- generic_find_legacy_serial_ports(&physport, &default_speed);
-
- DBG("phys port addr: %lx\n", (long)physport);
-
- if (physport) {
- void *comport;
- /* Map the uart for udbg. */
- comport = (void *)ioremap(physport, 16);
- udbg_init_uart(comport, default_speed);
-
- DBG("Hello World !\n");
- }
-
/* Setup interrupt mapping options */
ppc64_interrupt_controller = IC_OPEN_PIC;
- iommu_init_early_u3();
+ iommu_init_early_dart();
DBG(" <- maple_init_early\n");
}
@@ -270,7 +257,7 @@ static int __init maple_probe(int platform)
* occupies having to be broken up so the DART itself is not
* part of the cacheable linar mapping
*/
- alloc_u3_dart_table();
+ alloc_dart_table();
return 1;
}
@@ -292,4 +279,9 @@ struct machdep_calls __initdata maple_md = {
.calibrate_decr = generic_calibrate_decr,
.progress = maple_progress,
.idle_loop = native_idle,
+#ifdef CONFIG_KEXEC
+ .machine_kexec = default_machine_kexec,
+ .machine_kexec_prepare = default_machine_kexec_prepare,
+ .machine_crash_shutdown = default_machine_crash_shutdown,
+#endif
};
diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile
index c9df44fcf571..78093d7f97af 100644
--- a/arch/powerpc/platforms/powermac/Makefile
+++ b/arch/powerpc/platforms/powermac/Makefile
@@ -1,9 +1,14 @@
+CFLAGS_bootx_init.o += -fPIC
+
obj-y += pic.o setup.o time.o feature.o pci.o \
- sleep.o low_i2c.o cache.o
+ sleep.o low_i2c.o cache.o pfunc_core.o \
+ pfunc_base.o
obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o
obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq_32.o
obj-$(CONFIG_CPU_FREQ_PMAC64) += cpufreq_64.o
obj-$(CONFIG_NVRAM) += nvram.o
# ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff
obj-$(CONFIG_PPC64) += nvram.o
+obj-$(CONFIG_PPC32) += bootx_init.o
obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_PPC_MERGE) += udbg_scc.o udbg_adb.o
diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c
new file mode 100644
index 000000000000..fa8b4d7b5ded
--- /dev/null
+++ b/arch/powerpc/platforms/powermac/bootx_init.c
@@ -0,0 +1,547 @@
+/*
+ * Early boot support code for BootX bootloader
+ *
+ * Copyright (C) 2005 Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/page.h>
+#include <asm/bootx.h>
+#include <asm/bootinfo.h>
+#include <asm/btext.h>
+#include <asm/io.h>
+
+#undef DEBUG
+#define SET_BOOT_BAT
+
+#ifdef DEBUG
+#define DBG(fmt...) do { bootx_printf(fmt); } while(0)
+#else
+#define DBG(fmt...) do { } while(0)
+#endif
+
+extern void __start(unsigned long r3, unsigned long r4, unsigned long r5);
+
+static unsigned long __initdata bootx_dt_strbase;
+static unsigned long __initdata bootx_dt_strend;
+static unsigned long __initdata bootx_node_chosen;
+static boot_infos_t * __initdata bootx_info;
+static char __initdata bootx_disp_path[256];
+
+/* Is boot-info compatible ? */
+#define BOOT_INFO_IS_COMPATIBLE(bi) \
+ ((bi)->compatible_version <= BOOT_INFO_VERSION)
+#define BOOT_INFO_IS_V2_COMPATIBLE(bi) ((bi)->version >= 2)
+#define BOOT_INFO_IS_V4_COMPATIBLE(bi) ((bi)->version >= 4)
+
+#ifdef CONFIG_BOOTX_TEXT
+static void __init bootx_printf(const char *format, ...)
+{
+ const char *p, *q, *s;
+ va_list args;
+ unsigned long v;
+
+ va_start(args, format);
+ for (p = format; *p != 0; p = q) {
+ for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q)
+ ;
+ if (q > p)
+ btext_drawtext(p, q - p);
+ if (*q == 0)
+ break;
+ if (*q == '\n') {
+ ++q;
+ btext_flushline();
+ btext_drawstring("\r\n");
+ btext_flushline();
+ continue;
+ }
+ ++q;
+ if (*q == 0)
+ break;
+ switch (*q) {
+ case 's':
+ ++q;
+ s = va_arg(args, const char *);
+ if (s == NULL)
+ s = "<NULL>";
+ btext_drawstring(s);
+ break;
+ case 'x':
+ ++q;
+ v = va_arg(args, unsigned long);
+ btext_drawhex(v);
+ break;
+ }
+ }
+}
+#else /* CONFIG_BOOTX_TEXT */
+static void __init bootx_printf(const char *format, ...) {}
+#endif /* CONFIG_BOOTX_TEXT */
+
+static void * __init bootx_early_getprop(unsigned long base,
+ unsigned long node,
+ char *prop)
+{
+ struct bootx_dt_node *np = (struct bootx_dt_node *)(base + node);
+ u32 *ppp = &np->properties;
+
+ while(*ppp) {
+ struct bootx_dt_prop *pp =
+ (struct bootx_dt_prop *)(base + *ppp);
+
+ if (strcmp((char *)((unsigned long)pp->name + base),
+ prop) == 0) {
+ return (void *)((unsigned long)pp->value + base);
+ }
+ ppp = &pp->next;
+ }
+ return NULL;
+}
+
+#define dt_push_token(token, mem) \
+ do { \
+ *(mem) = _ALIGN_UP(*(mem),4); \
+ *((u32 *)*(mem)) = token; \
+ *(mem) += 4; \
+ } while(0)
+
+static unsigned long __init bootx_dt_find_string(char *str)
+{
+ char *s, *os;
+
+ s = os = (char *)bootx_dt_strbase;
+ s += 4;
+ while (s < (char *)bootx_dt_strend) {
+ if (strcmp(s, str) == 0)
+ return s - os;
+ s += strlen(s) + 1;
+ }
+ return 0;
+}
+
+static void __init bootx_dt_add_prop(char *name, void *data, int size,
+ unsigned long *mem_end)
+{
+ unsigned long soff = bootx_dt_find_string(name);
+ if (data == NULL)
+ size = 0;
+ if (soff == 0) {
+ bootx_printf("WARNING: Can't find string index for <%s>\n",
+ name);
+ return;
+ }
+ if (size > 0x20000) {
+ bootx_printf("WARNING: ignoring large property ");
+ bootx_printf("%s length 0x%x\n", name, size);
+ return;
+ }
+ dt_push_token(OF_DT_PROP, mem_end);
+ dt_push_token(size, mem_end);
+ dt_push_token(soff, mem_end);
+
+ /* push property content */
+ if (size && data) {
+ memcpy((void *)*mem_end, data, size);
+ *mem_end = _ALIGN_UP(*mem_end + size, 4);
+ }
+}
+
+static void __init bootx_add_chosen_props(unsigned long base,
+ unsigned long *mem_end)
+{
+ u32 val = _MACH_Pmac;
+
+ bootx_dt_add_prop("linux,platform", &val, 4, mem_end);
+
+ if (bootx_info->kernelParamsOffset) {
+ char *args = (char *)((unsigned long)bootx_info) +
+ bootx_info->kernelParamsOffset;
+ bootx_dt_add_prop("bootargs", args, strlen(args) + 1, mem_end);
+ }
+ if (bootx_info->ramDisk) {
+ val = ((unsigned long)bootx_info) + bootx_info->ramDisk;
+ bootx_dt_add_prop("linux,initrd-start", &val, 4, mem_end);
+ val += bootx_info->ramDiskSize;
+ bootx_dt_add_prop("linux,initrd-end", &val, 4, mem_end);
+ }
+ if (strlen(bootx_disp_path))
+ bootx_dt_add_prop("linux,stdout-path", bootx_disp_path,
+ strlen(bootx_disp_path) + 1, mem_end);
+}
+
+static void __init bootx_add_display_props(unsigned long base,
+ unsigned long *mem_end)
+{
+ bootx_dt_add_prop("linux,boot-display", NULL, 0, mem_end);
+ bootx_dt_add_prop("linux,opened", NULL, 0, mem_end);
+}
+
+static void __init bootx_dt_add_string(char *s, unsigned long *mem_end)
+{
+ unsigned int l = strlen(s) + 1;
+ memcpy((void *)*mem_end, s, l);
+ bootx_dt_strend = *mem_end = *mem_end + l;
+}
+
+static void __init bootx_scan_dt_build_strings(unsigned long base,
+ unsigned long node,
+ unsigned long *mem_end)
+{
+ struct bootx_dt_node *np = (struct bootx_dt_node *)(base + node);
+ u32 *cpp, *ppp = &np->properties;
+ unsigned long soff;
+ char *namep;
+
+ /* Keep refs to known nodes */
+ namep = np->full_name ? (char *)(base + np->full_name) : NULL;
+ if (namep == NULL) {
+ bootx_printf("Node without a full name !\n");
+ namep = "";
+ }
+ DBG("* strings: %s\n", namep);
+
+ if (!strcmp(namep, "/chosen")) {
+ DBG(" detected /chosen ! adding properties names !\n");
+ bootx_dt_add_string("linux,platform", mem_end);
+ bootx_dt_add_string("linux,stdout-path", mem_end);
+ bootx_dt_add_string("linux,initrd-start", mem_end);
+ bootx_dt_add_string("linux,initrd-end", mem_end);
+ bootx_dt_add_string("bootargs", mem_end);
+ bootx_node_chosen = node;
+ }
+ if (node == bootx_info->dispDeviceRegEntryOffset) {
+ DBG(" detected display ! adding properties names !\n");
+ bootx_dt_add_string("linux,boot-display", mem_end);
+ bootx_dt_add_string("linux,opened", mem_end);
+ strncpy(bootx_disp_path, namep, 255);
+ }
+
+ /* get and store all property names */
+ while (*ppp) {
+ struct bootx_dt_prop *pp =
+ (struct bootx_dt_prop *)(base + *ppp);
+
+ namep = pp->name ? (char *)(base + pp->name) : NULL;
+ if (namep == NULL || strcmp(namep, "name") == 0)
+ goto next;
+ /* get/create string entry */
+ soff = bootx_dt_find_string(namep);
+ if (soff == 0)
+ bootx_dt_add_string(namep, mem_end);
+ next:
+ ppp = &pp->next;
+ }
+
+ /* do all our children */
+ cpp = &np->child;
+ while(*cpp) {
+ np = (struct bootx_dt_node *)(base + *cpp);
+ bootx_scan_dt_build_strings(base, *cpp, mem_end);
+ cpp = &np->sibling;
+ }
+}
+
+static void __init bootx_scan_dt_build_struct(unsigned long base,
+ unsigned long node,
+ unsigned long *mem_end)
+{
+ struct bootx_dt_node *np = (struct bootx_dt_node *)(base + node);
+ u32 *cpp, *ppp = &np->properties;
+ char *namep, *p, *ep, *lp;
+ int l;
+
+ dt_push_token(OF_DT_BEGIN_NODE, mem_end);
+
+ /* get the node's full name */
+ namep = np->full_name ? (char *)(base + np->full_name) : NULL;
+ if (namep == NULL)
+ namep = "";
+ l = strlen(namep);
+
+ DBG("* struct: %s\n", namep);
+
+ /* Fixup an Apple bug where they have bogus \0 chars in the
+ * middle of the path in some properties, and extract
+ * the unit name (everything after the last '/').
+ */
+ memcpy((void *)*mem_end, namep, l + 1);
+ namep = (char *)*mem_end;
+ for (lp = p = namep, ep = namep + l; p < ep; p++) {
+ if (*p == '/')
+ lp = namep;
+ else if (*p != 0)
+ *lp++ = *p;
+ }
+ *lp = 0;
+ *mem_end = _ALIGN_UP((unsigned long)lp + 1, 4);
+
+ /* get and store all properties */
+ while (*ppp) {
+ struct bootx_dt_prop *pp =
+ (struct bootx_dt_prop *)(base + *ppp);
+
+ namep = pp->name ? (char *)(base + pp->name) : NULL;
+ /* Skip "name" */
+ if (namep == NULL || !strcmp(namep, "name"))
+ goto next;
+ /* Skip "bootargs" in /chosen too as we replace it */
+ if (node == bootx_node_chosen && !strcmp(namep, "bootargs"))
+ goto next;
+
+ /* push property head */
+ bootx_dt_add_prop(namep,
+ pp->value ? (void *)(base + pp->value): NULL,
+ pp->length, mem_end);
+ next:
+ ppp = &pp->next;
+ }
+
+ if (node == bootx_node_chosen)
+ bootx_add_chosen_props(base, mem_end);
+ if (node == bootx_info->dispDeviceRegEntryOffset)
+ bootx_add_display_props(base, mem_end);
+
+ /* do all our children */
+ cpp = &np->child;
+ while(*cpp) {
+ np = (struct bootx_dt_node *)(base + *cpp);
+ bootx_scan_dt_build_struct(base, *cpp, mem_end);
+ cpp = &np->sibling;
+ }
+
+ dt_push_token(OF_DT_END_NODE, mem_end);
+}
+
+static unsigned long __init bootx_flatten_dt(unsigned long start)
+{
+ boot_infos_t *bi = bootx_info;
+ unsigned long mem_start, mem_end;
+ struct boot_param_header *hdr;
+ unsigned long base;
+ u64 *rsvmap;
+
+ /* Start using memory after the big blob passed by BootX, get
+ * some space for the header
+ */
+ mem_start = mem_end = _ALIGN_UP(((unsigned long)bi) + start, 4);
+ DBG("Boot params header at: %x\n", mem_start);
+ hdr = (struct boot_param_header *)mem_start;
+ mem_end += sizeof(struct boot_param_header);
+ rsvmap = (u64 *)(_ALIGN_UP(mem_end, 8));
+ hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - mem_start;
+ mem_end = ((unsigned long)rsvmap) + 8 * sizeof(u64);
+
+ /* Get base of tree */
+ base = ((unsigned long)bi) + bi->deviceTreeOffset;
+
+ /* Build string array */
+ DBG("Building string array at: %x\n", mem_end);
+ DBG("Device Tree Base=%x\n", base);
+ bootx_dt_strbase = mem_end;
+ mem_end += 4;
+ bootx_dt_strend = mem_end;
+ bootx_scan_dt_build_strings(base, 4, &mem_end);
+ hdr->off_dt_strings = bootx_dt_strbase - mem_start;
+ hdr->dt_strings_size = bootx_dt_strend - bootx_dt_strbase;
+
+ /* Build structure */
+ mem_end = _ALIGN(mem_end, 16);
+ DBG("Building device tree structure at: %x\n", mem_end);
+ hdr->off_dt_struct = mem_end - mem_start;
+ bootx_scan_dt_build_struct(base, 4, &mem_end);
+ dt_push_token(OF_DT_END, &mem_end);
+
+ /* Finish header */
+ hdr->boot_cpuid_phys = 0;
+ hdr->magic = OF_DT_HEADER;
+ hdr->totalsize = mem_end - mem_start;
+ hdr->version = OF_DT_VERSION;
+ /* Version 16 is not backward compatible */
+ hdr->last_comp_version = 0x10;
+
+ /* Reserve the whole thing and copy the reserve map in, we
+ * also bump mem_reserve_cnt to cause further reservations to
+ * fail since it's too late.
+ */
+ mem_end = _ALIGN(mem_end, PAGE_SIZE);
+ DBG("End of boot params: %x\n", mem_end);
+ rsvmap[0] = mem_start;
+ rsvmap[1] = mem_end;
+ rsvmap[2] = 0;
+ rsvmap[3] = 0;
+
+ return (unsigned long)hdr;
+}
+
+
+#ifdef CONFIG_BOOTX_TEXT
+static void __init btext_welcome(boot_infos_t *bi)
+{
+ unsigned long flags;
+ unsigned long pvr;
+
+ bootx_printf("Welcome to Linux, kernel " UTS_RELEASE "\n");
+ bootx_printf("\nlinked at : 0x%x", KERNELBASE);
+ bootx_printf("\nframe buffer at : 0x%x", bi->dispDeviceBase);
+ bootx_printf(" (phys), 0x%x", bi->logicalDisplayBase);
+ bootx_printf(" (log)");
+ bootx_printf("\nklimit : 0x%x",(unsigned long)klimit);
+ bootx_printf("\nboot_info at : 0x%x", bi);
+ __asm__ __volatile__ ("mfmsr %0" : "=r" (flags));
+ bootx_printf("\nMSR : 0x%x", flags);
+ __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));
+ bootx_printf("\nPVR : 0x%x", pvr);
+ pvr >>= 16;
+ if (pvr > 1) {
+ __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags));
+ bootx_printf("\nHID0 : 0x%x", flags);
+ }
+ if (pvr == 8 || pvr == 12 || pvr == 0x800c) {
+ __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags));
+ bootx_printf("\nICTC : 0x%x", flags);
+ }
+#ifdef DEBUG
+ bootx_printf("\n\n");
+ bootx_printf("bi->deviceTreeOffset : 0x%x\n",
+ bi->deviceTreeOffset);
+ bootx_printf("bi->deviceTreeSize : 0x%x\n",
+ bi->deviceTreeSize);
+#endif
+ bootx_printf("\n\n");
+}
+#endif /* CONFIG_BOOTX_TEXT */
+
+void __init bootx_init(unsigned long r3, unsigned long r4)
+{
+ boot_infos_t *bi = (boot_infos_t *) r4;
+ unsigned long hdr;
+ unsigned long space;
+ unsigned long ptr, x;
+ char *model;
+ unsigned long offset = reloc_offset();
+
+ reloc_got2(offset);
+
+ bootx_info = bi;
+
+ /* We haven't cleared any bss at this point, make sure
+ * what we need is initialized
+ */
+ bootx_dt_strbase = bootx_dt_strend = 0;
+ bootx_node_chosen = 0;
+ bootx_disp_path[0] = 0;
+
+ if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
+ bi->logicalDisplayBase = bi->dispDeviceBase;
+
+#ifdef CONFIG_BOOTX_TEXT
+ btext_setup_display(bi->dispDeviceRect[2] - bi->dispDeviceRect[0],
+ bi->dispDeviceRect[3] - bi->dispDeviceRect[1],
+ bi->dispDeviceDepth, bi->dispDeviceRowBytes,
+ (unsigned long)bi->logicalDisplayBase);
+ btext_clearscreen();
+ btext_flushscreen();
+#endif /* CONFIG_BOOTX_TEXT */
+
+ /*
+ * Test if boot-info is compatible. Done only in config
+ * CONFIG_BOOTX_TEXT since there is nothing much we can do
+ * with an incompatible version, except display a message
+ * and eventually hang the processor...
+ *
+ * I'll try to keep enough of boot-info compatible in the
+ * future to always allow display of this message;
+ */
+ if (!BOOT_INFO_IS_COMPATIBLE(bi)) {
+ bootx_printf(" !!! WARNING - Incompatible version"
+ " of BootX !!!\n\n\n");
+ for (;;)
+ ;
+ }
+ if (bi->architecture != BOOT_ARCH_PCI) {
+ bootx_printf(" !!! WARNING - Usupported machine"
+ " architecture !\n");
+ for (;;)
+ ;
+ }
+
+#ifdef CONFIG_BOOTX_TEXT
+ btext_welcome(bi);
+#endif
+ /* New BootX enters kernel with MMU off, i/os are not allowed
+ * here. This hack will have been done by the boostrap anyway.
+ */
+ if (bi->version < 4) {
+ /*
+ * XXX If this is an iMac, turn off the USB controller.
+ */
+ model = (char *) bootx_early_getprop(r4 + bi->deviceTreeOffset,
+ 4, "model");
+ if (model
+ && (strcmp(model, "iMac,1") == 0
+ || strcmp(model, "PowerMac1,1") == 0)) {
+ bootx_printf("iMac,1 detected, shutting down USB \n");
+ out_le32((unsigned *)0x80880008, 1); /* XXX */
+ }
+ }
+
+ /* Get a pointer that points above the device tree, args, ramdisk,
+ * etc... to use for generating the flattened tree
+ */
+ if (bi->version < 5) {
+ space = bi->deviceTreeOffset + bi->deviceTreeSize;
+ if (bi->ramDisk)
+ space = bi->ramDisk + bi->ramDiskSize;
+ } else
+ space = bi->totalParamsSize;
+
+ bootx_printf("Total space used by parameters & ramdisk: %x \n", space);
+
+ /* New BootX will have flushed all TLBs and enters kernel with
+ * MMU switched OFF, so this should not be useful anymore.
+ */
+ if (bi->version < 4) {
+ bootx_printf("Touching pages...\n");
+
+ /*
+ * Touch each page to make sure the PTEs for them
+ * are in the hash table - the aim is to try to avoid
+ * getting DSI exceptions while copying the kernel image.
+ */
+ for (ptr = ((unsigned long) &_stext) & PAGE_MASK;
+ ptr < (unsigned long)bi + space; ptr += PAGE_SIZE)
+ x = *(volatile unsigned long *)ptr;
+ }
+
+ /* Ok, now we need to generate a flattened device-tree to pass
+ * to the kernel
+ */
+ bootx_printf("Preparing boot params...\n");
+
+ hdr = bootx_flatten_dt(space);
+
+#ifdef CONFIG_BOOTX_TEXT
+#ifdef SET_BOOT_BAT
+ bootx_printf("Preparing BAT...\n");
+ btext_prepare_BAT();
+#else
+ btext_unmap();
+#endif
+#endif
+
+ reloc_got2(-offset);
+
+ __start(hdr, KERNELBASE + offset, 0);
+}
diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
index 39150342c6f1..a4b50c4109c2 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_64.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_64.c
@@ -28,6 +28,7 @@
#include <asm/cputable.h>
#include <asm/time.h>
#include <asm/smu.h>
+#include <asm/pmac_pfunc.h>
#undef DEBUG
@@ -85,6 +86,10 @@ static u32 *g5_pmode_data;
static int g5_pmode_max;
static int g5_pmode_cur;
+static void (*g5_switch_volt)(int speed_mode);
+static int (*g5_switch_freq)(int speed_mode);
+static int (*g5_query_freq)(void);
+
static DECLARE_MUTEX(g5_switch_mutex);
@@ -92,9 +97,11 @@ static struct smu_sdbp_fvt *g5_fvt_table; /* table of op. points */
static int g5_fvt_count; /* number of op. points */
static int g5_fvt_cur; /* current op. point */
-/* ----------------- real hardware interface */
+/*
+ * SMU based voltage switching for Neo2 platforms
+ */
-static void g5_switch_volt(int speed_mode)
+static void g5_smu_switch_volt(int speed_mode)
{
struct smu_simple_cmd cmd;
@@ -105,26 +112,57 @@ static void g5_switch_volt(int speed_mode)
wait_for_completion(&comp);
}
-static int g5_switch_freq(int speed_mode)
+/*
+ * Platform function based voltage/vdnap switching for Neo2
+ */
+
+static struct pmf_function *pfunc_set_vdnap0;
+static struct pmf_function *pfunc_vdnap0_complete;
+
+static void g5_vdnap_switch_volt(int speed_mode)
{
- struct cpufreq_freqs freqs;
- int to;
+ struct pmf_args args;
+ u32 slew, done = 0;
+ unsigned long timeout;
- if (g5_pmode_cur == speed_mode)
- return 0;
+ slew = (speed_mode == CPUFREQ_LOW) ? 1 : 0;
+ args.count = 1;
+ args.u[0].p = &slew;
- down(&g5_switch_mutex);
+ pmf_call_one(pfunc_set_vdnap0, &args);
- freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency;
- freqs.new = g5_cpu_freqs[speed_mode].frequency;
- freqs.cpu = 0;
+ /* It's an irq GPIO so we should be able to just block here,
+ * I'll do that later after I've properly tested the IRQ code for
+ * platform functions
+ */
+ timeout = jiffies + HZ/10;
+ while(!time_after(jiffies, timeout)) {
+ args.count = 1;
+ args.u[0].p = &done;
+ pmf_call_one(pfunc_vdnap0_complete, &args);
+ if (done)
+ break;
+ msleep(1);
+ }
+ if (done == 0)
+ printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n");
+}
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+/*
+ * SCOM based frequency switching for 970FX rev3
+ */
+static int g5_scom_switch_freq(int speed_mode)
+{
+ unsigned long flags;
+ int to;
/* If frequency is going up, first ramp up the voltage */
if (speed_mode < g5_pmode_cur)
g5_switch_volt(speed_mode);
+ local_irq_save(flags);
+
/* Clear PCR high */
scom970_write(SCOM_PCR, 0);
/* Clear PCR low */
@@ -147,6 +185,8 @@ static int g5_switch_freq(int speed_mode)
udelay(100);
}
+ local_irq_restore(flags);
+
/* If frequency is going down, last ramp the voltage */
if (speed_mode > g5_pmode_cur)
g5_switch_volt(speed_mode);
@@ -154,14 +194,10 @@ static int g5_switch_freq(int speed_mode)
g5_pmode_cur = speed_mode;
ppc_proc_freq = g5_cpu_freqs[speed_mode].frequency * 1000ul;
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
- up(&g5_switch_mutex);
-
return 0;
}
-static int g5_query_freq(void)
+static int g5_scom_query_freq(void)
{
unsigned long psr = scom970_read(SCOM_PSR);
int i;
@@ -173,7 +209,104 @@ static int g5_query_freq(void)
return i;
}
-/* ----------------- cpufreq bookkeeping */
+/*
+ * Platform function based voltage switching for PowerMac7,2 & 7,3
+ */
+
+static struct pmf_function *pfunc_cpu0_volt_high;
+static struct pmf_function *pfunc_cpu0_volt_low;
+static struct pmf_function *pfunc_cpu1_volt_high;
+static struct pmf_function *pfunc_cpu1_volt_low;
+
+static void g5_pfunc_switch_volt(int speed_mode)
+{
+ if (speed_mode == CPUFREQ_HIGH) {
+ if (pfunc_cpu0_volt_high)
+ pmf_call_one(pfunc_cpu0_volt_high, NULL);
+ if (pfunc_cpu1_volt_high)
+ pmf_call_one(pfunc_cpu1_volt_high, NULL);
+ } else {
+ if (pfunc_cpu0_volt_low)
+ pmf_call_one(pfunc_cpu0_volt_low, NULL);
+ if (pfunc_cpu1_volt_low)
+ pmf_call_one(pfunc_cpu1_volt_low, NULL);
+ }
+ msleep(10); /* should be faster , to fix */
+}
+
+/*
+ * Platform function based frequency switching for PowerMac7,2 & 7,3
+ */
+
+static struct pmf_function *pfunc_cpu_setfreq_high;
+static struct pmf_function *pfunc_cpu_setfreq_low;
+static struct pmf_function *pfunc_cpu_getfreq;
+static struct pmf_function *pfunc_slewing_done;;
+
+static int g5_pfunc_switch_freq(int speed_mode)
+{
+ struct pmf_args args;
+ u32 done = 0;
+ unsigned long timeout;
+
+ /* If frequency is going up, first ramp up the voltage */
+ if (speed_mode < g5_pmode_cur)
+ g5_switch_volt(speed_mode);
+
+ /* Do it */
+ if (speed_mode == CPUFREQ_HIGH)
+ pmf_call_one(pfunc_cpu_setfreq_high, NULL);
+ else
+ pmf_call_one(pfunc_cpu_setfreq_low, NULL);
+
+ /* It's an irq GPIO so we should be able to just block here,
+ * I'll do that later after I've properly tested the IRQ code for
+ * platform functions
+ */
+ timeout = jiffies + HZ/10;
+ while(!time_after(jiffies, timeout)) {
+ args.count = 1;
+ args.u[0].p = &done;
+ pmf_call_one(pfunc_slewing_done, &args);
+ if (done)
+ break;
+ msleep(1);
+ }
+ if (done == 0)
+ printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n");
+
+ /* If frequency is going down, last ramp the voltage */
+ if (speed_mode > g5_pmode_cur)
+ g5_switch_volt(speed_mode);
+
+ g5_pmode_cur = speed_mode;
+ ppc_proc_freq = g5_cpu_freqs[speed_mode].frequency * 1000ul;
+
+ return 0;
+}
+
+static int g5_pfunc_query_freq(void)
+{
+ struct pmf_args args;
+ u32 val = 0;
+
+ args.count = 1;
+ args.u[0].p = &val;
+ pmf_call_one(pfunc_cpu_getfreq, &args);
+ return val ? CPUFREQ_HIGH : CPUFREQ_LOW;
+}
+
+/*
+ * Fake voltage switching for platforms with missing support
+ */
+
+static void g5_dummy_switch_volt(int speed_mode)
+{
+}
+
+/*
+ * Common interface to the cpufreq core
+ */
static int g5_cpufreq_verify(struct cpufreq_policy *policy)
{
@@ -183,13 +316,30 @@ static int g5_cpufreq_verify(struct cpufreq_policy *policy)
static int g5_cpufreq_target(struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int relation)
{
- unsigned int newstate = 0;
+ unsigned int newstate = 0;
+ struct cpufreq_freqs freqs;
+ int rc;
if (cpufreq_frequency_table_target(policy, g5_cpu_freqs,
target_freq, relation, &newstate))
return -EINVAL;
- return g5_switch_freq(newstate);
+ if (g5_pmode_cur == newstate)
+ return 0;
+
+ down(&g5_switch_mutex);
+
+ freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency;
+ freqs.new = g5_cpu_freqs[newstate].frequency;
+ freqs.cpu = 0;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ rc = g5_switch_freq(newstate);
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ up(&g5_switch_mutex);
+
+ return rc;
}
static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
@@ -205,6 +355,7 @@ static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = g5_cpu_freqs[g5_query_freq()].frequency;
+ policy->cpus = cpu_possible_map;
cpufreq_frequency_table_get_attr(g5_cpu_freqs, policy->cpu);
return cpufreq_frequency_table_cpuinfo(policy,
@@ -224,19 +375,39 @@ static struct cpufreq_driver g5_cpufreq_driver = {
};
-static int __init g5_cpufreq_init(void)
+static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
{
struct device_node *cpunode;
unsigned int psize, ssize;
- struct smu_sdbp_header *shdr;
unsigned long max_freq;
- u32 *valp;
+ char *freq_method, *volt_method;
+ u32 *valp, pvr_hi;
+ int use_volts_vdnap = 0;
+ int use_volts_smu = 0;
int rc = -ENODEV;
- /* Look for CPU and SMU nodes */
- cpunode = of_find_node_by_type(NULL, "cpu");
- if (!cpunode) {
- DBG("No CPU node !\n");
+ /* Check supported platforms */
+ if (machine_is_compatible("PowerMac8,1") ||
+ machine_is_compatible("PowerMac8,2") ||
+ machine_is_compatible("PowerMac9,1"))
+ use_volts_smu = 1;
+ else if (machine_is_compatible("PowerMac11,2"))
+ use_volts_vdnap = 1;
+ else
+ return -ENODEV;
+
+ /* Get first CPU node */
+ for (cpunode = NULL;
+ (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
+ u32 *reg =
+ (u32 *)get_property(cpunode, "reg", NULL);
+ if (reg == NULL || (*reg) != 0)
+ continue;
+ if (!strcmp(cpunode->type, "cpu"))
+ break;
+ }
+ if (cpunode == NULL) {
+ printk(KERN_ERR "cpufreq: Can't find any CPU 0 node\n");
return -ENODEV;
}
@@ -246,8 +417,9 @@ static int __init g5_cpufreq_init(void)
DBG("No cpu-version property !\n");
goto bail_noprops;
}
- if (((*valp) >> 16) != 0x3c) {
- DBG("Wrong CPU version: %08x\n", *valp);
+ pvr_hi = (*valp) >> 16;
+ if (pvr_hi != 0x3c && pvr_hi != 0x44) {
+ printk(KERN_ERR "cpufreq: Unsupported CPU version\n");
goto bail_noprops;
}
@@ -259,18 +431,50 @@ static int __init g5_cpufreq_init(void)
}
g5_pmode_max = psize / sizeof(u32) - 1;
- /* Look for the FVT table */
- shdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
- if (!shdr)
- goto bail_noprops;
- g5_fvt_table = (struct smu_sdbp_fvt *)&shdr[1];
- ssize = (shdr->len * sizeof(u32)) - sizeof(struct smu_sdbp_header);
- g5_fvt_count = ssize / sizeof(struct smu_sdbp_fvt);
- g5_fvt_cur = 0;
-
- /* Sanity checking */
- if (g5_fvt_count < 1 || g5_pmode_max < 1)
- goto bail_noprops;
+ if (use_volts_smu) {
+ struct smu_sdbp_header *shdr;
+
+ /* Look for the FVT table */
+ shdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
+ if (!shdr)
+ goto bail_noprops;
+ g5_fvt_table = (struct smu_sdbp_fvt *)&shdr[1];
+ ssize = (shdr->len * sizeof(u32)) -
+ sizeof(struct smu_sdbp_header);
+ g5_fvt_count = ssize / sizeof(struct smu_sdbp_fvt);
+ g5_fvt_cur = 0;
+
+ /* Sanity checking */
+ if (g5_fvt_count < 1 || g5_pmode_max < 1)
+ goto bail_noprops;
+
+ g5_switch_volt = g5_smu_switch_volt;
+ volt_method = "SMU";
+ } else if (use_volts_vdnap) {
+ struct device_node *root;
+
+ root = of_find_node_by_path("/");
+ if (root == NULL) {
+ printk(KERN_ERR "cpufreq: Can't find root of "
+ "device tree\n");
+ goto bail_noprops;
+ }
+ pfunc_set_vdnap0 = pmf_find_function(root, "set-vdnap0");
+ pfunc_vdnap0_complete =
+ pmf_find_function(root, "slewing-done");
+ if (pfunc_set_vdnap0 == NULL ||
+ pfunc_vdnap0_complete == NULL) {
+ printk(KERN_ERR "cpufreq: Can't find required "
+ "platform function\n");
+ goto bail_noprops;
+ }
+
+ g5_switch_volt = g5_vdnap_switch_volt;
+ volt_method = "GPIO";
+ } else {
+ g5_switch_volt = g5_dummy_switch_volt;
+ volt_method = "none";
+ }
/*
* From what I see, clock-frequency is always the maximal frequency.
@@ -286,19 +490,23 @@ static int __init g5_cpufreq_init(void)
g5_cpu_freqs[0].frequency = max_freq;
g5_cpu_freqs[1].frequency = max_freq/2;
- /* Check current frequency */
- g5_pmode_cur = g5_query_freq();
- if (g5_pmode_cur > 1)
- /* We don't support anything but 1:1 and 1:2, fixup ... */
- g5_pmode_cur = 1;
+ /* Set callbacks */
+ g5_switch_freq = g5_scom_switch_freq;
+ g5_query_freq = g5_scom_query_freq;
+ freq_method = "SCOM";
/* Force apply current frequency to make sure everything is in
* sync (voltage is right for example). Firmware may leave us with
* a strange setting ...
*/
- g5_switch_freq(g5_pmode_cur);
+ g5_switch_volt(CPUFREQ_HIGH);
+ msleep(10);
+ g5_pmode_cur = -1;
+ g5_switch_freq(g5_query_freq());
printk(KERN_INFO "Registering G5 CPU frequency driver\n");
+ printk(KERN_INFO "Frequency method: %s, Voltage method: %s\n",
+ freq_method, volt_method);
printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n",
g5_cpu_freqs[1].frequency/1000,
g5_cpu_freqs[0].frequency/1000,
@@ -317,6 +525,200 @@ static int __init g5_cpufreq_init(void)
return rc;
}
+static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
+{
+ struct device_node *cpuid = NULL, *hwclock = NULL, *cpunode = NULL;
+ u8 *eeprom = NULL;
+ u32 *valp;
+ u64 max_freq, min_freq, ih, il;
+ int has_volt = 1, rc = 0;
+
+ /* Get first CPU node */
+ for (cpunode = NULL;
+ (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
+ if (!strcmp(cpunode->type, "cpu"))
+ break;
+ }
+ if (cpunode == NULL) {
+ printk(KERN_ERR "cpufreq: Can't find any CPU node\n");
+ return -ENODEV;
+ }
+
+ /* Lookup the cpuid eeprom node */
+ cpuid = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/cpuid@a0");
+ if (cpuid != NULL)
+ eeprom = (u8 *)get_property(cpuid, "cpuid", NULL);
+ if (eeprom == NULL) {
+ printk(KERN_ERR "cpufreq: Can't find cpuid EEPROM !\n");
+ rc = -ENODEV;
+ goto bail;
+ }
+
+ /* Lookup the i2c hwclock */
+ for (hwclock = NULL;
+ (hwclock = of_find_node_by_name(hwclock, "i2c-hwclock")) != NULL;){
+ char *loc = get_property(hwclock, "hwctrl-location", NULL);
+ if (loc == NULL)
+ continue;
+ if (strcmp(loc, "CPU CLOCK"))
+ continue;
+ if (!get_property(hwclock, "platform-get-frequency", NULL))
+ continue;
+ break;
+ }
+ if (hwclock == NULL) {
+ printk(KERN_ERR "cpufreq: Can't find i2c clock chip !\n");
+ rc = -ENODEV;
+ goto bail;
+ }
+
+ DBG("cpufreq: i2c clock chip found: %s\n", hwclock->full_name);
+
+ /* Now get all the platform functions */
+ pfunc_cpu_getfreq =
+ pmf_find_function(hwclock, "get-frequency");
+ pfunc_cpu_setfreq_high =
+ pmf_find_function(hwclock, "set-frequency-high");
+ pfunc_cpu_setfreq_low =
+ pmf_find_function(hwclock, "set-frequency-low");
+ pfunc_slewing_done =
+ pmf_find_function(hwclock, "slewing-done");
+ pfunc_cpu0_volt_high =
+ pmf_find_function(hwclock, "set-voltage-high-0");
+ pfunc_cpu0_volt_low =
+ pmf_find_function(hwclock, "set-voltage-low-0");
+ pfunc_cpu1_volt_high =
+ pmf_find_function(hwclock, "set-voltage-high-1");
+ pfunc_cpu1_volt_low =
+ pmf_find_function(hwclock, "set-voltage-low-1");
+
+ /* Check we have minimum requirements */
+ if (pfunc_cpu_getfreq == NULL || pfunc_cpu_setfreq_high == NULL ||
+ pfunc_cpu_setfreq_low == NULL || pfunc_slewing_done == NULL) {
+ printk(KERN_ERR "cpufreq: Can't find platform functions !\n");
+ rc = -ENODEV;
+ goto bail;
+ }
+
+ /* Check that we have complete sets */
+ if (pfunc_cpu0_volt_high == NULL || pfunc_cpu0_volt_low == NULL) {
+ pmf_put_function(pfunc_cpu0_volt_high);
+ pmf_put_function(pfunc_cpu0_volt_low);
+ pfunc_cpu0_volt_high = pfunc_cpu0_volt_low = NULL;
+ has_volt = 0;
+ }
+ if (!has_volt ||
+ pfunc_cpu1_volt_high == NULL || pfunc_cpu1_volt_low == NULL) {
+ pmf_put_function(pfunc_cpu1_volt_high);
+ pmf_put_function(pfunc_cpu1_volt_low);
+ pfunc_cpu1_volt_high = pfunc_cpu1_volt_low = NULL;
+ }
+
+ /* Note: The device tree also contains a "platform-set-values"
+ * function for which I haven't quite figured out the usage. It
+ * might have to be called on init and/or wakeup, I'm not too sure
+ * but things seem to work fine without it so far ...
+ */
+
+ /* Get max frequency from device-tree */
+ valp = (u32 *)get_property(cpunode, "clock-frequency", NULL);
+ if (!valp) {
+ printk(KERN_ERR "cpufreq: Can't find CPU frequency !\n");
+ rc = -ENODEV;
+ goto bail;
+ }
+
+ max_freq = (*valp)/1000;
+
+ /* Now calculate reduced frequency by using the cpuid input freq
+ * ratio. This requires 64 bits math unless we are willing to lose
+ * some precision
+ */
+ ih = *((u32 *)(eeprom + 0x10));
+ il = *((u32 *)(eeprom + 0x20));
+ min_freq = 0;
+ if (ih != 0 && il != 0)
+ min_freq = (max_freq * il) / ih;
+
+ /* Sanity check */
+ if (min_freq >= max_freq || min_freq < 1000) {
+ printk(KERN_ERR "cpufreq: Can't calculate low frequency !\n");
+ rc = -ENODEV;
+ goto bail;
+ }
+ g5_cpu_freqs[0].frequency = max_freq;
+ g5_cpu_freqs[1].frequency = min_freq;
+
+ /* Set callbacks */
+ g5_switch_volt = g5_pfunc_switch_volt;
+ g5_switch_freq = g5_pfunc_switch_freq;
+ g5_query_freq = g5_pfunc_query_freq;
+
+ /* Force apply current frequency to make sure everything is in
+ * sync (voltage is right for example). Firmware may leave us with
+ * a strange setting ...
+ */
+ g5_switch_volt(CPUFREQ_HIGH);
+ msleep(10);
+ g5_pmode_cur = -1;
+ g5_switch_freq(g5_query_freq());
+
+ printk(KERN_INFO "Registering G5 CPU frequency driver\n");
+ printk(KERN_INFO "Frequency method: i2c/pfunc, "
+ "Voltage method: %s\n", has_volt ? "i2c/pfunc" : "none");
+ printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n",
+ g5_cpu_freqs[1].frequency/1000,
+ g5_cpu_freqs[0].frequency/1000,
+ g5_cpu_freqs[g5_pmode_cur].frequency/1000);
+
+ rc = cpufreq_register_driver(&g5_cpufreq_driver);
+ bail:
+ if (rc != 0) {
+ pmf_put_function(pfunc_cpu_getfreq);
+ pmf_put_function(pfunc_cpu_setfreq_high);
+ pmf_put_function(pfunc_cpu_setfreq_low);
+ pmf_put_function(pfunc_slewing_done);
+ pmf_put_function(pfunc_cpu0_volt_high);
+ pmf_put_function(pfunc_cpu0_volt_low);
+ pmf_put_function(pfunc_cpu1_volt_high);
+ pmf_put_function(pfunc_cpu1_volt_low);
+ }
+ of_node_put(hwclock);
+ of_node_put(cpuid);
+ of_node_put(cpunode);
+
+ return rc;
+}
+
+static int __init g5_rm31_cpufreq_init(struct device_node *cpus)
+{
+ /* NYI */
+ return 0;
+}
+
+static int __init g5_cpufreq_init(void)
+{
+ struct device_node *cpus;
+ int rc;
+
+ cpus = of_find_node_by_path("/cpus");
+ if (cpus == NULL) {
+ DBG("No /cpus node !\n");
+ return -ENODEV;
+ }
+
+ if (machine_is_compatible("PowerMac7,2") ||
+ machine_is_compatible("PowerMac7,3"))
+ rc = g5_pm72_cpufreq_init(cpus);
+ else if (machine_is_compatible("RackMac3,1"))
+ rc = g5_rm31_cpufreq_init(cpus);
+ else
+ rc = g5_neo2_cpufreq_init(cpus);
+
+ of_node_put(cpus);
+ return rc;
+}
+
module_init(g5_cpufreq_init);
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c
index f6e22da2a5da..558dd0692092 100644
--- a/arch/powerpc/platforms/powermac/feature.c
+++ b/arch/powerpc/platforms/powermac/feature.c
@@ -58,12 +58,11 @@ extern int powersave_lowspeed;
extern int powersave_nap;
extern struct device_node *k2_skiplist[2];
-
/*
* We use a single global lock to protect accesses. Each driver has
* to take care of its own locking
*/
-static DEFINE_SPINLOCK(feature_lock);
+DEFINE_SPINLOCK(feature_lock);
#define LOCK(flags) spin_lock_irqsave(&feature_lock, flags);
#define UNLOCK(flags) spin_unlock_irqrestore(&feature_lock, flags);
@@ -101,26 +100,17 @@ static const char *macio_names[] =
"Keylargo",
"Pangea",
"Intrepid",
- "K2"
+ "K2",
+ "Shasta",
};
+struct device_node *uninorth_node;
+u32 __iomem *uninorth_base;
-/*
- * Uninorth reg. access. Note that Uni-N regs are big endian
- */
-
-#define UN_REG(r) (uninorth_base + ((r) >> 2))
-#define UN_IN(r) (in_be32(UN_REG(r)))
-#define UN_OUT(r,v) (out_be32(UN_REG(r), (v)))
-#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v)))
-#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v)))
-
-static struct device_node *uninorth_node;
-static u32 __iomem *uninorth_base;
static u32 uninorth_rev;
-static int uninorth_u3;
-static void __iomem *u3_ht;
+static int uninorth_maj;
+static void __iomem *u3_ht_base;
/*
* For each motherboard family, we have a table of functions pointers
@@ -1399,8 +1389,15 @@ static long g5_fw_enable(struct device_node *node, long param, long value)
static long g5_mpic_enable(struct device_node *node, long param, long value)
{
unsigned long flags;
+ struct device_node *parent = of_get_parent(node);
+ int is_u3;
- if (node->parent == NULL || strcmp(node->parent->name, "u3"))
+ if (parent == NULL)
+ return 0;
+ is_u3 = strcmp(parent->name, "u3") == 0 ||
+ strcmp(parent->name, "u4") == 0;
+ of_node_put(parent);
+ if (!is_u3)
return 0;
LOCK(flags);
@@ -1445,20 +1442,53 @@ static long g5_i2s_enable(struct device_node *node, long param, long value)
/* Very crude implementation for now */
struct macio_chip *macio = &macio_chips[0];
unsigned long flags;
-
- if (value == 0)
- return 0; /* don't disable yet */
+ int cell;
+ u32 fcrs[3][3] = {
+ { 0,
+ K2_FCR1_I2S0_CELL_ENABLE |
+ K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE,
+ KL3_I2S0_CLK18_ENABLE
+ },
+ { KL0_SCC_A_INTF_ENABLE,
+ K2_FCR1_I2S1_CELL_ENABLE |
+ K2_FCR1_I2S1_CLK_ENABLE_BIT | K2_FCR1_I2S1_ENABLE,
+ KL3_I2S1_CLK18_ENABLE
+ },
+ { KL0_SCC_B_INTF_ENABLE,
+ SH_FCR1_I2S2_CELL_ENABLE |
+ SH_FCR1_I2S2_CLK_ENABLE_BIT | SH_FCR1_I2S2_ENABLE,
+ SH_FCR3_I2S2_CLK18_ENABLE
+ },
+ };
+
+ if (macio->type != macio_keylargo2 && macio->type != macio_shasta)
+ return -ENODEV;
+ if (strncmp(node->name, "i2s-", 4))
+ return -ENODEV;
+ cell = node->name[4] - 'a';
+ switch(cell) {
+ case 0:
+ case 1:
+ break;
+ case 2:
+ if (macio->type == macio_shasta)
+ break;
+ default:
+ return -ENODEV;
+ }
LOCK(flags);
- MACIO_BIS(KEYLARGO_FCR3, KL3_CLK45_ENABLE | KL3_CLK49_ENABLE |
- KL3_I2S0_CLK18_ENABLE);
- udelay(10);
- MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_I2S0_CELL_ENABLE |
- K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE);
+ if (value) {
+ MACIO_BIC(KEYLARGO_FCR0, fcrs[cell][0]);
+ MACIO_BIS(KEYLARGO_FCR1, fcrs[cell][1]);
+ MACIO_BIS(KEYLARGO_FCR3, fcrs[cell][2]);
+ } else {
+ MACIO_BIC(KEYLARGO_FCR3, fcrs[cell][2]);
+ MACIO_BIC(KEYLARGO_FCR1, fcrs[cell][1]);
+ MACIO_BIS(KEYLARGO_FCR0, fcrs[cell][0]);
+ }
udelay(10);
- MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_I2S0_RESET);
UNLOCK(flags);
- udelay(10);
return 0;
}
@@ -1473,7 +1503,7 @@ static long g5_reset_cpu(struct device_node *node, long param, long value)
struct device_node *np;
macio = &macio_chips[0];
- if (macio->type != macio_keylargo2)
+ if (macio->type != macio_keylargo2 && macio->type != macio_shasta)
return -ENODEV;
np = find_path_device("/cpus");
@@ -1512,14 +1542,17 @@ static long g5_reset_cpu(struct device_node *node, long param, long value)
*/
void g5_phy_disable_cpu1(void)
{
- UN_OUT(U3_API_PHY_CONFIG_1, 0);
+ if (uninorth_maj == 3)
+ UN_OUT(U3_API_PHY_CONFIG_1, 0);
}
#endif /* CONFIG_POWER4 */
#ifndef CONFIG_POWER4
-static void
-keylargo_shutdown(struct macio_chip *macio, int sleep_mode)
+
+#ifdef CONFIG_PM
+
+static void keylargo_shutdown(struct macio_chip *macio, int sleep_mode)
{
u32 temp;
@@ -1572,8 +1605,7 @@ keylargo_shutdown(struct macio_chip *macio, int sleep_mode)
(void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
}
-static void
-pangea_shutdown(struct macio_chip *macio, int sleep_mode)
+static void pangea_shutdown(struct macio_chip *macio, int sleep_mode)
{
u32 temp;
@@ -1606,8 +1638,7 @@ pangea_shutdown(struct macio_chip *macio, int sleep_mode)
(void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
}
-static void
-intrepid_shutdown(struct macio_chip *macio, int sleep_mode)
+static void intrepid_shutdown(struct macio_chip *macio, int sleep_mode)
{
u32 temp;
@@ -1635,124 +1666,6 @@ intrepid_shutdown(struct macio_chip *macio, int sleep_mode)
}
-void pmac_tweak_clock_spreading(int enable)
-{
- struct macio_chip *macio = &macio_chips[0];
-
- /* Hack for doing clock spreading on some machines PowerBooks and
- * iBooks. This implements the "platform-do-clockspreading" OF
- * property as decoded manually on various models. For safety, we also
- * check the product ID in the device-tree in cases we'll whack the i2c
- * chip to make reasonably sure we won't set wrong values in there
- *
- * Of course, ultimately, we have to implement a real parser for
- * the platform-do-* stuff...
- */
-
- if (macio->type == macio_intrepid) {
- struct device_node *clock =
- of_find_node_by_path("/uni-n@f8000000/hw-clock");
- if (clock && get_property(clock, "platform-do-clockspreading",
- NULL)) {
- printk(KERN_INFO "%sabling clock spreading on Intrepid"
- " ASIC\n", enable ? "En" : "Dis");
- if (enable)
- UN_OUT(UNI_N_CLOCK_SPREADING, 2);
- else
- UN_OUT(UNI_N_CLOCK_SPREADING, 0);
- mdelay(40);
- }
- of_node_put(clock);
- }
-
- while (machine_is_compatible("PowerBook5,2") ||
- machine_is_compatible("PowerBook5,3") ||
- machine_is_compatible("PowerBook6,2") ||
- machine_is_compatible("PowerBook6,3")) {
- struct device_node *ui2c = of_find_node_by_type(NULL, "i2c");
- struct device_node *dt = of_find_node_by_name(NULL, "device-tree");
- u8 buffer[9];
- u32 *productID;
- int i, rc, changed = 0;
-
- if (dt == NULL)
- break;
- productID = (u32 *)get_property(dt, "pid#", NULL);
- if (productID == NULL)
- break;
- while(ui2c) {
- struct device_node *p = of_get_parent(ui2c);
- if (p && !strcmp(p->name, "uni-n"))
- break;
- ui2c = of_find_node_by_type(ui2c, "i2c");
- }
- if (ui2c == NULL)
- break;
- DBG("Trying to bump clock speed for PID: %08x...\n", *productID);
- rc = pmac_low_i2c_open(ui2c, 1);
- if (rc != 0)
- break;
- pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
- rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
- DBG("read result: %d,", rc);
- if (rc != 0) {
- pmac_low_i2c_close(ui2c);
- break;
- }
- for (i=0; i<9; i++)
- DBG(" %02x", buffer[i]);
- DBG("\n");
-
- switch(*productID) {
- case 0x1182: /* AlBook 12" rev 2 */
- case 0x1183: /* iBook G4 12" */
- buffer[0] = (buffer[0] & 0x8f) | 0x70;
- buffer[2] = (buffer[2] & 0x7f) | 0x00;
- buffer[5] = (buffer[5] & 0x80) | 0x31;
- buffer[6] = (buffer[6] & 0x40) | 0xb0;
- buffer[7] = (buffer[7] & 0x00) | (enable ? 0xc0 : 0xba);
- buffer[8] = (buffer[8] & 0x00) | 0x30;
- changed = 1;
- break;
- case 0x3142: /* AlBook 15" (ATI M10) */
- case 0x3143: /* AlBook 17" (ATI M10) */
- buffer[0] = (buffer[0] & 0xaf) | 0x50;
- buffer[2] = (buffer[2] & 0x7f) | 0x00;
- buffer[5] = (buffer[5] & 0x80) | 0x31;
- buffer[6] = (buffer[6] & 0x40) | 0xb0;
- buffer[7] = (buffer[7] & 0x00) | (enable ? 0xd0 : 0xc0);
- buffer[8] = (buffer[8] & 0x00) | 0x30;
- changed = 1;
- break;
- default:
- DBG("i2c-hwclock: Machine model not handled\n");
- break;
- }
- if (!changed) {
- pmac_low_i2c_close(ui2c);
- break;
- }
- printk(KERN_INFO "%sabling clock spreading on i2c clock chip\n",
- enable ? "En" : "Dis");
-
- pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub);
- rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9);
- DBG("write result: %d,", rc);
- pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
- rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
- DBG("read result: %d,", rc);
- if (rc != 0) {
- pmac_low_i2c_close(ui2c);
- break;
- }
- for (i=0; i<9; i++)
- DBG(" %02x", buffer[i]);
- pmac_low_i2c_close(ui2c);
- break;
- }
-}
-
-
static int
core99_sleep(void)
{
@@ -1909,6 +1822,8 @@ core99_wake_up(void)
return 0;
}
+#endif /* CONFIG_PM */
+
static long
core99_sleep_state(struct device_node *node, long param, long value)
{
@@ -1930,10 +1845,13 @@ core99_sleep_state(struct device_node *node, long param, long value)
if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
return -EPERM;
+#ifdef CONFIG_PM
if (value == 1)
return core99_sleep();
else if (value == 0)
return core99_wake_up();
+
+#endif /* CONFIG_PM */
return 0;
}
@@ -2057,7 +1975,9 @@ static struct feature_table_entry core99_features[] = {
{ PMAC_FTR_USB_ENABLE, core99_usb_enable },
{ PMAC_FTR_1394_ENABLE, core99_firewire_enable },
{ PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power },
+#ifdef CONFIG_PM
{ PMAC_FTR_SLEEP_STATE, core99_sleep_state },
+#endif
#ifdef CONFIG_SMP
{ PMAC_FTR_RESET_CPU, core99_reset_cpu },
#endif /* CONFIG_SMP */
@@ -2427,6 +2347,14 @@ static struct pmac_mb_def pmac_mb_defs[] = {
PMAC_TYPE_POWERMAC_G5_U3L, g5_features,
0,
},
+ { "PowerMac11,2", "PowerMac G5 Dual Core",
+ PMAC_TYPE_POWERMAC_G5_U3L, g5_features,
+ 0,
+ },
+ { "PowerMac12,1", "iMac G5 (iSight)",
+ PMAC_TYPE_POWERMAC_G5_U3L, g5_features,
+ 0,
+ },
{ "RackMac3,1", "XServe G5",
PMAC_TYPE_XSERVE_G5, g5_features,
0,
@@ -2539,6 +2467,11 @@ static int __init probe_motherboard(void)
pmac_mb.model_name = "Unknown K2-based";
pmac_mb.features = g5_features;
break;
+ case macio_shasta:
+ pmac_mb.model_id = PMAC_TYPE_UNKNOWN_SHASTA;
+ pmac_mb.model_name = "Unknown Shasta-based";
+ pmac_mb.features = g5_features;
+ break;
#endif /* CONFIG_POWER4 */
default:
return -ENODEV;
@@ -2607,6 +2540,8 @@ found:
*/
static void __init probe_uninorth(void)
{
+ u32 *addrp;
+ phys_addr_t address;
unsigned long actrl;
/* Locate core99 Uni-N */
@@ -2614,22 +2549,31 @@ static void __init probe_uninorth(void)
/* Locate G5 u3 */
if (uninorth_node == NULL) {
uninorth_node = of_find_node_by_name(NULL, "u3");
- uninorth_u3 = 1;
- }
- if (uninorth_node && uninorth_node->n_addrs > 0) {
- unsigned long address = uninorth_node->addrs[0].address;
- uninorth_base = ioremap(address, 0x40000);
- uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
- if (uninorth_u3)
- u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
- } else
- uninorth_node = NULL;
-
- if (!uninorth_node)
+ uninorth_maj = 3;
+ }
+ /* Locate G5 u4 */
+ if (uninorth_node == NULL) {
+ uninorth_node = of_find_node_by_name(NULL, "u4");
+ uninorth_maj = 4;
+ }
+ if (uninorth_node == NULL)
return;
- printk(KERN_INFO "Found %s memory controller & host bridge, revision: %d\n",
- uninorth_u3 ? "U3" : "UniNorth", uninorth_rev);
+ addrp = (u32 *)get_property(uninorth_node, "reg", NULL);
+ if (addrp == NULL)
+ return;
+ address = of_translate_address(uninorth_node, addrp);
+ if (address == 0)
+ return;
+ uninorth_base = ioremap(address, 0x40000);
+ uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
+ if (uninorth_maj == 3 || uninorth_maj == 4)
+ u3_ht_base = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
+
+ printk(KERN_INFO "Found %s memory controller & host bridge"
+ " @ 0x%08x revision: 0x%02x\n", uninorth_maj == 3 ? "U3" :
+ uninorth_maj == 4 ? "U4" : "UniNorth",
+ (unsigned int)address, uninorth_rev);
printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base);
/* Set the arbitrer QAck delay according to what Apple does
@@ -2637,7 +2581,8 @@ static void __init probe_uninorth(void)
if (uninorth_rev < 0x11) {
actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK;
actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 :
- UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
+ UNI_N_ARB_CTRL_QACK_DELAY) <<
+ UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
UN_OUT(UNI_N_ARB_CTRL, actrl);
}
@@ -2645,7 +2590,8 @@ static void __init probe_uninorth(void)
* revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI
* memory timeout
*/
- if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) || uninorth_rev == 0xc0)
+ if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) ||
+ uninorth_rev == 0xc0)
UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff);
}
@@ -2653,18 +2599,17 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
{
struct device_node* node;
int i;
- volatile u32 __iomem * base;
- u32* revp;
+ volatile u32 __iomem *base;
+ u32 *addrp, *revp;
+ phys_addr_t addr;
+ u64 size;
- node = find_devices(name);
- if (!node || !node->n_addrs)
- return;
- if (compat)
- do {
- if (device_is_compatible(node, compat))
- break;
- node = node->next;
- } while (node);
+ for (node = NULL; (node = of_find_node_by_name(node, name)) != NULL;) {
+ if (!compat)
+ break;
+ if (device_is_compatible(node, compat))
+ break;
+ }
if (!node)
return;
for(i=0; i<MAX_MACIO_CHIPS; i++) {
@@ -2673,22 +2618,38 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
if (macio_chips[i].of_node == node)
return;
}
+
if (i >= MAX_MACIO_CHIPS) {
printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n");
printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);
return;
}
- base = ioremap(node->addrs[0].address, node->addrs[0].size);
+ addrp = of_get_pci_address(node, 0, &size, NULL);
+ if (addrp == NULL) {
+ printk(KERN_ERR "pmac_feature: %s: can't find base !\n",
+ node->full_name);
+ return;
+ }
+ addr = of_translate_address(node, addrp);
+ if (addr == 0) {
+ printk(KERN_ERR "pmac_feature: %s, can't translate base !\n",
+ node->full_name);
+ return;
+ }
+ base = ioremap(addr, (unsigned long)size);
if (!base) {
- printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n");
+ printk(KERN_ERR "pmac_feature: %s, can't map mac-io chip !\n",
+ node->full_name);
return;
}
- if (type == macio_keylargo) {
+ if (type == macio_keylargo || type == macio_keylargo2) {
u32 *did = (u32 *)get_property(node, "device-id", NULL);
if (*did == 0x00000025)
type = macio_pangea;
if (*did == 0x0000003e)
type = macio_intrepid;
+ if (*did == 0x0000004f)
+ type = macio_shasta;
}
macio_chips[i].of_node = node;
macio_chips[i].type = type;
@@ -2787,7 +2748,8 @@ set_initial_features(void)
}
#ifdef CONFIG_POWER4
- if (macio_chips[0].type == macio_keylargo2) {
+ if (macio_chips[0].type == macio_keylargo2 ||
+ macio_chips[0].type == macio_shasta) {
#ifndef CONFIG_SMP
/* On SMP machines running UP, we have the second CPU eating
* bus cycles. We need to take it off the bus. This is done
@@ -2896,12 +2858,6 @@ set_initial_features(void)
MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
}
- /* Some machine models need the clock chip to be properly setup for
- * clock spreading now. This should be a platform function but we
- * don't do these at the moment
- */
- pmac_tweak_clock_spreading(1);
-
#endif /* CONFIG_POWER4 */
/* On all machines, switch modem & serial ports off */
@@ -2929,9 +2885,6 @@ pmac_feature_init(void)
return;
}
- /* Setup low-level i2c stuffs */
- pmac_init_low_i2c();
-
/* Probe machine type */
if (probe_motherboard())
printk(KERN_WARNING "Unknown PowerMac !\n");
@@ -2942,26 +2895,6 @@ pmac_feature_init(void)
set_initial_features();
}
-int __init pmac_feature_late_init(void)
-{
-#if 0
- struct device_node *np;
-
- /* Request some resources late */
- if (uninorth_node)
- request_OF_resource(uninorth_node, 0, NULL);
- np = find_devices("hammerhead");
- if (np)
- request_OF_resource(np, 0, NULL);
- np = find_devices("interrupt-controller");
- if (np)
- request_OF_resource(np, 0, NULL);
-#endif
- return 0;
-}
-
-device_initcall(pmac_feature_late_init);
-
#if 0
static void dump_HT_speeds(char *name, u32 cfg, u32 frq)
{
@@ -2984,9 +2917,9 @@ void __init pmac_check_ht_link(void)
u8 px_bus, px_devfn;
struct pci_controller *px_hose;
- (void)in_be32(u3_ht + U3_HT_LINK_COMMAND);
- ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG);
- ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ);
+ (void)in_be32(u3_ht_base + U3_HT_LINK_COMMAND);
+ ucfg = cfg = in_be32(u3_ht_base + U3_HT_LINK_CONFIG);
+ ufreq = freq = in_be32(u3_ht_base + U3_HT_LINK_FREQ);
dump_HT_speeds("U3 HyperTransport", cfg, freq);
pcix_node = of_find_compatible_node(NULL, "pci", "pci-x");
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index f3f39e8e337a..535c802b369f 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -1,22 +1,34 @@
/*
- * arch/ppc/platforms/pmac_low_i2c.c
+ * arch/powerpc/platforms/powermac/low_i2c.c
*
- * Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org)
+ * Copyright (C) 2003-2005 Ben. Herrenschmidt (benh@kernel.crashing.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * This file contains some low-level i2c access routines that
- * need to be used by various bits of the PowerMac platform code
- * at times where the real asynchronous & interrupt driven driver
- * cannot be used. The API borrows some semantics from the darwin
- * driver in order to ease the implementation of the platform
- * properties parser
+ * The linux i2c layer isn't completely suitable for our needs for various
+ * reasons ranging from too late initialisation to semantics not perfectly
+ * matching some requirements of the apple platform functions etc...
+ *
+ * This file thus provides a simple low level unified i2c interface for
+ * powermac that covers the various types of i2c busses used in Apple machines.
+ * For now, keywest, PMU and SMU, though we could add Cuda, or other bit
+ * banging busses found on older chipstes in earlier machines if we ever need
+ * one of them.
+ *
+ * The drivers in this file are synchronous/blocking. In addition, the
+ * keywest one is fairly slow due to the use of msleep instead of interrupts
+ * as the interrupt is currently used by i2c-keywest. In the long run, we
+ * might want to get rid of those high-level interfaces to linux i2c layer
+ * either completely (converting all drivers) or replacing them all with a
+ * single stub driver on top of this one. Once done, the interrupt will be
+ * available for our use.
*/
#undef DEBUG
+#undef DEBUG_LOW
#include <linux/config.h>
#include <linux/types.h>
@@ -25,66 +37,91 @@
#include <linux/module.h>
#include <linux/adb.h>
#include <linux/pmu.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/timer.h>
#include <asm/keylargo.h>
#include <asm/uninorth.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/machdep.h>
+#include <asm/smu.h>
+#include <asm/pmac_pfunc.h>
#include <asm/pmac_low_i2c.h>
-#define MAX_LOW_I2C_HOST 4
-
#ifdef DEBUG
#define DBG(x...) do {\
- printk(KERN_DEBUG "KW:" x); \
+ printk(KERN_DEBUG "low_i2c:" x); \
} while(0)
#else
#define DBG(x...)
#endif
-struct low_i2c_host;
-
-typedef int (*low_i2c_func_t)(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len);
+#ifdef DEBUG_LOW
+#define DBG_LOW(x...) do {\
+ printk(KERN_DEBUG "low_i2c:" x); \
+ } while(0)
+#else
+#define DBG_LOW(x...)
+#endif
-struct low_i2c_host
-{
- struct device_node *np; /* OF device node */
- struct semaphore mutex; /* Access mutex for use by i2c-keywest */
- low_i2c_func_t func; /* Access function */
- unsigned int is_open : 1; /* Poor man's access control */
- int mode; /* Current mode */
- int channel; /* Current channel */
- int num_channels; /* Number of channels */
- void __iomem *base; /* For keywest-i2c, base address */
- int bsteps; /* And register stepping */
- int speed; /* And speed */
-};
-static struct low_i2c_host low_i2c_hosts[MAX_LOW_I2C_HOST];
+static int pmac_i2c_force_poll = 1;
-/* No locking is necessary on allocation, we are running way before
- * anything can race with us
+/*
+ * A bus structure. Each bus in the system has such a structure associated.
*/
-static struct low_i2c_host *find_low_i2c_host(struct device_node *np)
+struct pmac_i2c_bus
{
- int i;
+ struct list_head link;
+ struct device_node *controller;
+ struct device_node *busnode;
+ int type;
+ int flags;
+ struct i2c_adapter *adapter;
+ void *hostdata;
+ int channel; /* some hosts have multiple */
+ int mode; /* current mode */
+ struct semaphore sem;
+ int opened;
+ int polled; /* open mode */
+ struct platform_device *platform_dev;
+
+ /* ops */
+ int (*open)(struct pmac_i2c_bus *bus);
+ void (*close)(struct pmac_i2c_bus *bus);
+ int (*xfer)(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+ u32 subaddr, u8 *data, int len);
+};
- for (i = 0; i < MAX_LOW_I2C_HOST; i++)
- if (low_i2c_hosts[i].np == np)
- return &low_i2c_hosts[i];
- return NULL;
-}
+static LIST_HEAD(pmac_i2c_busses);
/*
- *
- * i2c-keywest implementation (UniNorth, U2, U3, Keylargo's)
- *
+ * Keywest implementation
*/
-/*
- * Keywest i2c definitions borrowed from drivers/i2c/i2c-keywest.h,
- * should be moved somewhere in include/asm-ppc/
- */
+struct pmac_i2c_host_kw
+{
+ struct semaphore mutex; /* Access mutex for use by
+ * i2c-keywest */
+ void __iomem *base; /* register base address */
+ int bsteps; /* register stepping */
+ int speed; /* speed */
+ int irq;
+ u8 *data;
+ unsigned len;
+ int state;
+ int rw;
+ int polled;
+ int result;
+ struct completion complete;
+ spinlock_t lock;
+ struct timer_list timeout_timer;
+};
+
/* Register indices */
typedef enum {
reg_mode = 0,
@@ -97,6 +134,8 @@ typedef enum {
reg_data
} reg_t;
+/* The Tumbler audio equalizer can be really slow sometimes */
+#define KW_POLL_TIMEOUT (2*HZ)
/* Mode register */
#define KW_I2C_MODE_100KHZ 0x00
@@ -140,8 +179,9 @@ enum {
};
#define WRONG_STATE(name) do {\
- printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \
- name, __kw_state_names[state], isr); \
+ printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s " \
+ "(isr: %02x)\n", \
+ name, __kw_state_names[host->state], isr); \
} while(0)
static const char *__kw_state_names[] = {
@@ -153,120 +193,137 @@ static const char *__kw_state_names[] = {
"state_dead"
};
-static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg)
+static inline u8 __kw_read_reg(struct pmac_i2c_host_kw *host, reg_t reg)
{
return readb(host->base + (((unsigned int)reg) << host->bsteps));
}
-static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val)
+static inline void __kw_write_reg(struct pmac_i2c_host_kw *host,
+ reg_t reg, u8 val)
{
writeb(val, host->base + (((unsigned)reg) << host->bsteps));
(void)__kw_read_reg(host, reg_subaddr);
}
-#define kw_write_reg(reg, val) __kw_write_reg(host, reg, val)
-#define kw_read_reg(reg) __kw_read_reg(host, reg)
-
+#define kw_write_reg(reg, val) __kw_write_reg(host, reg, val)
+#define kw_read_reg(reg) __kw_read_reg(host, reg)
-/* Don't schedule, the g5 fan controller is too
- * timing sensitive
- */
-static u8 kw_wait_interrupt(struct low_i2c_host* host)
+static u8 kw_i2c_wait_interrupt(struct pmac_i2c_host_kw *host)
{
int i, j;
u8 isr;
- for (i = 0; i < 100000; i++) {
+ for (i = 0; i < 1000; i++) {
isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK;
if (isr != 0)
return isr;
/* This code is used with the timebase frozen, we cannot rely
- * on udelay ! For now, just use a bogus loop
+ * on udelay nor schedule when in polled mode !
+ * For now, just use a bogus loop....
*/
- for (j = 1; j < 10000; j++)
- mb();
+ if (host->polled) {
+ for (j = 1; j < 100000; j++)
+ mb();
+ } else
+ msleep(1);
}
return isr;
}
-static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr)
+static void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr)
{
u8 ack;
- DBG("kw_handle_interrupt(%s, isr: %x)\n", __kw_state_names[state], isr);
+ DBG_LOW("kw_handle_interrupt(%s, isr: %x)\n",
+ __kw_state_names[host->state], isr);
+
+ if (host->state == state_idle) {
+ printk(KERN_WARNING "low_i2c: Keywest got an out of state"
+ " interrupt, ignoring\n");
+ kw_write_reg(reg_isr, isr);
+ return;
+ }
if (isr == 0) {
- if (state != state_stop) {
- DBG("KW: Timeout !\n");
- *rc = -EIO;
+ if (host->state != state_stop) {
+ DBG_LOW("KW: Timeout !\n");
+ host->result = -EIO;
goto stop;
}
- if (state == state_stop) {
+ if (host->state == state_stop) {
ack = kw_read_reg(reg_status);
- if (!(ack & KW_I2C_STAT_BUSY)) {
- state = state_idle;
- kw_write_reg(reg_ier, 0x00);
- }
+ if (ack & KW_I2C_STAT_BUSY)
+ kw_write_reg(reg_status, 0);
+ host->state = state_idle;
+ kw_write_reg(reg_ier, 0x00);
+ if (!host->polled)
+ complete(&host->complete);
}
- return state;
+ return;
}
if (isr & KW_I2C_IRQ_ADDR) {
ack = kw_read_reg(reg_status);
- if (state != state_addr) {
+ if (host->state != state_addr) {
kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
WRONG_STATE("KW_I2C_IRQ_ADDR");
- *rc = -EIO;
+ host->result = -EIO;
goto stop;
}
- if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
- *rc = -ENODEV;
- DBG("KW: NAK on address\n");
- return state_stop;
+ if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
+ host->result = -ENODEV;
+ DBG_LOW("KW: NAK on address\n");
+ host->state = state_stop;
+ return;
} else {
- if (rw) {
- state = state_read;
- if (*len > 1)
- kw_write_reg(reg_control, KW_I2C_CTL_AAK);
+ if (host->len == 0) {
+ kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
+ goto stop;
+ }
+ if (host->rw) {
+ host->state = state_read;
+ if (host->len > 1)
+ kw_write_reg(reg_control,
+ KW_I2C_CTL_AAK);
} else {
- state = state_write;
- kw_write_reg(reg_data, **data);
- (*data)++; (*len)--;
+ host->state = state_write;
+ kw_write_reg(reg_data, *(host->data++));
+ host->len--;
}
}
kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
}
if (isr & KW_I2C_IRQ_DATA) {
- if (state == state_read) {
- **data = kw_read_reg(reg_data);
- (*data)++; (*len)--;
+ if (host->state == state_read) {
+ *(host->data++) = kw_read_reg(reg_data);
+ host->len--;
kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
- if ((*len) == 0)
- state = state_stop;
- else if ((*len) == 1)
+ if (host->len == 0)
+ host->state = state_stop;
+ else if (host->len == 1)
kw_write_reg(reg_control, 0);
- } else if (state == state_write) {
+ } else if (host->state == state_write) {
ack = kw_read_reg(reg_status);
if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
- DBG("KW: nack on data write\n");
- *rc = -EIO;
+ DBG_LOW("KW: nack on data write\n");
+ host->result = -EIO;
goto stop;
- } else if (*len) {
- kw_write_reg(reg_data, **data);
- (*data)++; (*len)--;
+ } else if (host->len) {
+ kw_write_reg(reg_data, *(host->data++));
+ host->len--;
} else {
kw_write_reg(reg_control, KW_I2C_CTL_STOP);
- state = state_stop;
- *rc = 0;
+ host->state = state_stop;
+ host->result = 0;
}
kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
} else {
kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
WRONG_STATE("KW_I2C_IRQ_DATA");
- if (state != state_stop) {
- *rc = -EIO;
+ if (host->state != state_stop) {
+ host->result = -EIO;
goto stop;
}
}
@@ -274,98 +331,194 @@ static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int
if (isr & KW_I2C_IRQ_STOP) {
kw_write_reg(reg_isr, KW_I2C_IRQ_STOP);
- if (state != state_stop) {
+ if (host->state != state_stop) {
WRONG_STATE("KW_I2C_IRQ_STOP");
- *rc = -EIO;
+ host->result = -EIO;
}
- return state_idle;
+ host->state = state_idle;
+ if (!host->polled)
+ complete(&host->complete);
}
if (isr & KW_I2C_IRQ_START)
kw_write_reg(reg_isr, KW_I2C_IRQ_START);
- return state;
-
+ return;
stop:
kw_write_reg(reg_control, KW_I2C_CTL_STOP);
- return state_stop;
+ host->state = state_stop;
+ return;
}
-static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, u8 *data, int len)
+/* Interrupt handler */
+static irqreturn_t kw_i2c_irq(int irq, void *dev_id, struct pt_regs *regs)
{
+ struct pmac_i2c_host_kw *host = dev_id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ del_timer(&host->timeout_timer);
+ kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr));
+ if (host->state != state_idle) {
+ host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
+ add_timer(&host->timeout_timer);
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static void kw_i2c_timeout(unsigned long data)
+{
+ struct pmac_i2c_host_kw *host = (struct pmac_i2c_host_kw *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr));
+ if (host->state != state_idle) {
+ host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
+ add_timer(&host->timeout_timer);
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static int kw_i2c_open(struct pmac_i2c_bus *bus)
+{
+ struct pmac_i2c_host_kw *host = bus->hostdata;
+ down(&host->mutex);
+ return 0;
+}
+
+static void kw_i2c_close(struct pmac_i2c_bus *bus)
+{
+ struct pmac_i2c_host_kw *host = bus->hostdata;
+ up(&host->mutex);
+}
+
+static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+ u32 subaddr, u8 *data, int len)
+{
+ struct pmac_i2c_host_kw *host = bus->hostdata;
u8 mode_reg = host->speed;
- int state = state_addr;
- int rc = 0;
+ int use_irq = host->irq != NO_IRQ && !bus->polled;
/* Setup mode & subaddress if any */
- switch(host->mode) {
- case pmac_low_i2c_mode_dumb:
- printk(KERN_ERR "low_i2c: Dumb mode not supported !\n");
+ switch(bus->mode) {
+ case pmac_i2c_mode_dumb:
return -EINVAL;
- case pmac_low_i2c_mode_std:
+ case pmac_i2c_mode_std:
mode_reg |= KW_I2C_MODE_STANDARD;
+ if (subsize != 0)
+ return -EINVAL;
break;
- case pmac_low_i2c_mode_stdsub:
+ case pmac_i2c_mode_stdsub:
mode_reg |= KW_I2C_MODE_STANDARDSUB;
+ if (subsize != 1)
+ return -EINVAL;
break;
- case pmac_low_i2c_mode_combined:
+ case pmac_i2c_mode_combined:
mode_reg |= KW_I2C_MODE_COMBINED;
+ if (subsize != 1)
+ return -EINVAL;
break;
}
/* Setup channel & clear pending irqs */
kw_write_reg(reg_isr, kw_read_reg(reg_isr));
- kw_write_reg(reg_mode, mode_reg | (host->channel << 4));
+ kw_write_reg(reg_mode, mode_reg | (bus->channel << 4));
kw_write_reg(reg_status, 0);
- /* Set up address and r/w bit */
- kw_write_reg(reg_addr, addr);
+ /* Set up address and r/w bit, strip possible stale bus number from
+ * address top bits
+ */
+ kw_write_reg(reg_addr, addrdir & 0xff);
/* Set up the sub address */
if ((mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB
|| (mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED)
kw_write_reg(reg_subaddr, subaddr);
- /* Start sending address & disable interrupt*/
- kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/);
+ /* Prepare for async operations */
+ host->data = data;
+ host->len = len;
+ host->state = state_addr;
+ host->result = 0;
+ host->rw = (addrdir & 1);
+ host->polled = bus->polled;
+
+ /* Enable interrupt if not using polled mode and interrupt is
+ * available
+ */
+ if (use_irq) {
+ /* Clear completion */
+ INIT_COMPLETION(host->complete);
+ /* Ack stale interrupts */
+ kw_write_reg(reg_isr, kw_read_reg(reg_isr));
+ /* Arm timeout */
+ host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
+ add_timer(&host->timeout_timer);
+ /* Enable emission */
+ kw_write_reg(reg_ier, KW_I2C_IRQ_MASK);
+ }
+
+ /* Start sending address */
kw_write_reg(reg_control, KW_I2C_CTL_XADDR);
- /* State machine, to turn into an interrupt handler */
- while(state != state_idle) {
- u8 isr = kw_wait_interrupt(host);
- state = kw_handle_interrupt(host, state, addr & 1, &rc, &data, &len, isr);
+ /* Wait for completion */
+ if (use_irq)
+ wait_for_completion(&host->complete);
+ else {
+ while(host->state != state_idle) {
+ unsigned long flags;
+
+ u8 isr = kw_i2c_wait_interrupt(host);
+ spin_lock_irqsave(&host->lock, flags);
+ kw_i2c_handle_interrupt(host, isr);
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
}
- return rc;
+ /* Disable emission */
+ kw_write_reg(reg_ier, 0);
+
+ return host->result;
}
-static void keywest_low_i2c_add(struct device_node *np)
+static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
{
- struct low_i2c_host *host = find_low_i2c_host(NULL);
- u32 *psteps, *prate, steps, aoffset = 0;
- struct device_node *parent;
+ struct pmac_i2c_host_kw *host;
+ u32 *psteps, *prate, *addrp, steps;
+ host = kzalloc(sizeof(struct pmac_i2c_host_kw), GFP_KERNEL);
if (host == NULL) {
printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
np->full_name);
- return;
+ return NULL;
}
- memset(host, 0, sizeof(*host));
+ /* Apple is kind enough to provide a valid AAPL,address property
+ * on all i2c keywest nodes so far ... we would have to fallback
+ * to macio parsing if that wasn't the case
+ */
+ addrp = (u32 *)get_property(np, "AAPL,address", NULL);
+ if (addrp == NULL) {
+ printk(KERN_ERR "low_i2c: Can't find address for %s\n",
+ np->full_name);
+ kfree(host);
+ return NULL;
+ }
init_MUTEX(&host->mutex);
- host->np = of_node_get(np);
+ init_completion(&host->complete);
+ spin_lock_init(&host->lock);
+ init_timer(&host->timeout_timer);
+ host->timeout_timer.function = kw_i2c_timeout;
+ host->timeout_timer.data = (unsigned long)host;
+
psteps = (u32 *)get_property(np, "AAPL,address-step", NULL);
steps = psteps ? (*psteps) : 0x10;
for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++)
steps >>= 1;
- parent = of_get_parent(np);
- host->num_channels = 1;
- if (parent && parent->name[0] == 'u') {
- host->num_channels = 2;
- aoffset = 3;
- }
/* Select interface rate */
- host->speed = KW_I2C_MODE_100KHZ;
+ host->speed = KW_I2C_MODE_25KHZ;
prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL);
if (prate) switch(*prate) {
case 100:
@@ -378,146 +531,981 @@ static void keywest_low_i2c_add(struct device_node *np)
host->speed = KW_I2C_MODE_25KHZ;
break;
}
+ if (np->n_intrs > 0)
+ host->irq = np->intrs[0].line;
+ else
+ host->irq = NO_IRQ;
+
+ host->base = ioremap((*addrp), 0x1000);
+ if (host->base == NULL) {
+ printk(KERN_ERR "low_i2c: Can't map registers for %s\n",
+ np->full_name);
+ kfree(host);
+ return NULL;
+ }
+
+ /* Make sure IRA is disabled */
+ kw_write_reg(reg_ier, 0);
+
+ /* Request chip interrupt */
+ if (request_irq(host->irq, kw_i2c_irq, SA_SHIRQ, "keywest i2c", host))
+ host->irq = NO_IRQ;
+
+ printk(KERN_INFO "KeyWest i2c @0x%08x irq %d %s\n",
+ *addrp, host->irq, np->full_name);
- host->mode = pmac_low_i2c_mode_std;
- host->base = ioremap(np->addrs[0].address + aoffset,
- np->addrs[0].size);
- host->func = keywest_low_i2c_func;
+ return host;
}
+
+static void __init kw_i2c_add(struct pmac_i2c_host_kw *host,
+ struct device_node *controller,
+ struct device_node *busnode,
+ int channel)
+{
+ struct pmac_i2c_bus *bus;
+
+ bus = kzalloc(sizeof(struct pmac_i2c_bus), GFP_KERNEL);
+ if (bus == NULL)
+ return;
+
+ bus->controller = of_node_get(controller);
+ bus->busnode = of_node_get(busnode);
+ bus->type = pmac_i2c_bus_keywest;
+ bus->hostdata = host;
+ bus->channel = channel;
+ bus->mode = pmac_i2c_mode_std;
+ bus->open = kw_i2c_open;
+ bus->close = kw_i2c_close;
+ bus->xfer = kw_i2c_xfer;
+ init_MUTEX(&bus->sem);
+ if (controller == busnode)
+ bus->flags = pmac_i2c_multibus;
+ list_add(&bus->link, &pmac_i2c_busses);
+
+ printk(KERN_INFO " channel %d bus %s\n", channel,
+ (controller == busnode) ? "<multibus>" : busnode->full_name);
+}
+
+static void __init kw_i2c_probe(void)
+{
+ struct device_node *np, *child, *parent;
+
+ /* Probe keywest-i2c busses */
+ for (np = NULL;
+ (np = of_find_compatible_node(np, "i2c","keywest-i2c")) != NULL;){
+ struct pmac_i2c_host_kw *host;
+ int multibus, chans, i;
+
+ /* Found one, init a host structure */
+ host = kw_i2c_host_init(np);
+ if (host == NULL)
+ continue;
+
+ /* Now check if we have a multibus setup (old style) or if we
+ * have proper bus nodes. Note that the "new" way (proper bus
+ * nodes) might cause us to not create some busses that are
+ * kept hidden in the device-tree. In the future, we might
+ * want to work around that by creating busses without a node
+ * but not for now
+ */
+ child = of_get_next_child(np, NULL);
+ multibus = !child || strcmp(child->name, "i2c-bus");
+ of_node_put(child);
+
+ /* For a multibus setup, we get the bus count based on the
+ * parent type
+ */
+ if (multibus) {
+ parent = of_get_parent(np);
+ if (parent == NULL)
+ continue;
+ chans = parent->name[0] == 'u' ? 2 : 1;
+ for (i = 0; i < chans; i++)
+ kw_i2c_add(host, np, np, i);
+ } else {
+ for (child = NULL;
+ (child = of_get_next_child(np, child)) != NULL;) {
+ u32 *reg =
+ (u32 *)get_property(child, "reg", NULL);
+ if (reg == NULL)
+ continue;
+ kw_i2c_add(host, np, child, *reg);
+ }
+ }
+ }
+}
+
+
/*
*
* PMU implementation
*
*/
-
#ifdef CONFIG_ADB_PMU
-static int pmu_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len)
+/*
+ * i2c command block to the PMU
+ */
+struct pmu_i2c_hdr {
+ u8 bus;
+ u8 mode;
+ u8 bus2;
+ u8 address;
+ u8 sub_addr;
+ u8 comb_addr;
+ u8 count;
+ u8 data[];
+};
+
+static void pmu_i2c_complete(struct adb_request *req)
{
- // TODO
- return -ENODEV;
+ complete(req->arg);
}
-static void pmu_low_i2c_add(struct device_node *np)
+static int pmu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+ u32 subaddr, u8 *data, int len)
{
- struct low_i2c_host *host = find_low_i2c_host(NULL);
+ struct adb_request *req = bus->hostdata;
+ struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req->data[1];
+ struct completion comp;
+ int read = addrdir & 1;
+ int retry;
+ int rc = 0;
- if (host == NULL) {
- printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
- np->full_name);
- return;
+ /* For now, limit ourselves to 16 bytes transfers */
+ if (len > 16)
+ return -EINVAL;
+
+ init_completion(&comp);
+
+ for (retry = 0; retry < 16; retry++) {
+ memset(req, 0, sizeof(struct adb_request));
+ hdr->bus = bus->channel;
+ hdr->count = len;
+
+ switch(bus->mode) {
+ case pmac_i2c_mode_std:
+ if (subsize != 0)
+ return -EINVAL;
+ hdr->address = addrdir;
+ hdr->mode = PMU_I2C_MODE_SIMPLE;
+ break;
+ case pmac_i2c_mode_stdsub:
+ case pmac_i2c_mode_combined:
+ if (subsize != 1)
+ return -EINVAL;
+ hdr->address = addrdir & 0xfe;
+ hdr->comb_addr = addrdir;
+ hdr->sub_addr = subaddr;
+ if (bus->mode == pmac_i2c_mode_stdsub)
+ hdr->mode = PMU_I2C_MODE_STDSUB;
+ else
+ hdr->mode = PMU_I2C_MODE_COMBINED;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ INIT_COMPLETION(comp);
+ req->data[0] = PMU_I2C_CMD;
+ req->reply[0] = 0xff;
+ req->nbytes = sizeof(struct pmu_i2c_hdr) + 1;
+ req->done = pmu_i2c_complete;
+ req->arg = &comp;
+ if (!read && len) {
+ memcpy(hdr->data, data, len);
+ req->nbytes += len;
+ }
+ rc = pmu_queue_request(req);
+ if (rc)
+ return rc;
+ wait_for_completion(&comp);
+ if (req->reply[0] == PMU_I2C_STATUS_OK)
+ break;
+ msleep(15);
}
- memset(host, 0, sizeof(*host));
+ if (req->reply[0] != PMU_I2C_STATUS_OK)
+ return -EIO;
- init_MUTEX(&host->mutex);
- host->np = of_node_get(np);
- host->num_channels = 3;
- host->mode = pmac_low_i2c_mode_std;
- host->func = pmu_low_i2c_func;
+ for (retry = 0; retry < 16; retry++) {
+ memset(req, 0, sizeof(struct adb_request));
+
+ /* I know that looks like a lot, slow as hell, but darwin
+ * does it so let's be on the safe side for now
+ */
+ msleep(15);
+
+ hdr->bus = PMU_I2C_BUS_STATUS;
+
+ INIT_COMPLETION(comp);
+ req->data[0] = PMU_I2C_CMD;
+ req->reply[0] = 0xff;
+ req->nbytes = 2;
+ req->done = pmu_i2c_complete;
+ req->arg = &comp;
+ rc = pmu_queue_request(req);
+ if (rc)
+ return rc;
+ wait_for_completion(&comp);
+
+ if (req->reply[0] == PMU_I2C_STATUS_OK && !read)
+ return 0;
+ if (req->reply[0] == PMU_I2C_STATUS_DATAREAD && read) {
+ int rlen = req->reply_len - 1;
+
+ if (rlen != len) {
+ printk(KERN_WARNING "low_i2c: PMU returned %d"
+ " bytes, expected %d !\n", rlen, len);
+ return -EIO;
+ }
+ if (len)
+ memcpy(data, &req->reply[1], len);
+ return 0;
+ }
+ }
+ return -EIO;
+}
+
+static void __init pmu_i2c_probe(void)
+{
+ struct pmac_i2c_bus *bus;
+ struct device_node *busnode;
+ int channel, sz;
+
+ if (!pmu_present())
+ return;
+
+ /* There might or might not be a "pmu-i2c" node, we use that
+ * or via-pmu itself, whatever we find. I haven't seen a machine
+ * with separate bus nodes, so we assume a multibus setup
+ */
+ busnode = of_find_node_by_name(NULL, "pmu-i2c");
+ if (busnode == NULL)
+ busnode = of_find_node_by_name(NULL, "via-pmu");
+ if (busnode == NULL)
+ return;
+
+ printk(KERN_INFO "PMU i2c %s\n", busnode->full_name);
+
+ /*
+ * We add bus 1 and 2 only for now, bus 0 is "special"
+ */
+ for (channel = 1; channel <= 2; channel++) {
+ sz = sizeof(struct pmac_i2c_bus) + sizeof(struct adb_request);
+ bus = kzalloc(sz, GFP_KERNEL);
+ if (bus == NULL)
+ return;
+
+ bus->controller = busnode;
+ bus->busnode = busnode;
+ bus->type = pmac_i2c_bus_pmu;
+ bus->channel = channel;
+ bus->mode = pmac_i2c_mode_std;
+ bus->hostdata = bus + 1;
+ bus->xfer = pmu_i2c_xfer;
+ init_MUTEX(&bus->sem);
+ bus->flags = pmac_i2c_multibus;
+ list_add(&bus->link, &pmac_i2c_busses);
+
+ printk(KERN_INFO " channel %d bus <multibus>\n", channel);
+ }
}
#endif /* CONFIG_ADB_PMU */
-void __init pmac_init_low_i2c(void)
+
+/*
+ *
+ * SMU implementation
+ *
+ */
+
+#ifdef CONFIG_PMAC_SMU
+
+static void smu_i2c_complete(struct smu_i2c_cmd *cmd, void *misc)
{
- struct device_node *np;
+ complete(misc);
+}
- /* Probe keywest-i2c busses */
- np = of_find_compatible_node(NULL, "i2c", "keywest-i2c");
- while(np) {
- keywest_low_i2c_add(np);
- np = of_find_compatible_node(np, "i2c", "keywest-i2c");
+static int smu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+ u32 subaddr, u8 *data, int len)
+{
+ struct smu_i2c_cmd *cmd = bus->hostdata;
+ struct completion comp;
+ int read = addrdir & 1;
+ int rc = 0;
+
+ if ((read && len > SMU_I2C_READ_MAX) ||
+ ((!read) && len > SMU_I2C_WRITE_MAX))
+ return -EINVAL;
+
+ memset(cmd, 0, sizeof(struct smu_i2c_cmd));
+ cmd->info.bus = bus->channel;
+ cmd->info.devaddr = addrdir;
+ cmd->info.datalen = len;
+
+ switch(bus->mode) {
+ case pmac_i2c_mode_std:
+ if (subsize != 0)
+ return -EINVAL;
+ cmd->info.type = SMU_I2C_TRANSFER_SIMPLE;
+ break;
+ case pmac_i2c_mode_stdsub:
+ case pmac_i2c_mode_combined:
+ if (subsize > 3 || subsize < 1)
+ return -EINVAL;
+ cmd->info.sublen = subsize;
+ /* that's big-endian only but heh ! */
+ memcpy(&cmd->info.subaddr, ((char *)&subaddr) + (4 - subsize),
+ subsize);
+ if (bus->mode == pmac_i2c_mode_stdsub)
+ cmd->info.type = SMU_I2C_TRANSFER_STDSUB;
+ else
+ cmd->info.type = SMU_I2C_TRANSFER_COMBINED;
+ break;
+ default:
+ return -EINVAL;
}
+ if (!read && len)
+ memcpy(cmd->info.data, data, len);
+
+ init_completion(&comp);
+ cmd->done = smu_i2c_complete;
+ cmd->misc = &comp;
+ rc = smu_queue_i2c(cmd);
+ if (rc < 0)
+ return rc;
+ wait_for_completion(&comp);
+ rc = cmd->status;
+
+ if (read && len)
+ memcpy(data, cmd->info.data, len);
+ return rc < 0 ? rc : 0;
+}
+
+static void __init smu_i2c_probe(void)
+{
+ struct device_node *controller, *busnode;
+ struct pmac_i2c_bus *bus;
+ u32 *reg;
+ int sz;
+
+ if (!smu_present())
+ return;
+
+ controller = of_find_node_by_name(NULL, "smu-i2c-control");
+ if (controller == NULL)
+ controller = of_find_node_by_name(NULL, "smu");
+ if (controller == NULL)
+ return;
+
+ printk(KERN_INFO "SMU i2c %s\n", controller->full_name);
+
+ /* Look for childs, note that they might not be of the right
+ * type as older device trees mix i2c busses and other thigns
+ * at the same level
+ */
+ for (busnode = NULL;
+ (busnode = of_get_next_child(controller, busnode)) != NULL;) {
+ if (strcmp(busnode->type, "i2c") &&
+ strcmp(busnode->type, "i2c-bus"))
+ continue;
+ reg = (u32 *)get_property(busnode, "reg", NULL);
+ if (reg == NULL)
+ continue;
+
+ sz = sizeof(struct pmac_i2c_bus) + sizeof(struct smu_i2c_cmd);
+ bus = kzalloc(sz, GFP_KERNEL);
+ if (bus == NULL)
+ return;
+
+ bus->controller = controller;
+ bus->busnode = of_node_get(busnode);
+ bus->type = pmac_i2c_bus_smu;
+ bus->channel = *reg;
+ bus->mode = pmac_i2c_mode_std;
+ bus->hostdata = bus + 1;
+ bus->xfer = smu_i2c_xfer;
+ init_MUTEX(&bus->sem);
+ bus->flags = 0;
+ list_add(&bus->link, &pmac_i2c_busses);
+
+ printk(KERN_INFO " channel %x bus %s\n",
+ bus->channel, busnode->full_name);
+ }
+}
+
+#endif /* CONFIG_PMAC_SMU */
+
+/*
+ *
+ * Core code
+ *
+ */
-#ifdef CONFIG_ADB_PMU
- /* Probe PMU busses */
- np = of_find_node_by_name(NULL, "via-pmu");
- if (np)
- pmu_low_i2c_add(np);
-#endif /* CONFIG_ADB_PMU */
- /* TODO: Add CUDA support as well */
+struct pmac_i2c_bus *pmac_i2c_find_bus(struct device_node *node)
+{
+ struct device_node *p = of_node_get(node);
+ struct device_node *prev = NULL;
+ struct pmac_i2c_bus *bus;
+
+ while(p) {
+ list_for_each_entry(bus, &pmac_i2c_busses, link) {
+ if (p == bus->busnode) {
+ if (prev && bus->flags & pmac_i2c_multibus) {
+ u32 *reg;
+ reg = (u32 *)get_property(prev, "reg",
+ NULL);
+ if (!reg)
+ continue;
+ if (((*reg) >> 8) != bus->channel)
+ continue;
+ }
+ of_node_put(p);
+ of_node_put(prev);
+ return bus;
+ }
+ }
+ of_node_put(prev);
+ prev = p;
+ p = of_get_parent(p);
+ }
+ return NULL;
}
+EXPORT_SYMBOL_GPL(pmac_i2c_find_bus);
+
+u8 pmac_i2c_get_dev_addr(struct device_node *device)
+{
+ u32 *reg = (u32 *)get_property(device, "reg", NULL);
+
+ if (reg == NULL)
+ return 0;
+
+ return (*reg) & 0xff;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_dev_addr);
+
+struct device_node *pmac_i2c_get_controller(struct pmac_i2c_bus *bus)
+{
+ return bus->controller;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_controller);
+
+struct device_node *pmac_i2c_get_bus_node(struct pmac_i2c_bus *bus)
+{
+ return bus->busnode;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_bus_node);
+
+int pmac_i2c_get_type(struct pmac_i2c_bus *bus)
+{
+ return bus->type;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_type);
+
+int pmac_i2c_get_flags(struct pmac_i2c_bus *bus)
+{
+ return bus->flags;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_flags);
+
+int pmac_i2c_get_channel(struct pmac_i2c_bus *bus)
+{
+ return bus->channel;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_channel);
+
+
+void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus,
+ struct i2c_adapter *adapter)
+{
+ WARN_ON(bus->adapter != NULL);
+ bus->adapter = adapter;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_attach_adapter);
+
+void pmac_i2c_detach_adapter(struct pmac_i2c_bus *bus,
+ struct i2c_adapter *adapter)
+{
+ WARN_ON(bus->adapter != adapter);
+ bus->adapter = NULL;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_detach_adapter);
+
+struct i2c_adapter *pmac_i2c_get_adapter(struct pmac_i2c_bus *bus)
+{
+ return bus->adapter;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_adapter);
+
+struct pmac_i2c_bus *pmac_i2c_adapter_to_bus(struct i2c_adapter *adapter)
+{
+ struct pmac_i2c_bus *bus;
+
+ list_for_each_entry(bus, &pmac_i2c_busses, link)
+ if (bus->adapter == adapter)
+ return bus;
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_adapter_to_bus);
+
+extern int pmac_i2c_match_adapter(struct device_node *dev,
+ struct i2c_adapter *adapter)
+{
+ struct pmac_i2c_bus *bus = pmac_i2c_find_bus(dev);
+
+ if (bus == NULL)
+ return 0;
+ return (bus->adapter == adapter);
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_match_adapter);
int pmac_low_i2c_lock(struct device_node *np)
{
- struct low_i2c_host *host = find_low_i2c_host(np);
+ struct pmac_i2c_bus *bus, *found = NULL;
- if (!host)
+ list_for_each_entry(bus, &pmac_i2c_busses, link) {
+ if (np == bus->controller) {
+ found = bus;
+ break;
+ }
+ }
+ if (!found)
return -ENODEV;
- down(&host->mutex);
- return 0;
+ return pmac_i2c_open(bus, 0);
}
-EXPORT_SYMBOL(pmac_low_i2c_lock);
+EXPORT_SYMBOL_GPL(pmac_low_i2c_lock);
int pmac_low_i2c_unlock(struct device_node *np)
{
- struct low_i2c_host *host = find_low_i2c_host(np);
+ struct pmac_i2c_bus *bus, *found = NULL;
- if (!host)
+ list_for_each_entry(bus, &pmac_i2c_busses, link) {
+ if (np == bus->controller) {
+ found = bus;
+ break;
+ }
+ }
+ if (!found)
return -ENODEV;
- up(&host->mutex);
+ pmac_i2c_close(bus);
return 0;
}
-EXPORT_SYMBOL(pmac_low_i2c_unlock);
+EXPORT_SYMBOL_GPL(pmac_low_i2c_unlock);
-int pmac_low_i2c_open(struct device_node *np, int channel)
+int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled)
{
- struct low_i2c_host *host = find_low_i2c_host(np);
+ int rc;
+
+ down(&bus->sem);
+ bus->polled = polled || pmac_i2c_force_poll;
+ bus->opened = 1;
+ bus->mode = pmac_i2c_mode_std;
+ if (bus->open && (rc = bus->open(bus)) != 0) {
+ bus->opened = 0;
+ up(&bus->sem);
+ return rc;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_open);
- if (!host)
- return -ENODEV;
+void pmac_i2c_close(struct pmac_i2c_bus *bus)
+{
+ WARN_ON(!bus->opened);
+ if (bus->close)
+ bus->close(bus);
+ bus->opened = 0;
+ up(&bus->sem);
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_close);
- if (channel >= host->num_channels)
+int pmac_i2c_setmode(struct pmac_i2c_bus *bus, int mode)
+{
+ WARN_ON(!bus->opened);
+
+ /* Report me if you see the error below as there might be a new
+ * "combined4" mode that I need to implement for the SMU bus
+ */
+ if (mode < pmac_i2c_mode_dumb || mode > pmac_i2c_mode_combined) {
+ printk(KERN_ERR "low_i2c: Invalid mode %d requested on"
+ " bus %s !\n", mode, bus->busnode->full_name);
return -EINVAL;
-
- down(&host->mutex);
- host->is_open = 1;
- host->channel = channel;
+ }
+ bus->mode = mode;
return 0;
}
-EXPORT_SYMBOL(pmac_low_i2c_open);
+EXPORT_SYMBOL_GPL(pmac_i2c_setmode);
-int pmac_low_i2c_close(struct device_node *np)
+int pmac_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+ u32 subaddr, u8 *data, int len)
{
- struct low_i2c_host *host = find_low_i2c_host(np);
+ int rc;
- if (!host)
- return -ENODEV;
+ WARN_ON(!bus->opened);
- host->is_open = 0;
- up(&host->mutex);
+ DBG("xfer() chan=%d, addrdir=0x%x, mode=%d, subsize=%d, subaddr=0x%x,"
+ " %d bytes, bus %s\n", bus->channel, addrdir, bus->mode, subsize,
+ subaddr, len, bus->busnode->full_name);
- return 0;
+ rc = bus->xfer(bus, addrdir, subsize, subaddr, data, len);
+
+#ifdef DEBUG
+ if (rc)
+ DBG("xfer error %d\n", rc);
+#endif
+ return rc;
}
-EXPORT_SYMBOL(pmac_low_i2c_close);
+EXPORT_SYMBOL_GPL(pmac_i2c_xfer);
+
+/* some quirks for platform function decoding */
+enum {
+ pmac_i2c_quirk_invmask = 0x00000001u,
+};
-int pmac_low_i2c_setmode(struct device_node *np, int mode)
+static void pmac_i2c_devscan(void (*callback)(struct device_node *dev,
+ int quirks))
{
- struct low_i2c_host *host = find_low_i2c_host(np);
+ struct pmac_i2c_bus *bus;
+ struct device_node *np;
+ static struct whitelist_ent {
+ char *name;
+ char *compatible;
+ int quirks;
+ } whitelist[] = {
+ /* XXX Study device-tree's & apple drivers are get the quirks
+ * right !
+ */
+ { "i2c-hwclock", NULL, pmac_i2c_quirk_invmask },
+ { "i2c-cpu-voltage", NULL, 0},
+ { "temp-monitor", NULL, 0 },
+ { "supply-monitor", NULL, 0 },
+ { NULL, NULL, 0 },
+ };
+
+ /* Only some devices need to have platform functions instanciated
+ * here. For now, we have a table. Others, like 9554 i2c GPIOs used
+ * on Xserve, if we ever do a driver for them, will use their own
+ * platform function instance
+ */
+ list_for_each_entry(bus, &pmac_i2c_busses, link) {
+ for (np = NULL;
+ (np = of_get_next_child(bus->busnode, np)) != NULL;) {
+ struct whitelist_ent *p;
+ /* If multibus, check if device is on that bus */
+ if (bus->flags & pmac_i2c_multibus)
+ if (bus != pmac_i2c_find_bus(np))
+ continue;
+ for (p = whitelist; p->name != NULL; p++) {
+ if (strcmp(np->name, p->name))
+ continue;
+ if (p->compatible &&
+ !device_is_compatible(np, p->compatible))
+ continue;
+ callback(np, p->quirks);
+ break;
+ }
+ }
+ }
+}
- if (!host)
- return -ENODEV;
- WARN_ON(!host->is_open);
- host->mode = mode;
+#define MAX_I2C_DATA 64
+
+struct pmac_i2c_pf_inst
+{
+ struct pmac_i2c_bus *bus;
+ u8 addr;
+ u8 buffer[MAX_I2C_DATA];
+ u8 scratch[MAX_I2C_DATA];
+ int bytes;
+ int quirks;
+};
+
+static void* pmac_i2c_do_begin(struct pmf_function *func, struct pmf_args *args)
+{
+ struct pmac_i2c_pf_inst *inst;
+ struct pmac_i2c_bus *bus;
+
+ bus = pmac_i2c_find_bus(func->node);
+ if (bus == NULL) {
+ printk(KERN_ERR "low_i2c: Can't find bus for %s (pfunc)\n",
+ func->node->full_name);
+ return NULL;
+ }
+ if (pmac_i2c_open(bus, 0)) {
+ printk(KERN_ERR "low_i2c: Can't open i2c bus for %s (pfunc)\n",
+ func->node->full_name);
+ return NULL;
+ }
+
+ /* XXX might need GFP_ATOMIC when called during the suspend process,
+ * but then, there are already lots of issues with suspending when
+ * near OOM that need to be resolved, the allocator itself should
+ * probably make GFP_NOIO implicit during suspend
+ */
+ inst = kzalloc(sizeof(struct pmac_i2c_pf_inst), GFP_KERNEL);
+ if (inst == NULL) {
+ pmac_i2c_close(bus);
+ return NULL;
+ }
+ inst->bus = bus;
+ inst->addr = pmac_i2c_get_dev_addr(func->node);
+ inst->quirks = (int)(long)func->driver_data;
+ return inst;
+}
+
+static void pmac_i2c_do_end(struct pmf_function *func, void *instdata)
+{
+ struct pmac_i2c_pf_inst *inst = instdata;
+
+ if (inst == NULL)
+ return;
+ pmac_i2c_close(inst->bus);
+ if (inst)
+ kfree(inst);
+}
+
+static int pmac_i2c_do_read(PMF_STD_ARGS, u32 len)
+{
+ struct pmac_i2c_pf_inst *inst = instdata;
+
+ inst->bytes = len;
+ return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_read, 0, 0,
+ inst->buffer, len);
+}
+
+static int pmac_i2c_do_write(PMF_STD_ARGS, u32 len, const u8 *data)
+{
+ struct pmac_i2c_pf_inst *inst = instdata;
+
+ return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 0, 0,
+ (u8 *)data, len);
+}
+
+/* This function is used to do the masking & OR'ing for the "rmw" type
+ * callbacks. Ze should apply the mask and OR in the values in the
+ * buffer before writing back. The problem is that it seems that
+ * various darwin drivers implement the mask/or differently, thus
+ * we need to check the quirks first
+ */
+static void pmac_i2c_do_apply_rmw(struct pmac_i2c_pf_inst *inst,
+ u32 len, const u8 *mask, const u8 *val)
+{
+ int i;
+
+ if (inst->quirks & pmac_i2c_quirk_invmask) {
+ for (i = 0; i < len; i ++)
+ inst->scratch[i] = (inst->buffer[i] & mask[i]) | val[i];
+ } else {
+ for (i = 0; i < len; i ++)
+ inst->scratch[i] = (inst->buffer[i] & ~mask[i])
+ | (val[i] & mask[i]);
+ }
+}
+
+static int pmac_i2c_do_rmw(PMF_STD_ARGS, u32 masklen, u32 valuelen,
+ u32 totallen, const u8 *maskdata,
+ const u8 *valuedata)
+{
+ struct pmac_i2c_pf_inst *inst = instdata;
+
+ if (masklen > inst->bytes || valuelen > inst->bytes ||
+ totallen > inst->bytes || valuelen > masklen)
+ return -EINVAL;
+
+ pmac_i2c_do_apply_rmw(inst, masklen, maskdata, valuedata);
+
+ return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 0, 0,
+ inst->scratch, totallen);
+}
+
+static int pmac_i2c_do_read_sub(PMF_STD_ARGS, u8 subaddr, u32 len)
+{
+ struct pmac_i2c_pf_inst *inst = instdata;
+
+ inst->bytes = len;
+ return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_read, 1, subaddr,
+ inst->buffer, len);
+}
+
+static int pmac_i2c_do_write_sub(PMF_STD_ARGS, u8 subaddr, u32 len,
+ const u8 *data)
+{
+ struct pmac_i2c_pf_inst *inst = instdata;
+
+ return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 1,
+ subaddr, (u8 *)data, len);
+}
+static int pmac_i2c_do_set_mode(PMF_STD_ARGS, int mode)
+{
+ struct pmac_i2c_pf_inst *inst = instdata;
+
+ return pmac_i2c_setmode(inst->bus, mode);
+}
+
+static int pmac_i2c_do_rmw_sub(PMF_STD_ARGS, u8 subaddr, u32 masklen,
+ u32 valuelen, u32 totallen, const u8 *maskdata,
+ const u8 *valuedata)
+{
+ struct pmac_i2c_pf_inst *inst = instdata;
+
+ if (masklen > inst->bytes || valuelen > inst->bytes ||
+ totallen > inst->bytes || valuelen > masklen)
+ return -EINVAL;
+
+ pmac_i2c_do_apply_rmw(inst, masklen, maskdata, valuedata);
+
+ return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 1,
+ subaddr, inst->scratch, totallen);
+}
+
+static int pmac_i2c_do_mask_and_comp(PMF_STD_ARGS, u32 len,
+ const u8 *maskdata,
+ const u8 *valuedata)
+{
+ struct pmac_i2c_pf_inst *inst = instdata;
+ int i, match;
+
+ /* Get return value pointer, it's assumed to be a u32 */
+ if (!args || !args->count || !args->u[0].p)
+ return -EINVAL;
+
+ /* Check buffer */
+ if (len > inst->bytes)
+ return -EINVAL;
+
+ for (i = 0, match = 1; match && i < len; i ++)
+ if ((inst->buffer[i] & maskdata[i]) != valuedata[i])
+ match = 0;
+ *args->u[0].p = match;
return 0;
}
-EXPORT_SYMBOL(pmac_low_i2c_setmode);
-int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len)
+static int pmac_i2c_do_delay(PMF_STD_ARGS, u32 duration)
{
- struct low_i2c_host *host = find_low_i2c_host(np);
+ msleep((duration + 999) / 1000);
+ return 0;
+}
- if (!host)
- return -ENODEV;
- WARN_ON(!host->is_open);
- return host->func(host, addrdir, subaddr, data, len);
+static struct pmf_handlers pmac_i2c_pfunc_handlers = {
+ .begin = pmac_i2c_do_begin,
+ .end = pmac_i2c_do_end,
+ .read_i2c = pmac_i2c_do_read,
+ .write_i2c = pmac_i2c_do_write,
+ .rmw_i2c = pmac_i2c_do_rmw,
+ .read_i2c_sub = pmac_i2c_do_read_sub,
+ .write_i2c_sub = pmac_i2c_do_write_sub,
+ .rmw_i2c_sub = pmac_i2c_do_rmw_sub,
+ .set_i2c_mode = pmac_i2c_do_set_mode,
+ .mask_and_compare = pmac_i2c_do_mask_and_comp,
+ .delay = pmac_i2c_do_delay,
+};
+
+static void __init pmac_i2c_dev_create(struct device_node *np, int quirks)
+{
+ DBG("dev_create(%s)\n", np->full_name);
+
+ pmf_register_driver(np, &pmac_i2c_pfunc_handlers,
+ (void *)(long)quirks);
+}
+
+static void __init pmac_i2c_dev_init(struct device_node *np, int quirks)
+{
+ DBG("dev_create(%s)\n", np->full_name);
+
+ pmf_do_functions(np, NULL, 0, PMF_FLAGS_ON_INIT, NULL);
+}
+
+static void pmac_i2c_dev_suspend(struct device_node *np, int quirks)
+{
+ DBG("dev_suspend(%s)\n", np->full_name);
+ pmf_do_functions(np, NULL, 0, PMF_FLAGS_ON_SLEEP, NULL);
+}
+
+static void pmac_i2c_dev_resume(struct device_node *np, int quirks)
+{
+ DBG("dev_resume(%s)\n", np->full_name);
+ pmf_do_functions(np, NULL, 0, PMF_FLAGS_ON_WAKE, NULL);
+}
+
+void pmac_pfunc_i2c_suspend(void)
+{
+ pmac_i2c_devscan(pmac_i2c_dev_suspend);
+}
+
+void pmac_pfunc_i2c_resume(void)
+{
+ pmac_i2c_devscan(pmac_i2c_dev_resume);
+}
+
+/*
+ * Initialize us: probe all i2c busses on the machine, instantiate
+ * busses and platform functions as needed.
+ */
+/* This is non-static as it might be called early by smp code */
+int __init pmac_i2c_init(void)
+{
+ static int i2c_inited;
+
+ if (i2c_inited)
+ return 0;
+ i2c_inited = 1;
+
+ /* Probe keywest-i2c busses */
+ kw_i2c_probe();
+
+#ifdef CONFIG_ADB_PMU
+ /* Probe PMU i2c busses */
+ pmu_i2c_probe();
+#endif
+
+#ifdef CONFIG_PMAC_SMU
+ /* Probe SMU i2c busses */
+ smu_i2c_probe();
+#endif
+
+ /* Now add plaform functions for some known devices */
+ pmac_i2c_devscan(pmac_i2c_dev_create);
+
+ return 0;
}
-EXPORT_SYMBOL(pmac_low_i2c_xfer);
+arch_initcall(pmac_i2c_init);
+
+/* Since pmac_i2c_init can be called too early for the platform device
+ * registration, we need to do it at a later time. In our case, subsys
+ * happens to fit well, though I agree it's a bit of a hack...
+ */
+static int __init pmac_i2c_create_platform_devices(void)
+{
+ struct pmac_i2c_bus *bus;
+ int i = 0;
+
+ /* In the case where we are initialized from smp_init(), we must
+ * not use the timer (and thus the irq). It's safe from now on
+ * though
+ */
+ pmac_i2c_force_poll = 0;
+
+ /* Create platform devices */
+ list_for_each_entry(bus, &pmac_i2c_busses, link) {
+ bus->platform_dev =
+ platform_device_alloc("i2c-powermac", i++);
+ if (bus->platform_dev == NULL)
+ return -ENOMEM;
+ bus->platform_dev->dev.platform_data = bus;
+ platform_device_add(bus->platform_dev);
+ }
+
+ /* Now call platform "init" functions */
+ pmac_i2c_devscan(pmac_i2c_dev_init);
+ return 0;
+}
+subsys_initcall(pmac_i2c_create_platform_devices);
diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c
index 4042e2f06ee0..3ebd045a3350 100644
--- a/arch/powerpc/platforms/powermac/nvram.c
+++ b/arch/powerpc/platforms/powermac/nvram.c
@@ -514,7 +514,7 @@ static void core99_nvram_sync(void)
#endif
}
-static int __init core99_nvram_setup(struct device_node *dp)
+static int __init core99_nvram_setup(struct device_node *dp, unsigned long addr)
{
int i;
u32 gen_bank0, gen_bank1;
@@ -528,7 +528,7 @@ static int __init core99_nvram_setup(struct device_node *dp)
printk(KERN_ERR "nvram: can't allocate ram image\n");
return -ENOMEM;
}
- nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
+ nvram_data = ioremap(addr, NVRAM_SIZE*2);
nvram_naddrs = 1; /* Make sure we get the correct case */
DBG("nvram: Checking bank 0...\n");
@@ -549,6 +549,7 @@ static int __init core99_nvram_setup(struct device_node *dp)
ppc_md.nvram_write = core99_nvram_write;
ppc_md.nvram_size = core99_nvram_size;
ppc_md.nvram_sync = core99_nvram_sync;
+ ppc_md.machine_shutdown = core99_nvram_sync;
/*
* Maybe we could be smarter here though making an exclusive list
* of known flash chips is a bit nasty as older OF didn't provide us
@@ -569,34 +570,48 @@ static int __init core99_nvram_setup(struct device_node *dp)
int __init pmac_nvram_init(void)
{
struct device_node *dp;
+ struct resource r1, r2;
+ unsigned int s1 = 0, s2 = 0;
int err = 0;
nvram_naddrs = 0;
- dp = find_devices("nvram");
+ dp = of_find_node_by_name(NULL, "nvram");
if (dp == NULL) {
printk(KERN_ERR "Can't find NVRAM device\n");
return -ENODEV;
}
- nvram_naddrs = dp->n_addrs;
+
+ /* Try to obtain an address */
+ if (of_address_to_resource(dp, 0, &r1) == 0) {
+ nvram_naddrs = 1;
+ s1 = (r1.end - r1.start) + 1;
+ if (of_address_to_resource(dp, 1, &r2) == 0) {
+ nvram_naddrs = 2;
+ s2 = (r2.end - r2.start) + 1;
+ }
+ }
+
is_core_99 = device_is_compatible(dp, "nvram,flash");
- if (is_core_99)
- err = core99_nvram_setup(dp);
+ if (is_core_99) {
+ err = core99_nvram_setup(dp, r1.start);
+ goto bail;
+ }
+
#ifdef CONFIG_PPC32
- else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
- nvram_data = ioremap(dp->addrs[0].address + isa_mem_base,
- dp->addrs[0].size);
+ if (_machine == _MACH_chrp && nvram_naddrs == 1) {
+ nvram_data = ioremap(r1.start, s1);
nvram_mult = 1;
ppc_md.nvram_read_val = direct_nvram_read_byte;
ppc_md.nvram_write_val = direct_nvram_write_byte;
} else if (nvram_naddrs == 1) {
- nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
- nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE;
+ nvram_data = ioremap(r1.start, s1);
+ nvram_mult = (s1 + NVRAM_SIZE - 1) / NVRAM_SIZE;
ppc_md.nvram_read_val = direct_nvram_read_byte;
ppc_md.nvram_write_val = direct_nvram_write_byte;
} else if (nvram_naddrs == 2) {
- nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
- nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
+ nvram_addr = ioremap(r1.start, s1);
+ nvram_data = ioremap(r2.start, s2);
ppc_md.nvram_read_val = indirect_nvram_read_byte;
ppc_md.nvram_write_val = indirect_nvram_write_byte;
} else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
@@ -605,13 +620,15 @@ int __init pmac_nvram_init(void)
ppc_md.nvram_read_val = pmu_nvram_read_byte;
ppc_md.nvram_write_val = pmu_nvram_write_byte;
#endif /* CONFIG_ADB_PMU */
- }
-#endif
- else {
+ } else {
printk(KERN_ERR "Incompatible type of NVRAM\n");
- return -ENXIO;
+ err = -ENXIO;
}
- lookup_partitions();
+#endif /* CONFIG_PPC32 */
+bail:
+ of_node_put(dp);
+ if (err == 0)
+ lookup_partitions();
return err;
}
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index 443be526cde7..f671ed253901 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -1,7 +1,7 @@
/*
* Support for PCI bridges found on Power Macintoshes.
*
- * Copyright (C) 2003 Benjamin Herrenschmuidt (benh@kernel.crashing.org)
+ * Copyright (C) 2003-2005 Benjamin Herrenschmuidt (benh@kernel.crashing.org)
* Copyright (C) 1997 Paul Mackerras (paulus@samba.org)
*
* This program is free software; you can redistribute it and/or
@@ -25,7 +25,7 @@
#include <asm/pmac_feature.h>
#include <asm/grackle.h>
#ifdef CONFIG_PPC64
-#include <asm/iommu.h>
+//#include <asm/iommu.h>
#include <asm/ppc-pci.h>
#endif
@@ -44,6 +44,7 @@ static int add_bridge(struct device_node *dev);
static int has_uninorth;
#ifdef CONFIG_PPC64
static struct pci_controller *u3_agp;
+static struct pci_controller *u4_pcie;
static struct pci_controller *u3_ht;
#endif /* CONFIG_PPC64 */
@@ -97,11 +98,8 @@ static void __init fixup_bus_range(struct device_node *bridge)
/* Lookup the "bus-range" property for the hose */
bus_range = (int *) get_property(bridge, "bus-range", &len);
- if (bus_range == NULL || len < 2 * sizeof(int)) {
- printk(KERN_WARNING "Can't get bus-range for %s\n",
- bridge->full_name);
+ if (bus_range == NULL || len < 2 * sizeof(int))
return;
- }
bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
}
@@ -128,14 +126,14 @@ static void __init fixup_bus_range(struct device_node *bridge)
*/
#define MACRISC_CFA0(devfn, off) \
- ((1 << (unsigned long)PCI_SLOT(dev_fn)) \
- | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
- | (((unsigned long)(off)) & 0xFCUL))
+ ((1 << (unsigned int)PCI_SLOT(dev_fn)) \
+ | (((unsigned int)PCI_FUNC(dev_fn)) << 8) \
+ | (((unsigned int)(off)) & 0xFCUL))
#define MACRISC_CFA1(bus, devfn, off) \
- ((((unsigned long)(bus)) << 16) \
- |(((unsigned long)(devfn)) << 8) \
- |(((unsigned long)(off)) & 0xFCUL) \
+ ((((unsigned int)(bus)) << 16) \
+ |(((unsigned int)(devfn)) << 8) \
+ |(((unsigned int)(off)) & 0xFCUL) \
|1UL)
static unsigned long macrisc_cfg_access(struct pci_controller* hose,
@@ -168,7 +166,8 @@ static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn,
hose = pci_bus_to_host(bus);
if (hose == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
-
+ if (offset >= 0x100)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -199,7 +198,8 @@ static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn,
hose = pci_bus_to_host(bus);
if (hose == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
-
+ if (offset >= 0x100)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -234,12 +234,13 @@ static struct pci_ops macrisc_pci_ops =
/*
* Verify that a specific (bus, dev_fn) exists on chaos
*/
-static int
-chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
+static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
{
struct device_node *np;
u32 *vendor, *device;
+ if (offset >= 0x100)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
np = pci_busdev_to_OF_node(bus, devfn);
if (np == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -285,15 +286,13 @@ static struct pci_ops chaos_pci_ops =
};
static void __init setup_chaos(struct pci_controller *hose,
- struct reg_property *addr)
+ struct resource *addr)
{
/* assume a `chaos' bridge */
hose->ops = &chaos_pci_ops;
- hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
- hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+ hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000);
+ hose->cfg_data = ioremap(addr->start + 0xc00000, 0x1000);
}
-#else
-#define setup_chaos(hose, addr)
#endif /* CONFIG_PPC32 */
#ifdef CONFIG_PPC64
@@ -326,7 +325,7 @@ static int u3_ht_skip_device(struct pci_controller *hose,
else
busdn = hose->arch_data;
for (dn = busdn->child; dn; dn = dn->sibling)
- if (dn->data && PCI_DN(dn)->devfn == devfn)
+ if (PCI_DN(dn) && PCI_DN(dn)->devfn == devfn)
break;
if (dn == NULL)
return -1;
@@ -343,10 +342,10 @@ static int u3_ht_skip_device(struct pci_controller *hose,
}
#define U3_HT_CFA0(devfn, off) \
- ((((unsigned long)devfn) << 8) | offset)
+ ((((unsigned int)devfn) << 8) | offset)
#define U3_HT_CFA1(bus, devfn, off) \
(U3_HT_CFA0(devfn, off) \
- + (((unsigned long)bus) << 16) \
+ + (((unsigned int)bus) << 16) \
+ 0x01000000UL)
static unsigned long u3_ht_cfg_access(struct pci_controller* hose,
@@ -356,9 +355,11 @@ static unsigned long u3_ht_cfg_access(struct pci_controller* hose,
/* For now, we don't self probe U3 HT bridge */
if (PCI_SLOT(devfn) == 0)
return 0;
- return ((unsigned long)hose->cfg_data) + U3_HT_CFA0(devfn, offset);
+ return ((unsigned long)hose->cfg_data) +
+ U3_HT_CFA0(devfn, offset);
} else
- return ((unsigned long)hose->cfg_data) + U3_HT_CFA1(bus, devfn, offset);
+ return ((unsigned long)hose->cfg_data) +
+ U3_HT_CFA1(bus, devfn, offset);
}
static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
@@ -370,7 +371,8 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
hose = pci_bus_to_host(bus);
if (hose == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
-
+ if (offset >= 0x100)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -419,7 +421,8 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
hose = pci_bus_to_host(bus);
if (hose == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
-
+ if (offset >= 0x100)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -459,6 +462,112 @@ static struct pci_ops u3_ht_pci_ops =
u3_ht_read_config,
u3_ht_write_config
};
+
+#define U4_PCIE_CFA0(devfn, off) \
+ ((1 << ((unsigned int)PCI_SLOT(dev_fn))) \
+ | (((unsigned int)PCI_FUNC(dev_fn)) << 8) \
+ | ((((unsigned int)(off)) >> 8) << 28) \
+ | (((unsigned int)(off)) & 0xfcU))
+
+#define U4_PCIE_CFA1(bus, devfn, off) \
+ ((((unsigned int)(bus)) << 16) \
+ |(((unsigned int)(devfn)) << 8) \
+ | ((((unsigned int)(off)) >> 8) << 28) \
+ |(((unsigned int)(off)) & 0xfcU) \
+ |1UL)
+
+static unsigned long u4_pcie_cfg_access(struct pci_controller* hose,
+ u8 bus, u8 dev_fn, int offset)
+{
+ unsigned int caddr;
+
+ if (bus == hose->first_busno) {
+ caddr = U4_PCIE_CFA0(dev_fn, offset);
+ } else
+ caddr = U4_PCIE_CFA1(bus, dev_fn, offset);
+
+ /* Uninorth will return garbage if we don't read back the value ! */
+ do {
+ out_le32(hose->cfg_addr, caddr);
+ } while (in_le32(hose->cfg_addr) != caddr);
+
+ offset &= 0x03;
+ return ((unsigned long)hose->cfg_data) + offset;
+}
+
+static int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
+ int offset, int len, u32 *val)
+{
+ struct pci_controller *hose;
+ unsigned long addr;
+
+ hose = pci_bus_to_host(bus);
+ if (hose == NULL)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (offset >= 0x1000)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ switch (len) {
+ case 1:
+ *val = in_8((u8 *)addr);
+ break;
+ case 2:
+ *val = in_le16((u16 *)addr);
+ break;
+ default:
+ *val = in_le32((u32 *)addr);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
+ int offset, int len, u32 val)
+{
+ struct pci_controller *hose;
+ unsigned long addr;
+
+ hose = pci_bus_to_host(bus);
+ if (hose == NULL)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (offset >= 0x1000)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ switch (len) {
+ case 1:
+ out_8((u8 *)addr, val);
+ (void) in_8((u8 *)addr);
+ break;
+ case 2:
+ out_le16((u16 *)addr, val);
+ (void) in_le16((u16 *)addr);
+ break;
+ default:
+ out_le32((u32 *)addr, val);
+ (void) in_le32((u32 *)addr);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops u4_pcie_pci_ops =
+{
+ u4_pcie_read_config,
+ u4_pcie_write_config
+};
+
#endif /* CONFIG_PPC64 */
#ifdef CONFIG_PPC32
@@ -532,7 +641,8 @@ static void __init init_p2pbridge(void)
}
if (early_read_config_word(hose, bus, devfn,
PCI_BRIDGE_CONTROL, &val) < 0) {
- printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n");
+ printk(KERN_ERR "init_p2pbridge: couldn't read bridge"
+ " control\n");
return;
}
val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
@@ -576,36 +686,38 @@ static void __init fixup_nec_usb2(void)
continue;
early_read_config_dword(hose, bus, devfn, 0xe4, &data);
if (data & 1UL) {
- printk("Found NEC PD720100A USB2 chip with disabled EHCI, fixing up...\n");
+ printk("Found NEC PD720100A USB2 chip with disabled"
+ " EHCI, fixing up...\n");
data &= ~1UL;
early_write_config_dword(hose, bus, devfn, 0xe4, data);
- early_write_config_byte(hose, bus, devfn | 2, PCI_INTERRUPT_LINE,
+ early_write_config_byte(hose, bus,
+ devfn | 2, PCI_INTERRUPT_LINE,
nec->intrs[0].line);
}
}
}
static void __init setup_bandit(struct pci_controller *hose,
- struct reg_property *addr)
+ struct resource *addr)
{
hose->ops = &macrisc_pci_ops;
- hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
- hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+ hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000);
+ hose->cfg_data = ioremap(addr->start + 0xc00000, 0x1000);
init_bandit(hose);
}
static int __init setup_uninorth(struct pci_controller *hose,
- struct reg_property *addr)
+ struct resource *addr)
{
pci_assign_all_buses = 1;
has_uninorth = 1;
hose->ops = &macrisc_pci_ops;
- hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
- hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+ hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000);
+ hose->cfg_data = ioremap(addr->start + 0xc00000, 0x1000);
/* We "know" that the bridge at f2000000 has the PCI slots. */
- return addr->address == 0xf2000000;
+ return addr->start == 0xf2000000;
}
-#endif
+#endif /* CONFIG_PPC32 */
#ifdef CONFIG_PPC64
static void __init setup_u3_agp(struct pci_controller* hose)
@@ -625,15 +737,36 @@ static void __init setup_u3_agp(struct pci_controller* hose)
hose->ops = &macrisc_pci_ops;
hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
-
u3_agp = hose;
}
+static void __init setup_u4_pcie(struct pci_controller* hose)
+{
+ /* We currently only implement the "non-atomic" config space, to
+ * be optimised later.
+ */
+ hose->ops = &u4_pcie_pci_ops;
+ hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
+ hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
+
+ /* The bus contains a bridge from root -> device, we need to
+ * make it visible on bus 0 so that we pick the right type
+ * of config cycles. If we didn't, we would have to force all
+ * config cycles to be type 1. So we override the "bus-range"
+ * property here
+ */
+ hose->first_busno = 0x00;
+ hose->last_busno = 0xff;
+ u4_pcie = hose;
+}
+
static void __init setup_u3_ht(struct pci_controller* hose)
{
struct device_node *np = (struct device_node *)hose->arch_data;
+ struct pci_controller *other = NULL;
int i, cur;
+
hose->ops = &u3_ht_pci_ops;
/* We hard code the address because of the different size of
@@ -667,11 +800,20 @@ static void __init setup_u3_ht(struct pci_controller* hose)
u3_ht = hose;
- if (u3_agp == NULL) {
- DBG("U3 has no AGP, using full resource range\n");
+ if (u3_agp != NULL)
+ other = u3_agp;
+ else if (u4_pcie != NULL)
+ other = u4_pcie;
+
+ if (other == NULL) {
+ DBG("U3/4 has no AGP/PCIE, using full resource range\n");
return;
}
+ /* Fixup bus range vs. PCIE */
+ if (u4_pcie)
+ hose->last_busno = u4_pcie->first_busno - 1;
+
/* We "remove" the AGP resources from the resources allocated to HT,
* that is we create "holes". However, that code does assumptions
* that so far happen to be true (cross fingers...), typically that
@@ -679,7 +821,7 @@ static void __init setup_u3_ht(struct pci_controller* hose)
*/
cur = 0;
for (i=0; i<3; i++) {
- struct resource *res = &u3_agp->mem_resources[i];
+ struct resource *res = &other->mem_resources[i];
if (res->flags != IORESOURCE_MEM)
continue;
/* We don't care about "fine" resources */
@@ -722,7 +864,7 @@ static void __init setup_u3_ht(struct pci_controller* hose)
hose->mem_resources[cur-1].end = res->start - 1;
}
}
-#endif
+#endif /* CONFIG_PPC64 */
/*
* We assume that if we have a G3 powermac, we have one bridge called
@@ -733,24 +875,17 @@ static int __init add_bridge(struct device_node *dev)
{
int len;
struct pci_controller *hose;
-#ifdef CONFIG_PPC32
- struct reg_property *addr;
-#endif
+ struct resource rsrc;
char *disp_name;
int *bus_range;
- int primary = 1;
+ int primary = 1, has_address = 0;
DBG("Adding PCI host bridge %s\n", dev->full_name);
-#ifdef CONFIG_PPC32
- /* XXX fix this */
- addr = (struct reg_property *) get_property(dev, "reg", &len);
- if (addr == NULL || len < sizeof(*addr)) {
- printk(KERN_WARNING "Can't use %s: no address\n",
- dev->full_name);
- return -ENODEV;
- }
-#endif
+ /* Fetch host bridge registers address */
+ has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
+
+ /* Get bus range if any */
bus_range = (int *) get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get bus-range for %s, assume"
@@ -770,6 +905,8 @@ static int __init add_bridge(struct device_node *dev)
hose->last_busno = bus_range ? bus_range[1] : 0xff;
disp_name = NULL;
+
+ /* 64 bits only bridges */
#ifdef CONFIG_PPC64
if (device_is_compatible(dev, "u3-agp")) {
setup_u3_agp(hose);
@@ -779,28 +916,37 @@ static int __init add_bridge(struct device_node *dev)
setup_u3_ht(hose);
disp_name = "U3-HT";
primary = 1;
+ } else if (device_is_compatible(dev, "u4-pcie")) {
+ setup_u4_pcie(hose);
+ disp_name = "U4-PCIE";
+ primary = 0;
}
- printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n",
- disp_name, hose->first_busno, hose->last_busno);
-#else
+ printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number:"
+ " %d->%d\n", disp_name, hose->first_busno, hose->last_busno);
+#endif /* CONFIG_PPC64 */
+
+ /* 32 bits only bridges */
+#ifdef CONFIG_PPC32
if (device_is_compatible(dev, "uni-north")) {
- primary = setup_uninorth(hose, addr);
+ primary = setup_uninorth(hose, &rsrc);
disp_name = "UniNorth";
} else if (strcmp(dev->name, "pci") == 0) {
/* XXX assume this is a mpc106 (grackle) */
setup_grackle(hose);
disp_name = "Grackle (MPC106)";
} else if (strcmp(dev->name, "bandit") == 0) {
- setup_bandit(hose, addr);
+ setup_bandit(hose, &rsrc);
disp_name = "Bandit";
} else if (strcmp(dev->name, "chaos") == 0) {
- setup_chaos(hose, addr);
+ setup_chaos(hose, &rsrc);
disp_name = "Chaos";
primary = 0;
}
- printk(KERN_INFO "Found %s PCI host bridge at 0x%08lx. Firmware bus number: %d->%d\n",
- disp_name, addr->address, hose->first_busno, hose->last_busno);
-#endif
+ printk(KERN_INFO "Found %s PCI host bridge at 0x%08lx. "
+ "Firmware bus number: %d->%d\n",
+ disp_name, rsrc.start, hose->first_busno, hose->last_busno);
+#endif /* CONFIG_PPC32 */
+
DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
hose, hose->cfg_addr, hose->cfg_data);
@@ -814,8 +960,7 @@ static int __init add_bridge(struct device_node *dev)
return 0;
}
-static void __init
-pcibios_fixup_OF_interrupts(void)
+static void __init pcibios_fixup_OF_interrupts(void)
{
struct pci_dev* dev = NULL;
@@ -835,8 +980,7 @@ pcibios_fixup_OF_interrupts(void)
}
}
-void __init
-pmac_pcibios_fixup(void)
+void __init pmac_pcibios_fixup(void)
{
/* Fixup interrupts according to OF tree */
pcibios_fixup_OF_interrupts();
@@ -899,6 +1043,8 @@ void __init pmac_pci_init(void)
pci_setup_phb_io(u3_ht, 1);
if (u3_agp)
pci_setup_phb_io(u3_agp, 0);
+ if (u4_pcie)
+ pci_setup_phb_io(u4_pcie, 0);
/*
* On ppc64, fixup the IO resources on our host bridges as
@@ -911,7 +1057,8 @@ void __init pmac_pci_init(void)
/* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We
* assume there is no P2P bridge on the AGP bus, which should be a
- * safe assumptions hopefully.
+ * safe assumptions for now. We should do something better in the
+ * future though
*/
if (u3_agp) {
struct device_node *np = u3_agp->arch_data;
@@ -919,7 +1066,6 @@ void __init pmac_pci_init(void)
for (np = np->child; np; np = np->sibling)
PCI_DN(np)->busno = 0xf0;
}
-
/* pmac_check_ht_link(); */
/* Tell pci.c to not use the common resource allocation mechanism */
@@ -1126,7 +1272,8 @@ void pmac_pci_fixup_pciata(struct pci_dev* dev)
good:
pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
if ((progif & 5) != 5) {
- printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n", pci_name(dev));
+ printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n",
+ pci_name(dev));
(void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
(progif & 5) != 5)
@@ -1152,7 +1299,8 @@ static void fixup_k2_sata(struct pci_dev* dev)
for (i = 0; i < 6; i++) {
dev->resource[i].start = dev->resource[i].end = 0;
dev->resource[i].flags = 0;
- pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i,
+ 0);
}
} else {
pci_read_config_word(dev, PCI_COMMAND, &cmd);
@@ -1161,7 +1309,8 @@ static void fixup_k2_sata(struct pci_dev* dev)
for (i = 0; i < 5; i++) {
dev->resource[i].start = dev->resource[i].end = 0;
dev->resource[i].flags = 0;
- pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i,
+ 0);
}
}
}
diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c
new file mode 100644
index 000000000000..4ffd2a9832a0
--- /dev/null
+++ b/arch/powerpc/platforms/powermac/pfunc_base.c
@@ -0,0 +1,405 @@
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include <asm/pmac_feature.h>
+#include <asm/pmac_pfunc.h>
+
+#define DBG(fmt...) printk(fmt)
+
+static irqreturn_t macio_gpio_irq(int irq, void *data, struct pt_regs *regs)
+{
+ pmf_do_irq(data);
+
+ return IRQ_HANDLED;
+}
+
+static int macio_do_gpio_irq_enable(struct pmf_function *func)
+{
+ if (func->node->n_intrs < 1)
+ return -EINVAL;
+
+ return request_irq(func->node->intrs[0].line, macio_gpio_irq, 0,
+ func->node->name, func);
+}
+
+static int macio_do_gpio_irq_disable(struct pmf_function *func)
+{
+ if (func->node->n_intrs < 1)
+ return -EINVAL;
+
+ free_irq(func->node->intrs[0].line, func);
+ return 0;
+}
+
+static int macio_do_gpio_write(PMF_STD_ARGS, u8 value, u8 mask)
+{
+ u8 __iomem *addr = (u8 __iomem *)func->driver_data;
+ unsigned long flags;
+ u8 tmp;
+
+ /* Check polarity */
+ if (args && args->count && !args->u[0].v)
+ value = ~value;
+
+ /* Toggle the GPIO */
+ spin_lock_irqsave(&feature_lock, flags);
+ tmp = readb(addr);
+ tmp = (tmp & ~mask) | (value & mask);
+ DBG("Do write 0x%02x to GPIO %s (%p)\n",
+ tmp, func->node->full_name, addr);
+ writeb(tmp, addr);
+ spin_unlock_irqrestore(&feature_lock, flags);
+
+ return 0;
+}
+
+static int macio_do_gpio_read(PMF_STD_ARGS, u8 mask, int rshift, u8 xor)
+{
+ u8 __iomem *addr = (u8 __iomem *)func->driver_data;
+ u32 value;
+
+ /* Check if we have room for reply */
+ if (args == NULL || args->count == 0 || args->u[0].p == NULL)
+ return -EINVAL;
+
+ value = readb(addr);
+ *args->u[0].p = ((value & mask) >> rshift) ^ xor;
+
+ return 0;
+}
+
+static int macio_do_delay(PMF_STD_ARGS, u32 duration)
+{
+ /* assume we can sleep ! */
+ msleep((duration + 999) / 1000);
+ return 0;
+}
+
+static struct pmf_handlers macio_gpio_handlers = {
+ .irq_enable = macio_do_gpio_irq_enable,
+ .irq_disable = macio_do_gpio_irq_disable,
+ .write_gpio = macio_do_gpio_write,
+ .read_gpio = macio_do_gpio_read,
+ .delay = macio_do_delay,
+};
+
+static void macio_gpio_init_one(struct macio_chip *macio)
+{
+ struct device_node *gparent, *gp;
+
+ /*
+ * Find the "gpio" parent node
+ */
+
+ for (gparent = NULL;
+ (gparent = of_get_next_child(macio->of_node, gparent)) != NULL;)
+ if (strcmp(gparent->name, "gpio") == 0)
+ break;
+ if (gparent == NULL)
+ return;
+
+ DBG("Installing GPIO functions for macio %s\n",
+ macio->of_node->full_name);
+
+ /*
+ * Ok, got one, we dont need anything special to track them down, so
+ * we just create them all
+ */
+ for (gp = NULL; (gp = of_get_next_child(gparent, gp)) != NULL;) {
+ u32 *reg = (u32 *)get_property(gp, "reg", NULL);
+ unsigned long offset;
+ if (reg == NULL)
+ continue;
+ offset = *reg;
+ /* Deal with old style device-tree. We can safely hard code the
+ * offset for now too even if it's a bit gross ...
+ */
+ if (offset < 0x50)
+ offset += 0x50;
+ offset += (unsigned long)macio->base;
+ pmf_register_driver(gp, &macio_gpio_handlers, (void *)offset);
+ }
+
+ DBG("Calling initial GPIO functions for macio %s\n",
+ macio->of_node->full_name);
+
+ /* And now we run all the init ones */
+ for (gp = NULL; (gp = of_get_next_child(gparent, gp)) != NULL;)
+ pmf_do_functions(gp, NULL, 0, PMF_FLAGS_ON_INIT, NULL);
+
+ /* Note: We do not at this point implement the "at sleep" or "at wake"
+ * functions. I yet to find any for GPIOs anyway
+ */
+}
+
+static int macio_do_write_reg32(PMF_STD_ARGS, u32 offset, u32 value, u32 mask)
+{
+ struct macio_chip *macio = func->driver_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&feature_lock, flags);
+ MACIO_OUT32(offset, (MACIO_IN32(offset) & ~mask) | (value & mask));
+ spin_unlock_irqrestore(&feature_lock, flags);
+ return 0;
+}
+
+static int macio_do_read_reg32(PMF_STD_ARGS, u32 offset)
+{
+ struct macio_chip *macio = func->driver_data;
+
+ /* Check if we have room for reply */
+ if (args == NULL || args->count == 0 || args->u[0].p == NULL)
+ return -EINVAL;
+
+ *args->u[0].p = MACIO_IN32(offset);
+ return 0;
+}
+
+static int macio_do_write_reg8(PMF_STD_ARGS, u32 offset, u8 value, u8 mask)
+{
+ struct macio_chip *macio = func->driver_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&feature_lock, flags);
+ MACIO_OUT8(offset, (MACIO_IN8(offset) & ~mask) | (value & mask));
+ spin_unlock_irqrestore(&feature_lock, flags);
+ return 0;
+}
+
+static int macio_do_read_reg8(PMF_STD_ARGS, u32 offset)
+{
+ struct macio_chip *macio = func->driver_data;
+
+ /* Check if we have room for reply */
+ if (args == NULL || args->count == 0 || args->u[0].p == NULL)
+ return -EINVAL;
+
+ *((u8 *)(args->u[0].p)) = MACIO_IN8(offset);
+ return 0;
+}
+
+static int macio_do_read_reg32_msrx(PMF_STD_ARGS, u32 offset, u32 mask,
+ u32 shift, u32 xor)
+{
+ struct macio_chip *macio = func->driver_data;
+
+ /* Check if we have room for reply */
+ if (args == NULL || args->count == 0 || args->u[0].p == NULL)
+ return -EINVAL;
+
+ *args->u[0].p = ((MACIO_IN32(offset) & mask) >> shift) ^ xor;
+ return 0;
+}
+
+static int macio_do_read_reg8_msrx(PMF_STD_ARGS, u32 offset, u32 mask,
+ u32 shift, u32 xor)
+{
+ struct macio_chip *macio = func->driver_data;
+
+ /* Check if we have room for reply */
+ if (args == NULL || args->count == 0 || args->u[0].p == NULL)
+ return -EINVAL;
+
+ *((u8 *)(args->u[0].p)) = ((MACIO_IN8(offset) & mask) >> shift) ^ xor;
+ return 0;
+}
+
+static int macio_do_write_reg32_slm(PMF_STD_ARGS, u32 offset, u32 shift,
+ u32 mask)
+{
+ struct macio_chip *macio = func->driver_data;
+ unsigned long flags;
+ u32 tmp, val;
+
+ /* Check args */
+ if (args == NULL || args->count == 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&feature_lock, flags);
+ tmp = MACIO_IN32(offset);
+ val = args->u[0].v << shift;
+ tmp = (tmp & ~mask) | (val & mask);
+ MACIO_OUT32(offset, tmp);
+ spin_unlock_irqrestore(&feature_lock, flags);
+ return 0;
+}
+
+static int macio_do_write_reg8_slm(PMF_STD_ARGS, u32 offset, u32 shift,
+ u32 mask)
+{
+ struct macio_chip *macio = func->driver_data;
+ unsigned long flags;
+ u32 tmp, val;
+
+ /* Check args */
+ if (args == NULL || args->count == 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&feature_lock, flags);
+ tmp = MACIO_IN8(offset);
+ val = args->u[0].v << shift;
+ tmp = (tmp & ~mask) | (val & mask);
+ MACIO_OUT8(offset, tmp);
+ spin_unlock_irqrestore(&feature_lock, flags);
+ return 0;
+}
+
+static struct pmf_handlers macio_mmio_handlers = {
+ .write_reg32 = macio_do_write_reg32,
+ .read_reg32 = macio_do_read_reg32,
+ .write_reg8 = macio_do_write_reg8,
+ .read_reg32 = macio_do_read_reg8,
+ .read_reg32_msrx = macio_do_read_reg32_msrx,
+ .read_reg8_msrx = macio_do_read_reg8_msrx,
+ .write_reg32_slm = macio_do_write_reg32_slm,
+ .write_reg8_slm = macio_do_write_reg8_slm,
+ .delay = macio_do_delay,
+};
+
+static void macio_mmio_init_one(struct macio_chip *macio)
+{
+ DBG("Installing MMIO functions for macio %s\n",
+ macio->of_node->full_name);
+
+ pmf_register_driver(macio->of_node, &macio_mmio_handlers, macio);
+}
+
+static struct device_node *unin_hwclock;
+
+static int unin_do_write_reg32(PMF_STD_ARGS, u32 offset, u32 value, u32 mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&feature_lock, flags);
+ /* This is fairly bogus in darwin, but it should work for our needs
+ * implemeted that way:
+ */
+ UN_OUT(offset, (UN_IN(offset) & ~mask) | (value & mask));
+ spin_unlock_irqrestore(&feature_lock, flags);
+ return 0;
+}
+
+
+static struct pmf_handlers unin_mmio_handlers = {
+ .write_reg32 = unin_do_write_reg32,
+ .delay = macio_do_delay,
+};
+
+static void uninorth_install_pfunc(void)
+{
+ struct device_node *np;
+
+ DBG("Installing functions for UniN %s\n",
+ uninorth_node->full_name);
+
+ /*
+ * Install handlers for the bridge itself
+ */
+ pmf_register_driver(uninorth_node, &unin_mmio_handlers, NULL);
+ pmf_do_functions(uninorth_node, NULL, 0, PMF_FLAGS_ON_INIT, NULL);
+
+
+ /*
+ * Install handlers for the hwclock child if any
+ */
+ for (np = NULL; (np = of_get_next_child(uninorth_node, np)) != NULL;)
+ if (strcmp(np->name, "hw-clock") == 0) {
+ unin_hwclock = np;
+ break;
+ }
+ if (unin_hwclock) {
+ DBG("Installing functions for UniN clock %s\n",
+ unin_hwclock->full_name);
+ pmf_register_driver(unin_hwclock, &unin_mmio_handlers, NULL);
+ pmf_do_functions(unin_hwclock, NULL, 0, PMF_FLAGS_ON_INIT,
+ NULL);
+ }
+}
+
+/* We export this as the SMP code might init us early */
+int __init pmac_pfunc_base_install(void)
+{
+ static int pfbase_inited;
+ int i;
+
+ if (pfbase_inited)
+ return 0;
+ pfbase_inited = 1;
+
+
+ DBG("Installing base platform functions...\n");
+
+ /*
+ * Locate mac-io chips and install handlers
+ */
+ for (i = 0 ; i < MAX_MACIO_CHIPS; i++) {
+ if (macio_chips[i].of_node) {
+ macio_mmio_init_one(&macio_chips[i]);
+ macio_gpio_init_one(&macio_chips[i]);
+ }
+ }
+
+ /*
+ * Install handlers for northbridge and direct mapped hwclock
+ * if any. We do not implement the config space access callback
+ * which is only ever used for functions that we do not call in
+ * the current driver (enabling/disabling cells in U2, mostly used
+ * to restore the PCI settings, we do that differently)
+ */
+ if (uninorth_node && uninorth_base)
+ uninorth_install_pfunc();
+
+ DBG("All base functions installed\n");
+
+ return 0;
+}
+
+arch_initcall(pmac_pfunc_base_install);
+
+#ifdef CONFIG_PM
+
+/* Those can be called by pmac_feature. Ultimately, I should use a sysdev
+ * or a device, but for now, that's good enough until I sort out some
+ * ordering issues. Also, we do not bother with GPIOs, as so far I yet have
+ * to see a case where a GPIO function has the on-suspend or on-resume bit
+ */
+void pmac_pfunc_base_suspend(void)
+{
+ int i;
+
+ for (i = 0 ; i < MAX_MACIO_CHIPS; i++) {
+ if (macio_chips[i].of_node)
+ pmf_do_functions(macio_chips[i].of_node, NULL, 0,
+ PMF_FLAGS_ON_SLEEP, NULL);
+ }
+ if (uninorth_node)
+ pmf_do_functions(uninorth_node, NULL, 0,
+ PMF_FLAGS_ON_SLEEP, NULL);
+ if (unin_hwclock)
+ pmf_do_functions(unin_hwclock, NULL, 0,
+ PMF_FLAGS_ON_SLEEP, NULL);
+}
+
+void pmac_pfunc_base_resume(void)
+{
+ int i;
+
+ if (unin_hwclock)
+ pmf_do_functions(unin_hwclock, NULL, 0,
+ PMF_FLAGS_ON_WAKE, NULL);
+ if (uninorth_node)
+ pmf_do_functions(uninorth_node, NULL, 0,
+ PMF_FLAGS_ON_WAKE, NULL);
+ for (i = 0 ; i < MAX_MACIO_CHIPS; i++) {
+ if (macio_chips[i].of_node)
+ pmf_do_functions(macio_chips[i].of_node, NULL, 0,
+ PMF_FLAGS_ON_WAKE, NULL);
+ }
+}
+
+#endif /* CONFIG_PM */
diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c
new file mode 100644
index 000000000000..c32c623001dc
--- /dev/null
+++ b/arch/powerpc/platforms/powermac/pfunc_core.c
@@ -0,0 +1,989 @@
+/*
+ *
+ * FIXME: Properly make this race free with refcounting etc...
+ *
+ * FIXME: LOCKING !!!
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+
+#include <asm/semaphore.h>
+#include <asm/prom.h>
+#include <asm/pmac_pfunc.h>
+
+/* Debug */
+#define LOG_PARSE(fmt...)
+#define LOG_ERROR(fmt...) printk(fmt)
+#define LOG_BLOB(t,b,c)
+#define DBG(fmt...) printk(fmt)
+
+/* Command numbers */
+#define PMF_CMD_LIST 0
+#define PMF_CMD_WRITE_GPIO 1
+#define PMF_CMD_READ_GPIO 2
+#define PMF_CMD_WRITE_REG32 3
+#define PMF_CMD_READ_REG32 4
+#define PMF_CMD_WRITE_REG16 5
+#define PMF_CMD_READ_REG16 6
+#define PMF_CMD_WRITE_REG8 7
+#define PMF_CMD_READ_REG8 8
+#define PMF_CMD_DELAY 9
+#define PMF_CMD_WAIT_REG32 10
+#define PMF_CMD_WAIT_REG16 11
+#define PMF_CMD_WAIT_REG8 12
+#define PMF_CMD_READ_I2C 13
+#define PMF_CMD_WRITE_I2C 14
+#define PMF_CMD_RMW_I2C 15
+#define PMF_CMD_GEN_I2C 16
+#define PMF_CMD_SHIFT_BYTES_RIGHT 17
+#define PMF_CMD_SHIFT_BYTES_LEFT 18
+#define PMF_CMD_READ_CFG 19
+#define PMF_CMD_WRITE_CFG 20
+#define PMF_CMD_RMW_CFG 21
+#define PMF_CMD_READ_I2C_SUBADDR 22
+#define PMF_CMD_WRITE_I2C_SUBADDR 23
+#define PMF_CMD_SET_I2C_MODE 24
+#define PMF_CMD_RMW_I2C_SUBADDR 25
+#define PMF_CMD_READ_REG32_MASK_SHR_XOR 26
+#define PMF_CMD_READ_REG16_MASK_SHR_XOR 27
+#define PMF_CMD_READ_REG8_MASK_SHR_XOR 28
+#define PMF_CMD_WRITE_REG32_SHL_MASK 29
+#define PMF_CMD_WRITE_REG16_SHL_MASK 30
+#define PMF_CMD_WRITE_REG8_SHL_MASK 31
+#define PMF_CMD_MASK_AND_COMPARE 32
+#define PMF_CMD_COUNT 33
+
+/* This structure holds the state of the parser while walking through
+ * a function definition
+ */
+struct pmf_cmd {
+ const void *cmdptr;
+ const void *cmdend;
+ struct pmf_function *func;
+ void *instdata;
+ struct pmf_args *args;
+ int error;
+};
+
+#if 0
+/* Debug output */
+static void print_blob(const char *title, const void *blob, int bytes)
+{
+ printk("%s", title);
+ while(bytes--) {
+ printk("%02x ", *((u8 *)blob));
+ blob += 1;
+ }
+ printk("\n");
+}
+#endif
+
+/*
+ * Parser helpers
+ */
+
+static u32 pmf_next32(struct pmf_cmd *cmd)
+{
+ u32 value;
+ if ((cmd->cmdend - cmd->cmdptr) < 4) {
+ cmd->error = 1;
+ return 0;
+ }
+ value = *((u32 *)cmd->cmdptr);
+ cmd->cmdptr += 4;
+ return value;
+}
+
+static const void* pmf_next_blob(struct pmf_cmd *cmd, int count)
+{
+ const void *value;
+ if ((cmd->cmdend - cmd->cmdptr) < count) {
+ cmd->error = 1;
+ return NULL;
+ }
+ value = cmd->cmdptr;
+ cmd->cmdptr += count;
+ return value;
+}
+
+/*
+ * Individual command parsers
+ */
+
+#define PMF_PARSE_CALL(name, cmd, handlers, p...) \
+ do { \
+ if (cmd->error) \
+ return -ENXIO; \
+ if (handlers == NULL) \
+ return 0; \
+ if (handlers->name) \
+ return handlers->name(cmd->func, cmd->instdata, \
+ cmd->args, p); \
+ return -1; \
+ } while(0) \
+
+
+static int pmf_parser_write_gpio(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u8 value = (u8)pmf_next32(cmd);
+ u8 mask = (u8)pmf_next32(cmd);
+
+ LOG_PARSE("pmf: write_gpio(value: %02x, mask: %02x)\n", value, mask);
+
+ PMF_PARSE_CALL(write_gpio, cmd, h, value, mask);
+}
+
+static int pmf_parser_read_gpio(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u8 mask = (u8)pmf_next32(cmd);
+ int rshift = (int)pmf_next32(cmd);
+ u8 xor = (u8)pmf_next32(cmd);
+
+ LOG_PARSE("pmf: read_gpio(mask: %02x, rshift: %d, xor: %02x)\n",
+ mask, rshift, xor);
+
+ PMF_PARSE_CALL(read_gpio, cmd, h, mask, rshift, xor);
+}
+
+static int pmf_parser_write_reg32(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+ u32 value = pmf_next32(cmd);
+ u32 mask = pmf_next32(cmd);
+
+ LOG_PARSE("pmf: write_reg32(offset: %08x, value: %08x, mask: %08x)\n",
+ offset, value, mask);
+
+ PMF_PARSE_CALL(write_reg32, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_read_reg32(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+
+ LOG_PARSE("pmf: read_reg32(offset: %08x)\n", offset);
+
+ PMF_PARSE_CALL(read_reg32, cmd, h, offset);
+}
+
+
+static int pmf_parser_write_reg16(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+ u16 value = (u16)pmf_next32(cmd);
+ u16 mask = (u16)pmf_next32(cmd);
+
+ LOG_PARSE("pmf: write_reg16(offset: %08x, value: %04x, mask: %04x)\n",
+ offset, value, mask);
+
+ PMF_PARSE_CALL(write_reg16, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_read_reg16(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+
+ LOG_PARSE("pmf: read_reg16(offset: %08x)\n", offset);
+
+ PMF_PARSE_CALL(read_reg16, cmd, h, offset);
+}
+
+
+static int pmf_parser_write_reg8(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+ u8 value = (u16)pmf_next32(cmd);
+ u8 mask = (u16)pmf_next32(cmd);
+
+ LOG_PARSE("pmf: write_reg8(offset: %08x, value: %02x, mask: %02x)\n",
+ offset, value, mask);
+
+ PMF_PARSE_CALL(write_reg8, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_read_reg8(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+
+ LOG_PARSE("pmf: read_reg8(offset: %08x)\n", offset);
+
+ PMF_PARSE_CALL(read_reg8, cmd, h, offset);
+}
+
+static int pmf_parser_delay(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u32 duration = pmf_next32(cmd);
+
+ LOG_PARSE("pmf: delay(duration: %d us)\n", duration);
+
+ PMF_PARSE_CALL(delay, cmd, h, duration);
+}
+
+static int pmf_parser_wait_reg32(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+ u32 value = pmf_next32(cmd);
+ u32 mask = pmf_next32(cmd);
+
+ LOG_PARSE("pmf: wait_reg32(offset: %08x, comp_value: %08x,mask: %08x)\n",
+ offset, value, mask);
+
+ PMF_PARSE_CALL(wait_reg32, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_wait_reg16(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+ u16 value = (u16)pmf_next32(cmd);
+ u16 mask = (u16)pmf_next32(cmd);
+
+ LOG_PARSE("pmf: wait_reg16(offset: %08x, comp_value: %04x,mask: %04x)\n",
+ offset, value, mask);
+
+ PMF_PARSE_CALL(wait_reg16, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_wait_reg8(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+ u8 value = (u8)pmf_next32(cmd);
+ u8 mask = (u8)pmf_next32(cmd);
+
+ LOG_PARSE("pmf: wait_reg8(offset: %08x, comp_value: %02x,mask: %02x)\n",
+ offset, value, mask);
+
+ PMF_PARSE_CALL(wait_reg8, cmd, h, offset, value, mask);
+}
+
+static int pmf_parser_read_i2c(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u32 bytes = pmf_next32(cmd);
+
+ LOG_PARSE("pmf: read_i2c(bytes: %ud)\n", bytes);
+
+ PMF_PARSE_CALL(read_i2c, cmd, h, bytes);
+}
+
+static int pmf_parser_write_i2c(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u32 bytes = pmf_next32(cmd);
+ const void *blob = pmf_next_blob(cmd, bytes);
+
+ LOG_PARSE("pmf: write_i2c(bytes: %ud) ...\n", bytes);
+ LOG_BLOB("pmf: data: \n", blob, bytes);
+
+ PMF_PARSE_CALL(write_i2c, cmd, h, bytes, blob);
+}
+
+
+static int pmf_parser_rmw_i2c(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u32 maskbytes = pmf_next32(cmd);
+ u32 valuesbytes = pmf_next32(cmd);
+ u32 totalbytes = pmf_next32(cmd);
+ const void *maskblob = pmf_next_blob(cmd, maskbytes);
+ const void *valuesblob = pmf_next_blob(cmd, valuesbytes);
+
+ LOG_PARSE("pmf: rmw_i2c(maskbytes: %ud, valuebytes: %ud, "
+ "totalbytes: %d) ...\n",
+ maskbytes, valuesbytes, totalbytes);
+ LOG_BLOB("pmf: mask data: \n", maskblob, maskbytes);
+ LOG_BLOB("pmf: values data: \n", valuesblob, valuesbytes);
+
+ PMF_PARSE_CALL(rmw_i2c, cmd, h, maskbytes, valuesbytes, totalbytes,
+ maskblob, valuesblob);
+}
+
+static int pmf_parser_read_cfg(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+ u32 bytes = pmf_next32(cmd);
+
+ LOG_PARSE("pmf: read_cfg(offset: %x, bytes: %ud)\n", offset, bytes);
+
+ PMF_PARSE_CALL(read_cfg, cmd, h, offset, bytes);
+}
+
+
+static int pmf_parser_write_cfg(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+ u32 bytes = pmf_next32(cmd);
+ const void *blob = pmf_next_blob(cmd, bytes);
+
+ LOG_PARSE("pmf: write_cfg(offset: %x, bytes: %ud)\n", offset, bytes);
+ LOG_BLOB("pmf: data: \n", blob, bytes);
+
+ PMF_PARSE_CALL(write_cfg, cmd, h, offset, bytes, blob);
+}
+
+static int pmf_parser_rmw_cfg(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+ u32 maskbytes = pmf_next32(cmd);
+ u32 valuesbytes = pmf_next32(cmd);
+ u32 totalbytes = pmf_next32(cmd);
+ const void *maskblob = pmf_next_blob(cmd, maskbytes);
+ const void *valuesblob = pmf_next_blob(cmd, valuesbytes);
+
+ LOG_PARSE("pmf: rmw_cfg(maskbytes: %ud, valuebytes: %ud,"
+ " totalbytes: %d) ...\n",
+ maskbytes, valuesbytes, totalbytes);
+ LOG_BLOB("pmf: mask data: \n", maskblob, maskbytes);
+ LOG_BLOB("pmf: values data: \n", valuesblob, valuesbytes);
+
+ PMF_PARSE_CALL(rmw_cfg, cmd, h, offset, maskbytes, valuesbytes,
+ totalbytes, maskblob, valuesblob);
+}
+
+
+static int pmf_parser_read_i2c_sub(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u8 subaddr = (u8)pmf_next32(cmd);
+ u32 bytes = pmf_next32(cmd);
+
+ LOG_PARSE("pmf: read_i2c_sub(subaddr: %x, bytes: %ud)\n",
+ subaddr, bytes);
+
+ PMF_PARSE_CALL(read_i2c_sub, cmd, h, subaddr, bytes);
+}
+
+static int pmf_parser_write_i2c_sub(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u8 subaddr = (u8)pmf_next32(cmd);
+ u32 bytes = pmf_next32(cmd);
+ const void *blob = pmf_next_blob(cmd, bytes);
+
+ LOG_PARSE("pmf: write_i2c_sub(subaddr: %x, bytes: %ud) ...\n",
+ subaddr, bytes);
+ LOG_BLOB("pmf: data: \n", blob, bytes);
+
+ PMF_PARSE_CALL(write_i2c_sub, cmd, h, subaddr, bytes, blob);
+}
+
+static int pmf_parser_set_i2c_mode(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u32 mode = pmf_next32(cmd);
+
+ LOG_PARSE("pmf: set_i2c_mode(mode: %d)\n", mode);
+
+ PMF_PARSE_CALL(set_i2c_mode, cmd, h, mode);
+}
+
+
+static int pmf_parser_rmw_i2c_sub(struct pmf_cmd *cmd, struct pmf_handlers *h)
+{
+ u8 subaddr = (u8)pmf_next32(cmd);
+ u32 maskbytes = pmf_next32(cmd);
+ u32 valuesbytes = pmf_next32(cmd);
+ u32 totalbytes = pmf_next32(cmd);
+ const void *maskblob = pmf_next_blob(cmd, maskbytes);
+ const void *valuesblob = pmf_next_blob(cmd, valuesbytes);
+
+ LOG_PARSE("pmf: rmw_i2c_sub(subaddr: %x, maskbytes: %ud, valuebytes: %ud"
+ ", totalbytes: %d) ...\n",
+ subaddr, maskbytes, valuesbytes, totalbytes);
+ LOG_BLOB("pmf: mask data: \n", maskblob, maskbytes);
+ LOG_BLOB("pmf: values data: \n", valuesblob, valuesbytes);
+
+ PMF_PARSE_CALL(rmw_i2c_sub, cmd, h, subaddr, maskbytes, valuesbytes,
+ totalbytes, maskblob, valuesblob);
+}
+
+static int pmf_parser_read_reg32_msrx(struct pmf_cmd *cmd,
+ struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+ u32 mask = pmf_next32(cmd);
+ u32 shift = pmf_next32(cmd);
+ u32 xor = pmf_next32(cmd);
+
+ LOG_PARSE("pmf: read_reg32_msrx(offset: %x, mask: %x, shift: %x,"
+ " xor: %x\n", offset, mask, shift, xor);
+
+ PMF_PARSE_CALL(read_reg32_msrx, cmd, h, offset, mask, shift, xor);
+}
+
+static int pmf_parser_read_reg16_msrx(struct pmf_cmd *cmd,
+ struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+ u32 mask = pmf_next32(cmd);
+ u32 shift = pmf_next32(cmd);
+ u32 xor = pmf_next32(cmd);
+
+ LOG_PARSE("pmf: read_reg16_msrx(offset: %x, mask: %x, shift: %x,"
+ " xor: %x\n", offset, mask, shift, xor);
+
+ PMF_PARSE_CALL(read_reg16_msrx, cmd, h, offset, mask, shift, xor);
+}
+static int pmf_parser_read_reg8_msrx(struct pmf_cmd *cmd,
+ struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+ u32 mask = pmf_next32(cmd);
+ u32 shift = pmf_next32(cmd);
+ u32 xor = pmf_next32(cmd);
+
+ LOG_PARSE("pmf: read_reg8_msrx(offset: %x, mask: %x, shift: %x,"
+ " xor: %x\n", offset, mask, shift, xor);
+
+ PMF_PARSE_CALL(read_reg8_msrx, cmd, h, offset, mask, shift, xor);
+}
+
+static int pmf_parser_write_reg32_slm(struct pmf_cmd *cmd,
+ struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+ u32 shift = pmf_next32(cmd);
+ u32 mask = pmf_next32(cmd);
+
+ LOG_PARSE("pmf: write_reg32_slm(offset: %x, shift: %x, mask: %x\n",
+ offset, shift, mask);
+
+ PMF_PARSE_CALL(write_reg32_slm, cmd, h, offset, shift, mask);
+}
+
+static int pmf_parser_write_reg16_slm(struct pmf_cmd *cmd,
+ struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+ u32 shift = pmf_next32(cmd);
+ u32 mask = pmf_next32(cmd);
+
+ LOG_PARSE("pmf: write_reg16_slm(offset: %x, shift: %x, mask: %x\n",
+ offset, shift, mask);
+
+ PMF_PARSE_CALL(write_reg16_slm, cmd, h, offset, shift, mask);
+}
+
+static int pmf_parser_write_reg8_slm(struct pmf_cmd *cmd,
+ struct pmf_handlers *h)
+{
+ u32 offset = pmf_next32(cmd);
+ u32 shift = pmf_next32(cmd);
+ u32 mask = pmf_next32(cmd);
+
+ LOG_PARSE("pmf: write_reg8_slm(offset: %x, shift: %x, mask: %x\n",
+ offset, shift, mask);
+
+ PMF_PARSE_CALL(write_reg8_slm, cmd, h, offset, shift, mask);
+}
+
+static int pmf_parser_mask_and_compare(struct pmf_cmd *cmd,
+ struct pmf_handlers *h)
+{
+ u32 bytes = pmf_next32(cmd);
+ const void *maskblob = pmf_next_blob(cmd, bytes);
+ const void *valuesblob = pmf_next_blob(cmd, bytes);
+
+ LOG_PARSE("pmf: mask_and_compare(length: %ud ...\n", bytes);
+ LOG_BLOB("pmf: mask data: \n", maskblob, bytes);
+ LOG_BLOB("pmf: values data: \n", valuesblob, bytes);
+
+ PMF_PARSE_CALL(mask_and_compare, cmd, h,
+ bytes, maskblob, valuesblob);
+}
+
+
+typedef int (*pmf_cmd_parser_t)(struct pmf_cmd *cmd, struct pmf_handlers *h);
+
+static pmf_cmd_parser_t pmf_parsers[PMF_CMD_COUNT] =
+{
+ NULL,
+ pmf_parser_write_gpio,
+ pmf_parser_read_gpio,
+ pmf_parser_write_reg32,
+ pmf_parser_read_reg32,
+ pmf_parser_write_reg16,
+ pmf_parser_read_reg16,
+ pmf_parser_write_reg8,
+ pmf_parser_read_reg8,
+ pmf_parser_delay,
+ pmf_parser_wait_reg32,
+ pmf_parser_wait_reg16,
+ pmf_parser_wait_reg8,
+ pmf_parser_read_i2c,
+ pmf_parser_write_i2c,
+ pmf_parser_rmw_i2c,
+ NULL, /* Bogus command */
+ NULL, /* Shift bytes right: NYI */
+ NULL, /* Shift bytes left: NYI */
+ pmf_parser_read_cfg,
+ pmf_parser_write_cfg,
+ pmf_parser_rmw_cfg,
+ pmf_parser_read_i2c_sub,
+ pmf_parser_write_i2c_sub,
+ pmf_parser_set_i2c_mode,
+ pmf_parser_rmw_i2c_sub,
+ pmf_parser_read_reg32_msrx,
+ pmf_parser_read_reg16_msrx,
+ pmf_parser_read_reg8_msrx,
+ pmf_parser_write_reg32_slm,
+ pmf_parser_write_reg16_slm,
+ pmf_parser_write_reg8_slm,
+ pmf_parser_mask_and_compare,
+};
+
+struct pmf_device {
+ struct list_head link;
+ struct device_node *node;
+ struct pmf_handlers *handlers;
+ struct list_head functions;
+ struct kref ref;
+};
+
+static LIST_HEAD(pmf_devices);
+static spinlock_t pmf_lock = SPIN_LOCK_UNLOCKED;
+
+static void pmf_release_device(struct kref *kref)
+{
+ struct pmf_device *dev = container_of(kref, struct pmf_device, ref);
+ kfree(dev);
+}
+
+static inline void pmf_put_device(struct pmf_device *dev)
+{
+ kref_put(&dev->ref, pmf_release_device);
+}
+
+static inline struct pmf_device *pmf_get_device(struct pmf_device *dev)
+{
+ kref_get(&dev->ref);
+ return dev;
+}
+
+static inline struct pmf_device *pmf_find_device(struct device_node *np)
+{
+ struct pmf_device *dev;
+
+ list_for_each_entry(dev, &pmf_devices, link) {
+ if (dev->node == np)
+ return pmf_get_device(dev);
+ }
+ return NULL;
+}
+
+static int pmf_parse_one(struct pmf_function *func,
+ struct pmf_handlers *handlers,
+ void *instdata, struct pmf_args *args)
+{
+ struct pmf_cmd cmd;
+ u32 ccode;
+ int count, rc;
+
+ cmd.cmdptr = func->data;
+ cmd.cmdend = func->data + func->length;
+ cmd.func = func;
+ cmd.instdata = instdata;
+ cmd.args = args;
+ cmd.error = 0;
+
+ LOG_PARSE("pmf: func %s, %d bytes, %s...\n",
+ func->name, func->length,
+ handlers ? "executing" : "parsing");
+
+ /* One subcommand to parse for now */
+ count = 1;
+
+ while(count-- && cmd.cmdptr < cmd.cmdend) {
+ /* Get opcode */
+ ccode = pmf_next32(&cmd);
+ /* Check if we are hitting a command list, fetch new count */
+ if (ccode == 0) {
+ count = pmf_next32(&cmd) - 1;
+ ccode = pmf_next32(&cmd);
+ }
+ if (cmd.error) {
+ LOG_ERROR("pmf: parse error, not enough data\n");
+ return -ENXIO;
+ }
+ if (ccode >= PMF_CMD_COUNT) {
+ LOG_ERROR("pmf: command code %d unknown !\n", ccode);
+ return -ENXIO;
+ }
+ if (pmf_parsers[ccode] == NULL) {
+ LOG_ERROR("pmf: no parser for command %d !\n", ccode);
+ return -ENXIO;
+ }
+ rc = pmf_parsers[ccode](&cmd, handlers);
+ if (rc != 0) {
+ LOG_ERROR("pmf: parser for command %d returned"
+ " error %d\n", ccode, rc);
+ return rc;
+ }
+ }
+
+ /* We are doing an initial parse pass, we need to adjust the size */
+ if (handlers == NULL)
+ func->length = cmd.cmdptr - func->data;
+
+ return 0;
+}
+
+static int pmf_add_function_prop(struct pmf_device *dev, void *driverdata,
+ const char *name, u32 *data,
+ unsigned int length)
+{
+ int count = 0;
+ struct pmf_function *func = NULL;
+
+ DBG("pmf: Adding functions for platform-do-%s\n", name);
+
+ while (length >= 12) {
+ /* Allocate a structure */
+ func = kzalloc(sizeof(struct pmf_function), GFP_KERNEL);
+ if (func == NULL)
+ goto bail;
+ kref_init(&func->ref);
+ INIT_LIST_HEAD(&func->irq_clients);
+ func->node = dev->node;
+ func->driver_data = driverdata;
+ func->name = name;
+ func->phandle = data[0];
+ func->flags = data[1];
+ data += 2;
+ length -= 8;
+ func->data = data;
+ func->length = length;
+ func->dev = dev;
+ DBG("pmf: idx %d: flags=%08x, phandle=%08x "
+ " %d bytes remaining, parsing...\n",
+ count+1, func->flags, func->phandle, length);
+ if (pmf_parse_one(func, NULL, NULL, NULL)) {
+ kfree(func);
+ goto bail;
+ }
+ length -= func->length;
+ data = (u32 *)(((u8 *)data) + func->length);
+ list_add(&func->link, &dev->functions);
+ pmf_get_device(dev);
+ count++;
+ }
+ bail:
+ DBG("pmf: Added %d functions\n", count);
+
+ return count;
+}
+
+static int pmf_add_functions(struct pmf_device *dev, void *driverdata)
+{
+ struct property *pp;
+#define PP_PREFIX "platform-do-"
+ const int plen = strlen(PP_PREFIX);
+ int count = 0;
+
+ for (pp = dev->node->properties; pp != 0; pp = pp->next) {
+ char *name;
+ if (strncmp(pp->name, PP_PREFIX, plen) != 0)
+ continue;
+ name = pp->name + plen;
+ if (strlen(name) && pp->length >= 12)
+ count += pmf_add_function_prop(dev, driverdata, name,
+ (u32 *)pp->value,
+ pp->length);
+ }
+ return count;
+}
+
+
+int pmf_register_driver(struct device_node *np,
+ struct pmf_handlers *handlers,
+ void *driverdata)
+{
+ struct pmf_device *dev;
+ unsigned long flags;
+ int rc = 0;
+
+ if (handlers == NULL)
+ return -EINVAL;
+
+ DBG("pmf: registering driver for node %s\n", np->full_name);
+
+ spin_lock_irqsave(&pmf_lock, flags);
+ dev = pmf_find_device(np);
+ spin_unlock_irqrestore(&pmf_lock, flags);
+ if (dev != NULL) {
+ DBG("pmf: already there !\n");
+ pmf_put_device(dev);
+ return -EBUSY;
+ }
+
+ dev = kzalloc(sizeof(struct pmf_device), GFP_KERNEL);
+ if (dev == NULL) {
+ DBG("pmf: no memory !\n");
+ return -ENOMEM;
+ }
+ kref_init(&dev->ref);
+ dev->node = of_node_get(np);
+ dev->handlers = handlers;
+ INIT_LIST_HEAD(&dev->functions);
+
+ rc = pmf_add_functions(dev, driverdata);
+ if (rc == 0) {
+ DBG("pmf: no functions, disposing.. \n");
+ of_node_put(np);
+ kfree(dev);
+ return -ENODEV;
+ }
+
+ spin_lock_irqsave(&pmf_lock, flags);
+ list_add(&dev->link, &pmf_devices);
+ spin_unlock_irqrestore(&pmf_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pmf_register_driver);
+
+struct pmf_function *pmf_get_function(struct pmf_function *func)
+{
+ if (!try_module_get(func->dev->handlers->owner))
+ return NULL;
+ kref_get(&func->ref);
+ return func;
+}
+EXPORT_SYMBOL_GPL(pmf_get_function);
+
+static void pmf_release_function(struct kref *kref)
+{
+ struct pmf_function *func =
+ container_of(kref, struct pmf_function, ref);
+ pmf_put_device(func->dev);
+ kfree(func);
+}
+
+static inline void __pmf_put_function(struct pmf_function *func)
+{
+ kref_put(&func->ref, pmf_release_function);
+}
+
+void pmf_put_function(struct pmf_function *func)
+{
+ if (func == NULL)
+ return;
+ module_put(func->dev->handlers->owner);
+ __pmf_put_function(func);
+}
+EXPORT_SYMBOL_GPL(pmf_put_function);
+
+void pmf_unregister_driver(struct device_node *np)
+{
+ struct pmf_device *dev;
+ unsigned long flags;
+
+ DBG("pmf: unregistering driver for node %s\n", np->full_name);
+
+ spin_lock_irqsave(&pmf_lock, flags);
+ dev = pmf_find_device(np);
+ if (dev == NULL) {
+ DBG("pmf: not such driver !\n");
+ spin_unlock_irqrestore(&pmf_lock, flags);
+ return;
+ }
+ list_del(&dev->link);
+
+ while(!list_empty(&dev->functions)) {
+ struct pmf_function *func =
+ list_entry(dev->functions.next, typeof(*func), link);
+ list_del(&func->link);
+ __pmf_put_function(func);
+ }
+
+ pmf_put_device(dev);
+ spin_unlock_irqrestore(&pmf_lock, flags);
+}
+EXPORT_SYMBOL_GPL(pmf_unregister_driver);
+
+struct pmf_function *__pmf_find_function(struct device_node *target,
+ const char *name, u32 flags)
+{
+ struct device_node *actor = of_node_get(target);
+ struct pmf_device *dev;
+ struct pmf_function *func, *result = NULL;
+ char fname[64];
+ u32 *prop, ph;
+
+ /*
+ * Look for a "platform-*" function reference. If we can't find
+ * one, then we fallback to a direct call attempt
+ */
+ snprintf(fname, 63, "platform-%s", name);
+ prop = (u32 *)get_property(target, fname, NULL);
+ if (prop == NULL)
+ goto find_it;
+ ph = *prop;
+ if (ph == 0)
+ goto find_it;
+
+ /*
+ * Ok, now try to find the actor. If we can't find it, we fail,
+ * there is no point in falling back there
+ */
+ of_node_put(actor);
+ actor = of_find_node_by_phandle(ph);
+ if (actor == NULL)
+ return NULL;
+ find_it:
+ dev = pmf_find_device(actor);
+ if (dev == NULL)
+ return NULL;
+
+ list_for_each_entry(func, &dev->functions, link) {
+ if (name && strcmp(name, func->name))
+ continue;
+ if (func->phandle && target->node != func->phandle)
+ continue;
+ if ((func->flags & flags) == 0)
+ continue;
+ result = func;
+ break;
+ }
+ of_node_put(actor);
+ pmf_put_device(dev);
+ return result;
+}
+
+
+int pmf_register_irq_client(struct device_node *target,
+ const char *name,
+ struct pmf_irq_client *client)
+{
+ struct pmf_function *func;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pmf_lock, flags);
+ func = __pmf_find_function(target, name, PMF_FLAGS_INT_GEN);
+ if (func == NULL) {
+ spin_unlock_irqrestore(&pmf_lock, flags);
+ return -ENODEV;
+ }
+ list_add(&client->link, &func->irq_clients);
+ spin_unlock_irqrestore(&pmf_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pmf_register_irq_client);
+
+void pmf_unregister_irq_client(struct device_node *np,
+ const char *name,
+ struct pmf_irq_client *client)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pmf_lock, flags);
+ list_del(&client->link);
+ spin_unlock_irqrestore(&pmf_lock, flags);
+}
+EXPORT_SYMBOL_GPL(pmf_unregister_irq_client);
+
+
+void pmf_do_irq(struct pmf_function *func)
+{
+ unsigned long flags;
+ struct pmf_irq_client *client;
+
+ /* For now, using a spinlock over the whole function. Can be made
+ * to drop the lock using 2 lists if necessary
+ */
+ spin_lock_irqsave(&pmf_lock, flags);
+ list_for_each_entry(client, &func->irq_clients, link) {
+ if (!try_module_get(client->owner))
+ continue;
+ client->handler(client->data);
+ module_put(client->owner);
+ }
+ spin_unlock_irqrestore(&pmf_lock, flags);
+}
+EXPORT_SYMBOL_GPL(pmf_do_irq);
+
+
+int pmf_call_one(struct pmf_function *func, struct pmf_args *args)
+{
+ struct pmf_device *dev = func->dev;
+ void *instdata = NULL;
+ int rc = 0;
+
+ DBG(" ** pmf_call_one(%s/%s) **\n", dev->node->full_name, func->name);
+
+ if (dev->handlers->begin)
+ instdata = dev->handlers->begin(func, args);
+ rc = pmf_parse_one(func, dev->handlers, instdata, args);
+ if (dev->handlers->end)
+ dev->handlers->end(func, instdata);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(pmf_call_one);
+
+int pmf_do_functions(struct device_node *np, const char *name,
+ u32 phandle, u32 fflags, struct pmf_args *args)
+{
+ struct pmf_device *dev;
+ struct pmf_function *func, *tmp;
+ unsigned long flags;
+ int rc = -ENODEV;
+
+ spin_lock_irqsave(&pmf_lock, flags);
+
+ dev = pmf_find_device(np);
+ if (dev == NULL) {
+ spin_unlock_irqrestore(&pmf_lock, flags);
+ return -ENODEV;
+ }
+ list_for_each_entry_safe(func, tmp, &dev->functions, link) {
+ if (name && strcmp(name, func->name))
+ continue;
+ if (phandle && func->phandle && phandle != func->phandle)
+ continue;
+ if ((func->flags & fflags) == 0)
+ continue;
+ if (pmf_get_function(func) == NULL)
+ continue;
+ spin_unlock_irqrestore(&pmf_lock, flags);
+ rc = pmf_call_one(func, args);
+ pmf_put_function(func);
+ spin_lock_irqsave(&pmf_lock, flags);
+ }
+ pmf_put_device(dev);
+ spin_unlock_irqrestore(&pmf_lock, flags);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(pmf_do_functions);
+
+
+struct pmf_function *pmf_find_function(struct device_node *target,
+ const char *name)
+{
+ struct pmf_function *func;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pmf_lock, flags);
+ func = __pmf_find_function(target, name, PMF_FLAGS_ON_DEMAND);
+ if (func)
+ func = pmf_get_function(func);
+ spin_unlock_irqrestore(&pmf_lock, flags);
+ return func;
+}
+EXPORT_SYMBOL_GPL(pmf_find_function);
+
+int pmf_call_function(struct device_node *target, const char *name,
+ struct pmf_args *args)
+{
+ struct pmf_function *func = pmf_find_function(target, name);
+ int rc;
+
+ if (func == NULL)
+ return -ENODEV;
+
+ rc = pmf_call_one(func, args);
+ pmf_put_function(func);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(pmf_call_function);
+
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 90040c49494d..18bf3011d1e3 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -5,8 +5,8 @@
* in a separate file
*
* Copyright (C) 1997 Paul Mackerras (paulus@samba.org)
- *
- * Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ * Copyright (C) 2005 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ * IBM, Corp.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -54,12 +54,7 @@ struct pmac_irq_hw {
};
/* Default addresses */
-static volatile struct pmac_irq_hw *pmac_irq_hw[4] = {
- (struct pmac_irq_hw *) 0xf3000020,
- (struct pmac_irq_hw *) 0xf3000010,
- (struct pmac_irq_hw *) 0xf4000020,
- (struct pmac_irq_hw *) 0xf4000010,
-};
+static volatile struct pmac_irq_hw __iomem *pmac_irq_hw[4];
#define GC_LEVEL_MASK 0x3ff00000
#define OHARE_LEVEL_MASK 0x1ff00000
@@ -82,8 +77,7 @@ static unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
* since it can lose interrupts (see pmac_set_irq_mask).
* -- Cort
*/
-void
-__set_lost(unsigned long irq_nr, int nokick)
+void __set_lost(unsigned long irq_nr, int nokick)
{
if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
atomic_inc(&ppc_n_lost_interrupts);
@@ -92,8 +86,7 @@ __set_lost(unsigned long irq_nr, int nokick)
}
}
-static void
-pmac_mask_and_ack_irq(unsigned int irq_nr)
+static void pmac_mask_and_ack_irq(unsigned int irq_nr)
{
unsigned long bit = 1UL << (irq_nr & 0x1f);
int i = irq_nr >> 5;
@@ -224,8 +217,7 @@ static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
return IRQ_NONE;
}
-int
-pmac_get_irq(struct pt_regs *regs)
+static int pmac_get_irq(struct pt_regs *regs)
{
int irq;
unsigned long bits = 0;
@@ -256,34 +248,40 @@ pmac_get_irq(struct pt_regs *regs)
/* This routine will fix some missing interrupt values in the device tree
* on the gatwick mac-io controller used by some PowerBooks
+ *
+ * Walking of OF nodes could use a bit more fixing up here, but it's not
+ * very important as this is all boot time code on static portions of the
+ * device-tree.
+ *
+ * However, the modifications done to "intrs" will have to be removed and
+ * replaced with proper updates of the "interrupts" properties or
+ * AAPL,interrupts, yet to be decided, once the dynamic parsing is there.
*/
-static void __init
-pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
+static void __init pmac_fix_gatwick_interrupts(struct device_node *gw,
+ int irq_base)
{
struct device_node *node;
int count;
memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool));
- node = gw->child;
count = 0;
- while(node)
- {
+ for (node = NULL; (node = of_get_next_child(gw, node)) != NULL;) {
/* Fix SCC */
- if (strcasecmp(node->name, "escc") == 0)
- if (node->child) {
- if (node->child->n_intrs < 3) {
- node->child->intrs = &gatwick_int_pool[count];
- count += 3;
- }
- node->child->n_intrs = 3;
- node->child->intrs[0].line = 15+irq_base;
- node->child->intrs[1].line = 4+irq_base;
- node->child->intrs[2].line = 5+irq_base;
- printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n",
- node->child->intrs[0].line,
- node->child->intrs[1].line,
- node->child->intrs[2].line);
+ if ((strcasecmp(node->name, "escc") == 0) && node->child) {
+ if (node->child->n_intrs < 3) {
+ node->child->intrs = &gatwick_int_pool[count];
+ count += 3;
}
+ node->child->n_intrs = 3;
+ node->child->intrs[0].line = 15+irq_base;
+ node->child->intrs[1].line = 4+irq_base;
+ node->child->intrs[2].line = 5+irq_base;
+ printk(KERN_INFO "irq: fixed SCC on gatwick"
+ " (%d,%d,%d)\n",
+ node->child->intrs[0].line,
+ node->child->intrs[1].line,
+ node->child->intrs[2].line);
+ }
/* Fix media-bay & left SWIM */
if (strcasecmp(node->name, "media-bay") == 0) {
struct device_node* ya_node;
@@ -292,12 +290,11 @@ pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
node->intrs = &gatwick_int_pool[count++];
node->n_intrs = 1;
node->intrs[0].line = 29+irq_base;
- printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
- node->intrs[0].line);
+ printk(KERN_INFO "irq: fixed media-bay on gatwick"
+ " (%d)\n", node->intrs[0].line);
ya_node = node->child;
- while(ya_node)
- {
+ while(ya_node) {
if (strcasecmp(ya_node->name, "floppy") == 0) {
if (ya_node->n_intrs < 2) {
ya_node->intrs = &gatwick_int_pool[count];
@@ -323,7 +320,6 @@ pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
ya_node = ya_node->sibling;
}
}
- node = node->sibling;
}
if (count > 10) {
printk("WARNING !! Gatwick interrupt pool overflow\n");
@@ -338,45 +334,41 @@ pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
* controller. If we find this second ohare, set it up and fix the
* interrupt value in the device tree for the ethernet chip.
*/
-static int __init enable_second_ohare(void)
+static void __init enable_second_ohare(struct device_node *np)
{
unsigned char bus, devfn;
unsigned short cmd;
- unsigned long addr;
- struct device_node *irqctrler = find_devices("pci106b,7");
struct device_node *ether;
- if (irqctrler == NULL || irqctrler->n_addrs <= 0)
- return -1;
- addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40);
- pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20);
- max_irqs = 64;
- if (pci_device_from_OF_node(irqctrler, &bus, &devfn) == 0) {
- struct pci_controller* hose = pci_find_hose_for_OF_device(irqctrler);
- if (!hose)
- printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
- else {
- early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
- cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
- cmd &= ~PCI_COMMAND_IO;
- early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
+ /* This code doesn't strictly belong here, it could be part of
+ * either the PCI initialisation or the feature code. It's kept
+ * here for historical reasons.
+ */
+ if (pci_device_from_OF_node(np, &bus, &devfn) == 0) {
+ struct pci_controller* hose =
+ pci_find_hose_for_OF_device(np);
+ if (!hose) {
+ printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
+ return;
}
+ early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ cmd &= ~PCI_COMMAND_IO;
+ early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
}
/* Fix interrupt for the modem/ethernet combo controller. The number
- in the device tree (27) is bogus (correct for the ethernet-only
- board but not the combo ethernet/modem board).
- The real interrupt is 28 on the second controller -> 28+32 = 60.
- */
- ether = find_devices("pci1011,14");
+ * in the device tree (27) is bogus (correct for the ethernet-only
+ * board but not the combo ethernet/modem board).
+ * The real interrupt is 28 on the second controller -> 28+32 = 60.
+ */
+ ether = of_find_node_by_name(NULL, "pci1011,14");
if (ether && ether->n_intrs > 0) {
ether->intrs[0].line = 60;
printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n",
ether->intrs[0].line);
}
-
- /* Return the interrupt number of the cascade */
- return irqctrler->intrs[0].line;
+ of_node_put(ether);
}
#ifdef CONFIG_XMON
@@ -394,189 +386,251 @@ static struct irqaction gatwick_cascade_action = {
.mask = CPU_MASK_NONE,
.name = "cascade",
};
-#endif /* CONFIG_PPC32 */
-static int pmac_u3_cascade(struct pt_regs *regs, void *data)
+static void __init pmac_pic_probe_oldstyle(void)
{
- return mpic_get_one_irq((struct mpic *)data, regs);
-}
-
-void __init pmac_pic_init(void)
-{
- struct device_node *irqctrler = NULL;
- struct device_node *irqctrler2 = NULL;
- struct device_node *np;
-#ifdef CONFIG_PPC32
int i;
- unsigned long addr;
int irq_cascade = -1;
-#endif
- struct mpic *mpic1, *mpic2;
+ struct device_node *master = NULL;
+ struct device_node *slave = NULL;
+ u8 __iomem *addr;
+ struct resource r;
- /* We first try to detect Apple's new Core99 chipset, since mac-io
- * is quite different on those machines and contains an IBM MPIC2.
- */
- np = find_type_devices("open-pic");
- while (np) {
- if (np->parent && !strcmp(np->parent->name, "u3"))
- irqctrler2 = np;
- else
- irqctrler = np;
- np = np->next;
- }
- if (irqctrler != NULL && irqctrler->n_addrs > 0) {
- unsigned char senses[128];
-
- printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n",
- (unsigned int)irqctrler->addrs[0].address);
- pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0);
-
- prom_get_irq_senses(senses, 0, 128);
- mpic1 = mpic_alloc(irqctrler->addrs[0].address,
- MPIC_PRIMARY | MPIC_WANTS_RESET,
- 0, 0, 128, 252, senses, 128, " OpenPIC ");
- BUG_ON(mpic1 == NULL);
- mpic_init(mpic1);
-
- if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 &&
- irqctrler2->n_addrs > 0) {
- printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n",
- (u32)irqctrler2->addrs[0].address,
- irqctrler2->intrs[0].line);
-
- pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0);
- prom_get_irq_senses(senses, 128, 128 + 124);
-
- /* We don't need to set MPIC_BROKEN_U3 here since we don't have
- * hypertransport interrupts routed to it
- */
- mpic2 = mpic_alloc(irqctrler2->addrs[0].address,
- MPIC_BIG_ENDIAN | MPIC_WANTS_RESET,
- 0, 128, 124, 0, senses, 124,
- " U3-MPIC ");
- BUG_ON(mpic2 == NULL);
- mpic_init(mpic2);
- mpic_setup_cascade(irqctrler2->intrs[0].line,
- pmac_u3_cascade, mpic2);
- }
-#if defined(CONFIG_XMON) && defined(CONFIG_PPC32)
- {
- struct device_node* pswitch;
- int nmi_irq;
-
- pswitch = find_devices("programmer-switch");
- if (pswitch && pswitch->n_intrs) {
- nmi_irq = pswitch->intrs[0].line;
- mpic_irq_set_priority(nmi_irq, 9);
- setup_irq(nmi_irq, &xmon_action);
- }
- }
-#endif /* CONFIG_XMON */
- return;
- }
- irqctrler = NULL;
+ /* Set our get_irq function */
+ ppc_md.get_irq = pmac_get_irq;
-#ifdef CONFIG_PPC32
- /* Get the level/edge settings, assume if it's not
- * a Grand Central nor an OHare, then it's an Heathrow
- * (or Paddington).
+ /*
+ * Find the interrupt controller type & node
*/
- ppc_md.get_irq = pmac_get_irq;
- if (find_devices("gc"))
+
+ if ((master = of_find_node_by_name(NULL, "gc")) != NULL) {
+ max_irqs = max_real_irqs = 32;
level_mask[0] = GC_LEVEL_MASK;
- else if (find_devices("ohare")) {
+ } else if ((master = of_find_node_by_name(NULL, "ohare")) != NULL) {
+ max_irqs = max_real_irqs = 32;
level_mask[0] = OHARE_LEVEL_MASK;
+
/* We might have a second cascaded ohare */
- level_mask[1] = OHARE_LEVEL_MASK;
- } else {
+ slave = of_find_node_by_name(NULL, "pci106b,7");
+ if (slave) {
+ max_irqs = 64;
+ level_mask[1] = OHARE_LEVEL_MASK;
+ enable_second_ohare(slave);
+ }
+ } else if ((master = of_find_node_by_name(NULL, "mac-io")) != NULL) {
+ max_irqs = max_real_irqs = 64;
level_mask[0] = HEATHROW_LEVEL_MASK;
level_mask[1] = 0;
+
/* We might have a second cascaded heathrow */
- level_mask[2] = HEATHROW_LEVEL_MASK;
- level_mask[3] = 0;
- }
+ slave = of_find_node_by_name(master, "mac-io");
+
+ /* Check ordering of master & slave */
+ if (device_is_compatible(master, "gatwick")) {
+ struct device_node *tmp;
+ BUG_ON(slave == NULL);
+ tmp = master;
+ master = slave;
+ slave = tmp;
+ }
- /*
- * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
- * 1998 G3 Series PowerBooks have 128,
- * other powermacs have 32.
- * The combo ethernet/modem card for the Powerstar powerbooks
- * (2400/3400/3500, ohare based) has a second ohare chip
- * effectively making a total of 64.
- */
- max_irqs = max_real_irqs = 32;
- irqctrler = find_devices("mac-io");
- if (irqctrler)
- {
- max_real_irqs = 64;
- if (irqctrler->next)
+ /* We found a slave */
+ if (slave) {
max_irqs = 128;
- else
- max_irqs = 64;
+ level_mask[2] = HEATHROW_LEVEL_MASK;
+ level_mask[3] = 0;
+ pmac_fix_gatwick_interrupts(slave, max_real_irqs);
+ }
}
+ BUG_ON(master == NULL);
+
+ /* Set the handler for the main PIC */
for ( i = 0; i < max_real_irqs ; i++ )
irq_desc[i].handler = &pmac_pic;
- /* get addresses of first controller */
- if (irqctrler) {
- if (irqctrler->n_addrs > 0) {
- addr = (unsigned long)
- ioremap(irqctrler->addrs[0].address, 0x40);
- for (i = 0; i < 2; ++i)
- pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
- (addr + (2 - i) * 0x10);
- }
+ /* Get addresses of first controller if we have a node for it */
+ BUG_ON(of_address_to_resource(master, 0, &r));
- /* get addresses of second controller */
- irqctrler = irqctrler->next;
- if (irqctrler && irqctrler->n_addrs > 0) {
- addr = (unsigned long)
- ioremap(irqctrler->addrs[0].address, 0x40);
- for (i = 2; i < 4; ++i)
- pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
- (addr + (4 - i) * 0x10);
- irq_cascade = irqctrler->intrs[0].line;
- if (device_is_compatible(irqctrler, "gatwick"))
- pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
- }
- } else {
- /* older powermacs have a GC (grand central) or ohare at
- f3000000, with interrupt control registers at f3000020. */
- addr = (unsigned long) ioremap(0xf3000000, 0x40);
- pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20);
+ /* Map interrupts of primary controller */
+ addr = (u8 __iomem *) ioremap(r.start, 0x40);
+ i = 0;
+ pmac_irq_hw[i++] = (volatile struct pmac_irq_hw __iomem *)
+ (addr + 0x20);
+ if (max_real_irqs > 32)
+ pmac_irq_hw[i++] = (volatile struct pmac_irq_hw __iomem *)
+ (addr + 0x10);
+ of_node_put(master);
+
+ printk(KERN_INFO "irq: Found primary Apple PIC %s for %d irqs\n",
+ master->full_name, max_real_irqs);
+
+ /* Map interrupts of cascaded controller */
+ if (slave && !of_address_to_resource(slave, 0, &r)) {
+ addr = (u8 __iomem *)ioremap(r.start, 0x40);
+ pmac_irq_hw[i++] = (volatile struct pmac_irq_hw __iomem *)
+ (addr + 0x20);
+ if (max_irqs > 64)
+ pmac_irq_hw[i++] =
+ (volatile struct pmac_irq_hw __iomem *)
+ (addr + 0x10);
+ irq_cascade = slave->intrs[0].line;
+
+ printk(KERN_INFO "irq: Found slave Apple PIC %s for %d irqs"
+ " cascade: %d\n", slave->full_name,
+ max_irqs - max_real_irqs, irq_cascade);
}
-
- /* PowerBooks 3400 and 3500 can have a second controller in a second
- ohare chip, on the combo ethernet/modem card */
- if (machine_is_compatible("AAPL,3400/2400")
- || machine_is_compatible("AAPL,3500"))
- irq_cascade = enable_second_ohare();
+ of_node_put(slave);
/* disable all interrupts in all controllers */
for (i = 0; i * 32 < max_irqs; ++i)
out_le32(&pmac_irq_hw[i]->enable, 0);
+
/* mark level interrupts */
for (i = 0; i < max_irqs; i++)
if (level_mask[i >> 5] & (1UL << (i & 0x1f)))
irq_desc[i].status = IRQ_LEVEL;
- /* get interrupt line of secondary interrupt controller */
- if (irq_cascade >= 0) {
- printk(KERN_INFO "irq: secondary controller on irq %d\n",
- (int)irq_cascade);
+ /* Setup handlers for secondary controller and hook cascade irq*/
+ if (slave) {
for ( i = max_real_irqs ; i < max_irqs ; i++ )
irq_desc[i].handler = &gatwick_pic;
setup_irq(irq_cascade, &gatwick_cascade_action);
}
- printk("System has %d possible interrupts\n", max_irqs);
- if (max_irqs != max_real_irqs)
- printk(KERN_DEBUG "%d interrupts on main controller\n",
- max_real_irqs);
-
+ printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs);
#ifdef CONFIG_XMON
setup_irq(20, &xmon_action);
-#endif /* CONFIG_XMON */
-#endif /* CONFIG_PPC32 */
+#endif
+}
+#endif /* CONFIG_PPC32 */
+
+static int pmac_u3_cascade(struct pt_regs *regs, void *data)
+{
+ return mpic_get_one_irq((struct mpic *)data, regs);
+}
+
+static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic)
+{
+#if defined(CONFIG_XMON) && defined(CONFIG_PPC32)
+ struct device_node* pswitch;
+ int nmi_irq;
+
+ pswitch = of_find_node_by_name(NULL, "programmer-switch");
+ if (pswitch && pswitch->n_intrs) {
+ nmi_irq = pswitch->intrs[0].line;
+ mpic_irq_set_priority(nmi_irq, 9);
+ setup_irq(nmi_irq, &xmon_action);
+ }
+ of_node_put(pswitch);
+#endif /* defined(CONFIG_XMON) && defined(CONFIG_PPC32) */
+}
+
+static struct mpic * __init pmac_setup_one_mpic(struct device_node *np,
+ int master)
+{
+ unsigned char senses[128];
+ int offset = master ? 0 : 128;
+ int count = master ? 128 : 124;
+ const char *name = master ? " MPIC 1 " : " MPIC 2 ";
+ struct resource r;
+ struct mpic *mpic;
+ unsigned int flags = master ? MPIC_PRIMARY : 0;
+ int rc;
+
+ rc = of_address_to_resource(np, 0, &r);
+ if (rc)
+ return NULL;
+
+ pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0);
+
+ prom_get_irq_senses(senses, offset, offset + count);
+
+ flags |= MPIC_WANTS_RESET;
+ if (get_property(np, "big-endian", NULL))
+ flags |= MPIC_BIG_ENDIAN;
+
+ /* Primary Big Endian means HT interrupts. This is quite dodgy
+ * but works until I find a better way
+ */
+ if (master && (flags & MPIC_BIG_ENDIAN))
+ flags |= MPIC_BROKEN_U3;
+
+ mpic = mpic_alloc(r.start, flags, 0, offset, count, master ? 252 : 0,
+ senses, count, name);
+ if (mpic == NULL)
+ return NULL;
+
+ mpic_init(mpic);
+
+ return mpic;
+ }
+
+static int __init pmac_pic_probe_mpic(void)
+{
+ struct mpic *mpic1, *mpic2;
+ struct device_node *np, *master = NULL, *slave = NULL;
+
+ /* We can have up to 2 MPICs cascaded */
+ for (np = NULL; (np = of_find_node_by_type(np, "open-pic"))
+ != NULL;) {
+ if (master == NULL &&
+ get_property(np, "interrupts", NULL) == NULL)
+ master = of_node_get(np);
+ else if (slave == NULL)
+ slave = of_node_get(np);
+ if (master && slave)
+ break;
+ }
+
+ /* Check for bogus setups */
+ if (master == NULL && slave != NULL) {
+ master = slave;
+ slave = NULL;
+ }
+
+ /* Not found, default to good old pmac pic */
+ if (master == NULL)
+ return -ENODEV;
+
+ /* Set master handler */
+ ppc_md.get_irq = mpic_get_irq;
+
+ /* Setup master */
+ mpic1 = pmac_setup_one_mpic(master, 1);
+ BUG_ON(mpic1 == NULL);
+
+ /* Install NMI if any */
+ pmac_pic_setup_mpic_nmi(mpic1);
+
+ of_node_put(master);
+
+ /* No slave, let's go out */
+ if (slave == NULL || slave->n_intrs < 1)
+ return 0;
+
+ mpic2 = pmac_setup_one_mpic(slave, 0);
+ if (mpic2 == NULL) {
+ printk(KERN_ERR "Failed to setup slave MPIC\n");
+ of_node_put(slave);
+ return 0;
+ }
+ mpic_setup_cascade(slave->intrs[0].line, pmac_u3_cascade, mpic2);
+
+ of_node_put(slave);
+ return 0;
+}
+
+
+void __init pmac_pic_init(void)
+{
+ /* We first try to detect Apple's new Core99 chipset, since mac-io
+ * is quite different on those machines and contains an IBM MPIC2.
+ */
+ if (pmac_pic_probe_mpic() == 0)
+ return;
+
+#ifdef CONFIG_PPC32
+ pmac_pic_probe_oldstyle();
+#endif
}
#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
diff --git a/arch/powerpc/platforms/powermac/pmac.h b/arch/powerpc/platforms/powermac/pmac.h
index 2ad25e13423e..21c7b0f8f329 100644
--- a/arch/powerpc/platforms/powermac/pmac.h
+++ b/arch/powerpc/platforms/powermac/pmac.h
@@ -42,10 +42,6 @@ extern void pmac_ide_init_hwif_ports(hw_regs_t *hw,
unsigned long data_port, unsigned long ctrl_port, int *irq);
extern int pmac_nvram_init(void);
-
-extern struct hw_interrupt_type pmac_pic;
-
-void pmac_pic_init(void);
-int pmac_get_irq(struct pt_regs *regs);
+extern void pmac_pic_init(void);
#endif /* __PMAC_H__ */
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 7acb0546671f..3b1a9d4fcbc6 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -60,6 +60,7 @@
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/io.h>
+#include <asm/kexec.h>
#include <asm/pci-bridge.h>
#include <asm/ohare.h>
#include <asm/mediabay.h>
@@ -74,8 +75,8 @@
#include <asm/iommu.h>
#include <asm/smu.h>
#include <asm/pmc.h>
-#include <asm/mpic.h>
#include <asm/lmb.h>
+#include <asm/udbg.h>
#include "pmac.h"
@@ -321,16 +322,6 @@ void __init pmac_setup_arch(void)
l2cr_init();
#endif /* CONFIG_PPC32 */
-#ifdef CONFIG_PPC64
- /* Probe motherboard chipset */
- /* this is done earlier in setup_arch for 32-bit */
- pmac_feature_init();
-
- /* We can NAP */
- powersave_nap = 1;
- printk(KERN_INFO "Using native/NAP idle loop\n");
-#endif
-
#ifdef CONFIG_KGDB
zs_kgdb_hook(0);
#endif
@@ -354,7 +345,7 @@ void __init pmac_setup_arch(void)
#ifdef CONFIG_SMP
/* Check for Core99 */
- if (find_devices("uni-n") || find_devices("u3"))
+ if (find_devices("uni-n") || find_devices("u3") || find_devices("u4"))
smp_ops = &core99_smp_ops;
#ifdef CONFIG_PPC32
else
@@ -621,35 +612,31 @@ static void __init pmac_init_early(void)
* and call ioremap
*/
hpte_init_native();
+#endif
- /* Init SCC */
- if (strstr(cmd_line, "sccdbg")) {
- sccdbg = 1;
- udbg_init_scc(NULL);
+ /* Enable early btext debug if requested */
+ if (strstr(cmd_line, "btextdbg")) {
+ udbg_adb_init_early();
+ register_early_udbg_console();
}
- /* Setup interrupt mapping options */
- ppc64_interrupt_controller = IC_OPEN_PIC;
+ /* Probe motherboard chipset */
+ pmac_feature_init();
- iommu_init_early_u3();
-#endif
-}
+ /* We can NAP */
+ powersave_nap = 1;
+ printk(KERN_INFO "Using native/NAP idle loop\n");
+
+ /* Initialize debug stuff */
+ udbg_scc_init(!!strstr(cmd_line, "sccdbg"));
+ udbg_adb_init(!!strstr(cmd_line, "btextdbg"));
-static void __init pmac_progress(char *s, unsigned short hex)
-{
#ifdef CONFIG_PPC64
- if (sccdbg) {
- udbg_puts(s);
- udbg_puts("\n");
- return;
- }
+ /* Setup interrupt mapping options */
+ ppc64_interrupt_controller = IC_OPEN_PIC;
+
+ iommu_init_early_dart();
#endif
-#ifdef CONFIG_BOOTX_TEXT
- if (boot_text_mapped) {
- btext_drawstring(s);
- btext_drawchar('\n');
- }
-#endif /* CONFIG_BOOTX_TEXT */
}
/*
@@ -663,35 +650,14 @@ static int pmac_check_legacy_ioport(unsigned int baseport)
static int __init pmac_declare_of_platform_devices(void)
{
- struct device_node *np, *npp;
-
- np = find_devices("uni-n");
- if (np) {
- for (np = np->child; np != NULL; np = np->sibling)
- if (strncmp(np->name, "i2c", 3) == 0) {
- of_platform_device_create(np, "uni-n-i2c",
- NULL);
- break;
- }
- }
- np = find_devices("valkyrie");
+ struct device_node *np;
+
+ np = of_find_node_by_name(NULL, "valkyrie");
if (np)
of_platform_device_create(np, "valkyrie", NULL);
- np = find_devices("platinum");
+ np = of_find_node_by_name(NULL, "platinum");
if (np)
of_platform_device_create(np, "platinum", NULL);
-
- npp = of_find_node_by_name(NULL, "u3");
- if (npp) {
- for (np = NULL; (np = of_get_next_child(npp, np)) != NULL;) {
- if (strncmp(np->name, "i2c", 3) == 0) {
- of_platform_device_create(np, "u3-i2c", NULL);
- of_node_put(np);
- break;
- }
- }
- of_node_put(npp);
- }
np = of_find_node_by_type(NULL, "smu");
if (np) {
of_platform_device_create(np, "smu", NULL);
@@ -718,7 +684,7 @@ static int __init pmac_probe(int platform)
* occupies having to be broken up so the DART itself is not
* part of the cacheable linar mapping
*/
- alloc_u3_dart_table();
+ alloc_dart_table();
#endif
#ifdef CONFIG_PMAC_SMU
@@ -734,15 +700,17 @@ static int __init pmac_probe(int platform)
}
#ifdef CONFIG_PPC64
-static int pmac_probe_mode(struct pci_bus *bus)
+/* Move that to pci.c */
+static int pmac_pci_probe_mode(struct pci_bus *bus)
{
struct device_node *node = bus->sysdata;
/* We need to use normal PCI probing for the AGP bus,
- since the device for the AGP bridge isn't in the tree. */
- if (bus->self == NULL && device_is_compatible(node, "u3-agp"))
+ * since the device for the AGP bridge isn't in the tree.
+ */
+ if (bus->self == NULL && (device_is_compatible(node, "u3-agp") ||
+ device_is_compatible(node, "u4-pcie")))
return PCI_PROBE_NORMAL;
-
return PCI_PROBE_DEVTREE;
}
#endif
@@ -756,7 +724,7 @@ struct machdep_calls __initdata pmac_md = {
.init_early = pmac_init_early,
.show_cpuinfo = pmac_show_cpuinfo,
.init_IRQ = pmac_pic_init,
- .get_irq = mpic_get_irq, /* changed later */
+ .get_irq = NULL, /* changed later */
.pcibios_fixup = pmac_pcibios_fixup,
.restart = pmac_restart,
.power_off = pmac_power_off,
@@ -768,12 +736,17 @@ struct machdep_calls __initdata pmac_md = {
.calibrate_decr = pmac_calibrate_decr,
.feature_call = pmac_do_feature_call,
.check_legacy_ioport = pmac_check_legacy_ioport,
- .progress = pmac_progress,
+ .progress = udbg_progress,
#ifdef CONFIG_PPC64
- .pci_probe_mode = pmac_probe_mode,
+ .pci_probe_mode = pmac_pci_probe_mode,
.idle_loop = native_idle,
.enable_pmcs = power4_enable_pmcs,
+#ifdef CONFIG_KEXEC
+ .machine_kexec = default_machine_kexec,
+ .machine_kexec_prepare = default_machine_kexec_prepare,
+ .machine_crash_shutdown = default_machine_crash_shutdown,
#endif
+#endif /* CONFIG_PPC64 */
#ifdef CONFIG_PPC32
.pcibios_enable_device_hook = pmac_pci_enable_device_hook,
.pcibios_after_init = pmac_pcibios_after_init,
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index fb2a7c798e82..0df2cdcd805c 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -52,8 +52,9 @@
#include <asm/cacheflush.h>
#include <asm/keylargo.h>
#include <asm/pmac_low_i2c.h>
+#include <asm/pmac_pfunc.h>
-#undef DEBUG
+#define DEBUG
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
@@ -62,6 +63,7 @@
#endif
extern void __secondary_start_pmac_0(void);
+extern int pmac_pfunc_base_install(void);
#ifdef CONFIG_PPC32
@@ -361,7 +363,6 @@ static void __init psurge_dual_sync_tb(int cpu_nr)
set_dec(tb_ticks_per_jiffy);
/* XXX fixme */
set_tb(0, 0);
- last_jiffy_stamp(cpu_nr) = 0;
if (cpu_nr > 0) {
mb();
@@ -429,15 +430,62 @@ struct smp_ops_t psurge_smp_ops = {
};
#endif /* CONFIG_PPC32 - actually powersurge support */
+/*
+ * Core 99 and later support
+ */
+
+static void (*pmac_tb_freeze)(int freeze);
+static unsigned long timebase;
+static int tb_req;
+
+static void smp_core99_give_timebase(void)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ while(!tb_req)
+ barrier();
+ tb_req = 0;
+ (*pmac_tb_freeze)(1);
+ mb();
+ timebase = get_tb();
+ mb();
+ while (timebase)
+ barrier();
+ mb();
+ (*pmac_tb_freeze)(0);
+ mb();
+
+ local_irq_restore(flags);
+}
+
+
+static void __devinit smp_core99_take_timebase(void)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ tb_req = 1;
+ mb();
+ while (!timebase)
+ barrier();
+ mb();
+ set_tb(timebase >> 32, timebase & 0xffffffff);
+ timebase = 0;
+ mb();
+ set_dec(tb_ticks_per_jiffy/2);
+
+ local_irq_restore(flags);
+}
+
#ifdef CONFIG_PPC64
/*
* G5s enable/disable the timebase via an i2c-connected clock chip.
*/
-static struct device_node *pmac_tb_clock_chip_host;
+static struct pmac_i2c_bus *pmac_tb_clock_chip_host;
static u8 pmac_tb_pulsar_addr;
-static void (*pmac_tb_freeze)(int freeze);
-static DEFINE_SPINLOCK(timebase_lock);
-static unsigned long timebase;
static void smp_core99_cypress_tb_freeze(int freeze)
{
@@ -447,19 +495,20 @@ static void smp_core99_cypress_tb_freeze(int freeze)
/* Strangely, the device-tree says address is 0xd2, but darwin
* accesses 0xd0 ...
*/
- pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined);
- rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
- 0xd0 | pmac_low_i2c_read,
- 0x81, &data, 1);
+ pmac_i2c_setmode(pmac_tb_clock_chip_host,
+ pmac_i2c_mode_combined);
+ rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
+ 0xd0 | pmac_i2c_read,
+ 1, 0x81, &data, 1);
if (rc != 0)
goto bail;
data = (data & 0xf3) | (freeze ? 0x00 : 0x0c);
- pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub);
- rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
- 0xd0 | pmac_low_i2c_write,
- 0x81, &data, 1);
+ pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub);
+ rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
+ 0xd0 | pmac_i2c_write,
+ 1, 0x81, &data, 1);
bail:
if (rc != 0) {
@@ -475,19 +524,20 @@ static void smp_core99_pulsar_tb_freeze(int freeze)
u8 data;
int rc;
- pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined);
- rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
- pmac_tb_pulsar_addr | pmac_low_i2c_read,
- 0x2e, &data, 1);
+ pmac_i2c_setmode(pmac_tb_clock_chip_host,
+ pmac_i2c_mode_combined);
+ rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
+ pmac_tb_pulsar_addr | pmac_i2c_read,
+ 1, 0x2e, &data, 1);
if (rc != 0)
goto bail;
data = (data & 0x88) | (freeze ? 0x11 : 0x22);
- pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub);
- rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
- pmac_tb_pulsar_addr | pmac_low_i2c_write,
- 0x2e, &data, 1);
+ pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub);
+ rc = pmac_i2c_xfer(pmac_tb_clock_chip_host,
+ pmac_tb_pulsar_addr | pmac_i2c_write,
+ 1, 0x2e, &data, 1);
bail:
if (rc != 0) {
printk(KERN_ERR "Pulsar Timebase %s rc: %d\n",
@@ -496,54 +546,14 @@ static void smp_core99_pulsar_tb_freeze(int freeze)
}
}
-
-static void smp_core99_give_timebase(void)
-{
- /* Open i2c bus for synchronous access */
- if (pmac_low_i2c_open(pmac_tb_clock_chip_host, 0))
- panic("Can't open i2c for TB sync !\n");
-
- spin_lock(&timebase_lock);
- (*pmac_tb_freeze)(1);
- mb();
- timebase = get_tb();
- spin_unlock(&timebase_lock);
-
- while (timebase)
- barrier();
-
- spin_lock(&timebase_lock);
- (*pmac_tb_freeze)(0);
- spin_unlock(&timebase_lock);
-
- /* Close i2c bus */
- pmac_low_i2c_close(pmac_tb_clock_chip_host);
-}
-
-
-static void __devinit smp_core99_take_timebase(void)
-{
- while (!timebase)
- barrier();
- spin_lock(&timebase_lock);
- set_tb(timebase >> 32, timebase & 0xffffffff);
- timebase = 0;
- spin_unlock(&timebase_lock);
-}
-
-static void __init smp_core99_setup(int ncpus)
+static void __init smp_core99_setup_i2c_hwsync(int ncpus)
{
struct device_node *cc = NULL;
struct device_node *p;
+ const char *name = NULL;
u32 *reg;
int ok;
- /* HW sync only on these platforms */
- if (!machine_is_compatible("PowerMac7,2") &&
- !machine_is_compatible("PowerMac7,3") &&
- !machine_is_compatible("RackMac3,1"))
- return;
-
/* Look for the clock chip */
while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) {
p = of_get_parent(cc);
@@ -552,124 +562,86 @@ static void __init smp_core99_setup(int ncpus)
if (!ok)
continue;
+ pmac_tb_clock_chip_host = pmac_i2c_find_bus(cc);
+ if (pmac_tb_clock_chip_host == NULL)
+ continue;
reg = (u32 *)get_property(cc, "reg", NULL);
if (reg == NULL)
continue;
-
switch (*reg) {
case 0xd2:
- if (device_is_compatible(cc, "pulsar-legacy-slewing")) {
+ if (device_is_compatible(cc,"pulsar-legacy-slewing")) {
pmac_tb_freeze = smp_core99_pulsar_tb_freeze;
pmac_tb_pulsar_addr = 0xd2;
- printk(KERN_INFO "Timebase clock is Pulsar chip\n");
+ name = "Pulsar";
} else if (device_is_compatible(cc, "cy28508")) {
pmac_tb_freeze = smp_core99_cypress_tb_freeze;
- printk(KERN_INFO "Timebase clock is Cypress chip\n");
+ name = "Cypress";
}
break;
case 0xd4:
pmac_tb_freeze = smp_core99_pulsar_tb_freeze;
pmac_tb_pulsar_addr = 0xd4;
- printk(KERN_INFO "Timebase clock is Pulsar chip\n");
+ name = "Pulsar";
break;
}
- if (pmac_tb_freeze != NULL) {
- pmac_tb_clock_chip_host = of_get_parent(cc);
- of_node_put(cc);
+ if (pmac_tb_freeze != NULL)
break;
- }
}
- if (pmac_tb_freeze == NULL) {
- smp_ops->give_timebase = smp_generic_give_timebase;
- smp_ops->take_timebase = smp_generic_take_timebase;
+ if (pmac_tb_freeze != NULL) {
+ /* Open i2c bus for synchronous access */
+ if (pmac_i2c_open(pmac_tb_clock_chip_host, 1)) {
+ printk(KERN_ERR "Failed top open i2c bus for clock"
+ " sync, fallback to software sync !\n");
+ goto no_i2c_sync;
+ }
+ printk(KERN_INFO "Processor timebase sync using %s i2c clock\n",
+ name);
+ return;
}
+ no_i2c_sync:
+ pmac_tb_freeze = NULL;
+ pmac_tb_clock_chip_host = NULL;
}
-/* nothing to do here, caches are already set up by service processor */
-static inline void __devinit core99_init_caches(int cpu)
+
+
+/*
+ * Newer G5s uses a platform function
+ */
+
+static void smp_core99_pfunc_tb_freeze(int freeze)
{
+ struct device_node *cpus;
+ struct pmf_args args;
+
+ cpus = of_find_node_by_path("/cpus");
+ BUG_ON(cpus == NULL);
+ args.count = 1;
+ args.u[0].v = !freeze;
+ pmf_call_function(cpus, "cpu-timebase", &args);
+ of_node_put(cpus);
}
#else /* CONFIG_PPC64 */
/*
- * SMP G4 powermacs use a GPIO to enable/disable the timebase.
+ * SMP G4 use a GPIO to enable/disable the timebase.
*/
static unsigned int core99_tb_gpio; /* Timebase freeze GPIO */
-static unsigned int pri_tb_hi, pri_tb_lo;
-static unsigned int pri_tb_stamp;
-
-/* not __init, called in sleep/wakeup code */
-void smp_core99_give_timebase(void)
+static void smp_core99_gpio_tb_freeze(int freeze)
{
- unsigned long flags;
- unsigned int t;
-
- /* wait for the secondary to be in take_timebase */
- for (t = 100000; t > 0 && !sec_tb_reset; --t)
- udelay(10);
- if (!sec_tb_reset) {
- printk(KERN_WARNING "Timeout waiting sync on second CPU\n");
- return;
- }
-
- /* freeze the timebase and read it */
- /* disable interrupts so the timebase is disabled for the
- shortest possible time */
- local_irq_save(flags);
- pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);
+ if (freeze)
+ pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);
+ else
+ pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);
pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
- mb();
- pri_tb_hi = get_tbu();
- pri_tb_lo = get_tbl();
- pri_tb_stamp = last_jiffy_stamp(smp_processor_id());
- mb();
-
- /* tell the secondary we're ready */
- sec_tb_reset = 2;
- mb();
-
- /* wait for the secondary to have taken it */
- /* note: can't use udelay here, since it needs the timebase running */
- for (t = 10000000; t > 0 && sec_tb_reset; --t)
- barrier();
- if (sec_tb_reset)
- /* XXX BUG_ON here? */
- printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n");
-
- /* Now, restart the timebase by leaving the GPIO to an open collector */
- pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);
- pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
- local_irq_restore(flags);
}
-/* not __init, called in sleep/wakeup code */
-void smp_core99_take_timebase(void)
-{
- unsigned long flags;
-
- /* tell the primary we're here */
- sec_tb_reset = 1;
- mb();
-
- /* wait for the primary to set pri_tb_hi/lo */
- while (sec_tb_reset < 2)
- mb();
-
- /* set our stuff the same as the primary */
- local_irq_save(flags);
- set_dec(1);
- set_tb(pri_tb_hi, pri_tb_lo);
- last_jiffy_stamp(smp_processor_id()) = pri_tb_stamp;
- mb();
- /* tell the primary we're done */
- sec_tb_reset = 0;
- mb();
- local_irq_restore(flags);
-}
+#endif /* !CONFIG_PPC64 */
/* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */
volatile static long int core99_l2_cache;
@@ -677,6 +649,7 @@ volatile static long int core99_l3_cache;
static void __devinit core99_init_caches(int cpu)
{
+#ifndef CONFIG_PPC64
if (!cpu_has_feature(CPU_FTR_L2CR))
return;
@@ -702,30 +675,76 @@ static void __devinit core99_init_caches(int cpu)
_set_L3CR(core99_l3_cache);
printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache);
}
+#endif /* !CONFIG_PPC64 */
}
static void __init smp_core99_setup(int ncpus)
{
- struct device_node *cpu;
- u32 *tbprop = NULL;
- int i;
+#ifdef CONFIG_PPC64
+
+ /* i2c based HW sync on some G5s */
+ if (machine_is_compatible("PowerMac7,2") ||
+ machine_is_compatible("PowerMac7,3") ||
+ machine_is_compatible("RackMac3,1"))
+ smp_core99_setup_i2c_hwsync(ncpus);
- core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */
- cpu = of_find_node_by_type(NULL, "cpu");
- if (cpu != NULL) {
- tbprop = (u32 *)get_property(cpu, "timebase-enable", NULL);
- if (tbprop)
- core99_tb_gpio = *tbprop;
- of_node_put(cpu);
+ /* pfunc based HW sync on recent G5s */
+ if (pmac_tb_freeze == NULL) {
+ struct device_node *cpus =
+ of_find_node_by_path("/cpus");
+ if (cpus &&
+ get_property(cpus, "platform-cpu-timebase", NULL)) {
+ pmac_tb_freeze = smp_core99_pfunc_tb_freeze;
+ printk(KERN_INFO "Processor timebase sync using"
+ " platform function\n");
+ }
}
- /* XXX should get this from reg properties */
- for (i = 1; i < ncpus; ++i)
- smp_hw_index[i] = i;
- powersave_nap = 0;
-}
+#else /* CONFIG_PPC64 */
+
+ /* GPIO based HW sync on ppc32 Core99 */
+ if (pmac_tb_freeze == NULL && !machine_is_compatible("MacRISC4")) {
+ struct device_node *cpu;
+ u32 *tbprop = NULL;
+
+ core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */
+ cpu = of_find_node_by_type(NULL, "cpu");
+ if (cpu != NULL) {
+ tbprop = (u32 *)get_property(cpu, "timebase-enable",
+ NULL);
+ if (tbprop)
+ core99_tb_gpio = *tbprop;
+ of_node_put(cpu);
+ }
+ pmac_tb_freeze = smp_core99_gpio_tb_freeze;
+ printk(KERN_INFO "Processor timebase sync using"
+ " GPIO 0x%02x\n", core99_tb_gpio);
+ }
+
+#endif /* CONFIG_PPC64 */
+
+ /* No timebase sync, fallback to software */
+ if (pmac_tb_freeze == NULL) {
+ smp_ops->give_timebase = smp_generic_give_timebase;
+ smp_ops->take_timebase = smp_generic_take_timebase;
+ printk(KERN_INFO "Processor timebase sync using software\n");
+ }
+
+#ifndef CONFIG_PPC64
+ {
+ int i;
+
+ /* XXX should get this from reg properties */
+ for (i = 1; i < ncpus; ++i)
+ smp_hw_index[i] = i;
+ }
#endif
+ /* 32 bits SMP can't NAP */
+ if (!machine_is_compatible("MacRISC4"))
+ powersave_nap = 0;
+}
+
static int __init smp_core99_probe(void)
{
struct device_node *cpus;
@@ -743,8 +762,19 @@ static int __init smp_core99_probe(void)
if (ncpus <= 1)
return 1;
+ /* We need to perform some early initialisations before we can start
+ * setting up SMP as we are running before initcalls
+ */
+ pmac_pfunc_base_install();
+ pmac_i2c_init();
+
+ /* Setup various bits like timebase sync method, ability to nap, ... */
smp_core99_setup(ncpus);
+
+ /* Install IPIs */
mpic_request_ipis();
+
+ /* Collect l2cr and l3cr values from CPU 0 */
core99_init_caches(0);
return ncpus;
@@ -753,14 +783,15 @@ static int __init smp_core99_probe(void)
static void __devinit smp_core99_kick_cpu(int nr)
{
unsigned int save_vector;
- unsigned long new_vector;
- unsigned long flags;
+ unsigned long target, flags;
volatile unsigned int *vector
= ((volatile unsigned int *)(KERNELBASE+0x100));
if (nr < 0 || nr > 3)
return;
- if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346);
+
+ if (ppc_md.progress)
+ ppc_md.progress("smp_core99_kick_cpu", 0x346);
local_irq_save(flags);
local_irq_disable();
@@ -768,14 +799,11 @@ static void __devinit smp_core99_kick_cpu(int nr)
/* Save reset vector */
save_vector = *vector;
- /* Setup fake reset vector that does
+ /* Setup fake reset vector that does
* b __secondary_start_pmac_0 + nr*8 - KERNELBASE
*/
- new_vector = (unsigned long) __secondary_start_pmac_0 + nr * 8;
- *vector = 0x48000002 + new_vector - KERNELBASE;
-
- /* flush data cache and inval instruction cache */
- flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+ target = (unsigned long) __secondary_start_pmac_0 + nr * 8;
+ create_branch((unsigned long)vector, target, BRANCH_SET_LINK);
/* Put some life in our friend */
pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
@@ -805,17 +833,25 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr)
mpic_setup_this_cpu();
if (cpu_nr == 0) {
-#ifdef CONFIG_POWER4
+#ifdef CONFIG_PPC64
extern void g5_phy_disable_cpu1(void);
+ /* Close i2c bus if it was used for tb sync */
+ if (pmac_tb_clock_chip_host) {
+ pmac_i2c_close(pmac_tb_clock_chip_host);
+ pmac_tb_clock_chip_host = NULL;
+ }
+
/* If we didn't start the second CPU, we must take
* it off the bus
*/
if (machine_is_compatible("MacRISC4") &&
num_online_cpus() < 2)
g5_phy_disable_cpu1();
-#endif /* CONFIG_POWER4 */
- if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
+#endif /* CONFIG_PPC64 */
+
+ if (ppc_md.progress)
+ ppc_md.progress("core99_setup_cpu 0 done", 0x349);
}
}
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index feb0a94e7819..5d9afa1fa02d 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -258,15 +258,20 @@ int __init via_calibrate_decr(void)
volatile unsigned char __iomem *via;
int count = VIA_TIMER_FREQ_6 / 100;
unsigned int dstart, dend;
+ struct resource rsrc;
- vias = find_devices("via-cuda");
+ vias = of_find_node_by_name(NULL, "via-cuda");
if (vias == 0)
- vias = find_devices("via-pmu");
+ vias = of_find_node_by_name(NULL, "via-pmu");
if (vias == 0)
- vias = find_devices("via");
- if (vias == 0 || vias->n_addrs == 0)
+ vias = of_find_node_by_name(NULL, "via");
+ if (vias == 0 || of_address_to_resource(vias, 0, &rsrc))
return 0;
- via = ioremap(vias->addrs[0].address, vias->addrs[0].size);
+ via = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
+ if (via == NULL) {
+ printk(KERN_ERR "Failed to map VIA for timer calibration !\n");
+ return 0;
+ }
/* set timer 1 for continuous interrupts */
out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
diff --git a/arch/powerpc/platforms/powermac/udbg_adb.c b/arch/powerpc/platforms/powermac/udbg_adb.c
new file mode 100644
index 000000000000..06c8265c2baf
--- /dev/null
+++ b/arch/powerpc/platforms/powermac/udbg_adb.c
@@ -0,0 +1,221 @@
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/bitops.h>
+#include <linux/ptrace.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/cuda.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/xmon.h>
+#include <asm/prom.h>
+#include <asm/bootx.h>
+#include <asm/machdep.h>
+#include <asm/errno.h>
+#include <asm/pmac_feature.h>
+#include <asm/processor.h>
+#include <asm/delay.h>
+#include <asm/btext.h>
+#include <asm/time.h>
+#include <asm/udbg.h>
+
+/*
+ * This implementation is "special", it can "patch" the current
+ * udbg implementation and work on top of it. It must thus be
+ * initialized last
+ */
+
+static void (*udbg_adb_old_putc)(char c);
+static int (*udbg_adb_old_getc)(void);
+static int (*udbg_adb_old_getc_poll)(void);
+
+static enum {
+ input_adb_none,
+ input_adb_pmu,
+ input_adb_cuda,
+} input_type = input_adb_none;
+
+int xmon_wants_key, xmon_adb_keycode;
+
+static inline void udbg_adb_poll(void)
+{
+#ifdef CONFIG_ADB_PMU
+ if (input_type == input_adb_pmu)
+ pmu_poll_adb();
+#endif /* CONFIG_ADB_PMU */
+#ifdef CONFIG_ADB_CUDA
+ if (input_type == input_adb_cuda)
+ cuda_poll();
+#endif /* CONFIG_ADB_CUDA */
+}
+
+#ifdef CONFIG_BOOTX_TEXT
+
+static int udbg_adb_use_btext;
+static int xmon_adb_shiftstate;
+
+static unsigned char xmon_keytab[128] =
+ "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */
+ "yt123465=97-80]o" /* 0x10 - 0x1f */
+ "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */
+ "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
+ "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
+ "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
+
+static unsigned char xmon_shift_keytab[128] =
+ "ASDFHGZXCV\000BQWER" /* 0x00 - 0x0f */
+ "YT!@#$^%+(&_*)}O" /* 0x10 - 0x1f */
+ "U{IP\rLJ\"K:|<?NM>" /* 0x20 - 0x2f */
+ "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
+ "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
+ "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
+
+static int udbg_adb_local_getc(void)
+{
+ int k, t, on;
+
+ xmon_wants_key = 1;
+ for (;;) {
+ xmon_adb_keycode = -1;
+ t = 0;
+ on = 0;
+ k = -1;
+ do {
+ if (--t < 0) {
+ on = 1 - on;
+ btext_drawchar(on? 0xdb: 0x20);
+ btext_drawchar('\b');
+ t = 200000;
+ }
+ udbg_adb_poll();
+ if (udbg_adb_old_getc_poll)
+ k = udbg_adb_old_getc_poll();
+ } while (k == -1 && xmon_adb_keycode == -1);
+ if (on)
+ btext_drawstring(" \b");
+ if (k != -1)
+ return k;
+ k = xmon_adb_keycode;
+
+ /* test for shift keys */
+ if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
+ xmon_adb_shiftstate = (k & 0x80) == 0;
+ continue;
+ }
+ if (k >= 0x80)
+ continue; /* ignore up transitions */
+ k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
+ if (k != 0)
+ break;
+ }
+ xmon_wants_key = 0;
+ return k;
+}
+#endif /* CONFIG_BOOTX_TEXT */
+
+static int udbg_adb_getc(void)
+{
+#ifdef CONFIG_BOOTX_TEXT
+ if (udbg_adb_use_btext && input_type != input_adb_none)
+ return udbg_adb_local_getc();
+#endif
+ if (udbg_adb_old_getc)
+ return udbg_adb_old_getc();
+ return -1;
+}
+
+/* getc_poll() is not really used, unless you have the xmon-over modem
+ * hack that doesn't quite concern us here, thus we just poll the low level
+ * ADB driver to prevent it from timing out and call back the original poll
+ * routine.
+ */
+static int udbg_adb_getc_poll(void)
+{
+ udbg_adb_poll();
+
+ if (udbg_adb_old_getc_poll)
+ return udbg_adb_old_getc_poll();
+ return -1;
+}
+
+static void udbg_adb_putc(char c)
+{
+#ifdef CONFIG_BOOTX_TEXT
+ if (udbg_adb_use_btext)
+ btext_drawchar(c);
+#endif
+ if (udbg_adb_old_putc)
+ return udbg_adb_old_putc(c);
+}
+
+void udbg_adb_init_early(void)
+{
+#ifdef CONFIG_BOOTX_TEXT
+ if (btext_find_display(1) == 0) {
+ udbg_adb_use_btext = 1;
+ udbg_putc = udbg_adb_putc;
+ }
+#endif
+}
+
+int udbg_adb_init(int force_btext)
+{
+ struct device_node *np;
+
+ /* Capture existing callbacks */
+ udbg_adb_old_putc = udbg_putc;
+ udbg_adb_old_getc = udbg_getc;
+ udbg_adb_old_getc_poll = udbg_getc_poll;
+
+ /* Check if our early init was already called */
+ if (udbg_adb_old_putc == udbg_adb_putc)
+ udbg_adb_old_putc = NULL;
+#ifdef CONFIG_BOOTX_TEXT
+ if (udbg_adb_old_putc == btext_drawchar)
+ udbg_adb_old_putc = NULL;
+#endif
+
+ /* Set ours as output */
+ udbg_putc = udbg_adb_putc;
+ udbg_getc = udbg_adb_getc;
+ udbg_getc_poll = udbg_adb_getc_poll;
+
+#ifdef CONFIG_BOOTX_TEXT
+ /* Check if we should use btext output */
+ if (btext_find_display(force_btext) == 0)
+ udbg_adb_use_btext = 1;
+#endif
+
+ /* See if there is a keyboard in the device tree with a parent
+ * of type "adb". If not, we return a failure, but we keep the
+ * bext output set for now
+ */
+ for (np = NULL; (np = of_find_node_by_name(np, "keyboard")) != NULL;) {
+ struct device_node *parent = of_get_parent(np);
+ int found = (parent && strcmp(parent->type, "adb") == 0);
+ of_node_put(parent);
+ if (found)
+ break;
+ }
+ if (np == NULL)
+ return -ENODEV;
+ of_node_put(np);
+
+#ifdef CONFIG_ADB_PMU
+ if (find_via_pmu())
+ input_type = input_adb_pmu;
+#endif
+#ifdef CONFIG_ADB_CUDA
+ if (find_via_cuda())
+ input_type = input_adb_cuda;
+#endif
+
+ /* Same as above: nothing found, keep btext set for output */
+ if (input_type == input_adb_none)
+ return -ENODEV;
+
+ return 0;
+}
diff --git a/arch/powerpc/kernel/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c
index 820c53551507..e87d53acfb61 100644
--- a/arch/powerpc/kernel/udbg_scc.c
+++ b/arch/powerpc/platforms/powermac/udbg_scc.c
@@ -25,7 +25,7 @@ extern void real_writeb(u8 data, volatile u8 __iomem *addr);
static volatile u8 __iomem *sccc;
static volatile u8 __iomem *sccd;
-static void udbg_scc_putc(unsigned char c)
+static void udbg_scc_putc(char c)
{
if (sccc) {
while ((in_8(sccc) & SCC_TXRDY) == 0)
@@ -47,14 +47,14 @@ static int udbg_scc_getc_poll(void)
return -1;
}
-static unsigned char udbg_scc_getc(void)
+static int udbg_scc_getc(void)
{
if (sccc) {
while ((in_8(sccc) & SCC_RXRDY) == 0)
;
return in_8(sccd);
}
- return 0;
+ return -1;
}
static unsigned char scc_inittab[] = {
@@ -67,38 +67,59 @@ static unsigned char scc_inittab[] = {
3, 0xc1, /* rx enable, 8 bits */
};
-void udbg_init_scc(struct device_node *np)
+void udbg_scc_init(int force_scc)
{
u32 *reg;
unsigned long addr;
+ struct device_node *stdout = NULL, *escc = NULL, *macio = NULL;
+ struct device_node *ch, *ch_def = NULL, *ch_a = NULL;
+ char *path;
int i, x;
- if (np == NULL)
- np = of_find_node_by_name(NULL, "escc");
- if (np == NULL || np->parent == NULL)
- return;
+ escc = of_find_node_by_name(NULL, "escc");
+ if (escc == NULL)
+ goto bail;
+ macio = of_get_parent(escc);
+ if (macio == NULL)
+ goto bail;
+ path = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
+ if (path != NULL)
+ stdout = of_find_node_by_path(path);
+ for (ch = NULL; (ch = of_get_next_child(escc, ch)) != NULL;) {
+ if (ch == stdout)
+ ch_def = of_node_get(ch);
+ if (strcmp(ch->name, "ch-a") == 0)
+ ch_a = of_node_get(ch);
+ }
+ if (ch_def == NULL && !force_scc)
+ goto bail;
+
+ ch = ch_def ? ch_def : ch_a;
- udbg_printf("found SCC...\n");
/* Get address within mac-io ASIC */
- reg = (u32 *)get_property(np, "reg", NULL);
+ reg = (u32 *)get_property(escc, "reg", NULL);
if (reg == NULL)
- return;
+ goto bail;
addr = reg[0];
- udbg_printf("local addr: %lx\n", addr);
+
/* Get address of mac-io PCI itself */
- reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL);
+ reg = (u32 *)get_property(macio, "assigned-addresses", NULL);
if (reg == NULL)
- return;
+ goto bail;
addr += reg[2];
- udbg_printf("final addr: %lx\n", addr);
+
+ /* Lock the serial port */
+ pmac_call_feature(PMAC_FTR_SCC_ENABLE, ch,
+ PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
+
/* Setup for 57600 8N1 */
- addr += 0x20;
+ if (ch == ch_a)
+ addr += 0x20;
sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
sccc += addr & ~PAGE_MASK;
sccd = sccc + 0x10;
- udbg_printf("ioremap result sccc: %p\n", sccc);
mb();
for (i = 20000; i != 0; --i)
@@ -113,9 +134,17 @@ void udbg_init_scc(struct device_node *np)
udbg_getc_poll = udbg_scc_getc_poll;
udbg_puts("Hello World !\n");
+
+ bail:
+ of_node_put(macio);
+ of_node_put(escc);
+ of_node_put(stdout);
+ of_node_put(ch_def);
+ of_node_put(ch_a);
}
-static void udbg_real_scc_putc(unsigned char c)
+#ifdef CONFIG_PPC64
+static void udbg_real_scc_putc(char c)
{
while ((real_readb(sccc) & SCC_TXRDY) == 0)
;
@@ -133,3 +162,4 @@ void udbg_init_pmac_realmode(void)
udbg_getc = NULL;
udbg_getc_poll = NULL;
}
+#endif /* CONFIG_PPC64 */
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 06d5ef501218..6accdd155505 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -1,5 +1,5 @@
obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \
- setup.o iommu.o ras.o rtasd.o
+ setup.o iommu.o ras.o rtasd.o pci_dlpar.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_IBMVIO) += vio.o
obj-$(CONFIG_XICS) += xics.o
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index c8d2a40dc5b4..7fbfd16d72b7 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -1093,6 +1093,15 @@ void eeh_add_device_early(struct device_node *dn)
}
EXPORT_SYMBOL_GPL(eeh_add_device_early);
+void eeh_add_device_tree_early(struct device_node *dn)
+{
+ struct device_node *sib;
+ for (sib = dn->child; sib; sib = sib->sibling)
+ eeh_add_device_tree_early(sib);
+ eeh_add_device_early(dn);
+}
+EXPORT_SYMBOL_GPL(eeh_add_device_tree_early);
+
/**
* eeh_add_device_late - perform EEH initialization for the indicated pci device
* @dev: pci device for which to set up EEH
@@ -1147,6 +1156,23 @@ void eeh_remove_device(struct pci_dev *dev)
}
EXPORT_SYMBOL_GPL(eeh_remove_device);
+void eeh_remove_bus_device(struct pci_dev *dev)
+{
+ eeh_remove_device(dev);
+ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+ struct pci_bus *bus = dev->subordinate;
+ struct list_head *ln;
+ if (!bus)
+ return;
+ for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
+ struct pci_dev *pdev = pci_dev_b(ln);
+ if (pdev)
+ eeh_remove_bus_device(pdev);
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(eeh_remove_bus_device);
+
static int proc_eeh_show(struct seq_file *m, void *v)
{
unsigned int cpu;
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 2043659ea7b1..169f9148789c 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -436,7 +436,7 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus)
return;
}
- ppci = pdn->data;
+ ppci = PCI_DN(pdn);
if (!ppci->iommu_table) {
/* Bussubno hasn't been copied yet.
* Do it now because iommu_table_setparms_lpar needs it.
@@ -483,10 +483,10 @@ static void iommu_dev_setup_pSeries(struct pci_dev *dev)
* an already allocated iommu table is found and use that.
*/
- while (dn && dn->data && PCI_DN(dn)->iommu_table == NULL)
+ while (dn && PCI_DN(dn) && PCI_DN(dn)->iommu_table == NULL)
dn = dn->parent;
- if (dn && dn->data) {
+ if (dn && PCI_DN(dn)) {
PCI_DN(mydn)->iommu_table = PCI_DN(dn)->iommu_table;
} else {
DBG("iommu_dev_setup_pSeries, dev %p (%s) has no iommu table\n", dev, pci_name(dev));
@@ -497,7 +497,7 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti
{
int err = NOTIFY_OK;
struct device_node *np = node;
- struct pci_dn *pci = np->data;
+ struct pci_dn *pci = PCI_DN(np);
switch (action) {
case PSERIES_RECONFIG_REMOVE:
@@ -533,7 +533,7 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
*/
dn = pci_device_to_OF_node(dev);
- for (pdn = dn; pdn && pdn->data && !PCI_DN(pdn)->iommu_table;
+ for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
pdn = pdn->parent) {
dma_window = (unsigned int *)
get_property(pdn, "ibm,dma-window", NULL);
@@ -552,7 +552,7 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
DBG("Found DMA window, allocating table\n");
}
- pci = pdn->data;
+ pci = PCI_DN(pdn);
if (!pci->iommu_table) {
/* iommu_table_setparms_lpar needs bussubno. */
pci->bussubno = pci->phb->bus->number;
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index cf1bc11b3346..1fe445ab78a6 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -24,6 +24,7 @@
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/dma-mapping.h>
+#include <linux/console.h>
#include <asm/processor.h>
#include <asm/mmu.h>
#include <asm/page.h>
@@ -60,7 +61,7 @@ extern void pSeries_find_serial_port(void);
int vtermno; /* virtual terminal# for udbg */
#define __ALIGNED__ __attribute__((__aligned__(sizeof(long))))
-static void udbg_hvsi_putc(unsigned char c)
+static void udbg_hvsi_putc(char c)
{
/* packet's seqno isn't used anyways */
uint8_t packet[] __ALIGNED__ = { 0xff, 5, 0, 0, c };
@@ -111,7 +112,7 @@ static int udbg_hvsi_getc_poll(void)
return ch;
}
-static unsigned char udbg_hvsi_getc(void)
+static int udbg_hvsi_getc(void)
{
int ch;
for (;;) {
@@ -127,7 +128,7 @@ static unsigned char udbg_hvsi_getc(void)
}
}
-static void udbg_putcLP(unsigned char c)
+static void udbg_putcLP(char c)
{
char buf[16];
unsigned long rc;
@@ -172,7 +173,7 @@ static int udbg_getc_pollLP(void)
return ch;
}
-static unsigned char udbg_getcLP(void)
+static int udbg_getcLP(void)
{
int ch;
for (;;) {
@@ -191,7 +192,7 @@ static unsigned char udbg_getcLP(void)
/* call this from early_init() for a working debug console on
* vterm capable LPAR machines
*/
-void udbg_init_debug_lpar(void)
+void __init udbg_init_debug_lpar(void)
{
vtermno = 0;
udbg_putc = udbg_putcLP;
@@ -200,63 +201,54 @@ void udbg_init_debug_lpar(void)
}
/* returns 0 if couldn't find or use /chosen/stdout as console */
-int find_udbg_vterm(void)
+void __init find_udbg_vterm(void)
{
struct device_node *stdout_node;
u32 *termno;
char *name;
- int found = 0;
+ int add_console;
/* find the boot console from /chosen/stdout */
if (!of_chosen)
- return 0;
+ return;
name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
if (name == NULL)
- return 0;
+ return;
stdout_node = of_find_node_by_path(name);
if (!stdout_node)
- return 0;
-
- /* now we have the stdout node; figure out what type of device it is. */
+ return;
name = (char *)get_property(stdout_node, "name", NULL);
if (!name) {
printk(KERN_WARNING "stdout node missing 'name' property!\n");
goto out;
}
+ /* The user has requested a console so this is already set up. */
+ add_console = !strstr(cmd_line, "console=");
- if (strncmp(name, "vty", 3) == 0) {
- if (device_is_compatible(stdout_node, "hvterm1")) {
- termno = (u32 *)get_property(stdout_node, "reg", NULL);
- if (termno) {
- vtermno = termno[0];
- udbg_putc = udbg_putcLP;
- udbg_getc = udbg_getcLP;
- udbg_getc_poll = udbg_getc_pollLP;
- found = 1;
- }
- } else if (device_is_compatible(stdout_node, "hvterm-protocol")) {
- termno = (u32 *)get_property(stdout_node, "reg", NULL);
- if (termno) {
- vtermno = termno[0];
- udbg_putc = udbg_hvsi_putc;
- udbg_getc = udbg_hvsi_getc;
- udbg_getc_poll = udbg_hvsi_getc_poll;
- found = 1;
- }
- }
- } else if (strncmp(name, "serial", 6)) {
- /* XXX fix ISA serial console */
- printk(KERN_WARNING "serial stdout on LPAR ('%s')! "
- "can't print udbg messages\n",
- stdout_node->full_name);
- } else {
- printk(KERN_WARNING "don't know how to print to stdout '%s'\n",
- stdout_node->full_name);
+ /* Check if it's a virtual terminal */
+ if (strncmp(name, "vty", 3) != 0)
+ goto out;
+ termno = (u32 *)get_property(stdout_node, "reg", NULL);
+ if (termno == NULL)
+ goto out;
+ vtermno = termno[0];
+
+ if (device_is_compatible(stdout_node, "hvterm1")) {
+ udbg_putc = udbg_putcLP;
+ udbg_getc = udbg_getcLP;
+ udbg_getc_poll = udbg_getc_pollLP;
+ if (add_console)
+ add_preferred_console("hvc", termno[0] & 0xff, NULL);
+ } else if (device_is_compatible(stdout_node, "hvterm-protocol")) {
+ vtermno = termno[0];
+ udbg_putc = udbg_hvsi_putc;
+ udbg_getc = udbg_hvsi_getc;
+ udbg_getc_poll = udbg_hvsi_getc_poll;
+ if (add_console)
+ add_preferred_console("hvsi", termno[0] & 0xff, NULL);
}
-
out:
of_node_put(stdout_node);
- return found;
}
void vpa_init(int cpu)
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
new file mode 100644
index 000000000000..21934784f936
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -0,0 +1,174 @@
+/*
+ * PCI Dynamic LPAR, PCI Hot Plug and PCI EEH recovery code
+ * for RPA-compliant PPC64 platform.
+ * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
+ * Copyright (C) 2005 International Business Machines
+ *
+ * Updates, 2005, John Rose <johnrose@austin.ibm.com>
+ * Updates, 2005, Linas Vepstas <linas@austin.ibm.com>
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or
+ * NON INFRINGEMENT. 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/pci.h>
+#include <asm/pci-bridge.h>
+
+static struct pci_bus *
+find_bus_among_children(struct pci_bus *bus,
+ struct device_node *dn)
+{
+ struct pci_bus *child = NULL;
+ struct list_head *tmp;
+ struct device_node *busdn;
+
+ busdn = pci_bus_to_OF_node(bus);
+ if (busdn == dn)
+ return bus;
+
+ list_for_each(tmp, &bus->children) {
+ child = find_bus_among_children(pci_bus_b(tmp), dn);
+ if (child)
+ break;
+ };
+ return child;
+}
+
+struct pci_bus *
+pcibios_find_pci_bus(struct device_node *dn)
+{
+ struct pci_dn *pdn = dn->data;
+
+ if (!pdn || !pdn->phb || !pdn->phb->bus)
+ return NULL;
+
+ return find_bus_among_children(pdn->phb->bus, dn);
+}
+
+/**
+ * pcibios_remove_pci_devices - remove all devices under this bus
+ *
+ * Remove all of the PCI devices under this bus both from the
+ * linux pci device tree, and from the powerpc EEH address cache.
+ */
+void
+pcibios_remove_pci_devices(struct pci_bus *bus)
+{
+ struct pci_dev *dev, *tmp;
+
+ list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
+ eeh_remove_bus_device(dev);
+ pci_remove_bus_device(dev);
+ }
+}
+
+/* Must be called before pci_bus_add_devices */
+void
+pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
+{
+ struct pci_dev *dev;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ /*
+ * Skip already-present devices (which are on the
+ * global device list.)
+ */
+ if (list_empty(&dev->global_list)) {
+ int i;
+
+ /* Need to setup IOMMU tables */
+ ppc_md.iommu_dev_setup(dev);
+
+ if(fix_bus)
+ pcibios_fixup_device_resources(dev, bus);
+ pci_read_irq_line(dev);
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ struct resource *r = &dev->resource[i];
+
+ if (r->parent || !r->start || !r->flags)
+ continue;
+ pci_claim_resource(dev, i);
+ }
+ }
+ }
+}
+
+static int
+pcibios_pci_config_bridge(struct pci_dev *dev)
+{
+ u8 sec_busno;
+ struct pci_bus *child_bus;
+ struct pci_dev *child_dev;
+
+ /* Get busno of downstream bus */
+ pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno);
+
+ /* Add to children of PCI bridge dev->bus */
+ child_bus = pci_add_new_bus(dev->bus, dev, sec_busno);
+ if (!child_bus) {
+ printk (KERN_ERR "%s: could not add second bus\n", __FUNCTION__);
+ return -EIO;
+ }
+ sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number);
+
+ pci_scan_child_bus(child_bus);
+
+ list_for_each_entry(child_dev, &child_bus->devices, bus_list) {
+ eeh_add_device_late(child_dev);
+ }
+
+ /* Fixup new pci devices without touching bus struct */
+ pcibios_fixup_new_pci_devices(child_bus, 0);
+
+ /* Make the discovered devices available */
+ pci_bus_add_devices(child_bus);
+ return 0;
+}
+
+/**
+ * pcibios_add_pci_devices - adds new pci devices to bus
+ *
+ * This routine will find and fixup new pci devices under
+ * the indicated bus. This routine presumes that there
+ * might already be some devices under this bridge, so
+ * it carefully tries to add only new devices. (And that
+ * is how this routine differs from other, similar pcibios
+ * routines.)
+ */
+void
+pcibios_add_pci_devices(struct pci_bus * bus)
+{
+ int slotno, num;
+ struct pci_dev *dev;
+ struct device_node *dn = pci_bus_to_OF_node(bus);
+
+ eeh_add_device_tree_early(dn);
+
+ /* pci_scan_slot should find all children */
+ slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
+ num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
+ if (num) {
+ pcibios_fixup_new_pci_devices(bus, 1);
+ pci_bus_add_devices(bus);
+ }
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ eeh_add_device_late (dev);
+ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
+ pcibios_pci_config_bridge(dev);
+ }
+}
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index fbd214d68b07..b046bcf7443d 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -49,14 +49,14 @@
#include <asm/machdep.h>
#include <asm/rtas.h>
#include <asm/udbg.h>
+#include <asm/firmware.h>
+
+#include "ras.h"
static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX];
static DEFINE_SPINLOCK(ras_log_buf_lock);
-char mce_data_buf[RTAS_ERROR_LOG_MAX]
-;
-/* This is true if we are using the firmware NMI handler (typically LPAR) */
-extern int fwnmi_active;
+char mce_data_buf[RTAS_ERROR_LOG_MAX];
static int ras_get_sensor_state_token;
static int ras_check_exception_token;
@@ -280,7 +280,7 @@ static void fwnmi_release_errinfo(void)
printk("FWNMI: nmi-interlock failed: %d\n", ret);
}
-void pSeries_system_reset_exception(struct pt_regs *regs)
+int pSeries_system_reset_exception(struct pt_regs *regs)
{
if (fwnmi_active) {
struct rtas_error_log *errhdr = fwnmi_get_errinfo(regs);
@@ -289,6 +289,7 @@ void pSeries_system_reset_exception(struct pt_regs *regs)
}
fwnmi_release_errinfo();
}
+ return 0; /* need to perform reset */
}
/*
diff --git a/arch/powerpc/platforms/pseries/ras.h b/arch/powerpc/platforms/pseries/ras.h
new file mode 100644
index 000000000000..0e66b0da55e2
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/ras.h
@@ -0,0 +1,9 @@
+#ifndef _PSERIES_RAS_H
+#define _PSERIES_RAS_H
+
+struct pt_regs;
+
+extern int pSeries_system_reset_exception(struct pt_regs *regs);
+extern int pSeries_machine_check_exception(struct pt_regs *regs);
+
+#endif /* _PSERIES_RAS_H */
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 4a465f067ede..8903cf63236a 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -56,6 +56,7 @@
#include <asm/dma.h>
#include <asm/machdep.h>
#include <asm/irq.h>
+#include <asm/kexec.h>
#include <asm/time.h>
#include <asm/nvram.h>
#include "xics.h"
@@ -68,6 +69,7 @@
#include <asm/smp.h>
#include "plpar_wrappers.h"
+#include "ras.h"
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
@@ -76,16 +78,9 @@
#endif
extern void find_udbg_vterm(void);
-extern void system_reset_fwnmi(void); /* from head.S */
-extern void machine_check_fwnmi(void); /* from head.S */
-extern void generic_find_legacy_serial_ports(u64 *physport,
- unsigned int *default_speed);
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 void pseries_shared_idle(void);
static void pseries_dedicated_idle(void);
@@ -105,18 +100,22 @@ void pSeries_show_cpuinfo(struct seq_file *m)
/* Initialize firmware assisted non-maskable interrupts if
* the firmware supports this feature.
- *
*/
static void __init fwnmi_init(void)
{
- int ret;
+ unsigned long system_reset_addr, machine_check_addr;
+
int ibm_nmi_register = rtas_token("ibm,nmi-register");
if (ibm_nmi_register == RTAS_UNKNOWN_SERVICE)
return;
- ret = rtas_call(ibm_nmi_register, 2, 1, NULL,
- __pa((unsigned long)system_reset_fwnmi),
- __pa((unsigned long)machine_check_fwnmi));
- if (ret == 0)
+
+ /* If the kernel's not linked at zero we point the firmware at low
+ * addresses anyway, and use a trampoline to get to the real code. */
+ system_reset_addr = __pa(system_reset_fwnmi) - PHYSICAL_START;
+ machine_check_addr = __pa(machine_check_fwnmi) - PHYSICAL_START;
+
+ if (0 == rtas_call(ibm_nmi_register, 2, 1, NULL, system_reset_addr,
+ machine_check_addr))
fwnmi_active = 1;
}
@@ -323,15 +322,18 @@ static void __init pSeries_discover_pic(void)
ppc64_interrupt_controller = IC_INVALID;
for (np = NULL; (np = of_find_node_by_name(np, "interrupt-controller"));) {
typep = (char *)get_property(np, "compatible", NULL);
- if (strstr(typep, "open-pic"))
+ if (strstr(typep, "open-pic")) {
ppc64_interrupt_controller = IC_OPEN_PIC;
- else if (strstr(typep, "ppc-xicp"))
+ break;
+ } else if (strstr(typep, "ppc-xicp")) {
ppc64_interrupt_controller = IC_PPC_XIC;
- else
- printk("pSeries_discover_pic: failed to recognize"
- " interrupt-controller\n");
- break;
+ break;
+ }
}
+ if (ppc64_interrupt_controller == IC_INVALID)
+ printk("pSeries_discover_pic: failed to recognize"
+ " interrupt-controller\n");
+
}
static void pSeries_mach_cpu_die(void)
@@ -365,10 +367,7 @@ static int pseries_set_xdabr(unsigned long dabr)
*/
static void __init pSeries_init_early(void)
{
- void *comport;
int iommu_off = 0;
- unsigned int default_speed;
- u64 physport;
DBG(" -> pSeries_init_early()\n");
@@ -382,17 +381,8 @@ static void __init pSeries_init_early(void)
get_property(of_chosen, "linux,iommu-off", NULL));
}
- generic_find_legacy_serial_ports(&physport, &default_speed);
-
if (platform_is_lpar())
find_udbg_vterm();
- else if (physport) {
- /* Map the uart for udbg. */
- comport = (void *)ioremap(physport, 16);
- udbg_init_uart(comport, default_speed);
-
- DBG("Hello World !\n");
- }
if (firmware_has_feature(FW_FEATURE_DABR))
ppc_md.set_dabr = pseries_set_dabr;
@@ -638,5 +628,8 @@ struct machdep_calls __initdata pSeries_md = {
.machine_check_exception = pSeries_machine_check_exception,
#ifdef CONFIG_KEXEC
.kexec_cpu_down = pseries_kexec_cpu_down,
+ .machine_kexec = default_machine_kexec,
+ .machine_kexec_prepare = default_machine_kexec_prepare,
+ .machine_crash_shutdown = default_machine_crash_shutdown,
#endif
};
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index 0377decc0719..0c0cfa32eb58 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -407,7 +407,7 @@ irqreturn_t xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
smp_message_recv(PPC_MSG_MIGRATE_TASK, regs);
}
#endif
-#ifdef CONFIG_DEBUGGER
+#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK,
&xics_ipi_message[cpu].value)) {
mb();
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 6b7efcfc352a..14b9abde2d27 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -4,5 +4,6 @@ obj-$(CONFIG_PPC_I8259) += i8259.o
obj-$(CONFIG_PPC_MPC106) += grackle.o
obj-$(CONFIG_BOOKE) += dcr.o
obj-$(CONFIG_40x) += dcr.o
-obj-$(CONFIG_U3_DART) += u3_iommu.o
+obj-$(CONFIG_U3_DART) += dart_iommu.o
obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
+obj-$(CONFIG_83xx) += ipic.o
diff --git a/arch/powerpc/sysdev/dart.h b/arch/powerpc/sysdev/dart.h
index 33ed9ed7fc1e..c2d05763ccbe 100644
--- a/arch/powerpc/sysdev/dart.h
+++ b/arch/powerpc/sysdev/dart.h
@@ -20,29 +20,44 @@
#define _POWERPC_SYSDEV_DART_H
-/* physical base of DART registers */
-#define DART_BASE 0xf8033000UL
-
/* Offset from base to control register */
-#define DARTCNTL 0
+#define DART_CNTL 0
+
/* Offset from base to exception register */
-#define DARTEXCP 0x10
+#define DART_EXCP_U3 0x10
/* Offset from base to TLB tag registers */
-#define DARTTAG 0x1000
+#define DART_TAGS_U3 0x1000
+/* U4 registers */
+#define DART_BASE_U4 0x10
+#define DART_SIZE_U4 0x20
+#define DART_EXCP_U4 0x30
+#define DART_TAGS_U4 0x1000
/* Control Register fields */
-/* base address of table (pfn) */
-#define DARTCNTL_BASE_MASK 0xfffff
-#define DARTCNTL_BASE_SHIFT 12
+/* U3 registers */
+#define DART_CNTL_U3_BASE_MASK 0xfffff
+#define DART_CNTL_U3_BASE_SHIFT 12
+#define DART_CNTL_U3_FLUSHTLB 0x400
+#define DART_CNTL_U3_ENABLE 0x200
+#define DART_CNTL_U3_SIZE_MASK 0x1ff
+#define DART_CNTL_U3_SIZE_SHIFT 0
+
+/* U4 registers */
+#define DART_BASE_U4_BASE_MASK 0xffffff
+#define DART_BASE_U4_BASE_SHIFT 0
+#define DART_CNTL_U4_FLUSHTLB 0x20000000
+#define DART_CNTL_U4_ENABLE 0x80000000
+#define DART_SIZE_U4_SIZE_MASK 0x1fff
+#define DART_SIZE_U4_SIZE_SHIFT 0
+
+#define DART_REG(r) (dart + ((r) >> 2))
+#define DART_IN(r) (in_be32(DART_REG(r)))
+#define DART_OUT(r,v) (out_be32(DART_REG(r), (v)))
-#define DARTCNTL_FLUSHTLB 0x400
-#define DARTCNTL_ENABLE 0x200
/* size of table in pages */
-#define DARTCNTL_SIZE_MASK 0x1ff
-#define DARTCNTL_SIZE_SHIFT 0
/* DART table fields */
diff --git a/arch/powerpc/sysdev/u3_iommu.c b/arch/powerpc/sysdev/dart_iommu.c
index 5c1a26a6d00c..e00b46b9514e 100644
--- a/arch/powerpc/sysdev/u3_iommu.c
+++ b/arch/powerpc/sysdev/dart_iommu.c
@@ -1,25 +1,27 @@
/*
- * arch/powerpc/sysdev/u3_iommu.c
+ * arch/powerpc/sysdev/dart_iommu.c
*
* Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation
+ * Copyright (C) 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>,
+ * IBM Corporation
*
* Based on pSeries_iommu.c:
* Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
* Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation
*
- * Dynamic DMA mapping support, Apple U3 & IBM CPC925 "DART" iommu.
+ * Dynamic DMA mapping support, Apple U3, U4 & IBM CPC925 "DART" iommu.
+ *
*
- *
* 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
@@ -57,21 +59,22 @@ static unsigned long dart_tablesize;
static u32 *dart_vbase;
/* Mapped base address for the dart */
-static unsigned int *dart;
+static unsigned int *__iomem dart;
/* Dummy val that entries are set to when unused */
static unsigned int dart_emptyval;
-static struct iommu_table iommu_table_u3;
-static int iommu_table_u3_inited;
+static struct iommu_table iommu_table_dart;
+static int iommu_table_dart_inited;
static int dart_dirty;
+static int dart_is_u4;
#define DBG(...)
static inline void dart_tlb_invalidate_all(void)
{
unsigned long l = 0;
- unsigned int reg;
+ unsigned int reg, inv_bit;
unsigned long limit;
DBG("dart: flush\n");
@@ -81,29 +84,28 @@ static inline void dart_tlb_invalidate_all(void)
*
* Gotcha: Sometimes, the DART won't detect that the bit gets
* set. If so, clear it and set it again.
- */
+ */
limit = 0;
+ inv_bit = dart_is_u4 ? DART_CNTL_U4_FLUSHTLB : DART_CNTL_U3_FLUSHTLB;
retry:
- reg = in_be32((unsigned int *)dart+DARTCNTL);
- reg |= DARTCNTL_FLUSHTLB;
- out_be32((unsigned int *)dart+DARTCNTL, reg);
-
l = 0;
- while ((in_be32((unsigned int *)dart+DARTCNTL) & DARTCNTL_FLUSHTLB) &&
- l < (1L<<limit)) {
+ reg = DART_IN(DART_CNTL);
+ reg |= inv_bit;
+ DART_OUT(DART_CNTL, reg);
+
+ while ((DART_IN(DART_CNTL) & inv_bit) && l < (1L << limit))
l++;
- }
- if (l == (1L<<limit)) {
+ if (l == (1L << limit)) {
if (limit < 4) {
limit++;
- reg = in_be32((unsigned int *)dart+DARTCNTL);
- reg &= ~DARTCNTL_FLUSHTLB;
- out_be32((unsigned int *)dart+DARTCNTL, reg);
+ reg = DART_IN(DART_CNTL);
+ reg &= ~inv_bit;
+ DART_OUT(DART_CNTL, reg);
goto retry;
} else
- panic("U3-DART: TLB did not flush after waiting a long "
+ panic("DART: TLB did not flush after waiting a long "
"time. Buggy U3 ?");
}
}
@@ -115,7 +117,7 @@ static void dart_flush(struct iommu_table *tbl)
dart_dirty = 0;
}
-static void dart_build(struct iommu_table *tbl, long index,
+static void dart_build(struct iommu_table *tbl, long index,
long npages, unsigned long uaddr,
enum dma_data_direction direction)
{
@@ -128,7 +130,7 @@ static void dart_build(struct iommu_table *tbl, long index,
npages <<= DART_PAGE_FACTOR;
dp = ((unsigned int*)tbl->it_base) + index;
-
+
/* On U3, all memory is contigous, so we can move this
* out of the loop.
*/
@@ -148,7 +150,7 @@ static void dart_build(struct iommu_table *tbl, long index,
static void dart_free(struct iommu_table *tbl, long index, long npages)
{
unsigned int *dp;
-
+
/* We don't worry about flushing the TLB cache. The only drawback of
* not doing it is that we won't catch buggy device drivers doing
* bad DMAs, but then no 32-bit architecture ever does either.
@@ -160,7 +162,7 @@ static void dart_free(struct iommu_table *tbl, long index, long npages)
npages <<= DART_PAGE_FACTOR;
dp = ((unsigned int *)tbl->it_base) + index;
-
+
while (npages--)
*(dp++) = dart_emptyval;
}
@@ -168,20 +170,25 @@ static void dart_free(struct iommu_table *tbl, long index, long npages)
static int dart_init(struct device_node *dart_node)
{
- unsigned int regword;
unsigned int i;
- unsigned long tmp;
+ unsigned long tmp, base, size;
+ struct resource r;
if (dart_tablebase == 0 || dart_tablesize == 0) {
- printk(KERN_INFO "U3-DART: table not allocated, using direct DMA\n");
+ printk(KERN_INFO "DART: table not allocated, using "
+ "direct DMA\n");
return -ENODEV;
}
+ if (of_address_to_resource(dart_node, 0, &r))
+ panic("DART: can't get register base ! ");
+
/* Make sure nothing from the DART range remains in the CPU cache
* from a previous mapping that existed before the kernel took
* over
*/
- flush_dcache_phys_range(dart_tablebase, dart_tablebase + dart_tablesize);
+ flush_dcache_phys_range(dart_tablebase,
+ dart_tablebase + dart_tablesize);
/* Allocate a spare page to map all invalid DART pages. We need to do
* that to work around what looks like a problem with the HT bridge
@@ -189,21 +196,16 @@ static int dart_init(struct device_node *dart_node)
*/
tmp = lmb_alloc(DART_PAGE_SIZE, DART_PAGE_SIZE);
if (!tmp)
- panic("U3-DART: Cannot allocate spare page!");
- dart_emptyval = DARTMAP_VALID | ((tmp >> DART_PAGE_SHIFT) & DARTMAP_RPNMASK);
+ panic("DART: Cannot allocate spare page!");
+ dart_emptyval = DARTMAP_VALID | ((tmp >> DART_PAGE_SHIFT) &
+ DARTMAP_RPNMASK);
- /* Map in DART registers. FIXME: Use device node to get base address */
- dart = ioremap(DART_BASE, 0x7000);
+ /* Map in DART registers */
+ dart = ioremap(r.start, r.end - r.start + 1);
if (dart == NULL)
- panic("U3-DART: Cannot map registers!");
+ panic("DART: Cannot map registers!");
- /* Set initial control register contents: table base,
- * table size and enable bit
- */
- regword = DARTCNTL_ENABLE |
- ((dart_tablebase >> DART_PAGE_SHIFT) << DARTCNTL_BASE_SHIFT) |
- (((dart_tablesize >> DART_PAGE_SHIFT) & DARTCNTL_SIZE_MASK)
- << DARTCNTL_SIZE_SHIFT);
+ /* Map in DART table */
dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize);
/* Fill initial table */
@@ -211,36 +213,50 @@ static int dart_init(struct device_node *dart_node)
dart_vbase[i] = dart_emptyval;
/* Initialize DART with table base and enable it. */
- out_be32((unsigned int *)dart, regword);
+ base = dart_tablebase >> DART_PAGE_SHIFT;
+ size = dart_tablesize >> DART_PAGE_SHIFT;
+ if (dart_is_u4) {
+ size &= DART_SIZE_U4_SIZE_MASK;
+ DART_OUT(DART_BASE_U4, base);
+ DART_OUT(DART_SIZE_U4, size);
+ DART_OUT(DART_CNTL, DART_CNTL_U4_ENABLE);
+ } else {
+ size &= DART_CNTL_U3_SIZE_MASK;
+ DART_OUT(DART_CNTL,
+ DART_CNTL_U3_ENABLE |
+ (base << DART_CNTL_U3_BASE_SHIFT) |
+ (size << DART_CNTL_U3_SIZE_SHIFT));
+ }
/* Invalidate DART to get rid of possible stale TLBs */
dart_tlb_invalidate_all();
- printk(KERN_INFO "U3/CPC925 DART IOMMU initialized\n");
+ printk(KERN_INFO "DART IOMMU initialized for %s type chipset\n",
+ dart_is_u4 ? "U4" : "U3");
return 0;
}
-static void iommu_table_u3_setup(void)
+static void iommu_table_dart_setup(void)
{
- iommu_table_u3.it_busno = 0;
- iommu_table_u3.it_offset = 0;
+ iommu_table_dart.it_busno = 0;
+ iommu_table_dart.it_offset = 0;
/* it_size is in number of entries */
- iommu_table_u3.it_size = (dart_tablesize / sizeof(u32)) >> DART_PAGE_FACTOR;
+ iommu_table_dart.it_size = (dart_tablesize / sizeof(u32)) >> DART_PAGE_FACTOR;
/* Initialize the common IOMMU code */
- iommu_table_u3.it_base = (unsigned long)dart_vbase;
- iommu_table_u3.it_index = 0;
- iommu_table_u3.it_blocksize = 1;
- iommu_init_table(&iommu_table_u3);
+ iommu_table_dart.it_base = (unsigned long)dart_vbase;
+ iommu_table_dart.it_index = 0;
+ iommu_table_dart.it_blocksize = 1;
+ iommu_init_table(&iommu_table_dart);
/* Reserve the last page of the DART to avoid possible prefetch
* past the DART mapped area
*/
- set_bit(iommu_table_u3.it_size - 1, iommu_table_u3.it_map);
+ set_bit(iommu_table_dart.it_size - 1, iommu_table_dart.it_map);
}
-static void iommu_dev_setup_u3(struct pci_dev *dev)
+static void iommu_dev_setup_dart(struct pci_dev *dev)
{
struct device_node *dn;
@@ -254,35 +270,39 @@ static void iommu_dev_setup_u3(struct pci_dev *dev)
dn = pci_device_to_OF_node(dev);
if (dn)
- PCI_DN(dn)->iommu_table = &iommu_table_u3;
+ PCI_DN(dn)->iommu_table = &iommu_table_dart;
}
-static void iommu_bus_setup_u3(struct pci_bus *bus)
+static void iommu_bus_setup_dart(struct pci_bus *bus)
{
struct device_node *dn;
- if (!iommu_table_u3_inited) {
- iommu_table_u3_inited = 1;
- iommu_table_u3_setup();
+ if (!iommu_table_dart_inited) {
+ iommu_table_dart_inited = 1;
+ iommu_table_dart_setup();
}
dn = pci_bus_to_OF_node(bus);
if (dn)
- PCI_DN(dn)->iommu_table = &iommu_table_u3;
+ PCI_DN(dn)->iommu_table = &iommu_table_dart;
}
static void iommu_dev_setup_null(struct pci_dev *dev) { }
static void iommu_bus_setup_null(struct pci_bus *bus) { }
-void iommu_init_early_u3(void)
+void iommu_init_early_dart(void)
{
struct device_node *dn;
/* Find the DART in the device-tree */
dn = of_find_compatible_node(NULL, "dart", "u3-dart");
- if (dn == NULL)
- return;
+ if (dn == NULL) {
+ dn = of_find_compatible_node(NULL, "dart", "u4-dart");
+ if (dn == NULL)
+ goto bail;
+ dart_is_u4 = 1;
+ }
/* Setup low level TCE operations for the core IOMMU code */
ppc_md.tce_build = dart_build;
@@ -290,24 +310,27 @@ void iommu_init_early_u3(void)
ppc_md.tce_flush = dart_flush;
/* Initialize the DART HW */
- if (dart_init(dn)) {
- /* If init failed, use direct iommu and null setup functions */
- ppc_md.iommu_dev_setup = iommu_dev_setup_null;
- ppc_md.iommu_bus_setup = iommu_bus_setup_null;
-
- /* Setup pci_dma ops */
- pci_direct_iommu_init();
- } else {
- ppc_md.iommu_dev_setup = iommu_dev_setup_u3;
- ppc_md.iommu_bus_setup = iommu_bus_setup_u3;
+ if (dart_init(dn) == 0) {
+ ppc_md.iommu_dev_setup = iommu_dev_setup_dart;
+ ppc_md.iommu_bus_setup = iommu_bus_setup_dart;
/* Setup pci_dma ops */
pci_iommu_init();
+
+ return;
}
+
+ bail:
+ /* If init failed, use direct iommu and null setup functions */
+ ppc_md.iommu_dev_setup = iommu_dev_setup_null;
+ ppc_md.iommu_bus_setup = iommu_bus_setup_null;
+
+ /* Setup pci_dma ops */
+ pci_direct_iommu_init();
}
-void __init alloc_u3_dart_table(void)
+void __init alloc_dart_table(void)
{
/* Only reserve DART space if machine has more than 2GB of RAM
* or if requested with iommu=on on cmdline.
@@ -323,5 +346,5 @@ void __init alloc_u3_dart_table(void)
dart_tablebase = (unsigned long)
abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L));
- printk(KERN_INFO "U3-DART allocated at: %lx\n", dart_tablebase);
+ printk(KERN_INFO "DART table allocated at: %lx\n", dart_tablebase);
}
diff --git a/arch/ppc/syslib/ipic.c b/arch/powerpc/sysdev/ipic.c
index 8f01e0f1d847..8f01e0f1d847 100644
--- a/arch/ppc/syslib/ipic.c
+++ b/arch/powerpc/sysdev/ipic.c
diff --git a/arch/ppc/syslib/ipic.h b/arch/powerpc/sysdev/ipic.h
index a7ce7da8785c..a7ce7da8785c 100644
--- a/arch/ppc/syslib/ipic.h
+++ b/arch/powerpc/sysdev/ipic.h
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 58d1cc2023c8..4f26304d0263 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -13,6 +13,9 @@
*/
#undef DEBUG
+#undef DEBUG_IPI
+#undef DEBUG_IRQ
+#undef DEBUG_LOW
#include <linux/config.h>
#include <linux/types.h>
@@ -45,7 +48,11 @@ static struct mpic *mpic_primary;
static DEFINE_SPINLOCK(mpic_lock);
#ifdef CONFIG_PPC32 /* XXX for now */
-#define distribute_irqs CONFIG_IRQ_ALL_CPUS
+#ifdef CONFIG_IRQ_ALL_CPUS
+#define distribute_irqs (1)
+#else
+#define distribute_irqs (0)
+#endif
#endif
/*
@@ -164,70 +171,129 @@ static void __init mpic_test_broken_ipi(struct mpic *mpic)
/* Test if an interrupt is sourced from HyperTransport (used on broken U3s)
* to force the edge setting on the MPIC and do the ack workaround.
*/
-static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source_no)
+static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source)
{
- if (source_no >= 128 || !mpic->fixups)
+ if (source >= 128 || !mpic->fixups)
return 0;
- return mpic->fixups[source_no].base != NULL;
+ return mpic->fixups[source].base != NULL;
}
-static inline void mpic_apic_end_irq(struct mpic *mpic, unsigned int source_no)
+
+static inline void mpic_ht_end_irq(struct mpic *mpic, unsigned int source)
{
- struct mpic_irq_fixup *fixup = &mpic->fixups[source_no];
- u32 tmp;
+ struct mpic_irq_fixup *fixup = &mpic->fixups[source];
- spin_lock(&mpic->fixup_lock);
- writeb(0x11 + 2 * fixup->irq, fixup->base);
- tmp = readl(fixup->base + 2);
- writel(tmp | 0x80000000ul, fixup->base + 2);
- /* config writes shouldn't be posted but let's be safe ... */
- (void)readl(fixup->base + 2);
- spin_unlock(&mpic->fixup_lock);
+ if (fixup->applebase) {
+ unsigned int soff = (fixup->index >> 3) & ~3;
+ unsigned int mask = 1U << (fixup->index & 0x1f);
+ writel(mask, fixup->applebase + soff);
+ } else {
+ spin_lock(&mpic->fixup_lock);
+ writeb(0x11 + 2 * fixup->index, fixup->base + 2);
+ writel(fixup->data, fixup->base + 4);
+ spin_unlock(&mpic->fixup_lock);
+ }
}
+static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source,
+ unsigned int irqflags)
+{
+ struct mpic_irq_fixup *fixup = &mpic->fixups[source];
+ unsigned long flags;
+ u32 tmp;
-static void __init mpic_amd8111_read_irq(struct mpic *mpic, u8 __iomem *devbase)
+ if (fixup->base == NULL)
+ return;
+
+ DBG("startup_ht_interrupt(%u, %u) index: %d\n",
+ source, irqflags, fixup->index);
+ spin_lock_irqsave(&mpic->fixup_lock, flags);
+ /* Enable and configure */
+ writeb(0x10 + 2 * fixup->index, fixup->base + 2);
+ tmp = readl(fixup->base + 4);
+ tmp &= ~(0x23U);
+ if (irqflags & IRQ_LEVEL)
+ tmp |= 0x22;
+ writel(tmp, fixup->base + 4);
+ spin_unlock_irqrestore(&mpic->fixup_lock, flags);
+}
+
+static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source,
+ unsigned int irqflags)
{
- int i, irq;
+ struct mpic_irq_fixup *fixup = &mpic->fixups[source];
+ unsigned long flags;
u32 tmp;
- printk(KERN_INFO "mpic: - Workarounds on AMD 8111 @ %p\n", devbase);
+ if (fixup->base == NULL)
+ return;
- for (i=0; i < 24; i++) {
- writeb(0x10 + 2*i, devbase + 0xf2);
- tmp = readl(devbase + 0xf4);
- if ((tmp & 0x1) || !(tmp & 0x20))
- continue;
- irq = (tmp >> 16) & 0xff;
- mpic->fixups[irq].irq = i;
- mpic->fixups[irq].base = devbase + 0xf2;
- }
+ DBG("shutdown_ht_interrupt(%u, %u)\n", source, irqflags);
+
+ /* Disable */
+ spin_lock_irqsave(&mpic->fixup_lock, flags);
+ writeb(0x10 + 2 * fixup->index, fixup->base + 2);
+ tmp = readl(fixup->base + 4);
+ tmp &= ~1U;
+ writel(tmp, fixup->base + 4);
+ spin_unlock_irqrestore(&mpic->fixup_lock, flags);
}
-
-static void __init mpic_amd8131_read_irq(struct mpic *mpic, u8 __iomem *devbase)
+
+static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase,
+ unsigned int devfn, u32 vdid)
{
- int i, irq;
+ int i, irq, n;
+ u8 __iomem *base;
u32 tmp;
+ u8 pos;
+
+ for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0;
+ pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) {
+ u8 id = readb(devbase + pos + PCI_CAP_LIST_ID);
+ if (id == PCI_CAP_ID_HT_IRQCONF) {
+ id = readb(devbase + pos + 3);
+ if (id == 0x80)
+ break;
+ }
+ }
+ if (pos == 0)
+ return;
- printk(KERN_INFO "mpic: - Workarounds on AMD 8131 @ %p\n", devbase);
+ base = devbase + pos;
+ writeb(0x01, base + 2);
+ n = (readl(base + 4) >> 16) & 0xff;
- for (i=0; i < 4; i++) {
- writeb(0x10 + 2*i, devbase + 0xba);
- tmp = readl(devbase + 0xbc);
- if ((tmp & 0x1) || !(tmp & 0x20))
- continue;
+ printk(KERN_INFO "mpic: - HT:%02x.%x [0x%02x] vendor %04x device %04x"
+ " has %d irqs\n",
+ devfn >> 3, devfn & 0x7, pos, vdid & 0xffff, vdid >> 16, n + 1);
+
+ for (i = 0; i <= n; i++) {
+ writeb(0x10 + 2 * i, base + 2);
+ tmp = readl(base + 4);
irq = (tmp >> 16) & 0xff;
- mpic->fixups[irq].irq = i;
- mpic->fixups[irq].base = devbase + 0xba;
+ DBG("HT PIC index 0x%x, irq 0x%x, tmp: %08x\n", i, irq, tmp);
+ /* mask it , will be unmasked later */
+ tmp |= 0x1;
+ writel(tmp, base + 4);
+ mpic->fixups[irq].index = i;
+ mpic->fixups[irq].base = base;
+ /* Apple HT PIC has a non-standard way of doing EOIs */
+ if ((vdid & 0xffff) == 0x106b)
+ mpic->fixups[irq].applebase = devbase + 0x60;
+ else
+ mpic->fixups[irq].applebase = NULL;
+ writeb(0x11 + 2 * i, base + 2);
+ mpic->fixups[irq].data = readl(base + 4) | 0x80000000;
}
}
-static void __init mpic_scan_ioapics(struct mpic *mpic)
+
+static void __init mpic_scan_ht_pics(struct mpic *mpic)
{
unsigned int devfn;
u8 __iomem *cfgspace;
- printk(KERN_INFO "mpic: Setting up IO-APICs workarounds for U3\n");
+ printk(KERN_INFO "mpic: Setting up HT PICs workarounds for U3/U4\n");
/* Allocate fixups array */
mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup));
@@ -237,21 +303,20 @@ static void __init mpic_scan_ioapics(struct mpic *mpic)
/* Init spinlock */
spin_lock_init(&mpic->fixup_lock);
- /* Map u3 config space. We assume all IO-APICs are on the primary bus
- * and slot will never be above "0xf" so we only need to map 32k
+ /* Map U3 config space. We assume all IO-APICs are on the primary bus
+ * so we only need to map 64kB.
*/
- cfgspace = (unsigned char __iomem *)ioremap(0xf2000000, 0x8000);
+ cfgspace = ioremap(0xf2000000, 0x10000);
BUG_ON(cfgspace == NULL);
- /* Now we scan all slots. We do a very quick scan, we read the header type,
- * vendor ID and device ID only, that's plenty enough
+ /* Now we scan all slots. We do a very quick scan, we read the header
+ * type, vendor ID and device ID only, that's plenty enough
*/
- for (devfn = 0; devfn < PCI_DEVFN(0x10,0); devfn ++) {
+ for (devfn = 0; devfn < 0x100; devfn++) {
u8 __iomem *devbase = cfgspace + (devfn << 8);
u8 hdr_type = readb(devbase + PCI_HEADER_TYPE);
u32 l = readl(devbase + PCI_VENDOR_ID);
- u16 vendor_id, device_id;
- int multifunc = 0;
+ u16 s;
DBG("devfn %x, l: %x\n", devfn, l);
@@ -259,22 +324,16 @@ static void __init mpic_scan_ioapics(struct mpic *mpic)
if (l == 0xffffffff || l == 0x00000000 ||
l == 0x0000ffff || l == 0xffff0000)
goto next;
+ /* Check if is supports capability lists */
+ s = readw(devbase + PCI_STATUS);
+ if (!(s & PCI_STATUS_CAP_LIST))
+ goto next;
+
+ mpic_scan_ht_pic(mpic, devbase, devfn, l);
- /* Check if it's a multifunction device (only really used
- * to function 0 though
- */
- multifunc = !!(hdr_type & 0x80);
- vendor_id = l & 0xffff;
- device_id = (l >> 16) & 0xffff;
-
- /* If a known device, go to fixup setup code */
- if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7460)
- mpic_amd8111_read_irq(mpic, devbase);
- if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7450)
- mpic_amd8131_read_irq(mpic, devbase);
next:
/* next device, if function 0 */
- if ((PCI_FUNC(devfn) == 0) && !multifunc)
+ if (PCI_FUNC(devfn) == 0 && (hdr_type & 0x80) == 0)
devfn += 7;
}
}
@@ -371,6 +430,31 @@ static void mpic_enable_irq(unsigned int irq)
break;
}
} while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+ if (mpic->flags & MPIC_BROKEN_U3) {
+ unsigned int src = irq - mpic->irq_offset;
+ if (mpic_is_ht_interrupt(mpic, src) &&
+ (irq_desc[irq].status & IRQ_LEVEL))
+ mpic_ht_end_irq(mpic, src);
+ }
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+}
+
+static unsigned int mpic_startup_irq(unsigned int irq)
+{
+#ifdef CONFIG_MPIC_BROKEN_U3
+ struct mpic *mpic = mpic_from_irq(irq);
+ unsigned int src = irq - mpic->irq_offset;
+
+ if (mpic_is_ht_interrupt(mpic, src))
+ mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status);
+
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+ mpic_enable_irq(irq);
+
+ return 0;
}
static void mpic_disable_irq(unsigned int irq)
@@ -394,12 +478,27 @@ static void mpic_disable_irq(unsigned int irq)
} while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
}
+static void mpic_shutdown_irq(unsigned int irq)
+{
+#ifdef CONFIG_MPIC_BROKEN_U3
+ struct mpic *mpic = mpic_from_irq(irq);
+ unsigned int src = irq - mpic->irq_offset;
+
+ if (mpic_is_ht_interrupt(mpic, src))
+ mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status);
+
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+ mpic_disable_irq(irq);
+}
+
static void mpic_end_irq(unsigned int irq)
{
struct mpic *mpic = mpic_from_irq(irq);
+#ifdef DEBUG_IRQ
DBG("%s: end_irq: %d\n", mpic->name, irq);
-
+#endif
/* We always EOI on end_irq() even for edge interrupts since that
* should only lower the priority, the MPIC should have properly
* latched another edge interrupt coming in anyway
@@ -408,8 +507,9 @@ static void mpic_end_irq(unsigned int irq)
#ifdef CONFIG_MPIC_BROKEN_U3
if (mpic->flags & MPIC_BROKEN_U3) {
unsigned int src = irq - mpic->irq_offset;
- if (mpic_is_ht_interrupt(mpic, src))
- mpic_apic_end_irq(mpic, src);
+ if (mpic_is_ht_interrupt(mpic, src) &&
+ (irq_desc[irq].status & IRQ_LEVEL))
+ mpic_ht_end_irq(mpic, src);
}
#endif /* CONFIG_MPIC_BROKEN_U3 */
@@ -490,6 +590,8 @@ struct mpic * __init mpic_alloc(unsigned long phys_addr,
mpic->name = name;
mpic->hc_irq.typename = name;
+ mpic->hc_irq.startup = mpic_startup_irq;
+ mpic->hc_irq.shutdown = mpic_shutdown_irq;
mpic->hc_irq.enable = mpic_enable_irq;
mpic->hc_irq.disable = mpic_disable_irq;
mpic->hc_irq.end = mpic_end_irq;
@@ -658,10 +760,10 @@ void __init mpic_init(struct mpic *mpic)
mpic->irq_count = mpic->num_sources;
#ifdef CONFIG_MPIC_BROKEN_U3
- /* Do the ioapic fixups on U3 broken mpic */
+ /* Do the HT PIC fixups on U3 broken mpic */
DBG("MPIC flags: %x\n", mpic->flags);
if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
- mpic_scan_ioapics(mpic);
+ mpic_scan_ht_pics(mpic);
#endif /* CONFIG_MPIC_BROKEN_U3 */
for (i = 0; i < mpic->num_sources; i++) {
@@ -848,7 +950,9 @@ void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask)
BUG_ON(mpic == NULL);
+#ifdef DEBUG_IPI
DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no);
+#endif
mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10,
mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0]));
@@ -859,19 +963,28 @@ int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs)
u32 irq;
irq = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK;
+#ifdef DEBUG_LOW
DBG("%s: get_one_irq(): %d\n", mpic->name, irq);
-
+#endif
if (mpic->cascade && irq == mpic->cascade_vec) {
+#ifdef DEBUG_LOW
DBG("%s: cascading ...\n", mpic->name);
+#endif
irq = mpic->cascade(regs, mpic->cascade_data);
mpic_eoi(mpic);
return irq;
}
if (unlikely(irq == MPIC_VEC_SPURRIOUS))
return -1;
- if (irq < MPIC_VEC_IPI_0)
+ if (irq < MPIC_VEC_IPI_0) {
+#ifdef DEBUG_IRQ
+ DBG("%s: irq %d\n", mpic->name, irq + mpic->irq_offset);
+#endif
return irq + mpic->irq_offset;
+ }
+#ifdef DEBUG_IPI
DBG("%s: ipi %d !\n", mpic->name, irq - MPIC_VEC_IPI_0);
+#endif
return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset;
}
diff --git a/arch/powerpc/xmon/Makefile b/arch/powerpc/xmon/Makefile
index b20312e5ed27..109d874ecfbe 100644
--- a/arch/powerpc/xmon/Makefile
+++ b/arch/powerpc/xmon/Makefile
@@ -3,9 +3,5 @@
ifdef CONFIG_PPC64
EXTRA_CFLAGS += -mno-minimal-toc
endif
-
-obj-$(CONFIG_8xx) += start_8xx.o
-obj-$(CONFIG_6xx) += start_32.o
-obj-$(CONFIG_4xx) += start_32.o
-obj-$(CONFIG_PPC64) += start_64.o
-obj-y += xmon.o ppc-dis.o ppc-opc.o setjmp.o nonstdio.o
+obj-y += xmon.o ppc-dis.o ppc-opc.o setjmp.o start.o \
+ nonstdio.o
diff --git a/arch/powerpc/xmon/start_64.c b/arch/powerpc/xmon/start.c
index 712552c4f242..712552c4f242 100644
--- a/arch/powerpc/xmon/start_64.c
+++ b/arch/powerpc/xmon/start.c
diff --git a/arch/powerpc/xmon/start_32.c b/arch/powerpc/xmon/start_32.c
deleted file mode 100644
index c2464df4217e..000000000000
--- a/arch/powerpc/xmon/start_32.c
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * Copyright (C) 1996 Paul Mackerras.
- */
-#include <linux/config.h>
-#include <linux/string.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/page.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <linux/cuda.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/bitops.h>
-#include <asm/xmon.h>
-#include <asm/prom.h>
-#include <asm/bootx.h>
-#include <asm/machdep.h>
-#include <asm/errno.h>
-#include <asm/pmac_feature.h>
-#include <asm/processor.h>
-#include <asm/delay.h>
-#include <asm/btext.h>
-#include <asm/time.h>
-#include "nonstdio.h"
-
-static volatile unsigned char __iomem *sccc, *sccd;
-unsigned int TXRDY, RXRDY, DLAB;
-
-static int use_serial;
-static int use_screen;
-static int via_modem;
-static int xmon_use_sccb;
-static struct device_node *channel_node;
-
-void buf_access(void)
-{
- if (DLAB)
- sccd[3] &= ~DLAB; /* reset DLAB */
-}
-
-extern int adb_init(void);
-
-#ifdef CONFIG_PPC_CHRP
-/*
- * This looks in the "ranges" property for the primary PCI host bridge
- * to find the physical address of the start of PCI/ISA I/O space.
- * It is basically a cut-down version of pci_process_bridge_OF_ranges.
- */
-static unsigned long chrp_find_phys_io_base(void)
-{
- struct device_node *node;
- unsigned int *ranges;
- unsigned long base = CHRP_ISA_IO_BASE;
- int rlen = 0;
- int np;
-
- node = find_devices("isa");
- if (node != NULL) {
- node = node->parent;
- if (node == NULL || node->type == NULL
- || strcmp(node->type, "pci") != 0)
- node = NULL;
- }
- if (node == NULL)
- node = find_devices("pci");
- if (node == NULL)
- return base;
-
- ranges = (unsigned int *) get_property(node, "ranges", &rlen);
- np = prom_n_addr_cells(node) + 5;
- while ((rlen -= np * sizeof(unsigned int)) >= 0) {
- if ((ranges[0] >> 24) == 1 && ranges[2] == 0) {
- /* I/O space starting at 0, grab the phys base */
- base = ranges[np - 3];
- break;
- }
- ranges += np;
- }
- return base;
-}
-#endif /* CONFIG_PPC_CHRP */
-
-void xmon_map_scc(void)
-{
-#ifdef CONFIG_PPC_MULTIPLATFORM
- volatile unsigned char __iomem *base;
-
- if (_machine == _MACH_Pmac) {
- struct device_node *np;
- unsigned long addr;
-#ifdef CONFIG_BOOTX_TEXT
- if (!use_screen && !use_serial
- && !machine_is_compatible("iMac")) {
- /* see if there is a keyboard in the device tree
- with a parent of type "adb" */
- for (np = find_devices("keyboard"); np; np = np->next)
- if (np->parent && np->parent->type
- && strcmp(np->parent->type, "adb") == 0)
- break;
-
- /* needs to be hacked if xmon_printk is to be used
- from within find_via_pmu() */
-#ifdef CONFIG_ADB_PMU
- if (np != NULL && boot_text_mapped && find_via_pmu())
- use_screen = 1;
-#endif
-#ifdef CONFIG_ADB_CUDA
- if (np != NULL && boot_text_mapped && find_via_cuda())
- use_screen = 1;
-#endif
- }
- if (!use_screen && (np = find_devices("escc")) != NULL) {
- /*
- * look for the device node for the serial port
- * we're using and see if it says it has a modem
- */
- char *name = xmon_use_sccb? "ch-b": "ch-a";
- char *slots;
- int l;
-
- np = np->child;
- while (np != NULL && strcmp(np->name, name) != 0)
- np = np->sibling;
- if (np != NULL) {
- /* XXX should parse this properly */
- channel_node = np;
- slots = get_property(np, "slot-names", &l);
- if (slots != NULL && l >= 10
- && strcmp(slots+4, "Modem") == 0)
- via_modem = 1;
- }
- }
- btext_drawstring("xmon uses ");
- if (use_screen)
- btext_drawstring("screen and keyboard\n");
- else {
- if (via_modem)
- btext_drawstring("modem on ");
- btext_drawstring(xmon_use_sccb? "printer": "modem");
- btext_drawstring(" port\n");
- }
-
-#endif /* CONFIG_BOOTX_TEXT */
-
-#ifdef CHRP_ESCC
- addr = 0xc1013020;
-#else
- addr = 0xf3013020;
-#endif
- TXRDY = 4;
- RXRDY = 1;
-
- np = find_devices("mac-io");
- if (np && np->n_addrs)
- addr = np->addrs[0].address + 0x13020;
- base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE);
- sccc = base + (addr & ~PAGE_MASK);
- sccd = sccc + 0x10;
-
- } else {
- base = (volatile unsigned char *) isa_io_base;
-
-#ifdef CONFIG_PPC_CHRP
- if (_machine == _MACH_chrp)
- base = (volatile unsigned char __iomem *)
- ioremap(chrp_find_phys_io_base(), 0x1000);
-#endif
-
- sccc = base + 0x3fd;
- sccd = base + 0x3f8;
- if (xmon_use_sccb) {
- sccc -= 0x100;
- sccd -= 0x100;
- }
- TXRDY = 0x20;
- RXRDY = 1;
- DLAB = 0x80;
- }
-#elif defined(CONFIG_GEMINI)
- /* should already be mapped by the kernel boot */
- sccc = (volatile unsigned char __iomem *) 0xffeffb0d;
- sccd = (volatile unsigned char __iomem *) 0xffeffb08;
- TXRDY = 0x20;
- RXRDY = 1;
- DLAB = 0x80;
-#elif defined(CONFIG_405GP)
- sccc = (volatile unsigned char __iomem *)0xef600305;
- sccd = (volatile unsigned char __iomem *)0xef600300;
- TXRDY = 0x20;
- RXRDY = 1;
- DLAB = 0x80;
-#endif /* platform */
-}
-
-static int scc_initialized = 0;
-
-void xmon_init_scc(void);
-extern void cuda_poll(void);
-
-static inline void do_poll_adb(void)
-{
-#ifdef CONFIG_ADB_PMU
- if (sys_ctrler == SYS_CTRLER_PMU)
- pmu_poll_adb();
-#endif /* CONFIG_ADB_PMU */
-#ifdef CONFIG_ADB_CUDA
- if (sys_ctrler == SYS_CTRLER_CUDA)
- cuda_poll();
-#endif /* CONFIG_ADB_CUDA */
-}
-
-int xmon_write(void *ptr, int nb)
-{
- char *p = ptr;
- int i, c, ct;
-
-#ifdef CONFIG_SMP
- static unsigned long xmon_write_lock;
- int lock_wait = 1000000;
- int locked;
-
- while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0)
- if (--lock_wait == 0)
- break;
-#endif
-
-#ifdef CONFIG_BOOTX_TEXT
- if (use_screen) {
- /* write it on the screen */
- for (i = 0; i < nb; ++i)
- btext_drawchar(*p++);
- goto out;
- }
-#endif
- if (!scc_initialized)
- xmon_init_scc();
- ct = 0;
- for (i = 0; i < nb; ++i) {
- while ((*sccc & TXRDY) == 0)
- do_poll_adb();
- c = p[i];
- if (c == '\n' && !ct) {
- c = '\r';
- ct = 1;
- --i;
- } else {
- ct = 0;
- }
- buf_access();
- *sccd = c;
- eieio();
- }
-
- out:
-#ifdef CONFIG_SMP
- if (!locked)
- clear_bit(0, &xmon_write_lock);
-#endif
- return nb;
-}
-
-int xmon_wants_key;
-int xmon_adb_keycode;
-
-#ifdef CONFIG_BOOTX_TEXT
-static int xmon_adb_shiftstate;
-
-static unsigned char xmon_keytab[128] =
- "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */
- "yt123465=97-80]o" /* 0x10 - 0x1f */
- "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */
- "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
- "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
- "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
-
-static unsigned char xmon_shift_keytab[128] =
- "ASDFHGZXCV\000BQWER" /* 0x00 - 0x0f */
- "YT!@#$^%+(&_*)}O" /* 0x10 - 0x1f */
- "U{IP\rLJ\"K:|<?NM>" /* 0x20 - 0x2f */
- "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
- "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
- "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
-
-static int xmon_get_adb_key(void)
-{
- int k, t, on;
-
- xmon_wants_key = 1;
- for (;;) {
- xmon_adb_keycode = -1;
- t = 0;
- on = 0;
- do {
- if (--t < 0) {
- on = 1 - on;
- btext_drawchar(on? 0xdb: 0x20);
- btext_drawchar('\b');
- t = 200000;
- }
- do_poll_adb();
- } while (xmon_adb_keycode == -1);
- k = xmon_adb_keycode;
- if (on)
- btext_drawstring(" \b");
-
- /* test for shift keys */
- if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
- xmon_adb_shiftstate = (k & 0x80) == 0;
- continue;
- }
- if (k >= 0x80)
- continue; /* ignore up transitions */
- k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
- if (k != 0)
- break;
- }
- xmon_wants_key = 0;
- return k;
-}
-#endif /* CONFIG_BOOTX_TEXT */
-
-int xmon_readchar(void)
-{
-#ifdef CONFIG_BOOTX_TEXT
- if (use_screen)
- return xmon_get_adb_key();
-#endif
- if (!scc_initialized)
- xmon_init_scc();
- while ((*sccc & RXRDY) == 0)
- do_poll_adb();
- buf_access();
- return *sccd;
-}
-
-int xmon_read_poll(void)
-{
- if ((*sccc & RXRDY) == 0) {
- do_poll_adb();
- return -1;
- }
- buf_access();
- return *sccd;
-}
-
-static unsigned char scc_inittab[] = {
- 13, 0, /* set baud rate divisor */
- 12, 1,
- 14, 1, /* baud rate gen enable, src=rtxc */
- 11, 0x50, /* clocks = br gen */
- 5, 0xea, /* tx 8 bits, assert DTR & RTS */
- 4, 0x46, /* x16 clock, 1 stop */
- 3, 0xc1, /* rx enable, 8 bits */
-};
-
-void xmon_init_scc(void)
-{
- if ( _machine == _MACH_chrp )
- {
- sccd[3] = 0x83; eieio(); /* LCR = 8N1 + DLAB */
- sccd[0] = 12; eieio(); /* DLL = 9600 baud */
- sccd[1] = 0; eieio();
- sccd[2] = 0; eieio(); /* FCR = 0 */
- sccd[3] = 3; eieio(); /* LCR = 8N1 */
- sccd[1] = 0; eieio(); /* IER = 0 */
- }
- else if ( _machine == _MACH_Pmac )
- {
- int i, x;
- unsigned long timeout;
-
- if (channel_node != 0)
- pmac_call_feature(
- PMAC_FTR_SCC_ENABLE,
- channel_node,
- PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
- printk(KERN_INFO "Serial port locked ON by debugger !\n");
- if (via_modem && channel_node != 0) {
- unsigned int t0;
-
- pmac_call_feature(
- PMAC_FTR_MODEM_ENABLE,
- channel_node, 0, 1);
- printk(KERN_INFO "Modem powered up by debugger !\n");
- t0 = get_tbl();
- timeout = 3 * tb_ticks_per_sec;
- if (timeout == 0)
- /* assume 25MHz if tb_ticks_per_sec not set */
- timeout = 75000000;
- while (get_tbl() - t0 < timeout)
- eieio();
- }
- /* use the B channel if requested */
- if (xmon_use_sccb) {
- sccc = (volatile unsigned char *)
- ((unsigned long)sccc & ~0x20);
- sccd = sccc + 0x10;
- }
- for (i = 20000; i != 0; --i) {
- x = *sccc; eieio();
- }
- *sccc = 9; eieio(); /* reset A or B side */
- *sccc = ((unsigned long)sccc & 0x20)? 0x80: 0x40; eieio();
- for (i = 0; i < sizeof(scc_inittab); ++i) {
- *sccc = scc_inittab[i];
- eieio();
- }
- }
- scc_initialized = 1;
- if (via_modem) {
- for (;;) {
- xmon_write("ATE1V1\r", 7);
- if (xmon_expect("OK", 5)) {
- xmon_write("ATA\r", 4);
- if (xmon_expect("CONNECT", 40))
- break;
- }
- xmon_write("+++", 3);
- xmon_expect("OK", 3);
- }
- }
-}
-
-void xmon_enter(void)
-{
-#ifdef CONFIG_ADB_PMU
- if (_machine == _MACH_Pmac) {
- pmu_suspend();
- }
-#endif
-}
-
-void xmon_leave(void)
-{
-#ifdef CONFIG_ADB_PMU
- if (_machine == _MACH_Pmac) {
- pmu_resume();
- }
-#endif
-}
diff --git a/arch/powerpc/xmon/start_8xx.c b/arch/powerpc/xmon/start_8xx.c
deleted file mode 100644
index 4c17b0486ad5..000000000000
--- a/arch/powerpc/xmon/start_8xx.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 1996 Paul Mackerras.
- * Copyright (C) 2000 Dan Malek.
- * Quick hack of Paul's code to make XMON work on 8xx processors. Lots
- * of assumptions, like the SMC1 is used, it has been initialized by the
- * loader at some point, and we can just stuff and suck bytes.
- * We rely upon the 8xx uart driver to support us, as the interface
- * changes between boot up and operational phases of the kernel.
- */
-#include <linux/string.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/page.h>
-#include <linux/kernel.h>
-#include <asm/8xx_immap.h>
-#include <asm/mpc8xx.h>
-#include <asm/commproc.h>
-#include "nonstdio.h"
-
-extern int xmon_8xx_write(char *str, int nb);
-extern int xmon_8xx_read_poll(void);
-extern int xmon_8xx_read_char(void);
-
-void xmon_map_scc(void)
-{
- cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
-}
-
-void xmon_init_scc(void);
-
-int xmon_write(void *ptr, int nb)
-{
- return(xmon_8xx_write(ptr, nb));
-}
-
-int xmon_readchar(void)
-{
- return xmon_8xx_read_char();
-}
-
-int xmon_read_poll(void)
-{
- return(xmon_8xx_read_poll());
-}
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index c45a6ad5f3b7..22612ed5379c 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -450,7 +450,6 @@ int xmon_core(struct pt_regs *regs, int fromipi)
leave:
cpu_clear(cpu, cpus_in_xmon);
xmon_fault_jmp[cpu] = NULL;
-
#else
/* UP is simple... */
if (in_xmon) {
@@ -805,7 +804,10 @@ cmds(struct pt_regs *excp)
break;
case 'x':
case 'X':
+ return cmd;
case EOF:
+ printf(" <no input ...>\n");
+ mdelay(2000);
return cmd;
case '?':
printf(help_string);
@@ -1011,7 +1013,7 @@ static long check_bp_loc(unsigned long addr)
unsigned int instr;
addr &= ~3;
- if (addr < KERNELBASE) {
+ if (!is_kernel_addr(addr)) {
printf("Breakpoints may only be placed at kernel addresses\n");
return 0;
}
@@ -1062,7 +1064,7 @@ bpt_cmds(void)
dabr.address = 0;
dabr.enabled = 0;
if (scanhex(&dabr.address)) {
- if (dabr.address < KERNELBASE) {
+ if (!is_kernel_addr(dabr.address)) {
printf(badaddr);
break;
}
diff --git a/arch/ppc/boot/common/util.S b/arch/ppc/boot/common/util.S
index c96c9f80521e..368ec035e6cd 100644
--- a/arch/ppc/boot/common/util.S
+++ b/arch/ppc/boot/common/util.S
@@ -234,7 +234,8 @@ udelay:
* First, flush the data cache in case it was enabled and may be
* holding instructions for copy back.
*/
-_GLOBAL(flush_instruction_cache)
+ .globl flush_instruction_cache
+flush_instruction_cache:
mflr r6
bl flush_data_cache
@@ -279,7 +280,8 @@ _GLOBAL(flush_instruction_cache)
* Flush data cache
* Do this by just reading lots of stuff into the cache.
*/
-_GLOBAL(flush_data_cache)
+ .globl flush_data_cache
+flush_data_cache:
lis r3,cache_flush_buffer@h
ori r3,r3,cache_flush_buffer@l
li r4,NUM_CACHE_LINES
diff --git a/arch/ppc/boot/images/Makefile b/arch/ppc/boot/images/Makefile
index 532e7ef1edb6..58415d5718e3 100644
--- a/arch/ppc/boot/images/Makefile
+++ b/arch/ppc/boot/images/Makefile
@@ -26,7 +26,7 @@ quiet_cmd_uimage = UIMAGE $@
targets += uImage
$(obj)/uImage: $(obj)/vmlinux.gz
$(Q)rm -f $@
- $(call if_changed,uimage)
+ $(call cmd,uimage)
@echo -n ' Image: $@ '
@if [ -f $@ ]; then echo 'is ready' ; else echo 'not made'; fi
diff --git a/arch/ppc/configs/TQM8540_defconfig b/arch/ppc/configs/TQM8540_defconfig
new file mode 100644
index 000000000000..99bf3b7a2762
--- /dev/null
+++ b/arch/ppc/configs/TQM8540_defconfig
@@ -0,0 +1,973 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.15-rc2
+# Fri Nov 25 17:26:50 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# 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_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+# 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
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_E500=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+CONFIG_MATH_EMULATION=y
+# CONFIG_KEXEC is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_PPC_GEN550=y
+CONFIG_85xx=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Freescale 85xx options
+#
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8548_CDS is not set
+# CONFIG_MPC8555_CDS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_SBC8560 is not set
+# CONFIG_STX_GP3 is not set
+CONFIG_TQM8540=y
+# CONFIG_TQM8541 is not set
+# CONFIG_TQM8555 is not set
+# CONFIG_TQM8560 is not set
+CONFIG_MPC8540=y
+
+#
+# Platform options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_PPC_I8259=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+# CONFIG_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+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=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# 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_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP 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
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_TQM85xx=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND 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=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# 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
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+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
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY 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_CASSINI 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=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# 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_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# 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
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC 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=4
+# CONFIG_SERIAL_8250_EXTENDED 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=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X 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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_SENSORS_DS1337=y
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+CONFIG_SENSORS_LM75=y
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_HWMON_DEBUG_CHIP=y
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# 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
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# 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
+
+#
+# SN Devices
+#
+
+#
+# File systems
+#
+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=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# 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
+# 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=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# 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_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# 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
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SERIAL_TEXT_DEBUG 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
+#
diff --git a/arch/ppc/configs/TQM8541_defconfig b/arch/ppc/configs/TQM8541_defconfig
new file mode 100644
index 000000000000..0ff56695d349
--- /dev/null
+++ b/arch/ppc/configs/TQM8541_defconfig
@@ -0,0 +1,986 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.15-rc2
+# Wed Nov 30 13:36:28 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# 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_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+# 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
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_E500=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+CONFIG_MATH_EMULATION=y
+# CONFIG_KEXEC is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_PPC_GEN550=y
+CONFIG_85xx=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Freescale 85xx options
+#
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8548_CDS is not set
+# CONFIG_MPC8555_CDS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_SBC8560 is not set
+# CONFIG_STX_GP3 is not set
+# CONFIG_TQM8540 is not set
+CONFIG_TQM8541=y
+# CONFIG_TQM8555 is not set
+# CONFIG_TQM8560 is not set
+CONFIG_MPC8555=y
+
+#
+# Platform options
+#
+CONFIG_CPM2=y
+# CONFIG_PC_KEYBOARD is not set
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_PPC_I8259=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+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=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# 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_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP 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
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_TQM85xx=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND 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=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# 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
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+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
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY 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_CASSINI 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=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# 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
+# CONFIG_FS_ENET 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_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# 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
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC 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=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_CPM is not set
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X 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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_MPC8260 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_SENSORS_DS1337=y
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_MAX6900 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8563 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+CONFIG_SENSORS_LM75=y
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_HWMON_DEBUG_CHIP=y
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# 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
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# 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
+
+#
+# SN Devices
+#
+
+#
+# File systems
+#
+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=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# 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
+# 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=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# 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_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# 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
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+# CONFIG_SCC_ENET is not set
+# CONFIG_FEC_ENET is not set
+
+#
+# CPM2 Options
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_KGDB_CONSOLE is not set
+# CONFIG_SERIAL_TEXT_DEBUG 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
+#
diff --git a/arch/ppc/configs/TQM8555_defconfig b/arch/ppc/configs/TQM8555_defconfig
new file mode 100644
index 000000000000..730b3db2e47a
--- /dev/null
+++ b/arch/ppc/configs/TQM8555_defconfig
@@ -0,0 +1,983 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.15-rc2
+# Thu Nov 24 17:10:52 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# 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_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+# 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
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_E500=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+CONFIG_MATH_EMULATION=y
+# CONFIG_KEXEC is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_PPC_GEN550=y
+CONFIG_85xx=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Freescale 85xx options
+#
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8548_CDS is not set
+# CONFIG_MPC8555_CDS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_SBC8560 is not set
+# CONFIG_STX_GP3 is not set
+# CONFIG_TQM8540 is not set
+# CONFIG_TQM8541 is not set
+CONFIG_TQM8555=y
+# CONFIG_TQM8560 is not set
+CONFIG_MPC8555=y
+
+#
+# Platform options
+#
+CONFIG_CPM2=y
+# CONFIG_PC_KEYBOARD is not set
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_PPC_I8259=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+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=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# 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_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP 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
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_TQM85xx=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND 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=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# 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
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+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
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY 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_CASSINI 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=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# 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
+# CONFIG_FS_ENET 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_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# 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
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC 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=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_CPM is not set
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X 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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_SENSORS_DS1337=y
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+CONFIG_SENSORS_LM75=y
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_HWMON_DEBUG_CHIP=y
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# 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
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# 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
+
+#
+# SN Devices
+#
+
+#
+# File systems
+#
+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=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# 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
+# 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=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# 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_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# 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
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+# CONFIG_SCC_ENET is not set
+# CONFIG_FEC_ENET is not set
+
+#
+# CPM2 Options
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_KGDB_CONSOLE is not set
+# CONFIG_SERIAL_TEXT_DEBUG 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
+#
diff --git a/arch/ppc/configs/TQM8560_defconfig b/arch/ppc/configs/TQM8560_defconfig
new file mode 100644
index 000000000000..1d902072825e
--- /dev/null
+++ b/arch/ppc/configs/TQM8560_defconfig
@@ -0,0 +1,992 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.15-rc2
+# Wed Nov 30 16:47:53 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# 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_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+# 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
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_E500=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+CONFIG_MATH_EMULATION=y
+# CONFIG_KEXEC is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_85xx=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Freescale 85xx options
+#
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8548_CDS is not set
+# CONFIG_MPC8555_CDS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_SBC8560 is not set
+# CONFIG_STX_GP3 is not set
+# CONFIG_TQM8540 is not set
+# CONFIG_TQM8541 is not set
+# CONFIG_TQM8555 is not set
+CONFIG_TQM8560=y
+CONFIG_MPC8560=y
+
+#
+# Platform options
+#
+CONFIG_CPM2=y
+# CONFIG_PC_KEYBOARD is not set
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_PPC_I8259=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+# CONFIG_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+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=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# 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_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP 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
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_TQM85xx=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND 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=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# 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
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+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
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY 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_CASSINI 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=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# 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
+# CONFIG_FS_ENET 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_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# 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
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC 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=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+CONFIG_SERIAL_CPM_SCC1=y
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+# CONFIG_SERIAL_CPM_SMC1 is not set
+# CONFIG_SERIAL_CPM_SMC2 is not set
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X 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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_MPC8260 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_SENSORS_DS1337=y
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_MAX6900 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8563 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+CONFIG_SENSORS_LM75=y
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_HWMON_DEBUG_CHIP=y
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# 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
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# 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
+
+#
+# SN Devices
+#
+
+#
+# File systems
+#
+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=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# 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
+# 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=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# 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_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# 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
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+# CONFIG_SCC_ENET is not set
+# CONFIG_FEC_ENET is not set
+
+#
+# CPM2 Options
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_KGDB_CONSOLE 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
+#
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index 0bb23fce4293..e6c1d615bb86 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -49,5 +49,4 @@ obj-$(CONFIG_TAU) += temp.o
ifndef CONFIG_E200
obj-$(CONFIG_FSL_BOOKE) += perfmon_fsl_booke.o
endif
-obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
endif
diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c
index fe0e767fb94e..7964bf660e92 100644
--- a/arch/ppc/kernel/asm-offsets.c
+++ b/arch/ppc/kernel/asm-offsets.c
@@ -131,7 +131,7 @@ main(void)
DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features));
DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup));
- DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror));
+ DEFINE(TI_SIGFRAME, offsetof(struct thread_info, nvgprs_frame));
DEFINE(TI_TASK, offsetof(struct thread_info, task));
DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
index f044edbb454f..a48b950722a1 100644
--- a/arch/ppc/kernel/entry.S
+++ b/arch/ppc/kernel/entry.S
@@ -200,8 +200,6 @@ _GLOBAL(DoSyscall)
bl do_show_syscall
#endif /* SHOW_SYSCALLS */
rlwinm r10,r1,0,0,18 /* current_thread_info() */
- li r11,0
- stb r11,TI_SC_NOERR(r10)
lwz r11,TI_FLAGS(r10)
andi. r11,r11,_TIF_SYSCALL_T_OR_A
bne- syscall_dotrace
@@ -222,25 +220,21 @@ ret_from_syscall:
bl do_show_syscall_exit
#endif
mr r6,r3
- li r11,-_LAST_ERRNO
- cmplw 0,r3,r11
rlwinm r12,r1,0,0,18 /* current_thread_info() */
- blt+ 30f
- lbz r11,TI_SC_NOERR(r12)
- cmpwi r11,0
- bne 30f
- neg r3,r3
- lwz r10,_CCR(r1) /* Set SO bit in CR */
- oris r10,r10,0x1000
- stw r10,_CCR(r1)
-
/* disable interrupts so current_thread_info()->flags can't change */
-30: LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
+ LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
SYNC
MTMSRD(r10)
lwz r9,TI_FLAGS(r12)
- andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+ li r8,-_LAST_ERRNO
+ andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
bne- syscall_exit_work
+ cmplw 0,r3,r8
+ blt+ syscall_exit_cont
+ lwz r11,_CCR(r1) /* Load CR */
+ neg r3,r3
+ oris r11,r11,0x1000 /* Set SO bit in CR */
+ stw r11,_CCR(r1)
syscall_exit_cont:
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
/* If the process has its own DBCR0 value, load it up. The single
@@ -292,46 +286,113 @@ syscall_dotrace:
b syscall_dotrace_cont
syscall_exit_work:
- stw r6,RESULT(r1) /* Save result */
+ andi. r0,r9,_TIF_RESTOREALL
+ bne- 2f
+ cmplw 0,r3,r8
+ blt+ 1f
+ andi. r0,r9,_TIF_NOERROR
+ bne- 1f
+ lwz r11,_CCR(r1) /* Load CR */
+ neg r3,r3
+ oris r11,r11,0x1000 /* Set SO bit in CR */
+ stw r11,_CCR(r1)
+
+1: stw r6,RESULT(r1) /* Save result */
stw r3,GPR3(r1) /* Update return value */
- andi. r0,r9,_TIF_SYSCALL_T_OR_A
- beq 5f
- ori r10,r10,MSR_EE
- SYNC
- MTMSRD(r10) /* re-enable interrupts */
+2: andi. r0,r9,(_TIF_PERSYSCALL_MASK)
+ beq 4f
+
+ /* Clear per-syscall TIF flags if any are set, but _leave_
+ _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that
+ yet. */
+
+ li r11,_TIF_PERSYSCALL_MASK
+ addi r12,r12,TI_FLAGS
+3: lwarx r8,0,r12
+ andc r8,r8,r11
+#ifdef CONFIG_IBM405_ERR77
+ dcbt 0,r12
+#endif
+ stwcx. r8,0,r12
+ bne- 3b
+ subi r12,r12,TI_FLAGS
+
+4: /* Anything which requires enabling interrupts? */
+ andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS)
+ beq 7f
+
+ /* Save NVGPRS if they're not saved already */
lwz r4,TRAP(r1)
andi. r4,r4,1
- beq 4f
+ beq 5f
SAVE_NVGPRS(r1)
li r4,0xc00
stw r4,TRAP(r1)
-4:
+
+ /* Re-enable interrupts */
+5: ori r10,r10,MSR_EE
+ SYNC
+ MTMSRD(r10)
+
+ andi. r0,r9,_TIF_SAVE_NVGPRS
+ bne save_user_nvgprs
+
+save_user_nvgprs_cont:
+ andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
+ beq 7f
+
addi r3,r1,STACK_FRAME_OVERHEAD
bl do_syscall_trace_leave
REST_NVGPRS(r1)
-2:
- lwz r3,GPR3(r1)
+
+6: lwz r3,GPR3(r1)
LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
SYNC
MTMSRD(r10) /* disable interrupts again */
rlwinm r12,r1,0,0,18 /* current_thread_info() */
lwz r9,TI_FLAGS(r12)
-5:
+7:
andi. r0,r9,_TIF_NEED_RESCHED
- bne 1f
+ bne 8f
lwz r5,_MSR(r1)
andi. r5,r5,MSR_PR
- beq syscall_exit_cont
+ beq ret_from_except
andi. r0,r9,_TIF_SIGPENDING
- beq syscall_exit_cont
+ beq ret_from_except
b do_user_signal
-1:
+8:
ori r10,r10,MSR_EE
SYNC
MTMSRD(r10) /* re-enable interrupts */
bl schedule
- b 2b
+ b 6b
+
+save_user_nvgprs:
+ lwz r8,TI_SIGFRAME(r12)
+
+.macro savewords start, end
+ 1: stw \start,4*(\start)(r8)
+ .section __ex_table,"a"
+ .align 2
+ .long 1b,save_user_nvgprs_fault
+ .previous
+ .if \end - \start
+ savewords "(\start+1)",\end
+ .endif
+.endm
+ savewords 14,31
+ b save_user_nvgprs_cont
+
+
+save_user_nvgprs_fault:
+ li r3,11 /* SIGSEGV */
+ lwz r4,TI_TASK(r12)
+ bl force_sigsegv
+ rlwinm r12,r1,0,0,18 /* current_thread_info() */
+ lwz r9,TI_FLAGS(r12)
+ b save_user_nvgprs_cont
+
#ifdef SHOW_SYSCALLS
do_show_syscall:
#ifdef SHOW_SYSCALLS_TASK
@@ -401,28 +462,10 @@ show_syscalls_task:
#endif /* SHOW_SYSCALLS */
/*
- * The sigsuspend and rt_sigsuspend system calls can call do_signal
- * and thus put the process into the stopped state where we might
- * want to examine its user state with ptrace. Therefore we need
- * to save all the nonvolatile registers (r13 - r31) before calling
- * the C code.
+ * The fork/clone functions need to copy the full register set into
+ * the child process. Therefore we need to save all the nonvolatile
+ * registers (r13 - r31) before calling the C code.
*/
- .globl ppc_sigsuspend
-ppc_sigsuspend:
- SAVE_NVGPRS(r1)
- lwz r0,TRAP(r1)
- rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */
- stw r0,TRAP(r1) /* register set saved */
- b sys_sigsuspend
-
- .globl ppc_rt_sigsuspend
-ppc_rt_sigsuspend:
- SAVE_NVGPRS(r1)
- lwz r0,TRAP(r1)
- rlwinm r0,r0,0,0,30
- stw r0,TRAP(r1)
- b sys_rt_sigsuspend
-
.globl ppc_fork
ppc_fork:
SAVE_NVGPRS(r1)
@@ -447,14 +490,6 @@ ppc_clone:
stw r0,TRAP(r1) /* register set saved */
b sys_clone
- .globl ppc_swapcontext
-ppc_swapcontext:
- SAVE_NVGPRS(r1)
- lwz r0,TRAP(r1)
- rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */
- stw r0,TRAP(r1) /* register set saved */
- b sys_swapcontext
-
/*
* Top-level page fault handling.
* This is in assembler because if do_page_fault tells us that
@@ -626,16 +661,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_601)
.long ret_from_except
#endif
- .globl sigreturn_exit
-sigreturn_exit:
- subi r1,r3,STACK_FRAME_OVERHEAD
- rlwinm r12,r1,0,0,18 /* current_thread_info() */
- lwz r9,TI_FLAGS(r12)
- andi. r0,r9,_TIF_SYSCALL_T_OR_A
- beq+ ret_from_except_full
- bl do_syscall_trace_leave
- /* fall through */
-
.globl ret_from_except_full
ret_from_except_full:
REST_NVGPRS(r1)
@@ -658,7 +683,7 @@ user_exc_return: /* r10 contains MSR_KERNEL here */
/* Check current_thread_info()->flags */
rlwinm r9,r1,0,0,18
lwz r9,TI_FLAGS(r9)
- andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+ andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
bne do_work
restore_user:
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index 5e61124581d0..fb5658bba285 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -1197,7 +1197,7 @@ _GLOBAL(sys_call_table)
.long sys_ssetmask
.long sys_setreuid /* 70 */
.long sys_setregid
- .long ppc_sigsuspend
+ .long sys_sigsuspend
.long sys_sigpending
.long sys_sethostname
.long sys_setrlimit /* 75 */
@@ -1303,7 +1303,7 @@ _GLOBAL(sys_call_table)
.long sys_rt_sigpending /* 175 */
.long sys_rt_sigtimedwait
.long sys_rt_sigqueueinfo
- .long ppc_rt_sigsuspend
+ .long sys_rt_sigsuspend
.long sys_pread64
.long sys_pwrite64 /* 180 */
.long sys_chown
@@ -1374,7 +1374,7 @@ _GLOBAL(sys_call_table)
.long sys_clock_gettime
.long sys_clock_getres
.long sys_clock_nanosleep
- .long ppc_swapcontext
+ .long sys_swapcontext
.long sys_tgkill /* 250 */
.long sys_utimes
.long sys_statfs64
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index f7fae5f153b2..50c75eec8874 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -815,8 +815,7 @@ EXPORT_SYMBOL(pci_device_to_OF_node);
* to set pci_assign_all_buses to 1 and still use RTAS for PCI
* config cycles.
*/
-struct pci_controller*
-pci_find_hose_for_OF_device(struct device_node* node)
+struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
{
if (!have_of)
return NULL;
@@ -942,7 +941,7 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) {
res = NULL;
size = ranges[na+4];
- switch (ranges[0] >> 24) {
+ switch ((ranges[0] >> 24) & 0x3) {
case 1: /* I/O space */
if (ranges[2] != 0)
break;
@@ -956,6 +955,8 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
res = &hose->io_resource;
res->flags = IORESOURCE_IO;
res->start = ranges[2];
+ DBG("PCI: IO 0x%lx -> 0x%lx\n",
+ res->start, res->start + size - 1);
break;
case 2: /* memory space */
memno = 0;
@@ -973,7 +974,11 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
if (memno < 3) {
res = &hose->mem_resources[memno];
res->flags = IORESOURCE_MEM;
+ if(ranges[0] & 0x40000000)
+ res->flags |= IORESOURCE_PREFETCH;
res->start = ranges[na+2];
+ DBG("PCI: MEM[%d] 0x%lx -> 0x%lx\n", memno,
+ res->start, res->start + size - 1);
}
break;
}
@@ -1806,6 +1811,23 @@ void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
EXPORT_SYMBOL(pci_iomap);
EXPORT_SYMBOL(pci_iounmap);
+unsigned long pci_address_to_pio(phys_addr_t address)
+{
+ struct pci_controller* hose = hose_head;
+
+ for (; hose; hose = hose->next) {
+ unsigned int size = hose->io_resource.end -
+ hose->io_resource.start + 1;
+ if (address >= hose->io_base_phys &&
+ address < (hose->io_base_phys + size)) {
+ unsigned long base =
+ (unsigned long)hose->io_base_virt - _IO_BASE;
+ return base + (address - hose->io_base_phys);
+ }
+ }
+ return (unsigned int)-1;
+}
+EXPORT_SYMBOL(pci_address_to_pio);
/*
* Null PCI config access functions, for the case when we can't
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index bb6a5c6a64be..95075f99a6d4 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -82,10 +82,6 @@ EXPORT_SYMBOL(ppc_n_lost_interrupts);
EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
EXPORT_SYMBOL(DMA_MODE_READ);
EXPORT_SYMBOL(DMA_MODE_WRITE);
-#if defined(CONFIG_PPC_PREP)
-EXPORT_SYMBOL(_prep_type);
-EXPORT_SYMBOL(ucSystemType);
-#endif
#if !defined(__INLINE_BITOPS)
EXPORT_SYMBOL(set_bit);
@@ -311,7 +307,6 @@ EXPORT_SYMBOL(__res);
EXPORT_SYMBOL(next_mmu_context);
EXPORT_SYMBOL(set_context);
-EXPORT_SYMBOL_GPL(__handle_mm_fault); /* For MOL */
EXPORT_SYMBOL(disarm_decr);
#ifdef CONFIG_PPC_STD_MMU
extern long mol_trampoline;
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 0eb0b7085e6a..e707c6f6e61b 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -744,6 +744,9 @@ void __init setup_arch(char **cmdline_p)
/* so udelay does something sensible, assume <= 1000 bogomips */
loops_per_jiffy = 500000000 / HZ;
+ if (ppc_md.init_early)
+ ppc_md.init_early();
+
#ifdef CONFIG_PPC_MULTIPLATFORM
/* This could be called "early setup arch", it must be done
* now because xmon need it
diff --git a/arch/ppc/platforms/85xx/Kconfig b/arch/ppc/platforms/85xx/Kconfig
index c5bc2821d991..7ddd331a7145 100644
--- a/arch/ppc/platforms/85xx/Kconfig
+++ b/arch/ppc/platforms/85xx/Kconfig
@@ -39,7 +39,7 @@ config MPC8560_ADS
config SBC8560
bool "WindRiver PowerQUICC III SBC8560"
help
- This option enables support for the WindRiver PowerQUICC III
+ This option enables support for the WindRiver PowerQUICC III
SBC8560 board.
config STX_GP3
@@ -48,6 +48,26 @@ config STX_GP3
This option enables support for the Silicon Turnkey Express GP3
board.
+config TQM8540
+ bool "TQ Components TQM8540"
+ help
+ This option enablese support for the TQ Components TQM8540 board.
+
+config TQM8541
+ bool "TQ Components TQM8541"
+ help
+ This option enablese support for the TQ Components TQM8541 board.
+
+config TQM8555
+ bool "TQ Components TQM8555"
+ help
+ This option enablese support for the TQ Components TQM8555 board.
+
+config TQM8560
+ bool "TQ Components TQM8560"
+ help
+ This option enablese support for the TQ Components TQM8560 board.
+
endchoice
# It's often necessary to know the specific 85xx processor type.
@@ -55,7 +75,7 @@ endchoice
# don't need to ask more redundant questions.
config MPC8540
bool
- depends on MPC8540_ADS
+ depends on MPC8540_ADS || TQM8540
default y
config MPC8548
@@ -65,12 +85,12 @@ config MPC8548
config MPC8555
bool
- depends on MPC8555_CDS
+ depends on MPC8555_CDS || TQM8541 || TQM8555
default y
config MPC8560
bool
- depends on SBC8560 || MPC8560_ADS || STX_GP3
+ depends on SBC8560 || MPC8560_ADS || STX_GP3 || TQM8560
default y
config 85xx_PCI2
diff --git a/arch/ppc/platforms/85xx/Makefile b/arch/ppc/platforms/85xx/Makefile
index efdf813108f2..6c4753c144d3 100644
--- a/arch/ppc/platforms/85xx/Makefile
+++ b/arch/ppc/platforms/85xx/Makefile
@@ -7,3 +7,7 @@ obj-$(CONFIG_MPC8555_CDS) += mpc85xx_cds_common.o
obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads_common.o mpc8560_ads.o
obj-$(CONFIG_SBC8560) += sbc85xx.o sbc8560.o
obj-$(CONFIG_STX_GP3) += stx_gp3.o
+obj-$(CONFIG_TQM8540) += tqm85xx.o
+obj-$(CONFIG_TQM8541) += tqm85xx.o
+obj-$(CONFIG_TQM8555) += tqm85xx.o
+obj-$(CONFIG_TQM8560) += tqm85xx.o
diff --git a/arch/ppc/platforms/85xx/tqm85xx.c b/arch/ppc/platforms/85xx/tqm85xx.c
new file mode 100644
index 000000000000..c6dfd8f0f9df
--- /dev/null
+++ b/arch/ppc/platforms/85xx/tqm85xx.c
@@ -0,0 +1,419 @@
+/*
+ * arch/ppc/platforms/85xx/tqm85xx.c
+ *
+ * TQM85xx (40/41/55/60) board specific routines
+ *
+ * Copyright (c) 2005 DENX Software Engineering
+ * Stefan Roese <sr@denx.de>
+ *
+ * Based on original work by
+ * Kumar Gala <galak@kernel.crashing.org>
+ * Copyright 2004 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h> /* for linux/serial_core.h */
+#include <linux/serial_core.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/immap_85xx.h>
+#include <asm/kgdb.h>
+#include <asm/ppc_sys.h>
+#include <asm/cpm2.h>
+#include <mm/mmu_decl.h>
+
+#include <syslib/ppc85xx_setup.h>
+#include <syslib/cpm2_pic.h>
+#include <syslib/ppc85xx_common.h>
+#include <syslib/ppc85xx_rio.h>
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+
+extern unsigned long total_memory; /* in mm/init */
+
+unsigned char __res[sizeof (bd_t)];
+
+/* Internal interrupts are all Level Sensitive, and Positive Polarity */
+static u_char tqm85xx_openpic_initsenses[] __initdata = {
+ MPC85XX_INTERNAL_IRQ_SENSES,
+ 0x0, /* External 0: */
+ 0x0, /* External 1: */
+#if defined(CONFIG_PCI)
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 2: PCI INTA */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 3: PCI INTB */
+#else
+ 0x0, /* External 2: */
+ 0x0, /* External 3: */
+#endif
+ 0x0, /* External 4: */
+ 0x0, /* External 5: */
+ 0x0, /* External 6: */
+ 0x0, /* External 7: */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 8: PHY */
+ 0x0, /* External 9: */
+ 0x0, /* External 10: */
+ 0x0, /* External 11: */
+};
+
+static const char *GFAR_PHY_0 = "phy0:2";
+static const char *GFAR_PHY_1 = "phy0:1";
+#ifdef CONFIG_MPC8540
+static const char *GFAR_PHY_3 = "phy0:3";
+#endif
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init
+tqm85xx_setup_arch(void)
+{
+ bd_t *binfo = (bd_t *) __res;
+ unsigned int freq;
+ struct gianfar_platform_data *pdata;
+ struct gianfar_mdio_data *mdata;
+
+#ifdef CONFIG_MPC8560
+ cpm2_reset();
+#endif
+
+ /* get the core frequency */
+ freq = binfo->bi_intfreq;
+
+ if (ppc_md.progress)
+ ppc_md.progress("tqm85xx_setup_arch()", 0);
+
+ /* Set loops_per_jiffy to a half-way reasonable value,
+ for use until calibrate_delay gets called. */
+ loops_per_jiffy = freq / HZ;
+
+#ifdef CONFIG_PCI
+ /* setup PCI host bridges */
+ mpc85xx_setup_hose();
+#endif
+
+#ifndef CONFIG_MPC8560
+#if defined(CONFIG_SERIAL_8250)
+ mpc85xx_early_serial_map();
+#endif
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ /* Invalidate the entry we stole earlier the serial ports
+ * should be properly mapped */
+ invalidate_tlbcam_entry(num_tlbcam_entries - 1);
+#endif
+#endif /* CONFIG_MPC8560 */
+
+ /* setup the board related info for the MDIO bus */
+ mdata = (struct gianfar_mdio_data *) ppc_sys_get_pdata(MPC85xx_MDIO);
+
+ mdata->irq[0] = MPC85xx_IRQ_EXT8;
+ mdata->irq[1] = MPC85xx_IRQ_EXT8;
+ mdata->irq[2] = -1;
+ mdata->irq[3] = MPC85xx_IRQ_EXT8;
+ mdata->irq[31] = -1;
+ mdata->paddr += binfo->bi_immr_base;
+
+ /* setup the board related information for the enet controllers */
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
+ if (pdata) {
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->bus_id = GFAR_PHY_0;
+ memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+ }
+
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
+ if (pdata) {
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->bus_id = GFAR_PHY_1;
+ memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+ }
+
+#ifdef CONFIG_MPC8540
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_FEC);
+ if (pdata) {
+ pdata->board_flags = 0;
+ pdata->bus_id = GFAR_PHY_3;
+ memcpy(pdata->mac_addr, binfo->bi_enet2addr, 6);
+ }
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+}
+
+#ifdef CONFIG_MPC8560
+static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
+{
+ while ((irq = cpm2_get_irq(regs)) >= 0)
+ __do_IRQ(irq, regs);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction cpm2_irqaction = {
+ .handler = cpm2_cascade,
+ .flags = SA_INTERRUPT,
+ .mask = CPU_MASK_NONE,
+ .name = "cpm2_cascade",
+};
+#endif /* CONFIG_MPC8560 */
+
+void __init
+tqm85xx_init_IRQ(void)
+{
+ bd_t *binfo = (bd_t *) __res;
+
+ /* Determine the Physical Address of the OpenPIC regs */
+ phys_addr_t OpenPIC_PAddr =
+ binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET;
+ OpenPIC_Addr = ioremap(OpenPIC_PAddr, MPC85xx_OPENPIC_SIZE);
+ OpenPIC_InitSenses = tqm85xx_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof (tqm85xx_openpic_initsenses);
+
+ /* Skip reserved space and internal sources */
+ openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200);
+
+ /* Map PIC IRQs 0-11 */
+ openpic_set_sources(48, 12, OpenPIC_Addr + 0x10000);
+
+ /* we let openpic interrupts starting from an offset, to
+ * leave space for cascading interrupts underneath.
+ */
+ openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET);
+
+#ifdef CONFIG_MPC8560
+ /* Setup CPM2 PIC */
+ cpm2_init_IRQ();
+
+ setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction);
+#endif /* CONFIG_MPC8560 */
+
+ return;
+}
+
+int tqm85xx_show_cpuinfo(struct seq_file *m)
+{
+ uint pvid, svid, phid1;
+ uint memsize = total_memory;
+ bd_t *binfo = (bd_t *) __res;
+ unsigned int freq;
+
+ /* get the core frequency */
+ freq = binfo->bi_intfreq;
+
+ pvid = mfspr(SPRN_PVR);
+ svid = mfspr(SPRN_SVR);
+
+ seq_printf(m, "Vendor\t\t: TQ Components\n");
+ seq_printf(m, "Machine\t\t: TQM%s\n", cur_ppc_sys_spec->ppc_sys_name);
+ seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000);
+ seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
+ seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+
+ /* Display cpu Pll setting */
+ phid1 = mfspr(SPRN_HID1);
+ seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+
+ /* Display the amount of memory */
+ seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
+
+ return 0;
+}
+
+#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_DS1337)
+extern ulong ds1337_get_rtc_time(void);
+extern int ds1337_set_rtc_time(unsigned long nowtime);
+
+static int __init
+tqm85xx_rtc_hookup(void)
+{
+ struct timespec tv;
+
+ ppc_md.set_rtc_time = ds1337_set_rtc_time;
+ ppc_md.get_rtc_time = ds1337_get_rtc_time;
+
+ tv.tv_nsec = 0;
+ tv.tv_sec = (ppc_md.get_rtc_time)();
+ do_settimeofday(&tv);
+
+ return 0;
+}
+late_initcall(tqm85xx_rtc_hookup);
+#endif
+
+#ifdef CONFIG_PCI
+/*
+ * interrupt routing
+ */
+int mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {PIRQA, PIRQB, 0, 0},
+ };
+
+ const long min_idsel = 0x1c, max_idsel = 0x1c, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+int mpc85xx_exclude_device(u_char bus, u_char devfn)
+{
+ if (bus == 0 && PCI_SLOT(devfn) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ else
+ return PCIBIOS_SUCCESSFUL;
+}
+
+#endif /* CONFIG_PCI */
+
+#ifdef CONFIG_RAPIDIO
+void platform_rio_init(void)
+{
+ /* 512MB RIO LAW at 0xc0000000 */
+ mpc85xx_rio_setup(0xc0000000, 0x20000000);
+}
+#endif /* CONFIG_RAPIDIO */
+
+/* ************************************************************************ */
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ /* parse_bootinfo must always be called first */
+ parse_bootinfo(find_bootinfo());
+
+ /*
+ * If we were passed in a board information, copy it into the
+ * residual data area.
+ */
+ if (r3) {
+ memcpy((void *) __res, (void *) (r3 + KERNELBASE),
+ sizeof (bd_t));
+ }
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) && !defined(CONFIG_MPC8560)
+ {
+ bd_t *binfo = (bd_t *) __res;
+ struct uart_port p;
+
+ /* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */
+ settlbcam(num_tlbcam_entries - 1, binfo->bi_immr_base,
+ binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0);
+
+ memset(&p, 0, sizeof (p));
+ p.iotype = SERIAL_IO_MEM;
+ p.membase = (void *) binfo->bi_immr_base + MPC85xx_UART0_OFFSET;
+ p.uartclk = binfo->bi_busfreq;
+
+ gen550_init(0, &p);
+
+ memset(&p, 0, sizeof (p));
+ p.iotype = SERIAL_IO_MEM;
+ p.membase = (void *) binfo->bi_immr_base + MPC85xx_UART1_OFFSET;
+ p.uartclk = binfo->bi_busfreq;
+
+ gen550_init(1, &p);
+ }
+#endif
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+ /*
+ * If the init RAM disk has been configured in, and there's a valid
+ * starting address for it, set it up.
+ */
+ if (r4) {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ /* Copy the kernel command line arguments to a safe place. */
+
+ if (r6) {
+ *(char *) (r7 + KERNELBASE) = 0;
+ strcpy(cmd_line, (char *) (r6 + KERNELBASE));
+ }
+
+ identify_ppc_sys_by_id(mfspr(SPRN_SVR));
+
+ /* setup the PowerPC module struct */
+ ppc_md.setup_arch = tqm85xx_setup_arch;
+ ppc_md.show_cpuinfo = tqm85xx_show_cpuinfo;
+
+ ppc_md.init_IRQ = tqm85xx_init_IRQ;
+ ppc_md.get_irq = openpic_get_irq;
+
+ ppc_md.restart = mpc85xx_restart;
+ ppc_md.power_off = mpc85xx_power_off;
+ ppc_md.halt = mpc85xx_halt;
+
+ ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory;
+
+ ppc_md.time_init = NULL;
+ ppc_md.set_rtc_time = NULL;
+ ppc_md.get_rtc_time = NULL;
+ ppc_md.calibrate_decr = mpc85xx_calibrate_decr;
+
+#ifndef CONFIG_MPC8560
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
+ ppc_md.progress = gen550_progress;
+#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_KGDB)
+ ppc_md.early_serial_map = mpc85xx_early_serial_map;
+#endif /* CONFIG_SERIAL_8250 && CONFIG_KGDB */
+#endif /* CONFIG_MPC8560 */
+
+ if (ppc_md.progress)
+ ppc_md.progress("tqm85xx_init(): exit", 0);
+
+ return;
+}
diff --git a/arch/ppc/platforms/85xx/tqm85xx.h b/arch/ppc/platforms/85xx/tqm85xx.h
new file mode 100644
index 000000000000..3775eb363fde
--- /dev/null
+++ b/arch/ppc/platforms/85xx/tqm85xx.h
@@ -0,0 +1,56 @@
+/*
+ * arch/ppc/platforms/85xx/tqm85xx.h
+ *
+ * TQM85xx (40/41/55/60) board definitions
+ *
+ * Copyright (c) 2005 DENX Software Engineering
+ * Stefan Roese <sr@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __MACH_TQM85XX_H
+#define __MACH_TQM85XX_H
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/ppcboot.h>
+
+#define BOARD_CCSRBAR ((uint)0xe0000000)
+#define CCSRBAR_SIZE ((uint)1024*1024)
+
+#define CPM_MAP_ADDR (CCSRBAR + MPC85xx_CPM_OFFSET)
+
+#define PCI_CFG_ADDR_OFFSET (0x8000)
+#define PCI_CFG_DATA_OFFSET (0x8004)
+
+/* PCI interrupt controller */
+#define PIRQA MPC85xx_IRQ_EXT2
+#define PIRQB MPC85xx_IRQ_EXT3
+
+#define MPC85XX_PCI1_LOWER_IO 0x00000000
+#define MPC85XX_PCI1_UPPER_IO 0x00ffffff
+
+#define MPC85XX_PCI1_LOWER_MEM 0x80000000
+#define MPC85XX_PCI1_UPPER_MEM 0x9fffffff
+
+#define MPC85XX_PCI1_IO_BASE 0xe2000000
+#define MPC85XX_PCI1_MEM_OFFSET 0x00000000
+
+#define MPC85XX_PCI1_IO_SIZE 0x01000000
+
+#define BASE_BAUD 115200
+
+extern void mpc85xx_setup_hose(void) __init;
+extern void mpc85xx_restart(char *cmd);
+extern void mpc85xx_power_off(void);
+extern void mpc85xx_halt(void);
+extern void mpc85xx_init_IRQ(void) __init;
+extern unsigned long mpc85xx_find_end_of_memory(void) __init;
+extern void mpc85xx_calibrate_decr(void) __init;
+
+#endif /* __MACH_TQM85XX_H */
diff --git a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c
index f1b70ab3c6fd..056ac2a7b5c1 100644
--- a/arch/ppc/platforms/chrp_setup.c
+++ b/arch/ppc/platforms/chrp_setup.c
@@ -404,7 +404,6 @@ static struct irqaction xmon_irqaction = {
void __init chrp_init_IRQ(void)
{
struct device_node *np;
- int i;
unsigned long chrp_int_ack = 0;
unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
index 4415748071dc..d06535802003 100644
--- a/arch/ppc/platforms/prep_setup.c
+++ b/arch/ppc/platforms/prep_setup.c
@@ -72,7 +72,6 @@
TODC_ALLOC();
-unsigned char ucSystemType;
unsigned char ucBoardRev;
unsigned char ucBoardRevMaj, ucBoardRevMin;
@@ -954,7 +953,6 @@ prep_calibrate_decr(void)
static void __init
prep_init_IRQ(void)
{
- int i;
unsigned int pci_viddid, pci_did;
if (OpenPIC_Addr != NULL) {
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
index 5b7f2b80e56e..84ef03018d0e 100644
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -96,7 +96,7 @@ ifeq ($(CONFIG_85xx),y)
obj-$(CONFIG_PCI) += pci_auto.o
endif
obj-$(CONFIG_RAPIDIO) += ppc85xx_rio.o
-obj-$(CONFIG_83xx) += ipic.o ppc83xx_setup.o ppc_sys.o \
+obj-$(CONFIG_83xx) += ppc83xx_setup.o ppc_sys.o \
mpc83xx_sys.o mpc83xx_devices.o
ifeq ($(CONFIG_83xx),y)
obj-$(CONFIG_PCI) += pci_auto.o
diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c
index 1cc3abe6fa43..688616de3cde 100644
--- a/arch/ppc/syslib/m8xx_setup.c
+++ b/arch/ppc/syslib/m8xx_setup.c
@@ -135,6 +135,16 @@ static struct irqaction tbint_irqaction = {
.name = "tbint",
};
+/* per-board overridable init_internal_rtc() function. */
+void __init __attribute__ ((weak))
+init_internal_rtc(void)
+{
+ /* Disable the RTC one second and alarm interrupts. */
+ out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) & ~(RTCSC_SIE | RTCSC_ALE));
+ /* Enable the RTC */
+ out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) | (RTCSC_RTF | RTCSC_RTE));
+}
+
/* The decrementer counts at the system (internal) clock frequency divided by
* sixteen, or external oscillator divided by four. We force the processor
* to use system clock divided by sixteen.
@@ -183,10 +193,7 @@ void __init m8xx_calibrate_decr(void)
out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck, KAPWR_KEY);
out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk, KAPWR_KEY);
- /* Disable the RTC one second and alarm interrupts. */
- out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) & ~(RTCSC_SIE | RTCSC_ALE));
- /* Enable the RTC */
- out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) | (RTCSC_RTF | RTCSC_RTE));
+ init_internal_rtc();
/* Enabling the decrementer also enables the timebase interrupts
* (or from the other point of view, to get decrementer interrupts
diff --git a/arch/ppc/syslib/m8xx_wdt.c b/arch/ppc/syslib/m8xx_wdt.c
index a21632d37e5a..df6c9557b86a 100644
--- a/arch/ppc/syslib/m8xx_wdt.c
+++ b/arch/ppc/syslib/m8xx_wdt.c
@@ -19,6 +19,7 @@
#include <syslib/m8xx_wdt.h>
static int wdt_timeout;
+int m8xx_has_internal_rtc = 0;
static irqreturn_t m8xx_wdt_interrupt(int, void *, struct pt_regs *);
static struct irqaction m8xx_wdt_irqaction = {
@@ -45,35 +46,15 @@ static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs)
return IRQ_HANDLED;
}
-void __init m8xx_wdt_handler_install(bd_t * binfo)
+#define SYPCR_SWP 0x1
+#define SYPCR_SWE 0x4
+
+
+void __init m8xx_wdt_install_irq(volatile immap_t *imap, bd_t *binfo)
{
- volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
u32 pitc;
- u32 sypcr;
u32 pitrtclk;
- sypcr = in_be32(&imap->im_siu_conf.sc_sypcr);
-
- if (!(sypcr & 0x04)) {
- printk(KERN_NOTICE "m8xx_wdt: wdt disabled (SYPCR: 0x%08X)\n",
- sypcr);
- return;
- }
-
- m8xx_wdt_reset();
-
- printk(KERN_NOTICE
- "m8xx_wdt: active wdt found (SWTC: 0x%04X, SWP: 0x%01X)\n",
- (sypcr >> 16), sypcr & 0x01);
-
- wdt_timeout = (sypcr >> 16) & 0xFFFF;
-
- if (!wdt_timeout)
- wdt_timeout = 0xFFFF;
-
- if (sypcr & 0x01)
- wdt_timeout *= 2048;
-
/*
* Fire trigger if half of the wdt ticked down
*/
@@ -98,6 +79,67 @@ void __init m8xx_wdt_handler_install(bd_t * binfo)
printk(KERN_NOTICE
"m8xx_wdt: keep-alive trigger installed (PITC: 0x%04X)\n", pitc);
+}
+
+static void m8xx_wdt_timer_func(unsigned long data);
+
+static struct timer_list m8xx_wdt_timer =
+ TIMER_INITIALIZER(m8xx_wdt_timer_func, 0, 0);
+
+void m8xx_wdt_stop_timer(void)
+{
+ del_timer(&m8xx_wdt_timer);
+}
+
+void m8xx_wdt_install_timer(void)
+{
+ m8xx_wdt_timer.expires = jiffies + (HZ/2);
+ add_timer(&m8xx_wdt_timer);
+}
+
+static void m8xx_wdt_timer_func(unsigned long data)
+{
+ m8xx_wdt_reset();
+ m8xx_wdt_install_timer();
+}
+
+void __init m8xx_wdt_handler_install(bd_t * binfo)
+{
+ volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+ u32 sypcr;
+
+ sypcr = in_be32(&imap->im_siu_conf.sc_sypcr);
+
+ if (!(sypcr & SYPCR_SWE)) {
+ printk(KERN_NOTICE "m8xx_wdt: wdt disabled (SYPCR: 0x%08X)\n",
+ sypcr);
+ return;
+ }
+
+ m8xx_wdt_reset();
+
+ printk(KERN_NOTICE
+ "m8xx_wdt: active wdt found (SWTC: 0x%04X, SWP: 0x%01X)\n",
+ (sypcr >> 16), sypcr & SYPCR_SWP);
+
+ wdt_timeout = (sypcr >> 16) & 0xFFFF;
+
+ if (!wdt_timeout)
+ wdt_timeout = 0xFFFF;
+
+ if (sypcr & SYPCR_SWP)
+ wdt_timeout *= 2048;
+
+ m8xx_has_internal_rtc = in_be16(&imap->im_sit.sit_rtcsc) & RTCSC_RTE;
+
+ /* if the internal RTC is off use a kernel timer */
+ if (!m8xx_has_internal_rtc) {
+ if (wdt_timeout < (binfo->bi_intfreq/HZ))
+ printk(KERN_ERR "m8xx_wdt: timeout too short for ktimer!\n");
+ m8xx_wdt_install_timer();
+ } else
+ m8xx_wdt_install_irq(imap, binfo);
+
wdt_timeout /= binfo->bi_intfreq;
}
diff --git a/arch/ppc/syslib/m8xx_wdt.h b/arch/ppc/syslib/m8xx_wdt.h
index 0d81a9f8155f..e75835f0012b 100644
--- a/arch/ppc/syslib/m8xx_wdt.h
+++ b/arch/ppc/syslib/m8xx_wdt.h
@@ -9,8 +9,12 @@
#ifndef _PPC_SYSLIB_M8XX_WDT_H
#define _PPC_SYSLIB_M8XX_WDT_H
+extern int m8xx_has_internal_rtc;
+
extern void m8xx_wdt_handler_install(bd_t * binfo);
extern int m8xx_wdt_get_timeout(void);
extern void m8xx_wdt_reset(void);
+extern void m8xx_wdt_install_timer(void);
+extern void m8xx_wdt_stop_timer(void);
#endif /* _PPC_SYSLIB_M8XX_WDT_H */
diff --git a/block/elevator.c b/block/elevator.c
index 39dcccc82ada..99a4d7b2f8ad 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -64,7 +64,7 @@ inline int elv_rq_merge_ok(struct request *rq, struct bio *bio)
}
EXPORT_SYMBOL(elv_rq_merge_ok);
-inline int elv_try_merge(struct request *__rq, struct bio *bio)
+static inline int elv_try_merge(struct request *__rq, struct bio *bio)
{
int ret = ELEVATOR_NO_MERGE;
@@ -80,7 +80,6 @@ inline int elv_try_merge(struct request *__rq, struct bio *bio)
return ret;
}
-EXPORT_SYMBOL(elv_try_merge);
static struct elevator_type *elevator_find(const char *name)
{
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 91d3b4828c49..8e27d0ab0d7c 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -26,7 +26,8 @@
#include <linux/slab.h>
#include <linux/swap.h>
#include <linux/writeback.h>
-#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/cpu.h>
/*
* for max sense size
@@ -62,13 +63,15 @@ static wait_queue_head_t congestion_wqh[2] = {
/*
* Controlling structure to kblockd
*/
-static struct workqueue_struct *kblockd_workqueue;
+static struct workqueue_struct *kblockd_workqueue;
unsigned long blk_max_low_pfn, blk_max_pfn;
EXPORT_SYMBOL(blk_max_low_pfn);
EXPORT_SYMBOL(blk_max_pfn);
+static DEFINE_PER_CPU(struct list_head, blk_cpu_done);
+
/* Amount of time in which a process may batch requests */
#define BLK_BATCH_TIME (HZ/50UL)
@@ -207,6 +210,13 @@ void blk_queue_merge_bvec(request_queue_t *q, merge_bvec_fn *mbfn)
EXPORT_SYMBOL(blk_queue_merge_bvec);
+void blk_queue_softirq_done(request_queue_t *q, softirq_done_fn *fn)
+{
+ q->softirq_done_fn = fn;
+}
+
+EXPORT_SYMBOL(blk_queue_softirq_done);
+
/**
* blk_queue_make_request - define an alternate make_request function for a device
* @q: the request queue for the device to be affected
@@ -270,6 +280,7 @@ EXPORT_SYMBOL(blk_queue_make_request);
static inline void rq_init(request_queue_t *q, struct request *rq)
{
INIT_LIST_HEAD(&rq->queuelist);
+ INIT_LIST_HEAD(&rq->donelist);
rq->errors = 0;
rq->rq_status = RQ_ACTIVE;
@@ -286,6 +297,7 @@ static inline void rq_init(request_queue_t *q, struct request *rq)
rq->sense = NULL;
rq->end_io = NULL;
rq->end_io_data = NULL;
+ rq->completion_data = NULL;
}
/**
@@ -2735,30 +2747,6 @@ static inline int attempt_front_merge(request_queue_t *q, struct request *rq)
return 0;
}
-/**
- * blk_attempt_remerge - attempt to remerge active head with next request
- * @q: The &request_queue_t belonging to the device
- * @rq: The head request (usually)
- *
- * Description:
- * For head-active devices, the queue can easily be unplugged so quickly
- * that proper merging is not done on the front request. This may hurt
- * performance greatly for some devices. The block layer cannot safely
- * do merging on that first request for these queues, but the driver can
- * call this function and make it happen any way. Only the driver knows
- * when it is safe to do so.
- **/
-void blk_attempt_remerge(request_queue_t *q, struct request *rq)
-{
- unsigned long flags;
-
- spin_lock_irqsave(q->queue_lock, flags);
- attempt_back_merge(q, rq);
- spin_unlock_irqrestore(q->queue_lock, flags);
-}
-
-EXPORT_SYMBOL(blk_attempt_remerge);
-
static void init_request_from_bio(struct request *req, struct bio *bio)
{
req->flags |= REQ_CMD;
@@ -3287,6 +3275,87 @@ int end_that_request_chunk(struct request *req, int uptodate, int nr_bytes)
EXPORT_SYMBOL(end_that_request_chunk);
/*
+ * splice the completion data to a local structure and hand off to
+ * process_completion_queue() to complete the requests
+ */
+static void blk_done_softirq(struct softirq_action *h)
+{
+ struct list_head *cpu_list;
+ LIST_HEAD(local_list);
+
+ local_irq_disable();
+ cpu_list = &__get_cpu_var(blk_cpu_done);
+ list_splice_init(cpu_list, &local_list);
+ local_irq_enable();
+
+ while (!list_empty(&local_list)) {
+ struct request *rq = list_entry(local_list.next, struct request, donelist);
+
+ list_del_init(&rq->donelist);
+ rq->q->softirq_done_fn(rq);
+ }
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+static int blk_cpu_notify(struct notifier_block *self, unsigned long action,
+ void *hcpu)
+{
+ /*
+ * If a CPU goes away, splice its entries to the current CPU
+ * and trigger a run of the softirq
+ */
+ if (action == CPU_DEAD) {
+ int cpu = (unsigned long) hcpu;
+
+ local_irq_disable();
+ list_splice_init(&per_cpu(blk_cpu_done, cpu),
+ &__get_cpu_var(blk_cpu_done));
+ raise_softirq_irqoff(BLOCK_SOFTIRQ);
+ local_irq_enable();
+ }
+
+ return NOTIFY_OK;
+}
+
+
+static struct notifier_block __devinitdata blk_cpu_notifier = {
+ .notifier_call = blk_cpu_notify,
+};
+
+#endif /* CONFIG_HOTPLUG_CPU */
+
+/**
+ * blk_complete_request - end I/O on a request
+ * @req: the request being processed
+ *
+ * Description:
+ * Ends all I/O on a request. It does not handle partial completions,
+ * unless the driver actually implements this in its completionc callback
+ * through requeueing. Theh actual completion happens out-of-order,
+ * through a softirq handler. The user must have registered a completion
+ * callback through blk_queue_softirq_done().
+ **/
+
+void blk_complete_request(struct request *req)
+{
+ struct list_head *cpu_list;
+ unsigned long flags;
+
+ BUG_ON(!req->q->softirq_done_fn);
+
+ local_irq_save(flags);
+
+ cpu_list = &__get_cpu_var(blk_cpu_done);
+ list_add_tail(&req->donelist, cpu_list);
+ raise_softirq_irqoff(BLOCK_SOFTIRQ);
+
+ local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL(blk_complete_request);
+
+/*
* queue lock must be held
*/
void end_that_request_last(struct request *req, int uptodate)
@@ -3364,6 +3433,8 @@ EXPORT_SYMBOL(kblockd_flush);
int __init blk_dev_init(void)
{
+ int i;
+
kblockd_workqueue = create_workqueue("kblockd");
if (!kblockd_workqueue)
panic("Failed to create kblockd\n");
@@ -3377,6 +3448,14 @@ int __init blk_dev_init(void)
iocontext_cachep = kmem_cache_create("blkdev_ioc",
sizeof(struct io_context), 0, SLAB_PANIC, NULL, NULL);
+ for (i = 0; i < NR_CPUS; i++)
+ INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i));
+
+ open_softirq(BLOCK_SOFTIRQ, blk_done_softirq, NULL);
+#ifdef CONFIG_HOTPLUG_CPU
+ register_cpu_notifier(&blk_cpu_notifier);
+#endif
+
blk_max_low_pfn = max_low_pfn;
blk_max_pfn = max_pfn;
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index c2ac36dfe4f3..18de84c8ccd8 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -190,16 +190,21 @@ static int verify_command(struct file *file, unsigned char *cmd)
safe_for_write(GPCMD_SET_STREAMING),
};
unsigned char type = cmd_type[cmd[0]];
+ int has_write_perm = 0;
/* Anybody who can open the device can do a read-safe command */
if (type & CMD_READ_SAFE)
return 0;
+ /*
+ * file can be NULL from ioctl_by_bdev()...
+ */
+ if (file)
+ has_write_perm = file->f_mode & FMODE_WRITE;
+
/* Write-safe commands just require a writable open.. */
- if (type & CMD_WRITE_SAFE) {
- if (file->f_mode & FMODE_WRITE)
- return 0;
- }
+ if ((type & CMD_WRITE_SAFE) && has_write_perm)
+ return 0;
/* And root can do any command.. */
if (capable(CAP_SYS_RAWIO))
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 88452c79fb64..e4e9f255bd1f 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -2178,16 +2178,48 @@ static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c)
start_io(h);
}
+
+static void cciss_softirq_done(struct request *rq)
+{
+ CommandList_struct *cmd = rq->completion_data;
+ ctlr_info_t *h = hba[cmd->ctlr];
+ u64bit temp64;
+ int i, ddir;
+
+ if (cmd->Request.Type.Direction == XFER_READ)
+ ddir = PCI_DMA_FROMDEVICE;
+ else
+ ddir = PCI_DMA_TODEVICE;
+
+ /* command did not need to be retried */
+ /* unmap the DMA mapping for all the scatter gather elements */
+ for(i=0; i<cmd->Header.SGList; i++) {
+ temp64.val32.lower = cmd->SG[i].Addr.lower;
+ temp64.val32.upper = cmd->SG[i].Addr.upper;
+ pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir);
+ }
+
+ complete_buffers(rq->bio, rq->errors);
+
+#ifdef CCISS_DEBUG
+ printk("Done with %p\n", rq);
+#endif /* CCISS_DEBUG */
+
+ spin_lock_irq(&h->lock);
+ end_that_request_last(rq, rq->errors);
+ cmd_free(h, cmd,1);
+ spin_unlock_irq(&h->lock);
+}
+
/* checks the status of the job and calls complete buffers to mark all
- * buffers for the completed job.
+ * buffers for the completed job. Note that this function does not need
+ * to hold the hba/queue lock.
*/
static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd,
int timeout)
{
int status = 1;
- int i;
int retry_cmd = 0;
- u64bit temp64;
if (timeout)
status = 0;
@@ -2295,24 +2327,10 @@ static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd,
resend_cciss_cmd(h,cmd);
return;
}
- /* command did not need to be retried */
- /* unmap the DMA mapping for all the scatter gather elements */
- for(i=0; i<cmd->Header.SGList; i++) {
- temp64.val32.lower = cmd->SG[i].Addr.lower;
- temp64.val32.upper = cmd->SG[i].Addr.upper;
- pci_unmap_page(hba[cmd->ctlr]->pdev,
- temp64.val, cmd->SG[i].Len,
- (cmd->Request.Type.Direction == XFER_READ) ?
- PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
- }
- complete_buffers(cmd->rq->bio, status);
-
-#ifdef CCISS_DEBUG
- printk("Done with %p\n", cmd->rq);
-#endif /* CCISS_DEBUG */
- end_that_request_last(cmd->rq, status ? 1 : -EIO);
- cmd_free(h,cmd,1);
+ cmd->rq->completion_data = cmd;
+ cmd->rq->errors = status;
+ blk_complete_request(cmd->rq);
}
/*
@@ -3199,15 +3217,17 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
drv->queue = q;
q->backing_dev_info.ra_pages = READ_AHEAD;
- blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask);
+ blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask);
+
+ /* This is a hardware imposed limit. */
+ blk_queue_max_hw_segments(q, MAXSGENTRIES);
- /* This is a hardware imposed limit. */
- blk_queue_max_hw_segments(q, MAXSGENTRIES);
+ /* This is a limit in the driver and could be eliminated. */
+ blk_queue_max_phys_segments(q, MAXSGENTRIES);
- /* This is a limit in the driver and could be eliminated. */
- blk_queue_max_phys_segments(q, MAXSGENTRIES);
+ blk_queue_max_sectors(q, 512);
- blk_queue_max_sectors(q, 512);
+ blk_queue_softirq_done(q, cciss_softirq_done);
q->queuedata = hba[i];
sprintf(disk->disk_name, "cciss/c%dd%d", i, j);
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index af7cb2bfd670..01f042f6f1c4 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -1083,23 +1083,33 @@ static int swim3_add_device(struct device_node *swim)
{
struct device_node *mediabay;
struct floppy_state *fs = &floppy_states[floppy_count];
+ struct resource res_reg, res_dma;
- if (swim->n_addrs < 2)
- {
- printk(KERN_INFO "swim3: expecting 2 addrs (n_addrs:%d, n_intrs:%d)\n",
- swim->n_addrs, swim->n_intrs);
+ if (of_address_to_resource(swim, 0, &res_reg) ||
+ of_address_to_resource(swim, 1, &res_dma)) {
+ printk(KERN_ERR "swim3: Can't get addresses\n");
return -EINVAL;
}
-
- if (swim->n_intrs < 2)
- {
- printk(KERN_INFO "swim3: expecting 2 intrs (n_addrs:%d, n_intrs:%d)\n",
- swim->n_addrs, swim->n_intrs);
+ if (request_mem_region(res_reg.start, res_reg.end - res_reg.start + 1,
+ " (reg)") == NULL) {
+ printk(KERN_ERR "swim3: Can't request register space\n");
+ return -EINVAL;
+ }
+ if (request_mem_region(res_dma.start, res_dma.end - res_dma.start + 1,
+ " (dma)") == NULL) {
+ release_mem_region(res_reg.start,
+ res_reg.end - res_reg.start + 1);
+ printk(KERN_ERR "swim3: Can't request DMA space\n");
return -EINVAL;
}
- if (!request_OF_resource(swim, 0, NULL)) {
- printk(KERN_INFO "swim3: can't request IO resource !\n");
+ if (swim->n_intrs < 2) {
+ printk(KERN_INFO "swim3: expecting 2 intrs (n_intrs:%d)\n",
+ swim->n_intrs);
+ release_mem_region(res_reg.start,
+ res_reg.end - res_reg.start + 1);
+ release_mem_region(res_dma.start,
+ res_dma.end - res_dma.start + 1);
return -EINVAL;
}
@@ -1110,10 +1120,8 @@ static int swim3_add_device(struct device_node *swim)
memset(fs, 0, sizeof(*fs));
spin_lock_init(&fs->lock);
fs->state = idle;
- fs->swim3 = (struct swim3 __iomem *)
- ioremap(swim->addrs[0].address, 0x200);
- fs->dma = (struct dbdma_regs __iomem *)
- ioremap(swim->addrs[1].address, 0x200);
+ fs->swim3 = (struct swim3 __iomem *)ioremap(res_reg.start, 0x200);
+ fs->dma = (struct dbdma_regs __iomem *)ioremap(res_dma.start, 0x200);
fs->swim3_intr = swim->intrs[0].line;
fs->dma_intr = swim->intrs[1].line;
fs->cur_cyl = -1;
diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c
index 56d62ba7c6ce..b2fc71e20850 100644
--- a/drivers/char/watchdog/mpc8xx_wdt.c
+++ b/drivers/char/watchdog/mpc8xx_wdt.c
@@ -18,6 +18,7 @@
#include <linux/watchdog.h>
#include <asm/8xx_immap.h>
#include <asm/uaccess.h>
+#include <asm/io.h>
#include <syslib/m8xx_wdt.h>
static unsigned long wdt_opened;
@@ -25,18 +26,26 @@ static int wdt_status;
static void mpc8xx_wdt_handler_disable(void)
{
- volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+ volatile uint __iomem *piscr;
+ piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr;
- imap->im_sit.sit_piscr &= ~(PISCR_PIE | PISCR_PTE);
+ if (!m8xx_has_internal_rtc)
+ m8xx_wdt_stop_timer();
+ else
+ out_be32(piscr, in_be32(piscr) & ~(PISCR_PIE | PISCR_PTE));
printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n");
}
static void mpc8xx_wdt_handler_enable(void)
{
- volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+ volatile uint __iomem *piscr;
+ piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr;
- imap->im_sit.sit_piscr |= PISCR_PIE | PISCR_PTE;
+ if (!m8xx_has_internal_rtc)
+ m8xx_wdt_install_timer();
+ else
+ out_be32(piscr, in_be32(piscr) | PISCR_PIE | PISCR_PTE);
printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n");
}
@@ -68,9 +77,6 @@ static int mpc8xx_wdt_release(struct inode *inode, struct file *file)
static ssize_t mpc8xx_wdt_write(struct file *file, const char *data, size_t len,
loff_t * ppos)
{
- if (ppos != &file->f_pos)
- return -ESPIPE;
-
if (len)
m8xx_wdt_reset();
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 4010fe92e72b..08d5b8fed2dc 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -236,27 +236,17 @@ config I2C_IXP2000
This support is also available as a module. If so, the module
will be called i2c-ixp2000.
-config I2C_KEYWEST
- tristate "Powermac Keywest I2C interface"
+config I2C_POWERMAC
+ tristate "Powermac I2C interface"
depends on I2C && PPC_PMAC
+ default y
help
- This supports the use of the I2C interface in the combo-I/O
- chip on recent Apple machines. Say Y if you have such a machine.
-
- This support is also available as a module. If so, the module
- will be called i2c-keywest.
-
-config I2C_PMAC_SMU
- tristate "Powermac SMU I2C interface"
- depends on I2C && PMAC_SMU
- help
- This supports the use of the I2C interface in the SMU
- chip on recent Apple machines like the iMac G5. It is used
- among others by the thermal control driver for those machines.
- Say Y if you have such a machine.
+ This exposes the various PowerMac i2c interfaces to the linux i2c
+ layer and to userland. It is used by various drivers on the powemac
+ platform, thus should generally be enabled.
This support is also available as a module. If so, the module
- will be called i2c-pmac-smu.
+ will be called i2c-powermac.
config I2C_MPC
tristate "MPC107/824x/85xx/52xx"
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index f1df00f66c6c..b44831dff683 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -19,8 +19,7 @@ obj-$(CONFIG_I2C_ISA) += i2c-isa.o
obj-$(CONFIG_I2C_ITE) += i2c-ite.o
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o
-obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o
-obj-$(CONFIG_I2C_PMAC_SMU) += i2c-pmac-smu.o
+obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c
deleted file mode 100644
index d61f748278fc..000000000000
--- a/drivers/i2c/busses/i2c-keywest.c
+++ /dev/null
@@ -1,751 +0,0 @@
-/*
- i2c Support for Apple Keywest I2C Bus Controller
-
- Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
-
- Original work by
-
- Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Changes:
-
- 2001/12/13 BenH New implementation
- 2001/12/15 BenH Add support for "byte" and "quick"
- transfers. Add i2c_xfer routine.
- 2003/09/21 BenH Rework state machine with Paulus help
- 2004/01/21 BenH Merge in Greg KH changes, polled mode is back
- 2004/02/05 BenH Merge 64 bits fixes from the g5 ppc64 tree
-
- My understanding of the various modes supported by keywest are:
-
- - Dumb mode : not implemented, probably direct tweaking of lines
- - Standard mode : simple i2c transaction of type
- S Addr R/W A Data A Data ... T
- - Standard sub mode : combined 8 bit subaddr write with data read
- S Addr R/W A SubAddr A Data A Data ... T
- - Combined mode : Subaddress and Data sequences appended with no stop
- S Addr R/W A SubAddr S Addr R/W A Data A Data ... T
-
- Currently, this driver uses only Standard mode for i2c xfer, and
- smbus byte & quick transfers ; and uses StandardSub mode for
- other smbus transfers instead of combined as we need that for the
- sound driver to be happy
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/timer.h>
-#include <linux/spinlock.h>
-#include <linux/completion.h>
-#include <linux/interrupt.h>
-
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/pmac_low_i2c.h>
-
-#include "i2c-keywest.h"
-
-#undef POLLED_MODE
-
-/* Some debug macros */
-#define WRONG_STATE(name) do {\
- pr_debug("KW: wrong state. Got %s, state: %s (isr: %02x)\n", \
- name, __kw_state_names[iface->state], isr); \
- } while(0)
-
-#ifdef DEBUG
-static const char *__kw_state_names[] = {
- "state_idle",
- "state_addr",
- "state_read",
- "state_write",
- "state_stop",
- "state_dead"
-};
-#endif /* DEBUG */
-
-MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
-MODULE_DESCRIPTION("I2C driver for Apple's Keywest");
-MODULE_LICENSE("GPL");
-
-#ifdef POLLED_MODE
-/* Don't schedule, the g5 fan controller is too
- * timing sensitive
- */
-static u8
-wait_interrupt(struct keywest_iface* iface)
-{
- int i;
- u8 isr;
-
- for (i = 0; i < 200000; i++) {
- isr = read_reg(reg_isr) & KW_I2C_IRQ_MASK;
- if (isr != 0)
- return isr;
- udelay(10);
- }
- return isr;
-}
-#endif /* POLLED_MODE */
-
-static void
-do_stop(struct keywest_iface* iface, int result)
-{
- write_reg(reg_control, KW_I2C_CTL_STOP);
- iface->state = state_stop;
- iface->result = result;
-}
-
-/* Main state machine for standard & standard sub mode */
-static void
-handle_interrupt(struct keywest_iface *iface, u8 isr)
-{
- int ack;
-
- if (isr == 0) {
- if (iface->state != state_stop) {
- pr_debug("KW: Timeout !\n");
- do_stop(iface, -EIO);
- }
- if (iface->state == state_stop) {
- ack = read_reg(reg_status);
- if (!(ack & KW_I2C_STAT_BUSY)) {
- iface->state = state_idle;
- write_reg(reg_ier, 0x00);
-#ifndef POLLED_MODE
- complete(&iface->complete);
-#endif /* POLLED_MODE */
- }
- }
- return;
- }
-
- if (isr & KW_I2C_IRQ_ADDR) {
- ack = read_reg(reg_status);
- if (iface->state != state_addr) {
- write_reg(reg_isr, KW_I2C_IRQ_ADDR);
- WRONG_STATE("KW_I2C_IRQ_ADDR");
- do_stop(iface, -EIO);
- return;
- }
- if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
- iface->state = state_stop;
- iface->result = -ENODEV;
- pr_debug("KW: NAK on address\n");
- } else {
- /* Handle rw "quick" mode */
- if (iface->datalen == 0) {
- do_stop(iface, 0);
- } else if (iface->read_write == I2C_SMBUS_READ) {
- iface->state = state_read;
- if (iface->datalen > 1)
- write_reg(reg_control, KW_I2C_CTL_AAK);
- } else {
- iface->state = state_write;
- write_reg(reg_data, *(iface->data++));
- iface->datalen--;
- }
- }
- write_reg(reg_isr, KW_I2C_IRQ_ADDR);
- }
-
- if (isr & KW_I2C_IRQ_DATA) {
- if (iface->state == state_read) {
- *(iface->data++) = read_reg(reg_data);
- write_reg(reg_isr, KW_I2C_IRQ_DATA);
- iface->datalen--;
- if (iface->datalen == 0)
- iface->state = state_stop;
- else if (iface->datalen == 1)
- write_reg(reg_control, 0);
- } else if (iface->state == state_write) {
- /* Check ack status */
- ack = read_reg(reg_status);
- if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
- pr_debug("KW: nack on data write (%x): %x\n",
- iface->data[-1], ack);
- do_stop(iface, -EIO);
- } else if (iface->datalen) {
- write_reg(reg_data, *(iface->data++));
- iface->datalen--;
- } else {
- write_reg(reg_control, KW_I2C_CTL_STOP);
- iface->state = state_stop;
- iface->result = 0;
- }
- write_reg(reg_isr, KW_I2C_IRQ_DATA);
- } else {
- write_reg(reg_isr, KW_I2C_IRQ_DATA);
- WRONG_STATE("KW_I2C_IRQ_DATA");
- if (iface->state != state_stop)
- do_stop(iface, -EIO);
- }
- }
-
- if (isr & KW_I2C_IRQ_STOP) {
- write_reg(reg_isr, KW_I2C_IRQ_STOP);
- if (iface->state != state_stop) {
- WRONG_STATE("KW_I2C_IRQ_STOP");
- iface->result = -EIO;
- }
- iface->state = state_idle;
- write_reg(reg_ier, 0x00);
-#ifndef POLLED_MODE
- complete(&iface->complete);
-#endif /* POLLED_MODE */
- }
-
- if (isr & KW_I2C_IRQ_START)
- write_reg(reg_isr, KW_I2C_IRQ_START);
-}
-
-#ifndef POLLED_MODE
-
-/* Interrupt handler */
-static irqreturn_t
-keywest_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct keywest_iface *iface = (struct keywest_iface *)dev_id;
- unsigned long flags;
-
- spin_lock_irqsave(&iface->lock, flags);
- del_timer(&iface->timeout_timer);
- handle_interrupt(iface, read_reg(reg_isr));
- if (iface->state != state_idle) {
- iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
- add_timer(&iface->timeout_timer);
- }
- spin_unlock_irqrestore(&iface->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-keywest_timeout(unsigned long data)
-{
- struct keywest_iface *iface = (struct keywest_iface *)data;
- unsigned long flags;
-
- pr_debug("timeout !\n");
- spin_lock_irqsave(&iface->lock, flags);
- handle_interrupt(iface, read_reg(reg_isr));
- if (iface->state != state_idle) {
- iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
- add_timer(&iface->timeout_timer);
- }
- spin_unlock_irqrestore(&iface->lock, flags);
-}
-
-#endif /* POLLED_MODE */
-
-/*
- * SMBUS-type transfer entrypoint
- */
-static s32
-keywest_smbus_xfer( struct i2c_adapter* adap,
- u16 addr,
- unsigned short flags,
- char read_write,
- u8 command,
- int size,
- union i2c_smbus_data* data)
-{
- struct keywest_chan* chan = i2c_get_adapdata(adap);
- struct keywest_iface* iface = chan->iface;
- int len;
- u8* buffer;
- u16 cur_word;
- int rc = 0;
-
- if (iface->state == state_dead)
- return -ENXIO;
-
- /* Prepare datas & select mode */
- iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
- switch (size) {
- case I2C_SMBUS_QUICK:
- len = 0;
- buffer = NULL;
- iface->cur_mode |= KW_I2C_MODE_STANDARD;
- break;
- case I2C_SMBUS_BYTE:
- len = 1;
- buffer = &data->byte;
- iface->cur_mode |= KW_I2C_MODE_STANDARD;
- break;
- case I2C_SMBUS_BYTE_DATA:
- len = 1;
- buffer = &data->byte;
- iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
- break;
- case I2C_SMBUS_WORD_DATA:
- len = 2;
- cur_word = cpu_to_le16(data->word);
- buffer = (u8 *)&cur_word;
- iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
- break;
- case I2C_SMBUS_BLOCK_DATA:
- len = data->block[0];
- buffer = &data->block[1];
- iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
- break;
- default:
- return -1;
- }
-
- /* Turn a standardsub read into a combined mode access */
- if (read_write == I2C_SMBUS_READ
- && (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB) {
- iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
- iface->cur_mode |= KW_I2C_MODE_COMBINED;
- }
-
- /* Original driver had this limitation */
- if (len > 32)
- len = 32;
-
- if (pmac_low_i2c_lock(iface->node))
- return -ENXIO;
-
- pr_debug("chan: %d, addr: 0x%x, transfer len: %d, read: %d\n",
- chan->chan_no, addr, len, read_write == I2C_SMBUS_READ);
-
- iface->data = buffer;
- iface->datalen = len;
- iface->state = state_addr;
- iface->result = 0;
- iface->read_write = read_write;
-
- /* Setup channel & clear pending irqs */
- write_reg(reg_isr, read_reg(reg_isr));
- write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4));
- write_reg(reg_status, 0);
-
- /* Set up address and r/w bit */
- write_reg(reg_addr,
- (addr << 1) | ((read_write == I2C_SMBUS_READ) ? 0x01 : 0x00));
-
- /* Set up the sub address */
- if ((iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB
- || (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED)
- write_reg(reg_subaddr, command);
-
-#ifndef POLLED_MODE
- /* Arm timeout */
- iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
- add_timer(&iface->timeout_timer);
-#endif
-
- /* Start sending address & enable interrupt*/
- write_reg(reg_control, KW_I2C_CTL_XADDR);
- write_reg(reg_ier, KW_I2C_IRQ_MASK);
-
-#ifdef POLLED_MODE
- pr_debug("using polled mode...\n");
- /* State machine, to turn into an interrupt handler */
- while(iface->state != state_idle) {
- unsigned long flags;
-
- u8 isr = wait_interrupt(iface);
- spin_lock_irqsave(&iface->lock, flags);
- handle_interrupt(iface, isr);
- spin_unlock_irqrestore(&iface->lock, flags);
- }
-#else /* POLLED_MODE */
- pr_debug("using interrupt mode...\n");
- wait_for_completion(&iface->complete);
-#endif /* POLLED_MODE */
-
- rc = iface->result;
- pr_debug("transfer done, result: %d\n", rc);
-
- if (rc == 0 && size == I2C_SMBUS_WORD_DATA && read_write == I2C_SMBUS_READ)
- data->word = le16_to_cpu(cur_word);
-
- /* Release sem */
- pmac_low_i2c_unlock(iface->node);
-
- return rc;
-}
-
-/*
- * Generic i2c master transfer entrypoint
- */
-static int
-keywest_xfer( struct i2c_adapter *adap,
- struct i2c_msg *msgs,
- int num)
-{
- struct keywest_chan* chan = i2c_get_adapdata(adap);
- struct keywest_iface* iface = chan->iface;
- struct i2c_msg *pmsg;
- int i, completed;
- int rc = 0;
-
- if (iface->state == state_dead)
- return -ENXIO;
-
- if (pmac_low_i2c_lock(iface->node))
- return -ENXIO;
-
- /* Set adapter to standard mode */
- iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
- iface->cur_mode |= KW_I2C_MODE_STANDARD;
-
- completed = 0;
- for (i = 0; rc >= 0 && i < num;) {
- u8 addr;
-
- pmsg = &msgs[i++];
- addr = pmsg->addr;
- if (pmsg->flags & I2C_M_TEN) {
- printk(KERN_ERR "i2c-keywest: 10 bits addr not supported !\n");
- rc = -EINVAL;
- break;
- }
- pr_debug("xfer: chan: %d, doing %s %d bytes to 0x%02x - %d of %d messages\n",
- chan->chan_no,
- pmsg->flags & I2C_M_RD ? "read" : "write",
- pmsg->len, addr, i, num);
-
- /* Setup channel & clear pending irqs */
- write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4));
- write_reg(reg_isr, read_reg(reg_isr));
- write_reg(reg_status, 0);
-
- iface->data = pmsg->buf;
- iface->datalen = pmsg->len;
- iface->state = state_addr;
- iface->result = 0;
- if (pmsg->flags & I2C_M_RD)
- iface->read_write = I2C_SMBUS_READ;
- else
- iface->read_write = I2C_SMBUS_WRITE;
-
- /* Set up address and r/w bit */
- if (pmsg->flags & I2C_M_REV_DIR_ADDR)
- addr ^= 1;
- write_reg(reg_addr,
- (addr << 1) |
- ((iface->read_write == I2C_SMBUS_READ) ? 0x01 : 0x00));
-
-#ifndef POLLED_MODE
- /* Arm timeout */
- iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
- add_timer(&iface->timeout_timer);
-#endif
-
- /* Start sending address & enable interrupt*/
- write_reg(reg_ier, KW_I2C_IRQ_MASK);
- write_reg(reg_control, KW_I2C_CTL_XADDR);
-
-#ifdef POLLED_MODE
- pr_debug("using polled mode...\n");
- /* State machine, to turn into an interrupt handler */
- while(iface->state != state_idle) {
- u8 isr = wait_interrupt(iface);
- handle_interrupt(iface, isr);
- }
-#else /* POLLED_MODE */
- pr_debug("using interrupt mode...\n");
- wait_for_completion(&iface->complete);
-#endif /* POLLED_MODE */
-
- rc = iface->result;
- if (rc == 0)
- completed++;
- pr_debug("transfer done, result: %d\n", rc);
- }
-
- /* Release sem */
- pmac_low_i2c_unlock(iface->node);
-
- return completed;
-}
-
-static u32
-keywest_func(struct i2c_adapter * adapter)
-{
- return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
- I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_BLOCK_DATA;
-}
-
-/* For now, we only handle combined mode (smbus) */
-static struct i2c_algorithm keywest_algorithm = {
- .smbus_xfer = keywest_smbus_xfer,
- .master_xfer = keywest_xfer,
- .functionality = keywest_func,
-};
-
-
-static int
-create_iface(struct device_node *np, struct device *dev)
-{
- unsigned long steps;
- unsigned bsteps, tsize, i, nchan, addroffset;
- struct keywest_iface* iface;
- u32 *psteps, *prate;
- int rc;
-
- if (np->n_intrs < 1 || np->n_addrs < 1) {
- printk(KERN_ERR "%s: Missing interrupt or address !\n",
- np->full_name);
- return -ENODEV;
- }
- if (pmac_low_i2c_lock(np))
- return -ENODEV;
-
- psteps = (u32 *)get_property(np, "AAPL,address-step", NULL);
- steps = psteps ? (*psteps) : 0x10;
-
- /* Hrm... maybe we can be smarter here */
- for (bsteps = 0; (steps & 0x01) == 0; bsteps++)
- steps >>= 1;
-
- if (np->parent->name[0] == 'u') {
- nchan = 2;
- addroffset = 3;
- } else {
- addroffset = 0;
- nchan = 1;
- }
-
- tsize = sizeof(struct keywest_iface) +
- (sizeof(struct keywest_chan) + 4) * nchan;
- iface = kzalloc(tsize, GFP_KERNEL);
- if (iface == NULL) {
- printk(KERN_ERR "i2c-keywest: can't allocate inteface !\n");
- pmac_low_i2c_unlock(np);
- return -ENOMEM;
- }
- spin_lock_init(&iface->lock);
- init_completion(&iface->complete);
- iface->node = of_node_get(np);
- iface->bsteps = bsteps;
- iface->chan_count = nchan;
- iface->state = state_idle;
- iface->irq = np->intrs[0].line;
- iface->channels = (struct keywest_chan *)
- (((unsigned long)(iface + 1) + 3UL) & ~3UL);
- iface->base = ioremap(np->addrs[0].address + addroffset,
- np->addrs[0].size);
- if (!iface->base) {
- printk(KERN_ERR "i2c-keywest: can't map inteface !\n");
- kfree(iface);
- pmac_low_i2c_unlock(np);
- return -ENOMEM;
- }
-
-#ifndef POLLED_MODE
- init_timer(&iface->timeout_timer);
- iface->timeout_timer.function = keywest_timeout;
- iface->timeout_timer.data = (unsigned long)iface;
-#endif
-
- /* Select interface rate */
- iface->cur_mode = KW_I2C_MODE_100KHZ;
- prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL);
- if (prate) switch(*prate) {
- case 100:
- iface->cur_mode = KW_I2C_MODE_100KHZ;
- break;
- case 50:
- iface->cur_mode = KW_I2C_MODE_50KHZ;
- break;
- case 25:
- iface->cur_mode = KW_I2C_MODE_25KHZ;
- break;
- default:
- printk(KERN_WARNING "i2c-keywest: unknown rate %ldKhz, using 100KHz\n",
- (long)*prate);
- }
-
- /* Select standard mode by default */
- iface->cur_mode |= KW_I2C_MODE_STANDARD;
-
- /* Write mode */
- write_reg(reg_mode, iface->cur_mode);
-
- /* Switch interrupts off & clear them*/
- write_reg(reg_ier, 0x00);
- write_reg(reg_isr, KW_I2C_IRQ_MASK);
-
-#ifndef POLLED_MODE
- /* Request chip interrupt */
- rc = request_irq(iface->irq, keywest_irq, SA_INTERRUPT, "keywest i2c", iface);
- if (rc) {
- printk(KERN_ERR "i2c-keywest: can't get IRQ %d !\n", iface->irq);
- iounmap(iface->base);
- kfree(iface);
- pmac_low_i2c_unlock(np);
- return -ENODEV;
- }
-#endif /* POLLED_MODE */
-
- pmac_low_i2c_unlock(np);
- dev_set_drvdata(dev, iface);
-
- for (i=0; i<nchan; i++) {
- struct keywest_chan* chan = &iface->channels[i];
-
- sprintf(chan->adapter.name, "%s %d", np->parent->name, i);
- chan->iface = iface;
- chan->chan_no = i;
- chan->adapter.algo = &keywest_algorithm;
- chan->adapter.algo_data = NULL;
- chan->adapter.client_register = NULL;
- chan->adapter.client_unregister = NULL;
- i2c_set_adapdata(&chan->adapter, chan);
- chan->adapter.dev.parent = dev;
-
- rc = i2c_add_adapter(&chan->adapter);
- if (rc) {
- printk("i2c-keywest.c: Adapter %s registration failed\n",
- chan->adapter.name);
- i2c_set_adapdata(&chan->adapter, NULL);
- }
- }
-
- printk(KERN_INFO "Found KeyWest i2c on \"%s\", %d channel%s, stepping: %d bits\n",
- np->parent->name, nchan, nchan > 1 ? "s" : "", bsteps);
-
- return 0;
-}
-
-static int
-dispose_iface(struct device *dev)
-{
- struct keywest_iface *iface = dev_get_drvdata(dev);
- int i, rc;
-
- /* Make sure we stop all activity */
- if (pmac_low_i2c_lock(iface->node))
- return -ENODEV;
-
-#ifndef POLLED_MODE
- spin_lock_irq(&iface->lock);
- while (iface->state != state_idle) {
- spin_unlock_irq(&iface->lock);
- msleep(100);
- spin_lock_irq(&iface->lock);
- }
-#endif /* POLLED_MODE */
- iface->state = state_dead;
-#ifndef POLLED_MODE
- spin_unlock_irq(&iface->lock);
- free_irq(iface->irq, iface);
-#endif /* POLLED_MODE */
-
- pmac_low_i2c_unlock(iface->node);
-
- /* Release all channels */
- for (i=0; i<iface->chan_count; i++) {
- struct keywest_chan* chan = &iface->channels[i];
- if (i2c_get_adapdata(&chan->adapter) == NULL)
- continue;
- rc = i2c_del_adapter(&chan->adapter);
- i2c_set_adapdata(&chan->adapter, NULL);
- /* We aren't that prepared to deal with this... */
- if (rc)
- printk("i2c-keywest.c: i2c_del_adapter failed, that's bad !\n");
- }
- iounmap(iface->base);
- dev_set_drvdata(dev, NULL);
- of_node_put(iface->node);
- kfree(iface);
-
- return 0;
-}
-
-static int
-create_iface_macio(struct macio_dev* dev, const struct of_device_id *match)
-{
- return create_iface(dev->ofdev.node, &dev->ofdev.dev);
-}
-
-static int
-dispose_iface_macio(struct macio_dev* dev)
-{
- return dispose_iface(&dev->ofdev.dev);
-}
-
-static int
-create_iface_of_platform(struct of_device* dev, const struct of_device_id *match)
-{
- return create_iface(dev->node, &dev->dev);
-}
-
-static int
-dispose_iface_of_platform(struct of_device* dev)
-{
- return dispose_iface(&dev->dev);
-}
-
-static struct of_device_id i2c_keywest_match[] =
-{
- {
- .type = "i2c",
- .compatible = "keywest"
- },
- {},
-};
-
-static struct macio_driver i2c_keywest_macio_driver =
-{
- .owner = THIS_MODULE,
- .name = "i2c-keywest",
- .match_table = i2c_keywest_match,
- .probe = create_iface_macio,
- .remove = dispose_iface_macio
-};
-
-static struct of_platform_driver i2c_keywest_of_platform_driver =
-{
- .owner = THIS_MODULE,
- .name = "i2c-keywest",
- .match_table = i2c_keywest_match,
- .probe = create_iface_of_platform,
- .remove = dispose_iface_of_platform
-};
-
-static int __init
-i2c_keywest_init(void)
-{
- of_register_driver(&i2c_keywest_of_platform_driver);
- macio_register_driver(&i2c_keywest_macio_driver);
-
- return 0;
-}
-
-static void __exit
-i2c_keywest_cleanup(void)
-{
- of_unregister_driver(&i2c_keywest_of_platform_driver);
- macio_unregister_driver(&i2c_keywest_macio_driver);
-}
-
-module_init(i2c_keywest_init);
-module_exit(i2c_keywest_cleanup);
diff --git a/drivers/i2c/busses/i2c-keywest.h b/drivers/i2c/busses/i2c-keywest.h
deleted file mode 100644
index c5022e1ca6ff..000000000000
--- a/drivers/i2c/busses/i2c-keywest.h
+++ /dev/null
@@ -1,108 +0,0 @@
-#ifndef __I2C_KEYWEST_H__
-#define __I2C_KEYWEST_H__
-
-/* The Tumbler audio equalizer can be really slow sometimes */
-#define POLL_TIMEOUT (2*HZ)
-
-/* Register indices */
-typedef enum {
- reg_mode = 0,
- reg_control,
- reg_status,
- reg_isr,
- reg_ier,
- reg_addr,
- reg_subaddr,
- reg_data
-} reg_t;
-
-
-/* Mode register */
-#define KW_I2C_MODE_100KHZ 0x00
-#define KW_I2C_MODE_50KHZ 0x01
-#define KW_I2C_MODE_25KHZ 0x02
-#define KW_I2C_MODE_DUMB 0x00
-#define KW_I2C_MODE_STANDARD 0x04
-#define KW_I2C_MODE_STANDARDSUB 0x08
-#define KW_I2C_MODE_COMBINED 0x0C
-#define KW_I2C_MODE_MODE_MASK 0x0C
-#define KW_I2C_MODE_CHAN_MASK 0xF0
-
-/* Control register */
-#define KW_I2C_CTL_AAK 0x01
-#define KW_I2C_CTL_XADDR 0x02
-#define KW_I2C_CTL_STOP 0x04
-#define KW_I2C_CTL_START 0x08
-
-/* Status register */
-#define KW_I2C_STAT_BUSY 0x01
-#define KW_I2C_STAT_LAST_AAK 0x02
-#define KW_I2C_STAT_LAST_RW 0x04
-#define KW_I2C_STAT_SDA 0x08
-#define KW_I2C_STAT_SCL 0x10
-
-/* IER & ISR registers */
-#define KW_I2C_IRQ_DATA 0x01
-#define KW_I2C_IRQ_ADDR 0x02
-#define KW_I2C_IRQ_STOP 0x04
-#define KW_I2C_IRQ_START 0x08
-#define KW_I2C_IRQ_MASK 0x0F
-
-/* Physical interface */
-struct keywest_iface
-{
- struct device_node *node;
- void __iomem * base;
- unsigned bsteps;
- int irq;
- spinlock_t lock;
- struct keywest_chan *channels;
- unsigned chan_count;
- u8 cur_mode;
- char read_write;
- u8 *data;
- unsigned datalen;
- int state;
- int result;
- struct timer_list timeout_timer;
- struct completion complete;
-};
-
-enum {
- state_idle,
- state_addr,
- state_read,
- state_write,
- state_stop,
- state_dead
-};
-
-/* Channel on an interface */
-struct keywest_chan
-{
- struct i2c_adapter adapter;
- struct keywest_iface* iface;
- unsigned chan_no;
-};
-
-/* Register access */
-
-static inline u8 __read_reg(struct keywest_iface *iface, reg_t reg)
-{
- return in_8(iface->base
- + (((unsigned)reg) << iface->bsteps));
-}
-
-static inline void __write_reg(struct keywest_iface *iface, reg_t reg, u8 val)
-{
- out_8(iface->base
- + (((unsigned)reg) << iface->bsteps), val);
- (void)__read_reg(iface, reg_subaddr);
-}
-
-#define write_reg(reg, val) __write_reg(iface, reg, val)
-#define read_reg(reg) __read_reg(iface, reg)
-
-
-
-#endif /* __I2C_KEYWEST_H__ */
diff --git a/drivers/i2c/busses/i2c-pmac-smu.c b/drivers/i2c/busses/i2c-pmac-smu.c
deleted file mode 100644
index bfefe7f7a53d..000000000000
--- a/drivers/i2c/busses/i2c-pmac-smu.c
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- i2c Support for Apple SMU Controller
-
- Copyright (c) 2005 Benjamin Herrenschmidt, IBM Corp.
- <benh@kernel.crashing.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/completion.h>
-#include <linux/device.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
-#include <asm/smu.h>
-
-static int probe;
-
-MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
-MODULE_DESCRIPTION("I2C driver for Apple's SMU");
-MODULE_LICENSE("GPL");
-module_param(probe, bool, 0);
-
-
-/* Physical interface */
-struct smu_iface
-{
- struct i2c_adapter adapter;
- struct completion complete;
- u32 busid;
-};
-
-static void smu_i2c_done(struct smu_i2c_cmd *cmd, void *misc)
-{
- struct smu_iface *iface = misc;
- complete(&iface->complete);
-}
-
-/*
- * SMBUS-type transfer entrypoint
- */
-static s32 smu_smbus_xfer( struct i2c_adapter* adap,
- u16 addr,
- unsigned short flags,
- char read_write,
- u8 command,
- int size,
- union i2c_smbus_data* data)
-{
- struct smu_iface *iface = i2c_get_adapdata(adap);
- struct smu_i2c_cmd cmd;
- int rc = 0;
- int read = (read_write == I2C_SMBUS_READ);
-
- cmd.info.bus = iface->busid;
- cmd.info.devaddr = (addr << 1) | (read ? 0x01 : 0x00);
-
- /* Prepare datas & select mode */
- switch (size) {
- case I2C_SMBUS_QUICK:
- cmd.info.type = SMU_I2C_TRANSFER_SIMPLE;
- cmd.info.datalen = 0;
- break;
- case I2C_SMBUS_BYTE:
- cmd.info.type = SMU_I2C_TRANSFER_SIMPLE;
- cmd.info.datalen = 1;
- if (!read)
- cmd.info.data[0] = data->byte;
- break;
- case I2C_SMBUS_BYTE_DATA:
- cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
- cmd.info.datalen = 1;
- cmd.info.sublen = 1;
- cmd.info.subaddr[0] = command;
- cmd.info.subaddr[1] = 0;
- cmd.info.subaddr[2] = 0;
- if (!read)
- cmd.info.data[0] = data->byte;
- break;
- case I2C_SMBUS_WORD_DATA:
- cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
- cmd.info.datalen = 2;
- cmd.info.sublen = 1;
- cmd.info.subaddr[0] = command;
- cmd.info.subaddr[1] = 0;
- cmd.info.subaddr[2] = 0;
- if (!read) {
- cmd.info.data[0] = data->byte & 0xff;
- cmd.info.data[1] = (data->byte >> 8) & 0xff;
- }
- break;
- /* Note that these are broken vs. the expected smbus API where
- * on reads, the lenght is actually returned from the function,
- * but I think the current API makes no sense and I don't want
- * any driver that I haven't verified for correctness to go
- * anywhere near a pmac i2c bus anyway ...
- */
- case I2C_SMBUS_BLOCK_DATA:
- cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
- cmd.info.datalen = data->block[0] + 1;
- if (cmd.info.datalen > 6)
- return -EINVAL;
- if (!read)
- memcpy(cmd.info.data, data->block, cmd.info.datalen);
- cmd.info.sublen = 1;
- cmd.info.subaddr[0] = command;
- cmd.info.subaddr[1] = 0;
- cmd.info.subaddr[2] = 0;
- break;
- case I2C_SMBUS_I2C_BLOCK_DATA:
- cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
- cmd.info.datalen = data->block[0];
- if (cmd.info.datalen > 7)
- return -EINVAL;
- if (!read)
- memcpy(cmd.info.data, &data->block[1],
- cmd.info.datalen);
- cmd.info.sublen = 1;
- cmd.info.subaddr[0] = command;
- cmd.info.subaddr[1] = 0;
- cmd.info.subaddr[2] = 0;
- break;
-
- default:
- return -EINVAL;
- }
-
- /* Turn a standardsub read into a combined mode access */
- if (read_write == I2C_SMBUS_READ &&
- cmd.info.type == SMU_I2C_TRANSFER_STDSUB)
- cmd.info.type = SMU_I2C_TRANSFER_COMBINED;
-
- /* Finish filling command and submit it */
- cmd.done = smu_i2c_done;
- cmd.misc = iface;
- rc = smu_queue_i2c(&cmd);
- if (rc < 0)
- return rc;
- wait_for_completion(&iface->complete);
- rc = cmd.status;
-
- if (!read || rc < 0)
- return rc;
-
- switch (size) {
- case I2C_SMBUS_BYTE:
- case I2C_SMBUS_BYTE_DATA:
- data->byte = cmd.info.data[0];
- break;
- case I2C_SMBUS_WORD_DATA:
- data->word = ((u16)cmd.info.data[1]) << 8;
- data->word |= cmd.info.data[0];
- break;
- /* Note that these are broken vs. the expected smbus API where
- * on reads, the lenght is actually returned from the function,
- * but I think the current API makes no sense and I don't want
- * any driver that I haven't verified for correctness to go
- * anywhere near a pmac i2c bus anyway ...
- */
- case I2C_SMBUS_BLOCK_DATA:
- case I2C_SMBUS_I2C_BLOCK_DATA:
- memcpy(&data->block[0], cmd.info.data, cmd.info.datalen);
- break;
- }
-
- return rc;
-}
-
-static u32
-smu_smbus_func(struct i2c_adapter * adapter)
-{
- return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
- I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_BLOCK_DATA;
-}
-
-/* For now, we only handle combined mode (smbus) */
-static struct i2c_algorithm smu_algorithm = {
- .smbus_xfer = smu_smbus_xfer,
- .functionality = smu_smbus_func,
-};
-
-static int create_iface(struct device_node *np, struct device *dev)
-{
- struct smu_iface* iface;
- u32 *reg, busid;
- int rc;
-
- reg = (u32 *)get_property(np, "reg", NULL);
- if (reg == NULL) {
- printk(KERN_ERR "i2c-pmac-smu: can't find bus number !\n");
- return -ENXIO;
- }
- busid = *reg;
-
- iface = kzalloc(sizeof(struct smu_iface), GFP_KERNEL);
- if (iface == NULL) {
- printk(KERN_ERR "i2c-pmac-smu: can't allocate inteface !\n");
- return -ENOMEM;
- }
- init_completion(&iface->complete);
- iface->busid = busid;
-
- dev_set_drvdata(dev, iface);
-
- sprintf(iface->adapter.name, "smu-i2c-%02x", busid);
- iface->adapter.algo = &smu_algorithm;
- iface->adapter.algo_data = NULL;
- iface->adapter.client_register = NULL;
- iface->adapter.client_unregister = NULL;
- i2c_set_adapdata(&iface->adapter, iface);
- iface->adapter.dev.parent = dev;
-
- rc = i2c_add_adapter(&iface->adapter);
- if (rc) {
- printk(KERN_ERR "i2c-pamc-smu.c: Adapter %s registration "
- "failed\n", iface->adapter.name);
- i2c_set_adapdata(&iface->adapter, NULL);
- }
-
- if (probe) {
- unsigned char addr;
- printk("Probe: ");
- for (addr = 0x00; addr <= 0x7f; addr++) {
- if (i2c_smbus_xfer(&iface->adapter,addr,
- 0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
- printk("%02x ", addr);
- }
- printk("\n");
- }
-
- printk(KERN_INFO "SMU i2c bus %x registered\n", busid);
-
- return 0;
-}
-
-static int dispose_iface(struct device *dev)
-{
- struct smu_iface *iface = dev_get_drvdata(dev);
- int rc;
-
- rc = i2c_del_adapter(&iface->adapter);
- i2c_set_adapdata(&iface->adapter, NULL);
- /* We aren't that prepared to deal with this... */
- if (rc)
- printk("i2c-pmac-smu.c: Failed to remove bus %s !\n",
- iface->adapter.name);
- dev_set_drvdata(dev, NULL);
- kfree(iface);
-
- return 0;
-}
-
-
-static int create_iface_of_platform(struct of_device* dev,
- const struct of_device_id *match)
-{
- return create_iface(dev->node, &dev->dev);
-}
-
-
-static int dispose_iface_of_platform(struct of_device* dev)
-{
- return dispose_iface(&dev->dev);
-}
-
-
-static struct of_device_id i2c_smu_match[] =
-{
- {
- .compatible = "smu-i2c",
- },
- {},
-};
-static struct of_platform_driver i2c_smu_of_platform_driver =
-{
- .name = "i2c-smu",
- .match_table = i2c_smu_match,
- .probe = create_iface_of_platform,
- .remove = dispose_iface_of_platform
-};
-
-
-static int __init i2c_pmac_smu_init(void)
-{
- of_register_driver(&i2c_smu_of_platform_driver);
- return 0;
-}
-
-
-static void __exit i2c_pmac_smu_cleanup(void)
-{
- of_unregister_driver(&i2c_smu_of_platform_driver);
-}
-
-module_init(i2c_pmac_smu_init);
-module_exit(i2c_pmac_smu_cleanup);
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
new file mode 100644
index 000000000000..df786eb55295
--- /dev/null
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -0,0 +1,290 @@
+/*
+ i2c Support for Apple SMU Controller
+
+ Copyright (c) 2005 Benjamin Herrenschmidt, IBM Corp.
+ <benh@kernel.crashing.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/prom.h>
+#include <asm/pmac_low_i2c.h>
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("I2C driver for Apple PowerMac");
+MODULE_LICENSE("GPL");
+
+/*
+ * SMBUS-type transfer entrypoint
+ */
+static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap,
+ u16 addr,
+ unsigned short flags,
+ char read_write,
+ u8 command,
+ int size,
+ union i2c_smbus_data* data)
+{
+ struct pmac_i2c_bus *bus = i2c_get_adapdata(adap);
+ int rc = 0;
+ int read = (read_write == I2C_SMBUS_READ);
+ int addrdir = (addr << 1) | read;
+ u8 local[2];
+
+ rc = pmac_i2c_open(bus, 0);
+ if (rc)
+ return rc;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
+ if (rc)
+ goto bail;
+ rc = pmac_i2c_xfer(bus, addrdir, 0, 0, NULL, 0);
+ break;
+ case I2C_SMBUS_BYTE:
+ rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
+ if (rc)
+ goto bail;
+ rc = pmac_i2c_xfer(bus, addrdir, 0, 0, &data->byte, 1);
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ rc = pmac_i2c_setmode(bus, read ?
+ pmac_i2c_mode_combined :
+ pmac_i2c_mode_stdsub);
+ if (rc)
+ goto bail;
+ rc = pmac_i2c_xfer(bus, addrdir, 1, command, &data->byte, 1);
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ rc = pmac_i2c_setmode(bus, read ?
+ pmac_i2c_mode_combined :
+ pmac_i2c_mode_stdsub);
+ if (rc)
+ goto bail;
+ if (!read) {
+ local[0] = data->word & 0xff;
+ local[1] = (data->word >> 8) & 0xff;
+ }
+ rc = pmac_i2c_xfer(bus, addrdir, 1, command, local, 2);
+ if (rc == 0 && read) {
+ data->word = ((u16)local[1]) << 8;
+ data->word |= local[0];
+ }
+ break;
+
+ /* Note that these are broken vs. the expected smbus API where
+ * on reads, the lenght is actually returned from the function,
+ * but I think the current API makes no sense and I don't want
+ * any driver that I haven't verified for correctness to go
+ * anywhere near a pmac i2c bus anyway ...
+ *
+ * I'm also not completely sure what kind of phases to do between
+ * the actual command and the data (what I am _supposed_ to do that
+ * is). For now, I assume writes are a single stream and reads have
+ * a repeat start/addr phase (but not stop in between)
+ */
+ case I2C_SMBUS_BLOCK_DATA:
+ rc = pmac_i2c_setmode(bus, read ?
+ pmac_i2c_mode_combined :
+ pmac_i2c_mode_stdsub);
+ if (rc)
+ goto bail;
+ rc = pmac_i2c_xfer(bus, addrdir, 1, command, data->block,
+ data->block[0] + 1);
+
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ rc = pmac_i2c_setmode(bus, read ?
+ pmac_i2c_mode_combined :
+ pmac_i2c_mode_stdsub);
+ if (rc)
+ goto bail;
+ rc = pmac_i2c_xfer(bus, addrdir, 1, command,
+ read ? data->block : &data->block[1],
+ data->block[0]);
+ break;
+
+ default:
+ rc = -EINVAL;
+ }
+ bail:
+ pmac_i2c_close(bus);
+ return rc;
+}
+
+/*
+ * Generic i2c master transfer entrypoint. This driver only support single
+ * messages (for "lame i2c" transfers). Anything else should use the smbus
+ * entry point
+ */
+static int i2c_powermac_master_xfer( struct i2c_adapter *adap,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct pmac_i2c_bus *bus = i2c_get_adapdata(adap);
+ int rc = 0;
+ int read;
+ int addrdir;
+
+ if (num != 1)
+ return -EINVAL;
+ if (msgs->flags & I2C_M_TEN)
+ return -EINVAL;
+ read = (msgs->flags & I2C_M_RD) != 0;
+ addrdir = (msgs->addr << 1) | read;
+ if (msgs->flags & I2C_M_REV_DIR_ADDR)
+ addrdir ^= 1;
+
+ rc = pmac_i2c_open(bus, 0);
+ if (rc)
+ return rc;
+ rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
+ if (rc)
+ goto bail;
+ rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len);
+ bail:
+ pmac_i2c_close(bus);
+ return rc < 0 ? rc : msgs->len;
+}
+
+static u32 i2c_powermac_func(struct i2c_adapter * adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_I2C;
+}
+
+/* For now, we only handle smbus */
+static struct i2c_algorithm i2c_powermac_algorithm = {
+ .smbus_xfer = i2c_powermac_smbus_xfer,
+ .master_xfer = i2c_powermac_master_xfer,
+ .functionality = i2c_powermac_func,
+};
+
+
+static int i2c_powermac_remove(struct device *dev)
+{
+ struct i2c_adapter *adapter = dev_get_drvdata(dev);
+ struct pmac_i2c_bus *bus = i2c_get_adapdata(adapter);
+ int rc;
+
+ rc = i2c_del_adapter(adapter);
+ pmac_i2c_detach_adapter(bus, adapter);
+ i2c_set_adapdata(adapter, NULL);
+ /* We aren't that prepared to deal with this... */
+ if (rc)
+ printk("i2c-powermac.c: Failed to remove bus %s !\n",
+ adapter->name);
+ dev_set_drvdata(dev, NULL);
+ kfree(adapter);
+
+ return 0;
+}
+
+
+static int i2c_powermac_probe(struct device *dev)
+{
+ struct pmac_i2c_bus *bus = dev->platform_data;
+ struct device_node *parent = NULL;
+ struct i2c_adapter *adapter;
+ char name[32], *basename;
+ int rc;
+
+ if (bus == NULL)
+ return -EINVAL;
+
+ /* Ok, now we need to make up a name for the interface that will
+ * match what we used to do in the past, that is basically the
+ * controller's parent device node for keywest. PMU didn't have a
+ * naming convention and SMU has a different one
+ */
+ switch(pmac_i2c_get_type(bus)) {
+ case pmac_i2c_bus_keywest:
+ parent = of_get_parent(pmac_i2c_get_controller(bus));
+ if (parent == NULL)
+ return -EINVAL;
+ basename = parent->name;
+ break;
+ case pmac_i2c_bus_pmu:
+ basename = "pmu";
+ break;
+ case pmac_i2c_bus_smu:
+ /* This is not what we used to do but I'm fixing drivers at
+ * the same time as this change
+ */
+ basename = "smu";
+ break;
+ default:
+ return -EINVAL;
+ }
+ snprintf(name, 32, "%s %d", basename, pmac_i2c_get_channel(bus));
+ of_node_put(parent);
+
+ adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (adapter == NULL) {
+ printk(KERN_ERR "i2c-powermac: can't allocate inteface !\n");
+ return -ENOMEM;
+ }
+ dev_set_drvdata(dev, adapter);
+ strcpy(adapter->name, name);
+ adapter->algo = &i2c_powermac_algorithm;
+ i2c_set_adapdata(adapter, bus);
+ adapter->dev.parent = dev;
+ pmac_i2c_attach_adapter(bus, adapter);
+ rc = i2c_add_adapter(adapter);
+ if (rc) {
+ printk(KERN_ERR "i2c-powermac: Adapter %s registration "
+ "failed\n", name);
+ i2c_set_adapdata(adapter, NULL);
+ pmac_i2c_detach_adapter(bus, adapter);
+ }
+
+ printk(KERN_INFO "PowerMac i2c bus %s registered\n", name);
+ return rc;
+}
+
+
+static struct device_driver i2c_powermac_driver = {
+ .name = "i2c-powermac",
+ .bus = &platform_bus_type,
+ .probe = i2c_powermac_probe,
+ .remove = i2c_powermac_remove,
+};
+
+static int __init i2c_powermac_init(void)
+{
+ driver_register(&i2c_powermac_driver);
+ return 0;
+}
+
+
+static void __exit i2c_powermac_cleanup(void)
+{
+ driver_unregister(&i2c_powermac_driver);
+}
+
+module_init(i2c_powermac_init);
+module_exit(i2c_powermac_cleanup);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index d31117eb95aa..e4d55ad32d2f 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -1332,8 +1332,6 @@ static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block)
if (cdrom_read_from_buffer(drive))
return ide_stopped;
- blk_attempt_remerge(drive->queue, rq);
-
/* Clear the local sector buffer. */
info->nsectors_buffered = 0;
@@ -1874,14 +1872,6 @@ static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
return ide_stopped;
}
- /*
- * for dvd-ram and such media, it's a really big deal to get
- * big writes all the time. so scour the queue and attempt to
- * remerge requests, often the plugging will not have had time
- * to do this properly
- */
- blk_attempt_remerge(drive->queue, rq);
-
info->nsectors_buffered = 0;
/* use dma, if possible. we don't need to check more, since we
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index b5dc6df8e67d..dea2d4dcc698 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -55,9 +55,22 @@
#include <asm/io.h>
#include <asm/bitops.h>
+void ide_softirq_done(struct request *rq)
+{
+ request_queue_t *q = rq->q;
+
+ add_disk_randomness(rq->rq_disk);
+ end_that_request_chunk(rq, rq->errors, rq->data_len);
+
+ spin_lock_irq(q->queue_lock);
+ end_that_request_last(rq, rq->errors);
+ spin_unlock_irq(q->queue_lock);
+}
+
int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate,
int nr_sectors)
{
+ unsigned int nbytes;
int ret = 1;
BUG_ON(!(rq->flags & REQ_STARTED));
@@ -81,17 +94,28 @@ int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate,
HWGROUP(drive)->hwif->ide_dma_on(drive);
}
- if (!end_that_request_first(rq, uptodate, nr_sectors)) {
- add_disk_randomness(rq->rq_disk);
-
- if (blk_rq_tagged(rq))
- blk_queue_end_tag(drive->queue, rq);
-
+ /*
+ * For partial completions (or non fs/pc requests), use the regular
+ * direct completion path.
+ */
+ nbytes = nr_sectors << 9;
+ if (rq_all_done(rq, nbytes)) {
+ rq->errors = uptodate;
+ rq->data_len = nbytes;
blkdev_dequeue_request(rq);
HWGROUP(drive)->rq = NULL;
- end_that_request_last(rq, uptodate);
+ blk_complete_request(rq);
ret = 0;
+ } else {
+ if (!end_that_request_first(rq, uptodate, nr_sectors)) {
+ add_disk_randomness(rq->rq_disk);
+ blkdev_dequeue_request(rq);
+ HWGROUP(drive)->rq = NULL;
+ end_that_request_last(rq, uptodate);
+ ret = 0;
+ }
}
+
return ret;
}
EXPORT_SYMBOL(__ide_end_request);
@@ -113,6 +137,10 @@ int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
unsigned long flags;
int ret = 1;
+ /*
+ * room for locking improvements here, the calls below don't
+ * need the queue lock held at all
+ */
spin_lock_irqsave(&ide_lock, flags);
rq = HWGROUP(drive)->rq;
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 02167a5b751d..1ddaa71a8f45 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -1011,6 +1011,8 @@ static int ide_init_queue(ide_drive_t *drive)
blk_queue_max_hw_segments(q, max_sg_entries);
blk_queue_max_phys_segments(q, max_sg_entries);
+ blk_queue_softirq_done(q, ide_softirq_done);
+
/* assign drive queue */
drive->queue = q;
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 16b28357885b..5013b1285e22 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -1271,7 +1271,7 @@ static int
pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
{
struct device_node *np = pmif->node;
- int *bidp, i;
+ int *bidp;
pmif->cable_80 = 0;
pmif->broken_dma = pmif->broken_dma_warn = 0;
@@ -1430,7 +1430,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
pmif = &pmac_ide[i];
hwif = &ide_hwifs[i];
- if (mdev->ofdev.node->n_addrs == 0) {
+ if (macio_resource_count(mdev) == 0) {
printk(KERN_WARNING "ide%d: no address for %s\n",
i, mdev->ofdev.node->full_name);
return -ENXIO;
@@ -1686,7 +1686,7 @@ pmac_ide_probe(void)
#else
macio_register_driver(&pmac_ide_macio_driver);
pci_register_driver(&pmac_ide_pci_driver);
-#endif
+#endif
}
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index a0ea44c3e8b1..7d4a0ac28c06 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -149,14 +149,14 @@ config MAC_EMUMOUSEBTN
config THERM_WINDTUNNEL
tristate "Support for thermal management on Windtunnel G4s"
- depends on I2C && I2C_KEYWEST && PPC_PMAC && !PPC_PMAC64
+ depends on I2C && I2C_POWERMAC && PPC_PMAC && !PPC_PMAC64
help
This driver provides some thermostat and fan control for the desktop
G4 "Windtunnel"
config THERM_ADT746X
tristate "Support for thermal mgmnt on laptops with ADT 746x chipset"
- depends on I2C && I2C_KEYWEST && PPC_PMAC && !PPC_PMAC64
+ depends on I2C && I2C_POWERMAC && PPC_PMAC && !PPC_PMAC64
help
This driver provides some thermostat and fan control for the
iBook G4, and the ATI based aluminium PowerBooks, allowing slighlty
@@ -164,7 +164,7 @@ config THERM_ADT746X
config THERM_PM72
tristate "Support for thermal management on PowerMac G5"
- depends on I2C && I2C_KEYWEST && PPC_PMAC64
+ depends on I2C && I2C_POWERMAC && PPC_PMAC64
help
This driver provides thermostat and fan control for the desktop
G5 machines.
@@ -175,14 +175,14 @@ config WINDFARM
config WINDFARM_PM81
tristate "Support for thermal management on iMac G5"
depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU
- select I2C_PMAC_SMU
+ select I2C_POWERMAC
help
This driver provides thermal control for the iMacG5
config WINDFARM_PM91
tristate "Support for thermal management on PowerMac9,1"
depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU
- select I2C_PMAC_SMU
+ select I2C_POWERMAC
help
This driver provides thermal control for the PowerMac9,1
which is the recent (SMU based) single CPU desktop G5
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index 228e1852a836..2a545ceb523b 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -3,6 +3,13 @@
* a MacIO ASIC. Interface to new driver model mostly
* stolen from the PCI version.
*
+ * Copyright (C) 2005 Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
* TODO:
*
* - Don't probe below media bay by default, but instead provide
@@ -218,12 +225,14 @@ postcore_initcall(macio_bus_driver_init);
/**
- * macio_release_dev - free a macio device structure when all users of it are finished.
+ * macio_release_dev - free a macio device structure when all users of it are
+ * finished.
* @dev: device that's been disconnected
*
- * Will be called only by the device core when all users of this macio device are
- * done. This currently means never as we don't hot remove any macio device yet,
- * though that will happen with mediabay based devices in a later implementation.
+ * Will be called only by the device core when all users of this macio device
+ * are done. This currently means never as we don't hot remove any macio
+ * device yet, though that will happen with mediabay based devices in a later
+ * implementation.
*/
static void macio_release_dev(struct device *dev)
{
@@ -242,49 +251,114 @@ static void macio_release_dev(struct device *dev)
* If this routine returns non-null, then the resource is completely
* skipped.
*/
-static int macio_resource_quirks(struct device_node *np, struct resource *res, int index)
+static int macio_resource_quirks(struct device_node *np, struct resource *res,
+ int index)
{
if (res->flags & IORESOURCE_MEM) {
/* Grand Central has too large resource 0 on some machines */
- if (index == 0 && !strcmp(np->name, "gc")) {
- np->addrs[0].size = 0x20000;
+ if (index == 0 && !strcmp(np->name, "gc"))
res->end = res->start + 0x1ffff;
- }
+
/* Airport has bogus resource 2 */
if (index >= 2 && !strcmp(np->name, "radio"))
return 1;
+
+#ifndef CONFIG_PPC64
/* DBDMAs may have bogus sizes */
- if ((res->start & 0x0001f000) == 0x00008000) {
- np->addrs[index].size = 0x100;
+ if ((res->start & 0x0001f000) == 0x00008000)
res->end = res->start + 0xff;
- }
- /* ESCC parent eats child resources. We could have added a level of hierarchy,
- * but I don't really feel the need for it */
+#endif /* CONFIG_PPC64 */
+
+ /* ESCC parent eats child resources. We could have added a
+ * level of hierarchy, but I don't really feel the need
+ * for it
+ */
if (!strcmp(np->name, "escc"))
return 1;
+
/* ESCC has bogus resources >= 3 */
- if (index >= 3 && !(strcmp(np->name, "ch-a") && strcmp(np->name, "ch-b")))
+ if (index >= 3 && !(strcmp(np->name, "ch-a") &&
+ strcmp(np->name, "ch-b")))
return 1;
+
/* Media bay has too many resources, keep only first one */
if (index > 0 && !strcmp(np->name, "media-bay"))
return 1;
+
/* Some older IDE resources have bogus sizes */
if (!(strcmp(np->name, "IDE") && strcmp(np->name, "ATA") &&
strcmp(np->type, "ide") && strcmp(np->type, "ata"))) {
- if (index == 0 && np->addrs[0].size > 0x1000) {
- np->addrs[0].size = 0x1000;
+ if (index == 0 && (res->end - res->start) > 0xfff)
res->end = res->start + 0xfff;
- }
- if (index == 1 && np->addrs[1].size > 0x100) {
- np->addrs[1].size = 0x100;
+ if (index == 1 && (res->end - res->start) > 0xff)
res->end = res->start + 0xff;
- }
}
}
return 0;
}
+static void macio_setup_interrupts(struct macio_dev *dev)
+{
+ struct device_node *np = dev->ofdev.node;
+ int i,j;
+
+ /* For now, we use pre-parsed entries in the device-tree for
+ * interrupt routing and addresses, but we should change that
+ * to dynamically parsed entries and so get rid of most of the
+ * clutter in struct device_node
+ */
+ for (i = j = 0; i < np->n_intrs; i++) {
+ struct resource *res = &dev->interrupt[j];
+
+ if (j >= MACIO_DEV_COUNT_IRQS)
+ break;
+ res->start = np->intrs[i].line;
+ res->flags = IORESOURCE_IO;
+ if (np->intrs[j].sense)
+ res->flags |= IORESOURCE_IRQ_LOWLEVEL;
+ else
+ res->flags |= IORESOURCE_IRQ_HIGHEDGE;
+ res->name = dev->ofdev.dev.bus_id;
+ if (macio_resource_quirks(np, res, i))
+ memset(res, 0, sizeof(struct resource));
+ else
+ j++;
+ }
+ dev->n_interrupts = j;
+}
+
+static void macio_setup_resources(struct macio_dev *dev,
+ struct resource *parent_res)
+{
+ struct device_node *np = dev->ofdev.node;
+ struct resource r;
+ int index;
+
+ for (index = 0; of_address_to_resource(np, index, &r) == 0; index++) {
+ struct resource *res = &dev->resource[index];
+ if (index >= MACIO_DEV_COUNT_RESOURCES)
+ break;
+ *res = r;
+ res->name = dev->ofdev.dev.bus_id;
+
+ if (macio_resource_quirks(np, res, index)) {
+ memset(res, 0, sizeof(struct resource));
+ continue;
+ }
+ /* Currently, we consider failure as harmless, this may
+ * change in the future, once I've found all the device
+ * tree bugs in older machines & worked around them
+ */
+ if (insert_resource(parent_res, res)) {
+ printk(KERN_WARNING "Can't request resource "
+ "%d for MacIO device %s\n",
+ index, dev->ofdev.dev.bus_id);
+ }
+ }
+ dev->n_resources = index;
+}
+
/**
* macio_add_one_device - Add one device from OF node to the device tree
* @chip: pointer to the macio_chip holding the device
@@ -294,12 +368,13 @@ static int macio_resource_quirks(struct device_node *np, struct resource *res, i
* When media-bay is changed to hotswap drivers, this function will
* be exposed to the bay driver some way...
*/
-static struct macio_dev * macio_add_one_device(struct macio_chip *chip, struct device *parent,
- struct device_node *np, struct macio_dev *in_bay,
+static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
+ struct device *parent,
+ struct device_node *np,
+ struct macio_dev *in_bay,
struct resource *parent_res)
{
struct macio_dev *dev;
- int i, j;
u32 *reg;
if (np == NULL)
@@ -326,7 +401,8 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, struct d
/* MacIO itself has a different reg, we use it's PCI base */
if (np == chip->of_node) {
- sprintf(dev->ofdev.dev.bus_id, "%1d.%08lx:%.*s", chip->lbus.index,
+ sprintf(dev->ofdev.dev.bus_id, "%1d.%08lx:%.*s",
+ chip->lbus.index,
#ifdef CONFIG_PCI
pci_resource_start(chip->lbus.pdev, 0),
#else
@@ -335,57 +411,16 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, struct d
MAX_NODE_NAME_SIZE, np->name);
} else {
reg = (u32 *)get_property(np, "reg", NULL);
- sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s", chip->lbus.index,
+ sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s",
+ chip->lbus.index,
reg ? *reg : 0, MAX_NODE_NAME_SIZE, np->name);
}
- /* For now, we use pre-parsed entries in the device-tree for
- * interrupt routing and addresses, but we should change that
- * to dynamically parsed entries and so get rid of most of the
- * clutter in struct device_node
- */
- for (i = j = 0; i < np->n_intrs; i++) {
- struct resource *res = &dev->interrupt[j];
-
- if (j >= MACIO_DEV_COUNT_IRQS)
- break;
- res->start = np->intrs[i].line;
- res->flags = IORESOURCE_IO;
- if (np->intrs[j].sense)
- res->flags |= IORESOURCE_IRQ_LOWLEVEL;
- else
- res->flags |= IORESOURCE_IRQ_HIGHEDGE;
- res->name = dev->ofdev.dev.bus_id;
- if (macio_resource_quirks(np, res, i))
- memset(res, 0, sizeof(struct resource));
- else
- j++;
- }
- dev->n_interrupts = j;
- for (i = j = 0; i < np->n_addrs; i++) {
- struct resource *res = &dev->resource[j];
-
- if (j >= MACIO_DEV_COUNT_RESOURCES)
- break;
- res->start = np->addrs[i].address;
- res->end = np->addrs[i].address + np->addrs[i].size - 1;
- res->flags = IORESOURCE_MEM;
- res->name = dev->ofdev.dev.bus_id;
- if (macio_resource_quirks(np, res, i))
- memset(res, 0, sizeof(struct resource));
- else {
- j++;
- /* Currently, we consider failure as harmless, this may
- * change in the future, once I've found all the device
- * tree bugs in older machines & worked around them
- */
- if (insert_resource(parent_res, res))
- printk(KERN_WARNING "Can't request resource %d for MacIO"
- " device %s\n", i, dev->ofdev.dev.bus_id);
- }
- }
- dev->n_resources = j;
+ /* Setup interrupts & resources */
+ macio_setup_interrupts(dev);
+ macio_setup_resources(dev, parent_res);
+ /* Register with core */
if (of_device_register(&dev->ofdev) != 0) {
printk(KERN_DEBUG"macio: device registration error for %s!\n",
dev->ofdev.dev.bus_id);
@@ -442,36 +477,42 @@ static void macio_pci_add_devices(struct macio_chip *chip)
/* First scan 1st level */
for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) {
- if (!macio_skip_device(np)) {
- of_node_get(np);
- mdev = macio_add_one_device(chip, &rdev->ofdev.dev, np, NULL, root_res);
- if (mdev == NULL)
- of_node_put(np);
- else if (strncmp(np->name, "media-bay", 9) == 0)
- mbdev = mdev;
- else if (strncmp(np->name, "escc", 4) == 0)
- sdev = mdev;
- }
+ if (macio_skip_device(np))
+ continue;
+ of_node_get(np);
+ mdev = macio_add_one_device(chip, &rdev->ofdev.dev, np, NULL,
+ root_res);
+ if (mdev == NULL)
+ of_node_put(np);
+ else if (strncmp(np->name, "media-bay", 9) == 0)
+ mbdev = mdev;
+ else if (strncmp(np->name, "escc", 4) == 0)
+ sdev = mdev;
}
/* Add media bay devices if any */
if (mbdev)
- for (np = NULL; (np = of_get_next_child(mbdev->ofdev.node, np)) != NULL;)
- if (!macio_skip_device(np)) {
- of_node_get(np);
- if (macio_add_one_device(chip, &mbdev->ofdev.dev, np, mbdev,
- root_res) == NULL)
- of_node_put(np);
- }
+ for (np = NULL; (np = of_get_next_child(mbdev->ofdev.node, np))
+ != NULL;) {
+ if (macio_skip_device(np))
+ continue;
+ of_node_get(np);
+ if (macio_add_one_device(chip, &mbdev->ofdev.dev, np,
+ mbdev, root_res) == NULL)
+ of_node_put(np);
+ }
+
/* Add serial ports if any */
if (sdev) {
- for (np = NULL; (np = of_get_next_child(sdev->ofdev.node, np)) != NULL;)
- if (!macio_skip_device(np)) {
- of_node_get(np);
- if (macio_add_one_device(chip, &sdev->ofdev.dev, np, NULL,
- root_res) == NULL)
- of_node_put(np);
- }
+ for (np = NULL; (np = of_get_next_child(sdev->ofdev.node, np))
+ != NULL;) {
+ if (macio_skip_device(np))
+ continue;
+ of_node_get(np);
+ if (macio_add_one_device(chip, &sdev->ofdev.dev, np,
+ NULL, root_res) == NULL)
+ of_node_put(np);
+ }
}
}
@@ -519,7 +560,8 @@ void macio_unregister_driver(struct macio_driver *drv)
* Returns 0 on success, or %EBUSY on error. A warning
* message is also printed on failure.
*/
-int macio_request_resource(struct macio_dev *dev, int resource_no, const char *name)
+int macio_request_resource(struct macio_dev *dev, int resource_no,
+ const char *name)
{
if (macio_resource_len(dev, resource_no) == 0)
return 0;
@@ -606,20 +648,20 @@ static int __devinit macio_pci_probe(struct pci_dev *pdev, const struct pci_devi
if (ent->vendor != PCI_VENDOR_ID_APPLE)
return -ENODEV;
- /* Note regarding refcounting: We assume pci_device_to_OF_node() is ported
- * to new OF APIs and returns a node with refcount incremented. This isn't
- * the case today, but on the other hand ppc32 doesn't do refcounting. This
- * will have to be fixed when going to ppc64. --BenH.
+ /* Note regarding refcounting: We assume pci_device_to_OF_node() is
+ * ported to new OF APIs and returns a node with refcount incremented.
*/
np = pci_device_to_OF_node(pdev);
if (np == NULL)
return -ENODEV;
- /* This assumption is wrong, fix that here for now until I fix the arch */
+ /* The above assumption is wrong !!!
+ * fix that here for now until I fix the arch code
+ */
of_node_get(np);
- /* We also assume that pmac_feature will have done a get() on nodes stored
- * in the macio chips array
+ /* We also assume that pmac_feature will have done a get() on nodes
+ * stored in the macio chips array
*/
chip = macio_find(np, macio_unknown);
of_node_put(np);
@@ -639,9 +681,9 @@ static int __devinit macio_pci_probe(struct pci_dev *pdev, const struct pci_devi
/*
* HACK ALERT: The WallStreet PowerBook and some OHare based machines
- * have 2 macio ASICs. I must probe the "main" one first or IDE ordering
- * will be incorrect. So I put on "hold" the second one since it seem to
- * appear first on PCI
+ * have 2 macio ASICs. I must probe the "main" one first or IDE
+ * ordering will be incorrect. So I put on "hold" the second one since
+ * it seem to appear first on PCI
*/
if (chip->type == macio_gatwick || chip->type == macio_ohareII)
if (macio_chips[0].lbus.pdev == NULL) {
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index b856bb67169c..8dbf2852bae0 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -647,6 +647,7 @@ static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_de
struct media_bay_info* bay;
u32 __iomem *regbase;
struct device_node *ofnode;
+ unsigned long base;
int i;
ofnode = mdev->ofdev.node;
@@ -656,10 +657,11 @@ static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_de
if (macio_request_resources(mdev, "media-bay"))
return -EBUSY;
/* Media bay registers are located at the beginning of the
- * mac-io chip, we get the parent address for now (hrm...)
+ * mac-io chip, for now, we trick and align down the first
+ * resource passed in
*/
- regbase = (u32 __iomem *)
- ioremap(ofnode->parent->addrs[0].address, 0x100);
+ base = macio_resource_start(mdev, 0) & 0xffff0000u;
+ regbase = (u32 __iomem *)ioremap(base, 0x100);
if (regbase == NULL) {
macio_release_resources(mdev);
return -ENOMEM;
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index e8378274d710..db2ae71d07ef 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -53,7 +53,7 @@
#undef DEBUG_SMU
#ifdef DEBUG_SMU
-#define DPRINTK(fmt, args...) do { udbg_printf(KERN_DEBUG fmt , ##args); } while (0)
+#define DPRINTK(fmt, args...) do { printk(KERN_DEBUG fmt , ##args); } while (0)
#else
#define DPRINTK(fmt, args...) do { } while (0)
#endif
@@ -94,6 +94,8 @@ struct smu_device {
static struct smu_device *smu;
static DECLARE_MUTEX(smu_part_access);
+static void smu_i2c_retry(unsigned long data);
+
/*
* SMU driver low level stuff
*/
@@ -469,7 +471,6 @@ int __init smu_init (void)
smu->of_node = np;
smu->db_irq = NO_IRQ;
smu->msg_irq = NO_IRQ;
- init_timer(&smu->i2c_timer);
/* smu_cmdbuf_abs is in the low 2G of RAM, can be converted to a
* 32 bits value safely
@@ -544,6 +545,10 @@ static int smu_late_init(void)
if (!smu)
return 0;
+ init_timer(&smu->i2c_timer);
+ smu->i2c_timer.function = smu_i2c_retry;
+ smu->i2c_timer.data = (unsigned long)smu;
+
/*
* Try to request the interrupts
*/
@@ -570,7 +575,10 @@ static int smu_late_init(void)
return 0;
}
-arch_initcall(smu_late_init);
+/* This has to be before arch_initcall as the low i2c stuff relies on the
+ * above having been done before we reach arch_initcalls
+ */
+core_initcall(smu_late_init);
/*
* sysfs visibility
@@ -580,20 +588,10 @@ static void smu_expose_childs(void *unused)
{
struct device_node *np;
- for (np = NULL; (np = of_get_next_child(smu->of_node, np)) != NULL;) {
- if (device_is_compatible(np, "smu-i2c")) {
- char name[32];
- u32 *reg = (u32 *)get_property(np, "reg", NULL);
-
- if (reg == NULL)
- continue;
- sprintf(name, "smu-i2c-%02x", *reg);
- of_platform_device_create(np, name, &smu->of_dev->dev);
- }
+ for (np = NULL; (np = of_get_next_child(smu->of_node, np)) != NULL;)
if (device_is_compatible(np, "smu-sensors"))
- of_platform_device_create(np, "smu-sensors", &smu->of_dev->dev);
- }
-
+ of_platform_device_create(np, "smu-sensors",
+ &smu->of_dev->dev);
}
static DECLARE_WORK(smu_expose_childs_work, smu_expose_childs, NULL);
@@ -712,13 +710,13 @@ static void smu_i2c_complete_command(struct smu_i2c_cmd *cmd, int fail)
static void smu_i2c_retry(unsigned long data)
{
- struct smu_i2c_cmd *cmd = (struct smu_i2c_cmd *)data;
+ struct smu_i2c_cmd *cmd = smu->cmd_i2c_cur;
DPRINTK("SMU: i2c failure, requeuing...\n");
/* requeue command simply by resetting reply_len */
cmd->pdata[0] = 0xff;
- cmd->scmd.reply_len = 0x10;
+ cmd->scmd.reply_len = sizeof(cmd->pdata);
smu_queue_cmd(&cmd->scmd);
}
@@ -747,10 +745,8 @@ static void smu_i2c_low_completion(struct smu_cmd *scmd, void *misc)
*/
if (fail && --cmd->retries > 0) {
DPRINTK("SMU: i2c failure, starting timer...\n");
- smu->i2c_timer.function = smu_i2c_retry;
- smu->i2c_timer.data = (unsigned long)cmd;
- smu->i2c_timer.expires = jiffies + msecs_to_jiffies(5);
- add_timer(&smu->i2c_timer);
+ BUG_ON(cmd != smu->cmd_i2c_cur);
+ mod_timer(&smu->i2c_timer, jiffies + msecs_to_jiffies(5));
return;
}
@@ -764,7 +760,7 @@ static void smu_i2c_low_completion(struct smu_cmd *scmd, void *misc)
/* Ok, initial command complete, now poll status */
scmd->reply_buf = cmd->pdata;
- scmd->reply_len = 0x10;
+ scmd->reply_len = sizeof(cmd->pdata);
scmd->data_buf = cmd->pdata;
scmd->data_len = 1;
cmd->pdata[0] = 0;
@@ -786,7 +782,7 @@ int smu_queue_i2c(struct smu_i2c_cmd *cmd)
cmd->scmd.done = smu_i2c_low_completion;
cmd->scmd.misc = cmd;
cmd->scmd.reply_buf = cmd->pdata;
- cmd->scmd.reply_len = 0x10;
+ cmd->scmd.reply_len = sizeof(cmd->pdata);
cmd->scmd.data_buf = (u8 *)(char *)&cmd->info;
cmd->scmd.status = 1;
cmd->stage = 0;
@@ -909,10 +905,13 @@ static struct smu_sdbp_header *smu_create_sdb_partition(int id)
struct property *prop;
/* First query the partition info */
+ DPRINTK("SMU: Query partition infos ... (irq=%d)\n", smu->db_irq);
smu_queue_simple(&cmd, SMU_CMD_PARTITION_COMMAND, 2,
smu_done_complete, &comp,
SMU_CMD_PARTITION_LATEST, id);
wait_for_completion(&comp);
+ DPRINTK("SMU: done, status: %d, reply_len: %d\n",
+ cmd.cmd.status, cmd.cmd.reply_len);
/* Partition doesn't exist (or other error) */
if (cmd.cmd.status != 0 || cmd.cmd.reply_len != 6)
@@ -975,6 +974,8 @@ struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size,
sprintf(pname, "sdb-partition-%02x", id);
+ DPRINTK("smu_get_sdb_partition(%02x)\n", id);
+
if (interruptible) {
int rc;
rc = down_interruptible(&smu_part_access);
@@ -986,6 +987,7 @@ struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size,
part = (struct smu_sdbp_header *)get_property(smu->of_node,
pname, size);
if (part == NULL) {
+ DPRINTK("trying to extract from SMU ...\n");
part = smu_create_sdb_partition(id);
if (part != NULL && size)
*size = part->len << 2;
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index d843a6c9c6df..2d9d79150403 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -127,39 +127,34 @@ struct adb_driver via_cuda_driver = {
#endif /* CONFIG_ADB */
#ifdef CONFIG_PPC
-int __init
-find_via_cuda(void)
+int __init find_via_cuda(void)
{
- int err;
struct adb_request req;
+ phys_addr_t taddr;
+ u32 *reg;
+ int err;
if (vias != 0)
return 1;
- vias = find_devices("via-cuda");
+ vias = of_find_node_by_name(NULL, "via-cuda");
if (vias == 0)
return 0;
- if (vias->next != 0)
- printk(KERN_WARNING "Warning: only using 1st via-cuda\n");
-
-#if 0
- { int i;
-
- printk("find_via_cuda: node = %p, addrs =", vias->node);
- for (i = 0; i < vias->n_addrs; ++i)
- printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size);
- printk(", intrs =");
- for (i = 0; i < vias->n_intrs; ++i)
- printk(" %x", vias->intrs[i].line);
- printk("\n"); }
-#endif
- if (vias->n_addrs != 1 || vias->n_intrs != 1) {
- printk(KERN_ERR "via-cuda: expecting 1 address (%d) and 1 interrupt (%d)\n",
- vias->n_addrs, vias->n_intrs);
- if (vias->n_addrs < 1 || vias->n_intrs < 1)
- return 0;
+ reg = (u32 *)get_property(vias, "reg", NULL);
+ if (reg == NULL) {
+ printk(KERN_ERR "via-cuda: No \"reg\" property !\n");
+ goto fail;
+ }
+ taddr = of_translate_address(vias, reg);
+ if (taddr == 0) {
+ printk(KERN_ERR "via-cuda: Can't translate address !\n");
+ goto fail;
+ }
+ via = ioremap(taddr, 0x2000);
+ if (via == NULL) {
+ printk(KERN_ERR "via-cuda: Can't map address !\n");
+ goto fail;
}
- via = ioremap(vias->addrs->address, 0x2000);
cuda_state = idle;
sys_ctrler = SYS_CTRLER_CUDA;
@@ -185,6 +180,11 @@ find_via_cuda(void)
cuda_poll();
return 1;
+
+ fail:
+ of_node_put(vias);
+ vias = NULL;
+ return 0;
}
#endif /* CONFIG_PPC */
@@ -193,10 +193,6 @@ static int __init via_cuda_start(void)
if (via == NULL)
return -ENODEV;
-#ifdef CONFIG_PPC
- request_OF_resource(vias, 0, NULL);
-#endif
-
if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ);
return -EAGAIN;
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 564043508569..6eb93e45fcd3 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -55,6 +55,8 @@
#include <asm/sections.h>
#include <asm/irq.h>
#include <asm/pmac_feature.h>
+#include <asm/pmac_pfunc.h>
+#include <asm/pmac_low_i2c.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/cputable.h>
@@ -147,6 +149,7 @@ static struct device_node *vias;
static int pmu_kind = PMU_UNKNOWN;
static int pmu_fully_inited = 0;
static int pmu_has_adb;
+static struct device_node *gpio_node;
static unsigned char __iomem *gpio_reg = NULL;
static int gpio_irq = -1;
static int gpio_irq_enabled = -1;
@@ -157,8 +160,8 @@ static int pmu_version;
static int drop_interrupts;
#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
static int option_lid_wakeup = 1;
-static int sleep_in_progress;
#endif /* CONFIG_PM && CONFIG_PPC32 */
+static int sleep_in_progress;
static unsigned long async_req_locks;
static unsigned int pmu_irq_stats[11];
@@ -196,7 +199,6 @@ static int pmu_adb_reset_bus(void);
#endif /* CONFIG_ADB */
static int init_pmu(void);
-static int pmu_queue_request(struct adb_request *req);
static void pmu_start(void);
static irqreturn_t via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
static irqreturn_t gpio1_interrupt(int irq, void *arg, struct pt_regs *regs);
@@ -295,22 +297,26 @@ static struct backlight_controller pmu_backlight_controller = {
};
#endif /* CONFIG_PMAC_BACKLIGHT */
-int
-find_via_pmu(void)
+int __init find_via_pmu(void)
{
+ u64 taddr;
+ u32 *reg;
+
if (via != 0)
return 1;
- vias = find_devices("via-pmu");
- if (vias == 0)
+ vias = of_find_node_by_name(NULL, "via-pmu");
+ if (vias == NULL)
return 0;
- if (vias->next != 0)
- printk(KERN_WARNING "Warning: only using 1st via-pmu\n");
- if (vias->n_addrs < 1 || vias->n_intrs < 1) {
- printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n",
- vias->n_addrs, vias->n_intrs);
- if (vias->n_addrs < 1 || vias->n_intrs < 1)
- return 0;
+ reg = (u32 *)get_property(vias, "reg", NULL);
+ if (reg == NULL) {
+ printk(KERN_ERR "via-pmu: No \"reg\" property !\n");
+ goto fail;
+ }
+ taddr = of_translate_address(vias, reg);
+ if (taddr == OF_BAD_ADDR) {
+ printk(KERN_ERR "via-pmu: Can't translate address !\n");
+ goto fail;
}
spin_lock_init(&pmu_lock);
@@ -331,7 +337,8 @@ find_via_pmu(void)
pmu_kind = PMU_HEATHROW_BASED;
else if (device_is_compatible(vias->parent, "Keylargo")
|| device_is_compatible(vias->parent, "K2-Keylargo")) {
- struct device_node *gpio, *gpiop;
+ struct device_node *gpiop;
+ u64 gaddr = OF_BAD_ADDR;
pmu_kind = PMU_KEYLARGO_BASED;
pmu_has_adb = (find_type_devices("adb") != NULL);
@@ -341,19 +348,24 @@ find_via_pmu(void)
PMU_INT_TICK |
PMU_INT_ENVIRONMENT;
- gpiop = find_devices("gpio");
- if (gpiop && gpiop->n_addrs) {
- gpio_reg = ioremap(gpiop->addrs->address, 0x10);
- gpio = find_devices("extint-gpio1");
- if (gpio == NULL)
- gpio = find_devices("pmu-interrupt");
- if (gpio && gpio->parent == gpiop && gpio->n_intrs)
- gpio_irq = gpio->intrs[0].line;
+ gpiop = of_find_node_by_name(NULL, "gpio");
+ if (gpiop) {
+ reg = (u32 *)get_property(gpiop, "reg", NULL);
+ if (reg)
+ gaddr = of_translate_address(gpiop, reg);
+ if (gaddr != OF_BAD_ADDR)
+ gpio_reg = ioremap(gaddr, 0x10);
}
+ if (gpio_reg == NULL)
+ printk(KERN_ERR "via-pmu: Can't find GPIO reg !\n");
} else
pmu_kind = PMU_UNKNOWN;
- via = ioremap(vias->addrs->address, 0x2000);
+ via = ioremap(taddr, 0x2000);
+ if (via == NULL) {
+ printk(KERN_ERR "via-pmu: Can't map address !\n");
+ goto fail;
+ }
out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */
out_8(&via[IFR], 0x7f); /* clear IFR */
@@ -365,23 +377,25 @@ find_via_pmu(void)
return 0;
}
- printk(KERN_INFO "PMU driver %d initialized for %s, firmware: %02x\n",
+ printk(KERN_INFO "PMU driver v%d initialized for %s, firmware: %02x\n",
PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version);
sys_ctrler = SYS_CTRLER_PMU;
return 1;
+ fail:
+ of_node_put(vias);
+ vias = NULL;
+ return 0;
}
#ifdef CONFIG_ADB
-static int
-pmu_probe(void)
+static int pmu_probe(void)
{
return vias == NULL? -ENODEV: 0;
}
-static int __init
-pmu_init(void)
+static int __init pmu_init(void)
{
if (vias == NULL)
return -ENODEV;
@@ -405,7 +419,7 @@ static int __init via_pmu_start(void)
bright_req_2.complete = 1;
batt_req.complete = 1;
-#if defined(CONFIG_PPC32) && !defined(CONFIG_PPC_MERGE)
+#ifndef CONFIG_PPC_MERGE
if (pmu_kind == PMU_KEYLARGO_BASED)
openpic_set_irq_priority(vias->intrs[0].line,
OPENPIC_PRIORITY_DEFAULT + 1);
@@ -418,10 +432,22 @@ static int __init via_pmu_start(void)
return -EAGAIN;
}
- if (pmu_kind == PMU_KEYLARGO_BASED && gpio_irq != -1) {
- if (request_irq(gpio_irq, gpio1_interrupt, 0, "GPIO1 ADB", (void *)0))
- printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", gpio_irq);
- gpio_irq_enabled = 1;
+ if (pmu_kind == PMU_KEYLARGO_BASED) {
+ gpio_node = of_find_node_by_name(NULL, "extint-gpio1");
+ if (gpio_node == NULL)
+ gpio_node = of_find_node_by_name(NULL,
+ "pmu-interrupt");
+ if (gpio_node && gpio_node->n_intrs > 0)
+ gpio_irq = gpio_node->intrs[0].line;
+
+ if (gpio_irq != -1) {
+ if (request_irq(gpio_irq, gpio1_interrupt, 0,
+ "GPIO1 ADB", (void *)0))
+ printk(KERN_ERR "pmu: can't get irq %d"
+ " (GPIO1)\n", gpio_irq);
+ else
+ gpio_irq_enabled = 1;
+ }
}
/* Enable interrupts */
@@ -454,9 +480,6 @@ static int __init via_pmu_dev_init(void)
if (vias == NULL)
return -ENODEV;
-#ifndef CONFIG_PPC64
- request_OF_resource(vias, 0, NULL);
-#endif
#ifdef CONFIG_PMAC_BACKLIGHT
/* Enable backlight */
register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
@@ -1371,7 +1394,6 @@ next:
}
pmu_done(req);
} else {
-#if defined(CONFIG_XMON) && !defined(CONFIG_PPC64)
if (len == 4 && data[1] == 0x2c) {
extern int xmon_wants_key, xmon_adb_keycode;
if (xmon_wants_key) {
@@ -1379,7 +1401,6 @@ next:
return;
}
}
-#endif /* defined(CONFIG_XMON) && !defined(CONFIG_PPC64) */
#ifdef CONFIG_ADB
/*
* XXX On the [23]400 the PMU gives us an up
@@ -1782,258 +1803,6 @@ pmu_present(void)
return via != 0;
}
-struct pmu_i2c_hdr {
- u8 bus;
- u8 mode;
- u8 bus2;
- u8 address;
- u8 sub_addr;
- u8 comb_addr;
- u8 count;
-};
-
-int
-pmu_i2c_combined_read(int bus, int addr, int subaddr, u8* data, int len)
-{
- struct adb_request req;
- struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req.data[1];
- int retry;
- int rc;
-
- for (retry=0; retry<16; retry++) {
- memset(&req, 0, sizeof(req));
-
- hdr->bus = bus;
- hdr->address = addr & 0xfe;
- hdr->mode = PMU_I2C_MODE_COMBINED;
- hdr->bus2 = 0;
- hdr->sub_addr = subaddr;
- hdr->comb_addr = addr | 1;
- hdr->count = len;
-
- req.nbytes = sizeof(struct pmu_i2c_hdr) + 1;
- req.reply_expected = 0;
- req.reply_len = 0;
- req.data[0] = PMU_I2C_CMD;
- req.reply[0] = 0xff;
- rc = pmu_queue_request(&req);
- if (rc)
- return rc;
- while(!req.complete)
- pmu_poll();
- if (req.reply[0] == PMU_I2C_STATUS_OK)
- break;
- mdelay(15);
- }
- if (req.reply[0] != PMU_I2C_STATUS_OK)
- return -1;
-
- for (retry=0; retry<16; retry++) {
- memset(&req, 0, sizeof(req));
-
- mdelay(15);
-
- hdr->bus = PMU_I2C_BUS_STATUS;
- req.reply[0] = 0xff;
-
- req.nbytes = 2;
- req.reply_expected = 0;
- req.reply_len = 0;
- req.data[0] = PMU_I2C_CMD;
- rc = pmu_queue_request(&req);
- if (rc)
- return rc;
- while(!req.complete)
- pmu_poll();
- if (req.reply[0] == PMU_I2C_STATUS_DATAREAD) {
- memcpy(data, &req.reply[1], req.reply_len - 1);
- return req.reply_len - 1;
- }
- }
- return -1;
-}
-
-int
-pmu_i2c_stdsub_write(int bus, int addr, int subaddr, u8* data, int len)
-{
- struct adb_request req;
- struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req.data[1];
- int retry;
- int rc;
-
- for (retry=0; retry<16; retry++) {
- memset(&req, 0, sizeof(req));
-
- hdr->bus = bus;
- hdr->address = addr & 0xfe;
- hdr->mode = PMU_I2C_MODE_STDSUB;
- hdr->bus2 = 0;
- hdr->sub_addr = subaddr;
- hdr->comb_addr = addr & 0xfe;
- hdr->count = len;
-
- req.data[0] = PMU_I2C_CMD;
- memcpy(&req.data[sizeof(struct pmu_i2c_hdr) + 1], data, len);
- req.nbytes = sizeof(struct pmu_i2c_hdr) + len + 1;
- req.reply_expected = 0;
- req.reply_len = 0;
- req.reply[0] = 0xff;
- rc = pmu_queue_request(&req);
- if (rc)
- return rc;
- while(!req.complete)
- pmu_poll();
- if (req.reply[0] == PMU_I2C_STATUS_OK)
- break;
- mdelay(15);
- }
- if (req.reply[0] != PMU_I2C_STATUS_OK)
- return -1;
-
- for (retry=0; retry<16; retry++) {
- memset(&req, 0, sizeof(req));
-
- mdelay(15);
-
- hdr->bus = PMU_I2C_BUS_STATUS;
- req.reply[0] = 0xff;
-
- req.nbytes = 2;
- req.reply_expected = 0;
- req.reply_len = 0;
- req.data[0] = PMU_I2C_CMD;
- rc = pmu_queue_request(&req);
- if (rc)
- return rc;
- while(!req.complete)
- pmu_poll();
- if (req.reply[0] == PMU_I2C_STATUS_OK)
- return len;
- }
- return -1;
-}
-
-int
-pmu_i2c_simple_read(int bus, int addr, u8* data, int len)
-{
- struct adb_request req;
- struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req.data[1];
- int retry;
- int rc;
-
- for (retry=0; retry<16; retry++) {
- memset(&req, 0, sizeof(req));
-
- hdr->bus = bus;
- hdr->address = addr | 1;
- hdr->mode = PMU_I2C_MODE_SIMPLE;
- hdr->bus2 = 0;
- hdr->sub_addr = 0;
- hdr->comb_addr = 0;
- hdr->count = len;
-
- req.data[0] = PMU_I2C_CMD;
- req.nbytes = sizeof(struct pmu_i2c_hdr) + 1;
- req.reply_expected = 0;
- req.reply_len = 0;
- req.reply[0] = 0xff;
- rc = pmu_queue_request(&req);
- if (rc)
- return rc;
- while(!req.complete)
- pmu_poll();
- if (req.reply[0] == PMU_I2C_STATUS_OK)
- break;
- mdelay(15);
- }
- if (req.reply[0] != PMU_I2C_STATUS_OK)
- return -1;
-
- for (retry=0; retry<16; retry++) {
- memset(&req, 0, sizeof(req));
-
- mdelay(15);
-
- hdr->bus = PMU_I2C_BUS_STATUS;
- req.reply[0] = 0xff;
-
- req.nbytes = 2;
- req.reply_expected = 0;
- req.reply_len = 0;
- req.data[0] = PMU_I2C_CMD;
- rc = pmu_queue_request(&req);
- if (rc)
- return rc;
- while(!req.complete)
- pmu_poll();
- if (req.reply[0] == PMU_I2C_STATUS_DATAREAD) {
- memcpy(data, &req.reply[1], req.reply_len - 1);
- return req.reply_len - 1;
- }
- }
- return -1;
-}
-
-int
-pmu_i2c_simple_write(int bus, int addr, u8* data, int len)
-{
- struct adb_request req;
- struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req.data[1];
- int retry;
- int rc;
-
- for (retry=0; retry<16; retry++) {
- memset(&req, 0, sizeof(req));
-
- hdr->bus = bus;
- hdr->address = addr & 0xfe;
- hdr->mode = PMU_I2C_MODE_SIMPLE;
- hdr->bus2 = 0;
- hdr->sub_addr = 0;
- hdr->comb_addr = 0;
- hdr->count = len;
-
- req.data[0] = PMU_I2C_CMD;
- memcpy(&req.data[sizeof(struct pmu_i2c_hdr) + 1], data, len);
- req.nbytes = sizeof(struct pmu_i2c_hdr) + len + 1;
- req.reply_expected = 0;
- req.reply_len = 0;
- req.reply[0] = 0xff;
- rc = pmu_queue_request(&req);
- if (rc)
- return rc;
- while(!req.complete)
- pmu_poll();
- if (req.reply[0] == PMU_I2C_STATUS_OK)
- break;
- mdelay(15);
- }
- if (req.reply[0] != PMU_I2C_STATUS_OK)
- return -1;
-
- for (retry=0; retry<16; retry++) {
- memset(&req, 0, sizeof(req));
-
- mdelay(15);
-
- hdr->bus = PMU_I2C_BUS_STATUS;
- req.reply[0] = 0xff;
-
- req.nbytes = 2;
- req.reply_expected = 0;
- req.reply_len = 0;
- req.data[0] = PMU_I2C_CMD;
- rc = pmu_queue_request(&req);
- if (rc)
- return rc;
- while(!req.complete)
- pmu_poll();
- if (req.reply[0] == PMU_I2C_STATUS_OK)
- return len;
- }
- return -1;
-}
-
#ifdef CONFIG_PM
static LIST_HEAD(sleep_notifiers);
@@ -2338,8 +2107,9 @@ pmac_suspend_devices(void)
return -EBUSY;
}
- /* Disable clock spreading on some machines */
- pmac_tweak_clock_spreading(0);
+ /* Call platform functions marked "on sleep" */
+ pmac_pfunc_i2c_suspend();
+ pmac_pfunc_base_suspend();
/* Stop preemption */
preempt_disable();
@@ -2411,8 +2181,9 @@ pmac_wakeup_devices(void)
mdelay(10);
preempt_enable();
- /* Re-enable clock spreading on some machines */
- pmac_tweak_clock_spreading(1);
+ /* Call platform functions marked "on wake" */
+ pmac_pfunc_base_resume();
+ pmac_pfunc_i2c_resume();
/* Resume devices */
device_resume();
@@ -3130,16 +2901,13 @@ static int __init init_pmu_sysfs(void)
subsys_initcall(init_pmu_sysfs);
EXPORT_SYMBOL(pmu_request);
+EXPORT_SYMBOL(pmu_queue_request);
EXPORT_SYMBOL(pmu_poll);
EXPORT_SYMBOL(pmu_poll_adb);
EXPORT_SYMBOL(pmu_wait_complete);
EXPORT_SYMBOL(pmu_suspend);
EXPORT_SYMBOL(pmu_resume);
EXPORT_SYMBOL(pmu_unlock);
-EXPORT_SYMBOL(pmu_i2c_combined_read);
-EXPORT_SYMBOL(pmu_i2c_stdsub_write);
-EXPORT_SYMBOL(pmu_i2c_simple_read);
-EXPORT_SYMBOL(pmu_i2c_simple_write);
#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
EXPORT_SYMBOL(pmu_enable_irled);
EXPORT_SYMBOL(pmu_battery_count);
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index 57460e46c89f..906d3ecae6e6 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -21,6 +21,7 @@
#include <asm/io.h>
#include <asm/system.h>
#include <asm/sections.h>
+#include <asm/pmac_low_i2c.h>
#include "windfarm.h"
@@ -157,53 +158,21 @@ static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter,
static int wf_lm75_attach(struct i2c_adapter *adapter)
{
- u8 bus_id;
- struct device_node *smu, *bus, *dev;
-
- /* We currently only deal with LM75's hanging off the SMU
- * i2c busses. If we extend that driver to other/older
- * machines, we should split this function into SMU-i2c,
- * keywest-i2c, PMU-i2c, ...
- */
+ struct device_node *busnode, *dev;
+ struct pmac_i2c_bus *bus;
DBG("wf_lm75: adapter %s detected\n", adapter->name);
- if (strncmp(adapter->name, "smu-i2c-", 8) != 0)
- return 0;
- smu = of_find_node_by_type(NULL, "smu");
- if (smu == NULL)
- return 0;
-
- /* Look for the bus in the device-tree */
- bus_id = (u8)simple_strtoul(adapter->name + 8, NULL, 16);
-
- DBG("wf_lm75: bus ID is %x\n", bus_id);
-
- /* Look for sensors subdir */
- for (bus = NULL;
- (bus = of_get_next_child(smu, bus)) != NULL;) {
- u32 *reg;
-
- if (strcmp(bus->name, "i2c"))
- continue;
- reg = (u32 *)get_property(bus, "reg", NULL);
- if (reg == NULL)
- continue;
- if (bus_id == *reg)
- break;
- }
- of_node_put(smu);
- if (bus == NULL) {
- printk(KERN_WARNING "windfarm: SMU i2c bus 0x%x not found"
- " in device-tree !\n", bus_id);
- return 0;
- }
+ bus = pmac_i2c_adapter_to_bus(adapter);
+ if (bus == NULL)
+ return -ENODEV;
+ busnode = pmac_i2c_get_bus_node(bus);
DBG("wf_lm75: bus found, looking for device...\n");
/* Now look for lm75(s) in there */
for (dev = NULL;
- (dev = of_get_next_child(bus, dev)) != NULL;) {
+ (dev = of_get_next_child(busnode, dev)) != NULL;) {
const char *loc =
get_property(dev, "hwsensor-location", NULL);
u32 *reg = (u32 *)get_property(dev, "reg", NULL);
@@ -217,9 +186,6 @@ static int wf_lm75_attach(struct i2c_adapter *adapter)
else if (device_is_compatible(dev, "ds1775"))
wf_lm75_create(adapter, *reg, 1, loc);
}
-
- of_node_put(bus);
-
return 0;
}
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index 09ec964dec5c..b614612be7b4 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -253,7 +253,10 @@ static int fops_open(struct inode *inode, struct file *file)
if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
DEB_S(("initializing vbi...\n"));
- result = saa7146_vbi_uops.open(dev,file);
+ if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+ result = saa7146_vbi_uops.open(dev,file);
+ if (dev->ext_vv_data->vbi_fops.open)
+ dev->ext_vv_data->vbi_fops.open(inode, file);
} else {
DEB_S(("initializing video...\n"));
result = saa7146_video_uops.open(dev,file);
@@ -289,7 +292,10 @@ static int fops_release(struct inode *inode, struct file *file)
return -ERESTARTSYS;
if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- saa7146_vbi_uops.release(dev,file);
+ if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+ saa7146_vbi_uops.release(dev,file);
+ if (dev->ext_vv_data->vbi_fops.release)
+ dev->ext_vv_data->vbi_fops.release(inode, file);
} else {
saa7146_video_uops.release(dev,file);
}
@@ -332,6 +338,7 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma)
BUG();
return 0;
}
+
return videobuf_mmap_mapper(q,vma);
}
@@ -381,7 +388,10 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
}
case V4L2_BUF_TYPE_VBI_CAPTURE: {
// DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", file, data, (unsigned long)count));
- return saa7146_vbi_uops.read(file,data,count,ppos);
+ if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+ return saa7146_vbi_uops.read(file,data,count,ppos);
+ else
+ return -EINVAL;
}
break;
default:
@@ -390,12 +400,31 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
}
}
+static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
+{
+ struct saa7146_fh *fh = file->private_data;
+
+ switch (fh->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ return -EINVAL;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (fh->dev->ext_vv_data->vbi_fops.write)
+ return fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
+ else
+ return -EINVAL;
+ default:
+ BUG();
+ return -EINVAL;
+ }
+}
+
static struct file_operations video_fops =
{
.owner = THIS_MODULE,
.open = fops_open,
.release = fops_release,
.read = fops_read,
+ .write = fops_write,
.poll = fops_poll,
.mmap = fops_mmap,
.ioctl = fops_ioctl,
@@ -467,7 +496,8 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM);
saa7146_video_uops.init(dev,vv);
- saa7146_vbi_uops.init(dev,vv);
+ if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+ saa7146_vbi_uops.init(dev,vv);
dev->vv_data = vv;
dev->vv_callback = &vv_callback;
diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c
index ec52dff8cb69..33bec8a6843b 100644
--- a/drivers/media/common/saa7146_hlp.c
+++ b/drivers/media/common/saa7146_hlp.c
@@ -562,19 +562,26 @@ static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int
int b_depth = vv->ov_fmt->depth;
int b_bpl = vv->ov_fb.fmt.bytesperline;
- u32 base = (u32)vv->ov_fb.base;
+ /* The unsigned long cast is to remove a 64-bit compile warning since
+ it looks like a 64-bit address is cast to a 32-bit value, even
+ though the base pointer is really a 32-bit physical address that
+ goes into a 32-bit DMA register.
+ FIXME: might not work on some 64-bit platforms, but see the FIXME
+ in struct v4l2_framebuffer (videodev2.h) for that.
+ */
+ u32 base = (u32)(unsigned long)vv->ov_fb.base;
struct saa7146_video_dma vdma1;
/* calculate memory offsets for picture, look if we shall top-down-flip */
vdma1.pitch = 2*b_bpl;
if ( 0 == vv->vflip ) {
- vdma1.base_even = (u32)base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
+ vdma1.base_even = base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
vdma1.base_odd = vdma1.base_even + (vdma1.pitch / 2);
vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2));
}
else {
- vdma1.base_even = (u32)base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
+ vdma1.base_even = base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
vdma1.base_odd = vdma1.base_even - (vdma1.pitch / 2);
vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2));
}
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index 063986ec16b5..468d3c959075 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -500,9 +500,9 @@ static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff
}
struct saa7146_use_ops saa7146_vbi_uops = {
- .init = vbi_init,
- .open = vbi_open,
+ .init = vbi_init,
+ .open = vbi_open,
.release = vbi_close,
.irq_done = vbi_irq_done,
- .read = vbi_read,
+ .read = vbi_read,
};
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index 1d961023b837..7ebac7949df3 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -151,8 +151,8 @@ static int try_win(struct saa7146_dev *dev, struct v4l2_window *win)
if (V4L2_FIELD_ANY == field) {
field = (win->w.height > maxh/2)
- ? V4L2_FIELD_INTERLACED
- : V4L2_FIELD_TOP;
+ ? V4L2_FIELD_INTERLACED
+ : V4L2_FIELD_TOP;
}
switch (field) {
case V4L2_FIELD_TOP:
@@ -1114,10 +1114,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
return 0;
}
case VIDIOC_OVERLAY:
-
-
-
-
{
int on = *(int *)arg;
int err = 0;
@@ -1359,7 +1355,6 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
saa7146_buffer_queue(fh->dev,&vv->video_q,buf);
}
-
static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
{
struct file *file = q->priv_data;
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 21a9045b3ef6..0b940e152b79 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -298,7 +298,7 @@ static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct fir
}
static int lgdt3303_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
+ struct dvb_frontend_parameters* params)
{
struct flexcop_device *fc = fe->dvb->priv;
u8 buf[4];
@@ -485,12 +485,16 @@ static struct stv0297_config alps_tdee4_stv0297_config = {
/* try to figure out the frontend, each card/box can have on of the following list */
int flexcop_frontend_init(struct flexcop_device *fc)
{
+ struct dvb_frontend_ops *ops;
+
/* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
- fc->fe->ops->set_voltage = flexcop_set_voltage;
+ ops = fc->fe->ops;
+
+ ops->set_voltage = flexcop_set_voltage;
- fc->fe_sleep = fc->fe->ops->sleep;
- fc->fe->ops->sleep = flexcop_sleep;
+ fc->fe_sleep = ops->sleep;
+ ops->sleep = flexcop_sleep;
fc->dev_type = FC_SKY;
info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
@@ -522,15 +526,17 @@ int flexcop_frontend_init(struct flexcop_device *fc)
} else
/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
if ((fc->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
- fc->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
- fc->fe->ops->diseqc_send_burst = flexcop_diseqc_send_burst;
- fc->fe->ops->set_tone = flexcop_set_tone;
- fc->fe->ops->set_voltage = flexcop_set_voltage;
+ ops = fc->fe->ops;
+
+ ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
+ ops->diseqc_send_burst = flexcop_diseqc_send_burst;
+ ops->set_tone = flexcop_set_tone;
+ ops->set_voltage = flexcop_set_voltage;
- fc->fe_sleep = fc->fe->ops->sleep;
- fc->fe->ops->sleep = flexcop_sleep;
+ fc->fe_sleep = ops->sleep;
+ ops->sleep = flexcop_sleep;
- fc->dev_type = FC_SKY_OLD;
+ fc->dev_type = FC_SKY_OLD;
info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address);
}
@@ -540,8 +546,9 @@ int flexcop_frontend_init(struct flexcop_device *fc)
} else {
if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
err("frontend registration failed!");
- if (fc->fe->ops->release != NULL)
- fc->fe->ops->release(fc->fe);
+ ops = fc->fe->ops;
+ if (ops->release != NULL)
+ ops->release(fc->fe);
fc->fe = NULL;
return -EINVAL;
}
diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h
index 23cc6431e2b8..3153f9513c63 100644
--- a/drivers/media/dvb/b2c2/flexcop-reg.h
+++ b/drivers/media/dvb/b2c2/flexcop-reg.h
@@ -39,11 +39,13 @@ extern const char *flexcop_device_names[];
/* FlexCop IBI Registers */
#if defined(__LITTLE_ENDIAN)
#include "flexcop_ibi_value_le.h"
-#elif defined(__BIG_ENDIAN)
+#else
+#if defined(__BIG_ENDIAN)
#include "flexcop_ibi_value_be.h"
#else
#error no endian defined
#endif
+#endif
#define fc_data_Tag_ID_DVB 0x3e
#define fc_data_Tag_ID_ATSC 0x3f
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 8977c7a313df..3a2ff1cc24b7 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1341,30 +1341,40 @@ static int dst_read_snr(struct dvb_frontend *fe, u16 *snr)
return 0;
}
-static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int dst_set_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* p,
+ unsigned int mode_flags,
+ int *delay,
+ fe_status_t *status)
{
struct dst_state *state = fe->demodulator_priv;
- dst_set_freq(state, p->frequency);
- dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
+ if (p != NULL) {
+ dst_set_freq(state, p->frequency);
+ dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
- 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);
- dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", 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);
+ 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);
+ dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", 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);
}
- dst_write_tuna(fe);
+ if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
+ dst_read_status(fe, status);
+
+ *delay = HZ/10;
return 0;
}
@@ -1445,7 +1455,7 @@ static struct dvb_frontend_ops dst_dvbt_ops = {
.release = dst_release,
.init = dst_init,
- .set_frontend = dst_set_frontend,
+ .tune = dst_set_frontend,
.get_frontend = dst_get_frontend,
.read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength,
@@ -1469,7 +1479,7 @@ static struct dvb_frontend_ops dst_dvbs_ops = {
.release = dst_release,
.init = dst_init,
- .set_frontend = dst_set_frontend,
+ .tune = dst_set_frontend,
.get_frontend = dst_get_frontend,
.read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength,
@@ -1496,7 +1506,7 @@ static struct dvb_frontend_ops dst_dvbc_ops = {
.release = dst_release,
.init = dst_init,
- .set_frontend = dst_set_frontend,
+ .tune = dst_set_frontend,
.get_frontend = dst_get_frontend,
.read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength,
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index 2239651969c8..c650b4bf7f5f 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -283,16 +283,17 @@ static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message,
hw_buffer->msg[4] = 0x03;
hw_buffer->msg[5] = length & 0xff;
hw_buffer->msg[6] = 0x00;
+
/*
* Need to compute length for EN50221 section 8.3.2, for the time being
* assuming 8.3.2 is not applicable
*/
memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length);
}
+
return 0;
}
-
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, length, hw_buffer->msg, reply)) < 0) {
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index 77977e9c013e..01b4e0aac049 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -600,7 +600,6 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
struct dst_state* state = NULL;
switch(type) {
-#ifdef BTTV_BOARD_DVICO_DVBT_LITE
case BTTV_BOARD_DVICO_DVBT_LITE:
card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
if (card->fe != NULL) {
@@ -608,22 +607,15 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
card->fe->ops->info.frequency_max = 862000000;
}
break;
-#endif
-#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE
case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
lgdt330x_reset(card);
card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter);
if (card->fe != NULL)
dprintk ("dvb_bt8xx: lgdt330x detected\n");
break;
-#endif
-#ifdef BTTV_BOARD_TWINHAN_VP3021
- case BTTV_BOARD_TWINHAN_VP3021:
-#else
case BTTV_BOARD_NEBULA_DIGITV:
-#endif
/*
* It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK);
* this would be a cleaner solution than trying each frontend in turn.
@@ -812,9 +804,7 @@ static int dvb_bt8xx_probe(struct device *dev)
card->irq_err_ignore = 0;
break;
-#ifdef BTTV_BOARD_DVICO_DVBT_LITE
case BTTV_BOARD_DVICO_DVBT_LITE:
-#endif
card->gpio_mode = 0x0400C060;
card->op_sync_orin = 0;
card->irq_err_ignore = 0;
@@ -823,19 +813,13 @@ static int dvb_bt8xx_probe(struct device *dev)
* DA_APP(parallel) */
break;
-#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE
case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
-#endif
card->gpio_mode = 0x0400c060;
card->op_sync_orin = BT878_RISC_SYNC_MASK;
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
break;
-#ifdef BTTV_BOARD_TWINHAN_VP3021
- case BTTV_BOARD_TWINHAN_VP3021:
-#else
case BTTV_BOARD_NEBULA_DIGITV:
-#endif
case BTTV_BOARD_AVDVBT_761:
card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
card->op_sync_orin = 0;
diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig
index 7cf4c4a888ec..6018fcdba1e6 100644
--- a/drivers/media/dvb/cinergyT2/Kconfig
+++ b/drivers/media/dvb/cinergyT2/Kconfig
@@ -21,35 +21,35 @@ config DVB_CINERGYT2_TUNING
config DVB_CINERGYT2_STREAM_URB_COUNT
int "Number of queued USB Request Blocks for Highspeed Stream Transfers"
depends on DVB_CINERGYT2_TUNING
- default "32"
+ default "32"
help
USB Request Blocks for Highspeed Stream transfers are scheduled in
a queue for the Host Controller.
Usually the default value is a safe choice.
- You may increase this number if you are using this device in a
- Server Environment with many high-traffic USB Highspeed devices
+ You may increase this number if you are using this device in a
+ Server Environment with many high-traffic USB Highspeed devices
sharing the same USB bus.
config DVB_CINERGYT2_STREAM_BUF_SIZE
int "Size of URB Stream Buffers for Highspeed Transfers"
depends on DVB_CINERGYT2_TUNING
- default "512"
+ default "512"
help
Should be a multiple of native buffer size of 512 bytes.
Default value is a safe choice.
- You may increase this number if you are using this device in a
- Server Environment with many high-traffic USB Highspeed devices
+ You may increase this number if you are using this device in a
+ Server Environment with many high-traffic USB Highspeed devices
sharing the same USB bus.
config DVB_CINERGYT2_QUERY_INTERVAL
int "Status update interval [milliseconds]"
depends on DVB_CINERGYT2_TUNING
- default "250"
+ default "250"
help
This is the interval for status readouts from the demodulator.
You may try lower values if you need more responsive signal quality
@@ -64,9 +64,9 @@ config DVB_CINERGYT2_QUERY_INTERVAL
config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
bool "Register the onboard IR Remote Control Receiver as Input Device"
depends on DVB_CINERGYT2_TUNING
- default "yes"
+ default "yes"
help
- Enable this option if you want to use the onboard Infrared Remote
+ Enable this option if you want to use the onboard Infrared Remote
Control Receiver as Linux-Input device.
Right now only the keycode table for the default Remote Control
@@ -77,7 +77,7 @@ config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
config DVB_CINERGYT2_RC_QUERY_INTERVAL
int "Infrared Remote Controller update interval [milliseconds]"
depends on DVB_CINERGYT2_TUNING && DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
- default "50"
+ default "50"
help
If you have a very fast-repeating remote control you can try lower
values, for normal consumer receivers the default value should be
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index 1d69bf031fb9..c4b4c5b6b7c8 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -131,6 +131,8 @@ struct cinergyt2 {
wait_queue_head_t poll_wq;
int pending_fe_events;
+ int disconnect_pending;
+ atomic_t inuse;
void *streambuf;
dma_addr_t streambuf_dmahandle;
@@ -343,7 +345,7 @@ static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed)
struct dvb_demux *demux = dvbdmxfeed->demux;
struct cinergyt2 *cinergyt2 = demux->priv;
- if (down_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
if (cinergyt2->streaming == 0)
@@ -359,7 +361,7 @@ static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
struct dvb_demux *demux = dvbdmxfeed->demux;
struct cinergyt2 *cinergyt2 = demux->priv;
- if (down_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
if (--cinergyt2->streaming == 0)
@@ -479,23 +481,37 @@ static int cinergyt2_open (struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
struct cinergyt2 *cinergyt2 = dvbdev->priv;
- int err;
+ int err = -ERESTARTSYS;
- if ((err = dvb_generic_open(inode, file)))
+ if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+ return -ERESTARTSYS;
+
+ if ((err = dvb_generic_open(inode, file))) {
+ up(&cinergyt2->sem);
return err;
+ }
- if (down_interruptible(&cinergyt2->sem))
- return -ERESTARTSYS;
if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
cinergyt2_sleep(cinergyt2, 0);
schedule_delayed_work(&cinergyt2->query_work, HZ/2);
}
+ atomic_inc(&cinergyt2->inuse);
+
up(&cinergyt2->sem);
return 0;
}
+static void cinergyt2_unregister(struct cinergyt2 *cinergyt2)
+{
+ dvb_unregister_device(cinergyt2->fedev);
+ dvb_unregister_adapter(&cinergyt2->adapter);
+
+ cinergyt2_free_stream_urbs(cinergyt2);
+ kfree(cinergyt2);
+}
+
static int cinergyt2_release (struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
@@ -504,7 +520,7 @@ static int cinergyt2_release (struct inode *inode, struct file *file)
if (down_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
- if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+ if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) {
cancel_delayed_work(&cinergyt2->query_work);
flush_scheduled_work();
cinergyt2_sleep(cinergyt2, 1);
@@ -512,6 +528,11 @@ static int cinergyt2_release (struct inode *inode, struct file *file)
up(&cinergyt2->sem);
+ if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) {
+ warn("delayed unregister in release");
+ cinergyt2_unregister(cinergyt2);
+ }
+
return dvb_generic_release(inode, file);
}
@@ -519,7 +540,14 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct
{
struct dvb_device *dvbdev = file->private_data;
struct cinergyt2 *cinergyt2 = dvbdev->priv;
+
+ if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+ return -ERESTARTSYS;
+
poll_wait(file, &cinergyt2->poll_wq, wait);
+
+ up(&cinergyt2->sem);
+
return (POLLIN | POLLRDNORM | POLLPRI);
}
@@ -564,10 +592,15 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
(__u16 __user *) arg);
case FE_READ_UNCORRECTED_BLOCKS:
- /* UNC are already converted to host byte order... */
- return put_user(stat->uncorrected_block_count,
- (__u32 __user *) arg);
+ {
+ uint32_t unc_count;
+
+ unc_count = stat->uncorrected_block_count;
+ stat->uncorrected_block_count = 0;
+ /* UNC are already converted to host byte order... */
+ return put_user(unc_count,(__u32 __user *) arg);
+ }
case FE_SET_FRONTEND:
{
struct dvbt_set_parameters_msg *param = &cinergyt2->param;
@@ -580,7 +613,7 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
if (copy_from_user(&p, (void __user*) arg, sizeof(p)))
return -EFAULT;
- if (down_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
@@ -691,7 +724,7 @@ static void cinergyt2_query_rc (void *data)
struct cinergyt2_rc_event rc_events[12];
int n, len, i;
- if (down_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
return;
len = cinergyt2_command(cinergyt2, buf, sizeof(buf),
@@ -786,7 +819,6 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2)
{
cancel_delayed_work(&cinergyt2->rc_query_work);
- flush_scheduled_work();
input_unregister_device(cinergyt2->rc_input_dev);
}
@@ -817,7 +849,7 @@ static void cinergyt2_query (void *data)
uint8_t lock_bits;
uint32_t unc;
- if (down_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
return;
unc = s->uncorrected_block_count;
@@ -917,28 +949,25 @@ static void cinergyt2_disconnect (struct usb_interface *intf)
{
struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
- if (down_interruptible(&cinergyt2->sem))
- return;
+ flush_scheduled_work();
cinergyt2_unregister_rc(cinergyt2);
+ cancel_delayed_work(&cinergyt2->query_work);
+ wake_up_interruptible(&cinergyt2->poll_wq);
+
cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx);
- dvb_net_release(&cinergyt2->dvbnet);
- dvb_dmxdev_release(&cinergyt2->dmxdev);
- dvb_dmx_release(&cinergyt2->demux);
- dvb_unregister_device(cinergyt2->fedev);
- dvb_unregister_adapter(&cinergyt2->adapter);
+ cinergyt2->disconnect_pending = 1;
- cinergyt2_free_stream_urbs(cinergyt2);
- up(&cinergyt2->sem);
- kfree(cinergyt2);
+ if (!atomic_read(&cinergyt2->inuse))
+ cinergyt2_unregister(cinergyt2);
}
static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
{
struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
- if (down_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
if (state.event > PM_EVENT_ON) {
@@ -961,7 +990,7 @@ static int cinergyt2_resume (struct usb_interface *intf)
struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
struct dvbt_set_parameters_msg *param = &cinergyt2->param;
- if (down_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
if (!cinergyt2->sleeping) {
@@ -1014,4 +1043,3 @@ module_exit (cinergyt2_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Holger Waechtler, Daniel Mack");
-
diff --git a/drivers/media/dvb/dvb-core/Kconfig b/drivers/media/dvb/dvb-core/Kconfig
index a9a7b3421048..12ee912a5705 100644
--- a/drivers/media/dvb/dvb-core/Kconfig
+++ b/drivers/media/dvb/dvb-core/Kconfig
@@ -5,7 +5,7 @@ config DVB_CORE
help
DVB core utility functions for device handling, software fallbacks etc.
Say Y when you have a DVB card and want to use it. Say Y if your want
- to build your drivers outside the kernel, but need the DVB core. All
+ to build your drivers outside the kernel, but need the DVB core. All
in-kernel drivers will select this automatically if needed.
If unsure say N.
diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile
index c6baac20f529..7adb50c1e8eb 100644
--- a/drivers/media/dvb/dvb-core/Makefile
+++ b/drivers/media/dvb/dvb-core/Makefile
@@ -3,7 +3,7 @@
#
dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
- dvb_ca_en50221.o dvb_frontend.o \
+ dvb_ca_en50221.o dvb_frontend.o \
dvb_net.o dvb_ringbuffer.o
obj-$(CONFIG_DVB_CORE) += dvb-core.o
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 5956c35d34ac..4bb779aeff6a 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -1745,9 +1745,7 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
for (i = 0; i < ca->slot_count; i++) {
dvb_ca_en50221_slot_shutdown(ca, i);
- if (ca->slot_info[i].rx_buffer.data != NULL) {
- vfree(ca->slot_info[i].rx_buffer.data);
- }
+ vfree(ca->slot_info[i].rx_buffer.data);
}
kfree(ca->slot_info);
dvb_unregister_device(ca->dvbdev);
diff --git a/drivers/media/dvb/dvb-core/dvb_filter.c b/drivers/media/dvb/dvb-core/dvb_filter.c
index c49fd0bd7181..772003fb1821 100644
--- a/drivers/media/dvb/dvb-core/dvb_filter.c
+++ b/drivers/media/dvb/dvb-core/dvb_filter.c
@@ -409,16 +409,16 @@ static u8 *skip_pes_header(u8 **bufp)
if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */
if (buf[7] & PTS_ONLY)
- pts = buf+9;
+ pts = buf+9;
else pts = NULL;
buf = inbuf + 9 + inbuf[8];
} else { /* mpeg1 */
for (buf = inbuf + 6; *buf == 0xff; buf++)
- if (buf == inbuf + 6 + 16) {
- break;
- }
+ if (buf == inbuf + 6 + 16) {
+ break;
+ }
if ((*buf & 0xc0) == 0x40)
- buf += 2;
+ buf += 2;
skip = mpeg1_skip_table [*buf >> 4];
if (skip == 5 || skip == 10) pts = buf;
else pts = NULL;
@@ -529,9 +529,9 @@ static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_t
pic->picture_header = 0;
pic->sequence_header_data
= ( INIT_HORIZONTAL_SIZE << 20 )
- | ( INIT_VERTICAL_SIZE << 8 )
- | ( INIT_ASPECT_RATIO << 4 )
- | ( INIT_FRAME_RATE );
+ | ( INIT_VERTICAL_SIZE << 8 )
+ | ( INIT_ASPECT_RATIO << 4 )
+ | ( INIT_FRAME_RATE );
pic->mpeg1_flag = 0;
pic->vinfo.horizontal_size
= INIT_DISP_HORIZONTAL_SIZE;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 95ea5095e07e..4a08c4ab6730 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -92,6 +92,7 @@ static DECLARE_MUTEX(frontend_mutex);
struct dvb_frontend_private {
+ /* thread/frontend values */
struct dvb_device *dvbdev;
struct dvb_frontend_parameters parameters;
struct dvb_fe_events events;
@@ -100,20 +101,25 @@ struct dvb_frontend_private {
wait_queue_head_t wait_queue;
pid_t thread_pid;
unsigned long release_jiffies;
- int state;
- int bending;
- int lnb_drift;
- int inversion;
- int auto_step;
- int auto_sub_step;
- int started_auto_step;
- int min_delay;
- int max_drift;
- int step_size;
- int exit;
- int wakeup;
+ unsigned int exit;
+ unsigned int wakeup;
fe_status_t status;
- fe_sec_tone_mode_t tone;
+ unsigned long tune_mode_flags;
+ unsigned int delay;
+
+ /* swzigzag values */
+ unsigned int state;
+ unsigned int bending;
+ int lnb_drift;
+ unsigned int inversion;
+ unsigned int auto_step;
+ unsigned int auto_sub_step;
+ unsigned int started_auto_step;
+ unsigned int min_delay;
+ unsigned int max_drift;
+ unsigned int step_size;
+ int quality;
+ unsigned int check_wrapped;
};
@@ -208,21 +214,21 @@ static void dvb_frontend_init(struct dvb_frontend *fe)
fe->ops->init(fe);
}
-static void update_delay(int *quality, int *delay, int min_delay, int locked)
+static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked)
{
- int q2;
+ int q2;
- dprintk ("%s\n", __FUNCTION__);
+ dprintk ("%s\n", __FUNCTION__);
- if (locked)
- (*quality) = (*quality * 220 + 36*256) / 256;
- else
- (*quality) = (*quality * 220 + 0) / 256;
+ if (locked)
+ (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256;
+ else
+ (fepriv->quality) = (fepriv->quality * 220 + 0) / 256;
- q2 = *quality - 128;
- q2 *= q2;
+ q2 = fepriv->quality - 128;
+ q2 *= q2;
- *delay = min_delay + q2 * HZ / (128*128);
+ fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128);
}
/**
@@ -232,7 +238,7 @@ static void update_delay(int *quality, int *delay, int min_delay, int locked)
* @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT
* @returns Number of complete iterations that have been performed.
*/
-static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped)
+static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped)
{
int autoinversion;
int ready = 0;
@@ -321,6 +327,129 @@ static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped)
return 0;
}
+static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
+{
+ fe_status_t s;
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+ /* if we've got no parameters, just keep idling */
+ if (fepriv->state & FESTATE_IDLE) {
+ fepriv->delay = 3*HZ;
+ fepriv->quality = 0;
+ return;
+ }
+
+ /* in SCAN mode, we just set the frontend when asked and leave it alone */
+ if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
+ if (fepriv->state & FESTATE_RETUNE) {
+ if (fe->ops->set_frontend)
+ fe->ops->set_frontend(fe, &fepriv->parameters);
+ fepriv->state = FESTATE_TUNED;
+ }
+ fepriv->delay = 3*HZ;
+ fepriv->quality = 0;
+ return;
+ }
+
+ /* get the frontend status */
+ if (fepriv->state & FESTATE_RETUNE) {
+ s = 0;
+ } else {
+ if (fe->ops->read_status)
+ fe->ops->read_status(fe, &s);
+ if (s != fepriv->status) {
+ dvb_frontend_add_event(fe, s);
+ fepriv->status = s;
+ }
+ }
+
+ /* if we're not tuned, and we have a lock, move to the TUNED state */
+ if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
+ dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+ fepriv->state = FESTATE_TUNED;
+
+ /* if we're tuned, then we have determined the correct inversion */
+ if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+ (fepriv->parameters.inversion == INVERSION_AUTO)) {
+ fepriv->parameters.inversion = fepriv->inversion;
+ }
+ return;
+ }
+
+ /* if we are tuned already, check we're still locked */
+ if (fepriv->state & FESTATE_TUNED) {
+ dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+
+ /* we're tuned, and the lock is still good... */
+ if (s & FE_HAS_LOCK) {
+ return;
+ } else { /* if we _WERE_ tuned, but now don't have a lock */
+ fepriv->state = FESTATE_ZIGZAG_FAST;
+ fepriv->started_auto_step = fepriv->auto_step;
+ fepriv->check_wrapped = 0;
+ }
+ }
+
+ /* don't actually do anything if we're in the LOSTLOCK state,
+ * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
+ if ((fepriv->state & FESTATE_LOSTLOCK) &&
+ (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
+ dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+ return;
+ }
+
+ /* don't do anything if we're in the DISEQC state, since this
+ * might be someone with a motorized dish controlled by DISEQC.
+ * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
+ if (fepriv->state & FESTATE_DISEQC) {
+ dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+ return;
+ }
+
+ /* if we're in the RETUNE state, set everything up for a brand
+ * new scan, keeping the current inversion setting, as the next
+ * tune is _very_ likely to require the same */
+ if (fepriv->state & FESTATE_RETUNE) {
+ fepriv->lnb_drift = 0;
+ fepriv->auto_step = 0;
+ fepriv->auto_sub_step = 0;
+ fepriv->started_auto_step = 0;
+ fepriv->check_wrapped = 0;
+ }
+
+ /* fast zigzag. */
+ if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
+ fepriv->delay = fepriv->min_delay;
+
+ /* peform a tune */
+ if (dvb_frontend_swzigzag_autotune(fe, fepriv->check_wrapped)) {
+ /* OK, if we've run out of trials at the fast speed.
+ * Drop back to slow for the _next_ attempt */
+ fepriv->state = FESTATE_SEARCHING_SLOW;
+ fepriv->started_auto_step = fepriv->auto_step;
+ return;
+ }
+ fepriv->check_wrapped = 1;
+
+ /* if we've just retuned, enter the ZIGZAG_FAST state.
+ * This ensures we cannot return from an
+ * FE_SET_FRONTEND ioctl before the first frontend tune
+ * occurs */
+ if (fepriv->state & FESTATE_RETUNE) {
+ fepriv->state = FESTATE_TUNING_FAST;
+ }
+ }
+
+ /* slow zigzag */
+ if (fepriv->state & FESTATE_SEARCHING_SLOW) {
+ dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+
+ /* Note: don't bother checking for wrapping; we stay in this
+ * state until we get a lock */
+ dvb_frontend_swzigzag_autotune(fe, 0);
+ }
+}
+
static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
{
struct dvb_frontend_private *fepriv = fe->frontend_priv;
@@ -330,7 +459,7 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
if (fepriv->dvbdev->writers == 1)
if (time_after(jiffies, fepriv->release_jiffies +
- dvb_shutdown_timeout * HZ))
+ dvb_shutdown_timeout * HZ))
return 1;
return 0;
@@ -355,18 +484,14 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe)
wake_up_interruptible(&fepriv->wait_queue);
}
-/*
- * FIXME: use linux/kthread.h
- */
static int dvb_frontend_thread(void *data)
{
struct dvb_frontend *fe = data;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
unsigned long timeout;
char name [15];
- int quality = 0, delay = 3*HZ;
fe_status_t s;
- int check_wrapped = 0;
+ struct dvb_frontend_parameters *params;
dprintk("%s\n", __FUNCTION__);
@@ -377,6 +502,9 @@ static int dvb_frontend_thread(void *data)
sigfillset(&current->blocked);
unlock_kernel();
+ fepriv->check_wrapped = 0;
+ fepriv->quality = 0;
+ fepriv->delay = 3*HZ;
fepriv->status = 0;
dvb_frontend_init(fe);
fepriv->wakeup = 0;
@@ -386,7 +514,7 @@ static int dvb_frontend_thread(void *data)
timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
dvb_frontend_should_wakeup(fe),
- delay);
+ fepriv->delay);
if (0 != dvb_frontend_is_exiting(fe)) {
/* got signal or quitting */
break;
@@ -397,108 +525,22 @@ static int dvb_frontend_thread(void *data)
if (down_interruptible(&fepriv->sem))
break;
- /* if we've got no parameters, just keep idling */
- if (fepriv->state & FESTATE_IDLE) {
- delay = 3*HZ;
- quality = 0;
- continue;
- }
+ /* do an iteration of the tuning loop */
+ if (fe->ops->tune) {
+ /* have we been asked to retune? */
+ params = NULL;
+ if (fepriv->state & FESTATE_RETUNE) {
+ params = &fepriv->parameters;
+ fepriv->state = FESTATE_TUNED;
+ }
- /* get the frontend status */
- if (fepriv->state & FESTATE_RETUNE) {
- s = 0;
- } else {
- if (fe->ops->read_status)
- fe->ops->read_status(fe, &s);
+ fe->ops->tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
if (s != fepriv->status) {
dvb_frontend_add_event(fe, s);
fepriv->status = s;
}
- }
- /* if we're not tuned, and we have a lock, move to the TUNED state */
- if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
- update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
- fepriv->state = FESTATE_TUNED;
-
- /* if we're tuned, then we have determined the correct inversion */
- if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
- (fepriv->parameters.inversion == INVERSION_AUTO)) {
- fepriv->parameters.inversion = fepriv->inversion;
- }
- continue;
- }
-
- /* if we are tuned already, check we're still locked */
- if (fepriv->state & FESTATE_TUNED) {
- update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-
- /* 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 */
- fepriv->state = FESTATE_ZIGZAG_FAST;
- fepriv->started_auto_step = fepriv->auto_step;
- check_wrapped = 0;
- }
- }
-
- /* don't actually do anything if we're in the LOSTLOCK state,
- * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
- if ((fepriv->state & FESTATE_LOSTLOCK) &&
- (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
- update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
- continue;
- }
-
- /* don't do anything if we're in the DISEQC state, since this
- * might be someone with a motorized dish controlled by DISEQC.
- * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
- if (fepriv->state & FESTATE_DISEQC) {
- update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
- continue;
- }
-
- /* if we're in the RETUNE state, set everything up for a brand
- * new scan, keeping the current inversion setting, as the next
- * tune is _very_ likely to require the same */
- if (fepriv->state & FESTATE_RETUNE) {
- fepriv->lnb_drift = 0;
- fepriv->auto_step = 0;
- fepriv->auto_sub_step = 0;
- fepriv->started_auto_step = 0;
- check_wrapped = 0;
- }
-
- /* fast zigzag. */
- if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
- delay = fepriv->min_delay;
-
- /* peform a tune */
- if (dvb_frontend_autotune(fe, check_wrapped)) {
- /* OK, if we've run out of trials at the fast speed.
- * Drop back to slow for the _next_ attempt */
- fepriv->state = FESTATE_SEARCHING_SLOW;
- fepriv->started_auto_step = fepriv->auto_step;
- continue;
- }
- check_wrapped = 1;
-
- /* if we've just retuned, enter the ZIGZAG_FAST state.
- * This ensures we cannot return from an
- * FE_SET_FRONTEND ioctl before the first frontend tune
- * occurs */
- if (fepriv->state & FESTATE_RETUNE) {
- fepriv->state = FESTATE_TUNING_FAST;
- }
- }
-
- /* slow zigzag */
- if (fepriv->state & FESTATE_SEARCHING_SLOW) {
- update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-
- /* Note: don't bother checking for wrapping; we stay in this
- * state until we get a lock */
- dvb_frontend_autotune(fe, 0);
+ } else {
+ dvb_frontend_swzigzag(fe);
}
}
@@ -733,7 +775,6 @@ 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;
@@ -747,7 +788,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
case FE_DISHNETWORK_SEND_LEGACY_CMD:
if (fe->ops->dishnetwork_send_legacy_command) {
- err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned int) parg);
+ err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned long) parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
} else if (fe->ops->set_voltage) {
@@ -767,13 +808,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
* initialization, so parg is 8 bits and does not
* include the initialization or start bit
*/
- unsigned int cmd = ((unsigned int) parg) << 1;
+ unsigned long cmd = ((unsigned long) parg) << 1;
struct timeval nexttime;
struct timeval tv[10];
int i;
u8 last = 1;
if (dvb_frontend_debug)
- printk("%s switch command: 0x%04x\n", __FUNCTION__, cmd);
+ printk("%s switch command: 0x%04lx\n", __FUNCTION__, cmd);
do_gettimeofday(&nexttime);
if (dvb_frontend_debug)
memcpy(&tv[0], &nexttime, sizeof(struct timeval));
@@ -814,7 +855,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
case FE_ENABLE_HIGH_LNB_VOLTAGE:
if (fe->ops->enable_high_lnb_voltage)
- err = fe->ops->enable_high_lnb_voltage(fe, (int) parg);
+ err = fe->ops->enable_high_lnb_voltage(fe, (long) parg);
break;
case FE_SET_FRONTEND: {
@@ -891,6 +932,10 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg);
}
break;
+
+ case FE_SET_FRONTEND_TUNE_MODE:
+ fepriv->tune_mode_flags = (unsigned long) parg;
+ break;
};
up (&fepriv->sem);
@@ -932,6 +977,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
/* empty event queue */
fepriv->events.eventr = fepriv->events.eventw = 0;
+
+ /* normal tune mode when opened R/W */
+ fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
}
return ret;
@@ -990,7 +1038,6 @@ 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 1e0840d02f1f..70a6d14efda7 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -58,10 +58,19 @@ struct dvb_frontend_ops {
int (*init)(struct dvb_frontend* fe);
int (*sleep)(struct dvb_frontend* fe);
+ /* if this is set, it overrides the default swzigzag */
+ int (*tune)(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params,
+ unsigned int mode_flags,
+ int *delay,
+ fe_status_t *status);
+
+ /* these two are only used for the swzigzag code */
int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
- int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
+ int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+
int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
int (*read_ber)(struct dvb_frontend* fe, u32* ber);
int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
@@ -74,8 +83,9 @@ struct dvb_frontend_ops {
int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
- int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, int arg);
- int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd);
+ int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
+ int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
+ int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
};
#define MAX_EVENT 8
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 86bba81e851e..6711eb6a058c 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -1222,7 +1222,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
return if_num;
}
-static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned int num)
+static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)
{
struct net_device *net = dvbnet->device[num];
struct dvb_net_priv *priv;
@@ -1296,9 +1296,9 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file,
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if ((unsigned int) parg >= DVB_NET_DEVICES_MAX)
+ if ((unsigned long) parg >= DVB_NET_DEVICES_MAX)
return -EINVAL;
- ret = dvb_net_remove_if(dvbnet, (unsigned int) parg);
+ ret = dvb_net_remove_if(dvbnet, (unsigned long) parg);
if (!ret)
module_put(dvbdev->adapter->module);
return ret;
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
index 283c6e9339a4..77ad2410f4d3 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
@@ -112,10 +112,10 @@ ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, in
split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
if (split > 0) {
if (!usermem)
- memcpy(buf, rbuf->data+rbuf->pread, split);
+ memcpy(buf, rbuf->data+rbuf->pread, split);
else
- if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
- return -EFAULT;
+ if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
+ return -EFAULT;
buf += split;
todo -= split;
rbuf->pread = 0;
@@ -124,7 +124,7 @@ ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, in
memcpy(buf, rbuf->data+rbuf->pread, todo);
else
if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
- return -EFAULT;
+ return -EFAULT;
rbuf->pread = (rbuf->pread + todo) % rbuf->size;
@@ -167,7 +167,7 @@ ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t le
}
ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
- int offset, u8* buf, size_t len, int usermem)
+ int offset, u8* buf, size_t len, int usermem)
{
size_t todo;
size_t split;
@@ -183,10 +183,10 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
if (split > 0) {
if (!usermem)
- memcpy(buf, rbuf->data+idx, split);
+ memcpy(buf, rbuf->data+idx, split);
else
- if (copy_to_user(buf, rbuf->data+idx, split))
- return -EFAULT;
+ if (copy_to_user(buf, rbuf->data+idx, split))
+ return -EFAULT;
buf += split;
todo -= split;
idx = 0;
@@ -195,7 +195,7 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
memcpy(buf, rbuf->data+idx, todo);
else
if (copy_to_user(buf, rbuf->data+idx, todo))
- return -EFAULT;
+ return -EFAULT;
return len;
}
@@ -209,12 +209,12 @@ void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
// clean up disposed packets
while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) {
if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) {
- pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8;
- pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1);
- DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE);
+ pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8;
+ pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1);
+ DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE);
} else {
- // first packet is not disposed, so we stop cleaning now
- break;
+ // first packet is not disposed, so we stop cleaning now
+ break;
}
}
}
@@ -242,8 +242,8 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t*
curpktstatus = rbuf->data[(idx + 2) % rbuf->size];
if (curpktstatus == PKT_READY) {
- *pktlen = curpktlen;
- return idx;
+ *pktlen = curpktlen;
+ return idx;
}
consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE;
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
index fa476f662f82..6d2560972771 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
@@ -106,7 +106,7 @@ extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
** returns number of bytes transferred or -EFAULT
*/
extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
- size_t len, int usermem);
+ size_t len, int usermem);
/* write routines & macros */
@@ -121,7 +121,7 @@ extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
** returns number of bytes transferred or -EFAULT
*/
extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
- size_t len);
+ size_t len);
/**
@@ -133,7 +133,7 @@ extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
* returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
*/
extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
- size_t len);
+ size_t len);
/**
* Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this
@@ -149,7 +149,7 @@ extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
* returns Number of bytes read, or -EFAULT.
*/
extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
- int offset, u8* buf, size_t len, int usermem);
+ int offset, u8* buf, size_t len, int usermem);
/**
* Dispose of a packet in the ring buffer.
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index a4aee8665854..06b696e9acbd 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -92,10 +92,10 @@ static int dvb_device_open(struct inode *inode, struct file *file)
old_fops = file->f_op;
file->f_op = fops_get(dvbdev->fops);
if(file->f_op->open)
- err = file->f_op->open(inode,file);
+ err = file->f_op->open(inode,file);
if (err) {
- fops_put(file->f_op);
- file->f_op = fops_get(old_fops);
+ fops_put(file->f_op);
+ file->f_op = fops_get(old_fops);
}
fops_put(old_fops);
return err;
@@ -356,18 +356,18 @@ int dvb_usercopy(struct inode *inode, struct file *file,
case _IOC_WRITE:
case (_IOC_WRITE | _IOC_READ):
if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
- parg = sbuf;
+ parg = sbuf;
} else {
- /* too big to allocate from stack */
- mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
- if (NULL == mbuf)
- return -ENOMEM;
- parg = mbuf;
+ /* too big to allocate from stack */
+ mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
+ if (NULL == mbuf)
+ return -ENOMEM;
+ parg = mbuf;
}
err = -EFAULT;
if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
- goto out;
+ goto out;
break;
}
@@ -384,7 +384,7 @@ int dvb_usercopy(struct inode *inode, struct file *file,
case _IOC_READ:
case (_IOC_WRITE | _IOC_READ):
if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
- err = -EFAULT;
+ err = -EFAULT;
break;
}
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
index 0cc6e4a0e27c..74ed5853f0fb 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/drivers/media/dvb/dvb-core/dvbdev.h
@@ -97,7 +97,7 @@ we simply define out own dvb_usercopy(), which will hopefully become
generic_usercopy() someday... */
extern int dvb_usercopy(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg,
+ unsigned int cmd, unsigned long arg,
int (*func)(struct inode *inode, struct file *file,
unsigned int cmd, void *arg));
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 54e2b29076b1..90a69d343b79 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -37,16 +37,16 @@ config DVB_USB_DIBUSB_MB
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
Devices supported by this driver:
- TwinhanDTV USB-Ter (VP7041)
- TwinhanDTV Magic Box (VP7041e)
- KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
- Hama DVB-T USB1.1-Box
- DiBcom USB1.1 reference devices (non-public)
- Ultima Electronic/Artec T1 USB TVBOX
+ Artec T1 USB1.1 boxes
+ Avermedia AverTV DVBT USB1.1
Compro Videomate DVB-U2000 - DVB-T USB
+ DiBcom USB1.1 reference devices (non-public)
Grandtec DVB-T USB
- Avermedia AverTV DVBT USB1.1
- Artec T1 USB1.1 boxes
+ Hama DVB-T USB1.1-Box
+ KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
+ TwinhanDTV Magic Box (VP7041e)
+ TwinhanDTV USB-Ter (VP7041)
+ Ultima Electronic/Artec T1 USB TVBOX
The VP7041 seems to be identical to "CTS Portable" (Chinese
Television System).
@@ -54,6 +54,12 @@ config DVB_USB_DIBUSB_MB
Say Y if you own such a device and want to use it. You should build it as
a module.
+config DVB_USB_DIBUSB_MB_FAULTY
+ bool "Support faulty USB IDs"
+ depends on DVB_USB_DIBUSB_MB
+ help
+ Support for faulty USB IDs due to an invalid EEPROM on some Artec devices.
+
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
@@ -63,8 +69,8 @@ config DVB_USB_DIBUSB_MC
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
Devices supported by this driver:
- DiBcom USB2.0 reference devices (non-public)
Artec T1 USB2.0 boxes
+ DiBcom USB2.0 reference devices (non-public)
Say Y if you own such a device and want to use it. You should build it as
a module.
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index d05fab01cccd..358ed153865f 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -11,10 +11,11 @@
* 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
+ * TODO: Use the cx25840-driver for the analogue part
*
* Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2005 Michael Krufky (mkrufky@m1k.net)
+ * Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au)
*
* 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
@@ -25,6 +26,9 @@
#include "cxusb.h"
#include "cx22702.h"
+#include "lgdt330x.h"
+#include "mt352.h"
+#include "mt352_priv.h"
/* debug */
int dvb_usb_cxusb_debug;
@@ -156,6 +160,99 @@ static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
return 0;
}
+static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+ struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ u8 ircode[4];
+ int i;
+
+ cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4);
+
+ *event = 0;
+ *state = REMOTE_NO_KEY_PRESSED;
+
+ for (i = 0; i < d->props.rc_key_map_size; i++) {
+ if (keymap[i].custom == ircode[2] &&
+ keymap[i].data == ircode[3]) {
+ *event = keymap[i].event;
+ *state = REMOTE_KEY_PRESSED;
+
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+struct dvb_usb_rc_key dvico_mce_rc_keys[] = {
+ { 0xfe, 0x02, KEY_TV },
+ { 0xfe, 0x0e, KEY_MP3 },
+ { 0xfe, 0x1a, KEY_DVD },
+ { 0xfe, 0x1e, KEY_FAVORITES },
+ { 0xfe, 0x16, KEY_SETUP },
+ { 0xfe, 0x46, KEY_POWER2 },
+ { 0xfe, 0x0a, KEY_EPG },
+ { 0xfe, 0x49, KEY_BACK },
+ { 0xfe, 0x4d, KEY_MENU },
+ { 0xfe, 0x51, KEY_UP },
+ { 0xfe, 0x5b, KEY_LEFT },
+ { 0xfe, 0x5f, KEY_RIGHT },
+ { 0xfe, 0x53, KEY_DOWN },
+ { 0xfe, 0x5e, KEY_OK },
+ { 0xfe, 0x59, KEY_INFO },
+ { 0xfe, 0x55, KEY_TAB },
+ { 0xfe, 0x0f, KEY_PREVIOUSSONG },/* Replay */
+ { 0xfe, 0x12, KEY_NEXTSONG }, /* Skip */
+ { 0xfe, 0x42, KEY_ENTER }, /* Windows/Start */
+ { 0xfe, 0x15, KEY_VOLUMEUP },
+ { 0xfe, 0x05, KEY_VOLUMEDOWN },
+ { 0xfe, 0x11, KEY_CHANNELUP },
+ { 0xfe, 0x09, KEY_CHANNELDOWN },
+ { 0xfe, 0x52, KEY_CAMERA },
+ { 0xfe, 0x5a, KEY_TUNER }, /* Live */
+ { 0xfe, 0x19, KEY_OPEN },
+ { 0xfe, 0x0b, KEY_1 },
+ { 0xfe, 0x17, KEY_2 },
+ { 0xfe, 0x1b, KEY_3 },
+ { 0xfe, 0x07, KEY_4 },
+ { 0xfe, 0x50, KEY_5 },
+ { 0xfe, 0x54, KEY_6 },
+ { 0xfe, 0x48, KEY_7 },
+ { 0xfe, 0x4c, KEY_8 },
+ { 0xfe, 0x58, KEY_9 },
+ { 0xfe, 0x13, KEY_ANGLE }, /* Aspect */
+ { 0xfe, 0x03, KEY_0 },
+ { 0xfe, 0x1f, KEY_ZOOM },
+ { 0xfe, 0x43, KEY_REWIND },
+ { 0xfe, 0x47, KEY_PLAYPAUSE },
+ { 0xfe, 0x4f, KEY_FASTFORWARD },
+ { 0xfe, 0x57, KEY_MUTE },
+ { 0xfe, 0x0d, KEY_STOP },
+ { 0xfe, 0x01, KEY_RECORD },
+ { 0xfe, 0x4e, KEY_POWER },
+};
+
+static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
+{
+ static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x38 };
+ static u8 reset [] = { RESET, 0x80 };
+ static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+ static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 };
+ static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
+ static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(200);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+ return 0;
+}
+
struct cx22702_config cxusb_cx22702_config = {
.demod_address = 0x63,
@@ -165,17 +262,47 @@ struct cx22702_config cxusb_cx22702_config = {
.pll_set = dvb_usb_pll_set_i2c,
};
+struct lgdt330x_config cxusb_lgdt330x_config = {
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3303,
+ .pll_set = dvb_usb_pll_set_i2c,
+};
+
+struct mt352_config cxusb_dee1601_config = {
+ .demod_address = 0x0f,
+ .demod_init = cxusb_dee1601_demod_init,
+ .pll_set = dvb_usb_pll_set,
+};
+
/* Callbacks for DVB USB */
-static int cxusb_tuner_attach(struct dvb_usb_device *d)
+static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_device *d)
{
u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
d->pll_addr = 0x61;
- memcpy(d->pll_init,bpll,4);
+ memcpy(d->pll_init, bpll, 4);
d->pll_desc = &dvb_pll_fmd1216me;
return 0;
}
-static int cxusb_frontend_attach(struct dvb_usb_device *d)
+static int cxusb_lgh064f_tuner_attach(struct dvb_usb_device *d)
+{
+ u8 bpll[4] = { 0x00, 0x00, 0x18, 0x50 };
+ /* bpll[2] : unset bit 3, set bits 4&5
+ bpll[3] : 0x50 - digital, 0x20 - analog */
+ d->pll_addr = 0x61;
+ memcpy(d->pll_init, bpll, 4);
+ d->pll_desc = &dvb_pll_tdvs_tua6034;
+ return 0;
+}
+
+static int cxusb_dee1601_tuner_attach(struct dvb_usb_device *d)
+{
+ d->pll_addr = 0x61;
+ d->pll_desc = &dvb_pll_thomson_dtt7579;
+ return 0;
+}
+
+static int cxusb_cx22702_frontend_attach(struct dvb_usb_device *d)
{
u8 b;
if (usb_set_interface(d->udev,0,6) < 0)
@@ -189,22 +316,84 @@ static int cxusb_frontend_attach(struct dvb_usb_device *d)
return -EIO;
}
+static int cxusb_lgdt330x_frontend_attach(struct dvb_usb_device *d)
+{
+ if (usb_set_interface(d->udev,0,7) < 0)
+ err("set interface failed");
+
+ cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
+
+ if ((d->fe = lgdt330x_attach(&cxusb_lgdt330x_config, &d->i2c_adap)) != NULL)
+ return 0;
+
+ return -EIO;
+}
+
+static int cxusb_dee1601_frontend_attach(struct dvb_usb_device *d)
+{
+ if (usb_set_interface(d->udev,0,0) < 0)
+ err("set interface failed");
+
+ cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
+
+ if ((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL)
+ return 0;
+
+ return -EIO;
+}
+
+/*
+ * DViCO bluebird firmware needs the "warm" product ID to be patched into the
+ * firmware file before download.
+ */
+
+#define BLUEBIRD_01_ID_OFFSET 6638
+static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const struct firmware *fw)
+{
+ if (fw->size < BLUEBIRD_01_ID_OFFSET + 4)
+ return -EINVAL;
+
+ if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) &&
+ fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) {
+
+ /* FIXME: are we allowed to change the fw-data ? */
+ fw->data[BLUEBIRD_01_ID_OFFSET + 2] = udev->descriptor.idProduct + 1;
+ fw->data[BLUEBIRD_01_ID_OFFSET + 3] = udev->descriptor.idProduct >> 8;
+
+ return usb_cypress_load_firmware(udev,fw,CYPRESS_FX2);
+ }
+
+ return -EINVAL;
+}
+
/* DVB USB Driver stuff */
-static struct dvb_usb_properties cxusb_properties;
+static struct dvb_usb_properties cxusb_medion_properties;
+static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties;
+static struct dvb_usb_properties cxusb_bluebird_dee1601_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,NULL);
+ if (dvb_usb_device_init(intf,&cxusb_medion_properties,THIS_MODULE,NULL) == 0 ||
+ dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 ||
+ dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0) {
+ return 0;
+ }
+
+ return -EINVAL;
}
static struct usb_device_id cxusb_table [] = {
{ USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
+ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) },
+ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) },
+ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_COLD) },
+ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_WARM) },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, cxusb_table);
-static struct dvb_usb_properties cxusb_properties = {
+static struct dvb_usb_properties cxusb_medion_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_FX2,
@@ -213,8 +402,8 @@ static struct dvb_usb_properties cxusb_properties = {
.streaming_ctrl = cxusb_streaming_ctrl,
.power_ctrl = cxusb_power_ctrl,
- .frontend_attach = cxusb_frontend_attach,
- .tuner_attach = cxusb_tuner_attach,
+ .frontend_attach = cxusb_cx22702_frontend_attach,
+ .tuner_attach = cxusb_fmd1216me_tuner_attach,
.i2c_algo = &cxusb_i2c_algo,
@@ -240,6 +429,91 @@ static struct dvb_usb_properties cxusb_properties = {
}
};
+static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .firmware = "dvb-usb-bluebird-01.fw",
+ .download_firmware = bluebird_patch_dvico_firmware_download,
+ /* use usb alt setting 0 for EP4 transfer (dvb-t),
+ use usb alt setting 7 for EP2 transfer (atsc) */
+
+ .size_of_priv = sizeof(struct cxusb_state),
+
+ .streaming_ctrl = cxusb_streaming_ctrl,
+ .power_ctrl = cxusb_power_ctrl,
+ .frontend_attach = cxusb_lgdt330x_frontend_attach,
+ .tuner_attach = cxusb_lgh064f_tuner_attach,
+
+ .i2c_algo = &cxusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 5,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 8192,
+ }
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { "DViCO FusionHDTV5 USB Gold",
+ { &cxusb_table[1], NULL },
+ { &cxusb_table[2], NULL },
+ },
+ }
+};
+
+static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .firmware = "dvb-usb-bluebird-01.fw",
+ .download_firmware = bluebird_patch_dvico_firmware_download,
+ /* use usb alt setting 0 for EP4 transfer (dvb-t),
+ use usb alt setting 7 for EP2 transfer (atsc) */
+
+ .size_of_priv = sizeof(struct cxusb_state),
+
+ .streaming_ctrl = cxusb_streaming_ctrl,
+ .power_ctrl = cxusb_power_ctrl,
+ .frontend_attach = cxusb_dee1601_frontend_attach,
+ .tuner_attach = cxusb_dee1601_tuner_attach,
+
+ .i2c_algo = &cxusb_i2c_algo,
+
+ .rc_interval = 150,
+ .rc_key_map = dvico_mce_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys),
+ .rc_query = cxusb_rc_query,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 5,
+ .endpoint = 0x04,
+ .u = {
+ .bulk = {
+ .buffersize = 8192,
+ }
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { "DViCO FusionHDTV DVB-T Dual USB",
+ { &cxusb_table[3], NULL },
+ { &cxusb_table[4], NULL },
+ },
+ }
+};
+
static struct usb_driver cxusb_driver = {
.name = "dvb_usb_cxusb",
.probe = cxusb_probe,
diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h
index 135c2a81f581..087c99427853 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.h
+++ b/drivers/media/dvb/dvb-usb/cxusb.h
@@ -21,6 +21,8 @@ extern int dvb_usb_cxusb_debug;
#define CMD_STREAMING_ON 0x36
#define CMD_STREAMING_OFF 0x37
+#define CMD_GET_IR_CODE 0x47
+
#define CMD_ANALOG 0x50
#define CMD_DIGITAL 0x51
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index 52ac3e5adf5d..dd5a13195886 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -65,11 +65,11 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d)
d->tuner_pass_ctrl(d->fe,0,msg[0].addr);
if (b2[0] == 0xfe) {
- info("this device has the Thomson Cable onboard. Which is default.");
+ info("This device has the Thomson Cable onboard. Which is default.");
dibusb_thomson_tuner_attach(d);
} else {
u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
- info("this device has the Panasonic ENV77H11D5 onboard.");
+ info("This device has the Panasonic ENV77H11D5 onboard.");
d->pll_addr = 0x60;
memcpy(d->pll_init,bpll,4);
d->pll_desc = &dvb_pll_tda665x;
@@ -98,15 +98,15 @@ 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_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_COLD)},
-/* 01 */ { USB_DEVICE(USB_VID_WIDEVIEW, 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) },
/* 05 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_COLD) },
/* 06 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_WARM) },
-/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) },
-/* 08 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) },
+/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) },
+/* 08 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) },
/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_COLD) },
/* 10 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_WARM) },
/* 11 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_COLD) },
@@ -117,27 +117,34 @@ static struct usb_device_id dibusb_dib3000mb_table [] = {
/* 16 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_WARM) },
/* 17 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_COLD) },
/* 18 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_WARM) },
-/* 19 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
-/* 20 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
-/* 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) },
+/* 19 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
+/* 20 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
+/* 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) },
+/* 25 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_COLD) },
+/* 26 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_WARM) },
/* 27 */ { USB_DEVICE(USB_VID_KWORLD, USB_PID_KWORLD_VSTREAM_COLD) },
-/* 28 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
-/* 29 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) },
+/* 28 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
+/* 29 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) },
-// #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+/*
+ * XXX: As Artec just 'forgot' to program the EEPROM on some Artec T1 devices
+ * we don't catch these faulty IDs (namely 'Cypress FX1 USB controller') that
+ * have been left on the device. If you don't have such a device but an Artec
+ * device that's supposed to work with this driver but is not detected by it,
+ * free to enable CONFIG_DVB_USB_DIBUSB_MB_FAULTY via your kernel config.
+ */
-#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
/* 30 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
#endif
+
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table);
@@ -257,7 +264,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
}
},
-#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
.num_device_descs = 2,
#else
.num_device_descs = 1,
@@ -267,11 +274,12 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
{ &dibusb_dib3000mb_table[20], NULL },
{ &dibusb_dib3000mb_table[21], NULL },
},
-#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
{ "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
{ &dibusb_dib3000mb_table[30], NULL },
{ NULL },
},
+ { NULL },
#endif
}
};
@@ -323,6 +331,7 @@ static struct dvb_usb_properties dibusb2_0b_properties = {
{ &dibusb_dib3000mb_table[27], NULL },
{ NULL }
},
+ { NULL },
}
};
@@ -369,6 +378,7 @@ static struct dvb_usb_properties artec_t1_usb2_properties = {
{ &dibusb_dib3000mb_table[28], NULL },
{ &dibusb_dib3000mb_table[29], NULL },
},
+ { NULL },
}
};
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index 450417a9e64b..e6c55c9c9417 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -32,7 +32,7 @@ static int digitv_ctrl_msg(struct dvb_usb_device *d,
sndbuf[1] = vv;
sndbuf[2] = wo ? wlen : rlen;
- if (!wo) {
+ if (wo) {
memcpy(&sndbuf[3],wbuf,wlen);
dvb_usb_generic_write(d,sndbuf,7);
} else {
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
index 6e2bac873445..130ea7f21f5e 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -151,7 +151,7 @@ static struct dvb_usb_properties dtt200u_properties = {
.cold_ids = { &dtt200u_usb_table[0], NULL },
.warm_ids = { &dtt200u_usb_table[1], NULL },
},
- { NULL },
+ { 0 },
}
};
@@ -160,7 +160,7 @@ static struct dvb_usb_properties wt220u_properties = {
.pid_filter_count = 15,
.usb_ctrl = CYPRESS_FX2,
- .firmware = "dvb-usb-wt220u-01.fw",
+ .firmware = "dvb-usb-wt220u-02.fw",
.power_ctrl = dtt200u_power_ctrl,
.streaming_ctrl = dtt200u_streaming_ctrl,
@@ -192,7 +192,7 @@ static struct dvb_usb_properties wt220u_properties = {
.cold_ids = { &dtt200u_usb_table[2], NULL },
.warm_ids = { &dtt200u_usb_table[3], NULL },
},
- { NULL },
+ { 0 },
}
};
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.h b/drivers/media/dvb/dvb-usb/dtt200u.h
index 6f1f3042e21a..005b0a7df358 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.h
+++ b/drivers/media/dvb/dvb-usb/dtt200u.h
@@ -13,6 +13,7 @@
#define _DVB_USB_DTT200U_H_
#define DVB_USB_LOG_PREFIX "dtt200u"
+
#include "dvb-usb.h"
extern int dvb_usb_dtt200u_debug;
@@ -25,15 +26,15 @@ extern int dvb_usb_dtt200u_debug;
* 88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
*/
-#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
+#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 - init
@@ -44,12 +45,12 @@ extern int dvb_usb_dtt200u_debug;
* 08 - transfer switch
*/
-#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_STREAMING 0x08
+#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_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 7300489d3e24..a3460bf2d9fa 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-common.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-common.h
@@ -24,7 +24,7 @@ extern int dvb_usb_disable_rc_polling;
#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);
+extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_properties *);
extern int dvb_usb_urb_submit(struct dvb_usb_device *);
extern int dvb_usb_urb_kill(struct dvb_usb_device *);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
index 5244e39770a0..8535895819fb 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
@@ -9,7 +9,6 @@
*/
#include "dvb-usb-common.h"
-#include <linux/firmware.h>
#include <linux/usb.h>
struct usb_cypress_controller {
@@ -19,9 +18,10 @@ struct usb_cypress_controller {
};
static struct usb_cypress_controller cypress[] = {
- { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 },
- { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 },
- { .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 },
+ { .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 },
+ { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 },
+ { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 },
+ { .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 },
};
/*
@@ -30,71 +30,117 @@ static struct usb_cypress_controller cypress[] = {
static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
{
return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
- 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5*HZ);
+ 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
}
-int usb_cypress_load_firmware(struct usb_device *udev, const char *filename, int type)
+int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
{
- const struct firmware *fw = NULL;
- u16 addr;
- u8 *b,*p;
- int ret = 0,i;
+ struct hexline hx;
+ u8 reset;
+ int ret,pos=0;
- if ((ret = request_firmware(&fw, filename, &udev->dev)) != 0) {
- err("did not find the firmware file. (%s) "
- "Please see linux/Documentation/dvb/ for more details on firmware-problems.",
- filename);
+ /* stop the CPU */
+ reset = 1;
+ if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
+ err("could not stop the USB controller CPU.");
+
+ while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) {
+ deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk);
+ ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len);
+
+ if (ret != hx.len) {
+ err("error while transferring firmware "
+ "(transferred size: %d, block size: %d)",
+ ret,hx.len);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ if (ret < 0) {
+ err("firmware download failed at %d with %d",pos,ret);
return ret;
}
- info("downloading firmware from file '%s' to the '%s'",filename,cypress[type].name);
-
- p = kmalloc(fw->size,GFP_KERNEL);
- if (p != NULL) {
- u8 reset;
- /*
- * you cannot use the fw->data as buffer for
- * usb_control_msg, a new buffer has to be
- * created
- */
- memcpy(p,fw->data,fw->size);
-
- /* stop the CPU */
- reset = 1;
- if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
- err("could not stop the USB controller CPU.");
- for(i = 0; p[i+3] == 0 && i < fw->size; ) {
- b = (u8 *) &p[i];
- addr = cpu_to_le16( *((u16 *) &b[1]) );
-
- deb_fw("writing to address 0x%04x (buffer: 0x%02x%02x)\n",addr,b[1],b[2]);
-
- ret = usb_cypress_writemem(udev,addr,&b[4],b[0]);
-
- if (ret != b[0]) {
- err("error while transferring firmware "
- "(transferred size: %d, block size: %d)",
- ret,b[0]);
- ret = -EINVAL;
- break;
- }
- i += 5 + b[0];
- }
- /* length in ret */
- if (ret > 0)
- ret = 0;
+ if (ret == 0) {
/* restart the CPU */
reset = 0;
if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
err("could not restart the USB controller CPU.");
ret = -EINVAL;
}
+ } else
+ ret = -EIO;
- kfree(p);
- } else {
- ret = -ENOMEM;
+ return ret;
+}
+EXPORT_SYMBOL(usb_cypress_load_firmware);
+
+int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_properties *props)
+{
+ int ret;
+ const struct firmware *fw = NULL;
+
+ if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) {
+ err("did not find the firmware file. (%s) "
+ "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
+ props->firmware,ret);
+ return ret;
}
- release_firmware(fw);
+ info("downloading firmware from file '%s'",props->firmware);
+
+ switch (props->usb_ctrl) {
+ case CYPRESS_AN2135:
+ case CYPRESS_AN2235:
+ case CYPRESS_FX2:
+ ret = usb_cypress_load_firmware(udev, fw, props->usb_ctrl);
+ break;
+ case DEVICE_SPECIFIC:
+ if (props->download_firmware)
+ ret = props->download_firmware(udev,fw);
+ else {
+ err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one.");
+ ret = -EINVAL;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ release_firmware(fw);
return ret;
}
+
+int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos)
+{
+ u8 *b = (u8 *) &fw->data[*pos];
+ int data_offs = 4;
+ if (*pos >= fw->size)
+ return 0;
+
+ memset(hx,0,sizeof(struct hexline));
+
+ hx->len = b[0];
+
+ if ((*pos + hx->len + 4) >= fw->size)
+ return -EINVAL;
+
+ hx->addr = le16_to_cpu( *((u16 *) &b[1]) );
+ hx->type = b[3];
+
+ if (hx->type == 0x04) {
+ /* b[4] and b[5] are the Extended linear address record data field */
+ hx->addr |= (b[4] << 24) | (b[5] << 16);
+/* hx->len -= 2;
+ data_offs += 2; */
+ }
+ memcpy(hx->data,&b[data_offs],hx->len);
+ hx->chk = b[hx->len + data_offs];
+
+ *pos += hx->len + 5;
+
+ return *pos;
+}
+EXPORT_SYMBOL(dvb_usb_get_hexline);
+
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index da970947dfc7..9b254532af4d 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -52,9 +52,8 @@ int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 };
int ret = 0;
- /* if there is nothing to initialize */
- if (d->pll_init[0] == 0x00 && d->pll_init[1] == 0x00 &&
- d->pll_init[2] == 0x00 && d->pll_init[3] == 0x00)
+ /* if pll_desc is not used */
+ if (d->pll_desc == NULL)
return 0;
if (d->tuner_pass_ctrl)
@@ -80,6 +79,9 @@ int dvb_usb_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep
{
struct dvb_usb_device *d = fe->dvb->priv;
+ if (d->pll_desc == NULL)
+ return 0;
+
deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc);
b[0] = d->pll_addr << 1;
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 6be99e537e12..d22934383226 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -86,11 +86,15 @@
#define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300
#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301
#define USB_PID_NEBULA_DIGITV 0x0201
-#define USB_PID_DVICO_BLUEBIRD_LGZ201 0xdb00
-#define USB_PID_DVICO_BLUEBIRD_TH7579 0xdb10
#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_DVICO_BLUEBIRD_LG064F_COLD 0xd500
+#define USB_PID_DVICO_BLUEBIRD_LG064F_WARM 0xd501
+#define USB_PID_DVICO_BLUEBIRD_LGZ201_COLD 0xdb00
+#define USB_PID_DVICO_BLUEBIRD_LGZ201_WARM 0xdb01
+#define USB_PID_DVICO_BLUEBIRD_TH7579_COLD 0xdb10
+#define USB_PID_DVICO_BLUEBIRD_TH7579_WARM 0xdb11
+#define USB_PID_DVICO_BLUEBIRD_DEE1601_COLD 0xdb50
+#define USB_PID_DVICO_BLUEBIRD_DEE1601_WARM 0xdb51
#define USB_PID_MEDION_MD95700 0x0932
#define USB_PID_KYE_DVB_T_COLD 0x701e
#define USB_PID_KYE_DVB_T_WARM 0x701f
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
index dd8e0b94edba..2e23060cbbca 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
@@ -138,6 +138,9 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
int ret = -ENOMEM,cold=0;
+ if (du != NULL)
+ *du = NULL;
+
if ((desc = dvb_usb_find_device(udev,props,&cold)) == NULL) {
deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
return -ENODEV;
@@ -145,38 +148,40 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
if (cold) {
info("found a '%s' in cold state, will try to load a firmware",desc->name);
- ret = usb_cypress_load_firmware(udev,props->firmware,props->usb_ctrl);
- } else {
- info("found a '%s' in warm state.",desc->name);
- d = kmalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
- if (d == NULL) {
- err("no memory for 'struct dvb_usb_device'");
+ ret = dvb_usb_download_firmware(udev,props);
+ if (!props->no_reconnect)
return ret;
+ }
+
+ info("found a '%s' in warm state.",desc->name);
+ d = kmalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
+ if (d == NULL) {
+ err("no memory for 'struct dvb_usb_device'");
+ return ret;
+ }
+ memset(d,0,sizeof(struct dvb_usb_device));
+
+ d->udev = udev;
+ memcpy(&d->props,props,sizeof(struct dvb_usb_properties));
+ d->desc = desc;
+ d->owner = owner;
+
+ if (d->props.size_of_priv > 0) {
+ d->priv = kmalloc(d->props.size_of_priv,GFP_KERNEL);
+ if (d->priv == NULL) {
+ err("no memory for priv in 'struct dvb_usb_device'");
+ kfree(d);
+ return -ENOMEM;
}
- memset(d,0,sizeof(struct dvb_usb_device));
-
- d->udev = udev;
- memcpy(&d->props,props,sizeof(struct dvb_usb_properties));
- d->desc = desc;
- d->owner = owner;
-
- if (d->props.size_of_priv > 0) {
- d->priv = kmalloc(d->props.size_of_priv,GFP_KERNEL);
- if (d->priv == NULL) {
- err("no memory for priv in 'struct dvb_usb_device'");
- kfree(d);
- return -ENOMEM;
- }
- memset(d->priv,0,d->props.size_of_priv);
- }
+ memset(d->priv,0,d->props.size_of_priv);
+ }
- usb_set_intfdata(intf, d);
+ usb_set_intfdata(intf, d);
- if (du != NULL)
- *du = d;
+ if (du != NULL)
+ *du = d;
- ret = dvb_usb_init(d);
- }
+ ret = dvb_usb_init(d);
if (ret == 0)
info("%s successfully initialized and connected.",desc->name);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index b4a1a98006c7..dd568396e594 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -10,8 +10,8 @@
#include <linux/config.h>
#include <linux/input.h>
-#include <linux/module.h>
#include <linux/usb.h>
+#include <linux/firmware.h>
#include "dvb_frontend.h"
#include "dvb_demux.h"
@@ -94,7 +94,11 @@ struct dvb_usb_device;
* @usb_ctrl: which USB device-side controller is in use. Needed for firmware
* download.
* @firmware: name of the firmware file.
- *
+ * @download_firmware: called to download the firmware when the usb_ctrl is
+ * DEVICE_SPECIFIC.
+ * @no_reconnect: device doesn't do a reconnect after downloading the firmware,
+ so do the warm initialization right after it
+
* @size_of_priv: how many bytes shall be allocated for the private field
* of struct dvb_usb_device.
*
@@ -142,11 +146,14 @@ struct dvb_usb_properties {
int caps;
int pid_filter_count;
-#define CYPRESS_AN2135 0
-#define CYPRESS_AN2235 1
-#define CYPRESS_FX2 2
+#define DEVICE_SPECIFIC 0
+#define CYPRESS_AN2135 1
+#define CYPRESS_AN2235 2
+#define CYPRESS_FX2 3
int usb_ctrl;
- const char *firmware;
+ const char firmware[FIRMWARE_NAME_MAX];
+ int (*download_firmware) (struct usb_device *, const struct firmware *);
+ int no_reconnect;
int size_of_priv;
@@ -326,5 +333,15 @@ extern int dvb_usb_pll_init_i2c(struct dvb_frontend *);
extern int dvb_usb_pll_set(struct dvb_frontend *, struct dvb_frontend_parameters *, u8[]);
extern int dvb_usb_pll_set_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
+/* commonly used firmware download types and function */
+struct hexline {
+ u8 len;
+ u32 addr;
+ u8 type;
+ u8 data[255];
+ u8 chk;
+};
+extern int dvb_usb_get_hexline(const struct firmware *, struct hexline *, int *);
+extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type);
#endif
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
index fac48fc7a4ac..412039d8dbae 100644
--- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
@@ -129,10 +129,6 @@ static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6])
dibusb_read_eeprom_byte(d,i, &b);
mac[5 - (i - 136)] = b;
-
-/* deb_ee("%02x ",b);
- if ((i+1) % 16 == 0)
- deb_ee("\n");*/
}
return 0;
@@ -153,7 +149,7 @@ static struct usb_device_id nova_t_table [] = {
/* 01 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_WARM) },
{ } /* Terminating entry */
};
-MODULE_DEVICE_TABLE (usb, nova_t_table);
+MODULE_DEVICE_TABLE(usb, nova_t_table);
static struct dvb_usb_properties nova_t_properties = {
.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
@@ -198,6 +194,7 @@ static struct dvb_usb_properties nova_t_properties = {
{ &nova_t_table[0], NULL },
{ &nova_t_table[1], NULL },
},
+ { NULL },
}
};
diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c
index 104b5d016c7b..0885d9fb2bf2 100644
--- a/drivers/media/dvb/dvb-usb/vp702x-fe.c
+++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c
@@ -190,7 +190,7 @@ static int vp702x_fe_get_frontend(struct dvb_frontend* fe,
}
static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
- struct dvb_diseqc_master_cmd *m)
+ struct dvb_diseqc_master_cmd *m)
{
struct vp702x_fe_state *st = fe->demodulator_priv;
u8 cmd[8],ibuf[10];
diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/dvb/dvb-usb/vp702x.h
index 4a3e8c7eca2b..a808d48e7bf2 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.h
+++ b/drivers/media/dvb/dvb-usb/vp702x.h
@@ -13,47 +13,47 @@ extern int dvb_usb_vp702x_debug;
/* commands are read and written with USB control messages */
/* consecutive read/write operation */
-#define REQUEST_OUT 0xB2
-#define REQUEST_IN 0xB3
+#define REQUEST_OUT 0xB2
+#define REQUEST_IN 0xB3
/* the out-buffer of these consecutive operations contain sub-commands when b[0] = 0
* request: 0xB2; i: 0; v: 0; b[0] = 0, b[1] = subcmd, additional buffer
* the returning buffer looks as follows
* request: 0xB3; i: 0; v: 0; b[0] = 0xB3, additional buffer */
-#define GET_TUNER_STATUS 0x05
+#define GET_TUNER_STATUS 0x05
/* additional in buffer:
* 0 1 2 3 4 5 6 7 8
* N/A N/A 0x05 signal-quality N/A N/A signal-strength lock==0 N/A */
-#define GET_SYSTEM_STRING 0x06
+#define GET_SYSTEM_STRING 0x06
/* additional in buffer:
* 0 1 2 3 4 5 6 7 8
* N/A 'U' 'S' 'B' '7' '0' '2' 'X' N/A */
-#define SET_DISEQC_CMD 0x08
+#define SET_DISEQC_CMD 0x08
/* additional out buffer:
* 0 1 2 3 4
* len X1 X2 X3 X4
* additional in buffer:
* 0 1 2
- * N/A 0 0 b[1] == b[2] == 0 -> success otherwise not */
+ * N/A 0 0 b[1] == b[2] == 0 -> success, failure otherwise */
-#define SET_LNB_POWER 0x09
+#define SET_LNB_POWER 0x09
/* additional out buffer:
* 0 1 2
* 0x00 0xff 1 = on, 0 = off
* additional in buffer:
* 0 1 2
- * N/A 0 0 b[1] == b[2] == 0 -> success otherwise not */
+ * N/A 0 0 b[1] == b[2] == 0 -> success failure otherwise */
-#define GET_MAC_ADDRESS 0x0A
+#define GET_MAC_ADDRESS 0x0A
/* #define GET_MAC_ADDRESS 0x0B */
/* additional in buffer:
* 0 1 2 3 4 5 6 7 8
* N/A N/A 0x0A or 0x0B MAC0 MAC1 MAC2 MAC3 MAC4 MAC5 */
-#define SET_PID_FILTER 0x11
+#define SET_PID_FILTER 0x11
/* additional in buffer:
* 0 1 ... 14 15 16
* PID0_MSB PID0_LSB ... PID7_MSB PID7_LSB PID_active (bits) */
@@ -64,39 +64,38 @@ extern int dvb_usb_vp702x_debug;
* freq0 freq1 divstep srate0 srate1 srate2 flag chksum
*/
-
/* one direction requests */
-#define READ_REMOTE_REQ 0xB4
+#define READ_REMOTE_REQ 0xB4
/* IN i: 0; v: 0; b[0] == request, b[1] == key */
-#define READ_PID_NUMBER_REQ 0xB5
+#define READ_PID_NUMBER_REQ 0xB5
/* IN i: 0; v: 0; b[0] == request, b[1] == 0, b[2] = pid number */
-#define WRITE_EEPROM_REQ 0xB6
+#define WRITE_EEPROM_REQ 0xB6
/* OUT i: offset; v: value to write; no extra buffer */
-#define READ_EEPROM_REQ 0xB7
+#define READ_EEPROM_REQ 0xB7
/* IN i: bufferlen; v: offset; buffer with bufferlen bytes */
-#define READ_STATUS 0xB8
+#define READ_STATUS 0xB8
/* IN i: 0; v: 0; bufferlen 10 */
-#define READ_TUNER_REG_REQ 0xB9
+#define READ_TUNER_REG_REQ 0xB9
/* IN i: 0; v: register; b[0] = value */
-#define READ_FX2_REG_REQ 0xBA
+#define READ_FX2_REG_REQ 0xBA
/* IN i: offset; v: 0; b[0] = value */
-#define WRITE_FX2_REG_REQ 0xBB
+#define WRITE_FX2_REG_REQ 0xBB
/* OUT i: offset; v: value to write; 1 byte extra buffer */
-#define SET_TUNER_POWER_REQ 0xBC
+#define SET_TUNER_POWER_REQ 0xBC
/* IN i: 0 = power off, 1 = power on */
-#define WRITE_TUNER_REG_REQ 0xBD
+#define WRITE_TUNER_REG_REQ 0xBD
/* IN i: register, v: value to write, no extra buffer */
-#define RESET_TUNER 0xBE
+#define RESET_TUNER 0xBE
/* IN i: 0, v: 0, no extra buffer */
extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d);
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index 3835235b68df..028204956bb0 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -247,7 +247,7 @@ static struct dvb_usb_properties vp7045_properties = {
.cold_ids = { &vp7045_usb_table[2], NULL },
.warm_ids = { &vp7045_usb_table[3], NULL },
},
- { NULL },
+ { 0 },
}
};
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 8e269e1c1f9d..db3a8b40031e 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -16,6 +16,12 @@ config DVB_CX24110
help
A DVB-S tuner module. Say Y when you want to support this frontend.
+config DVB_CX24123
+ tristate "Conexant CX24123 based"
+ depends on DVB_CORE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
config DVB_TDA8083
tristate "Philips TDA8083 based"
depends on DVB_CORE
@@ -50,18 +56,19 @@ comment "DVB-T (terrestrial) frontends"
depends on DVB_CORE
config DVB_SP8870
- tristate "Spase sp8870 based"
+ tristate "Spase sp8870 based"
depends on DVB_CORE
select FW_LOADER
help
- A DVB-T tuner module. Say Y when you want to support this frontend.
+ A DVB-T tuner module. Say Y when you want to support this frontend.
This driver needs external firmware. Please use the command
"<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to
- download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ or /lib/firmware (depending on configuration of firmware hotplug).
config DVB_SP887X
- tristate "Spase sp887x based"
+ tristate "Spase sp887x based"
depends on DVB_CORE
select FW_LOADER
help
@@ -69,7 +76,8 @@ config DVB_SP887X
This driver needs external firmware. Please use the command
"<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
- download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ or /lib/firmware (depending on configuration of firmware hotplug).
config DVB_CX22700
tristate "Conexant CX22700 based"
@@ -78,10 +86,10 @@ config DVB_CX22700
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_CX22702
- tristate "Conexant cx22702 demodulator (OFDM)"
- depends on DVB_CORE
- help
- A DVB-T tuner module. Say Y when you want to support this frontend.
+ tristate "Conexant cx22702 demodulator (OFDM)"
+ depends on DVB_CORE
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_L64781
tristate "LSI L64781"
@@ -98,8 +106,9 @@ config DVB_TDA1004X
This driver needs external firmware. Please use the commands
"<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
- "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
- download/extract them, and then copy them to /usr/lib/hotplug/firmware.
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
+ download/extract them, and then copy them to /usr/lib/hotplug/firmware
+ or /lib/firmware (depending on configuration of firmware hotplug).
config DVB_NXT6000
tristate "NxtWave Communications NXT6000 based"
@@ -140,13 +149,13 @@ config DVB_VES1820
tristate "VLSI VES1820 based"
depends on DVB_CORE
help
- A DVB-C tuner module. Say Y when you want to support this frontend.
+ A DVB-C tuner module. Say Y when you want to support this frontend.
config DVB_TDA10021
tristate "Philips TDA10021 based"
depends on DVB_CORE
help
- A DVB-C tuner module. Say Y when you want to support this frontend.
+ A DVB-C tuner module. Say Y when you want to support this frontend.
config DVB_STV0297
tristate "ST STV0297 based"
@@ -164,6 +173,11 @@ config DVB_NXT2002
help
An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
+ This driver needs external firmware. Please use the command
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" to
+ download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ or /lib/firmware (depending on configuration of firmware hotplug).
+
config DVB_NXT200X
tristate "Nextwave NXT2002/NXT2004 based"
depends on DVB_CORE
@@ -172,6 +186,12 @@ config DVB_NXT200X
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
+ This driver needs external firmware. Please use the commands
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" and
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
+ download/extract them, and then copy them to /usr/lib/hotplug/firmware
+ or /lib/firmware (depending on configuration of firmware hotplug).
+
config DVB_OR51211
tristate "or51211 based (pcHDTV HD2000 card)"
depends on DVB_CORE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index a98760fe08a1..615ec830e1c9 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -32,3 +32,4 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o
obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
+obj-$(CONFIG_DVB_CX24123) += cx24123.o
diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c
index 8ceb9a33c7af..3b132bafd4de 100644
--- a/drivers/media/dvb/frontends/bcm3510.c
+++ b/drivers/media/dvb/frontends/bcm3510.c
@@ -255,7 +255,7 @@ static int bcm3510_bert_reset(struct bcm3510_state *st)
bcm3510_register_value b;
int ret;
- if ((ret < bcm3510_readB(st,0xfa,&b)) < 0)
+ if ((ret = bcm3510_readB(st,0xfa,&b)) < 0)
return ret;
b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b);
@@ -623,13 +623,13 @@ static int bcm3510_download_firmware(struct dvb_frontend* fe)
err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret);
return ret;
}
- deb_info("got firmware: %d\n",fw->size);
+ deb_info("got firmware: %zd\n",fw->size);
b = fw->data;
for (i = 0; i < fw->size;) {
addr = le16_to_cpu( *( (u16 *)&b[i] ) );
len = le16_to_cpu( *( (u16 *)&b[i+2] ) );
- deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04x\n",addr,len,fw->size);
+ deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size);
if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) {
err("firmware download failed: %d\n",ret);
return ret;
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 5de0e6d350b1..0fc899f81c5e 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -195,6 +195,16 @@ static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_paramet
return 0;
}
+static int cx22702_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct cx22702_state* state = fe->demodulator_priv;
+ dprintk ("%s(%d)\n", __FUNCTION__, enable);
+ if (enable)
+ return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) & 0xfe);
+ else
+ return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) | 1);
+}
+
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
@@ -202,7 +212,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_i2c_gate_ctrl(fe, 1);
if (state->config->pll_set) {
state->config->pll_set(fe, p);
} else if (state->config->pll_desc) {
@@ -216,7 +226,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_i2c_gate_ctrl(fe, 0);
/* set inversion */
cx22702_set_inversion (state, p->inversion);
@@ -349,11 +359,10 @@ static int cx22702_init (struct dvb_frontend* fe)
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);
+ if (state->config->pll_init)
state->config->pll_init(fe);
- cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
- }
+
+ cx22702_i2c_gate_ctrl(fe, 0);
return 0;
}
@@ -531,6 +540,7 @@ static struct dvb_frontend_ops cx22702_ops = {
.read_signal_strength = cx22702_read_signal_strength,
.read_snr = cx22702_read_snr,
.read_ucblocks = cx22702_read_ucblocks,
+ .i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
};
module_param(debug, int, 0644);
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index 0c4db80ec332..d15d32c51dc5 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -27,7 +27,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
-#include <linux/jiffies.h>
#include "dvb_frontend.h"
#include "cx24110.h"
@@ -56,7 +55,7 @@ static int debug;
static struct {u8 reg; u8 data;} cx24110_regdata[]=
/* Comments beginning with @ denote this value should
- be the default */
+ be the default */
{{0x09,0x01}, /* SoftResetAll */
{0x09,0x00}, /* release reset */
{0x01,0xe8}, /* MSB of code rate 27.5MS/s */
@@ -67,26 +66,26 @@ static struct {u8 reg; u8 data;} cx24110_regdata[]=
{0x07,0x01}, /* @ Fclk, i.e. sampling clock, 60MHz */
{0x0a,0x00}, /* @ partial chip disables, do not set */
{0x0b,0x01}, /* set output clock in gapped mode, start signal low
- active for first byte */
+ active for first byte */
{0x0c,0x11}, /* no parity bytes, large hold time, serial data out */
{0x0d,0x6f}, /* @ RS Sync/Unsync thresholds */
{0x10,0x40}, /* chip doc is misleading here: write bit 6 as 1
- to avoid starting the BER counter. Reset the
- CRC test bit. Finite counting selected */
+ to avoid starting the BER counter. Reset the
+ CRC test bit. Finite counting selected */
{0x15,0xff}, /* @ size of the limited time window for RS BER
- estimation. It is <value>*256 RS blocks, this
- gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */
+ estimation. It is <value>*256 RS blocks, this
+ gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */
{0x16,0x00}, /* @ enable all RS output ports */
{0x17,0x04}, /* @ time window allowed for the RS to sync */
{0x18,0xae}, /* @ allow all standard DVB code rates to be scanned
- for automatically */
+ for automatically */
/* leave the current code rate and normalization
- registers as they are after reset... */
+ registers as they are after reset... */
{0x21,0x10}, /* @ during AutoAcq, search each viterbi setting
- only once */
+ only once */
{0x23,0x18}, /* @ size of the limited time window for Viterbi BER
- estimation. It is <value>*65536 channel bits, i.e.
- approx. 38ms at 27.5MS/s, rate 3/4 */
+ estimation. It is <value>*65536 channel bits, i.e.
+ approx. 38ms at 27.5MS/s, rate 3/4 */
{0x24,0x24}, /* do not trigger Viterbi CRC test. Finite count window */
/* leave front-end AGC parameters at default values */
/* leave decimation AGC parameters at default values */
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
new file mode 100644
index 000000000000..d661c6f9cbe5
--- /dev/null
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -0,0 +1,889 @@
+/*
+ Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
+
+ Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+
+ Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc>
+
+ 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/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+
+#include "dvb_frontend.h"
+#include "cx24123.h"
+
+static int debug;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk (KERN_DEBUG "cx24123: " args); \
+ } while (0)
+
+struct cx24123_state
+{
+ struct i2c_adapter* i2c;
+ struct dvb_frontend_ops ops;
+ const struct cx24123_config* config;
+
+ struct dvb_frontend frontend;
+
+ u32 lastber;
+ u16 snr;
+ u8 lnbreg;
+
+ /* Some PLL specifics for tuning */
+ u32 VCAarg;
+ u32 VGAarg;
+ u32 bandselectarg;
+ u32 pllarg;
+
+ /* The Demod/Tuner can't easily provide these, we cache them */
+ u32 currentfreq;
+ u32 currentsymbolrate;
+};
+
+/* Various tuner defaults need to be established for a given symbol rate Sps */
+static struct
+{
+ u32 symbolrate_low;
+ u32 symbolrate_high;
+ u32 VCAslope;
+ u32 VCAoffset;
+ u32 VGA1offset;
+ u32 VGA2offset;
+ u32 VCAprogdata;
+ u32 VGAprogdata;
+} cx24123_AGC_vals[] =
+{
+ {
+ .symbolrate_low = 1000000,
+ .symbolrate_high = 4999999,
+ .VCAslope = 0x07,
+ .VCAoffset = 0x0f,
+ .VGA1offset = 0x1f8,
+ .VGA2offset = 0x1f8,
+ .VGAprogdata = (2 << 18) | (0x1f8 << 9) | 0x1f8,
+ .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x07,
+ },
+ {
+ .symbolrate_low = 5000000,
+ .symbolrate_high = 14999999,
+ .VCAslope = 0x1f,
+ .VCAoffset = 0x1f,
+ .VGA1offset = 0x1e0,
+ .VGA2offset = 0x180,
+ .VGAprogdata = (2 << 18) | (0x180 << 9) | 0x1e0,
+ .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x1f,
+ },
+ {
+ .symbolrate_low = 15000000,
+ .symbolrate_high = 45000000,
+ .VCAslope = 0x3f,
+ .VCAoffset = 0x3f,
+ .VGA1offset = 0x180,
+ .VGA2offset = 0x100,
+ .VGAprogdata = (2 << 18) | (0x100 << 9) | 0x180,
+ .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x3f,
+ },
+};
+
+/*
+ * Various tuner defaults need to be established for a given frequency kHz.
+ * fixme: The bounds on the bands do not match the doc in real life.
+ * fixme: Some of them have been moved, other might need adjustment.
+ */
+static struct
+{
+ u32 freq_low;
+ u32 freq_high;
+ u32 bandselect;
+ u32 VCOdivider;
+ u32 VCOnumber;
+ u32 progdata;
+} cx24123_bandselect_vals[] =
+{
+ {
+ .freq_low = 950000,
+ .freq_high = 1018999,
+ .bandselect = 0x40,
+ .VCOdivider = 4,
+ .VCOnumber = 7,
+ .progdata = (0 << 18) | (0 << 9) | 0x40,
+ },
+ {
+ .freq_low = 1019000,
+ .freq_high = 1074999,
+ .bandselect = 0x80,
+ .VCOdivider = 4,
+ .VCOnumber = 8,
+ .progdata = (0 << 18) | (0 << 9) | 0x80,
+ },
+ {
+ .freq_low = 1075000,
+ .freq_high = 1227999,
+ .bandselect = 0x01,
+ .VCOdivider = 2,
+ .VCOnumber = 1,
+ .progdata = (0 << 18) | (1 << 9) | 0x01,
+ },
+ {
+ .freq_low = 1228000,
+ .freq_high = 1349999,
+ .bandselect = 0x02,
+ .VCOdivider = 2,
+ .VCOnumber = 2,
+ .progdata = (0 << 18) | (1 << 9) | 0x02,
+ },
+ {
+ .freq_low = 1350000,
+ .freq_high = 1481999,
+ .bandselect = 0x04,
+ .VCOdivider = 2,
+ .VCOnumber = 3,
+ .progdata = (0 << 18) | (1 << 9) | 0x04,
+ },
+ {
+ .freq_low = 1482000,
+ .freq_high = 1595999,
+ .bandselect = 0x08,
+ .VCOdivider = 2,
+ .VCOnumber = 4,
+ .progdata = (0 << 18) | (1 << 9) | 0x08,
+ },
+ {
+ .freq_low = 1596000,
+ .freq_high = 1717999,
+ .bandselect = 0x10,
+ .VCOdivider = 2,
+ .VCOnumber = 5,
+ .progdata = (0 << 18) | (1 << 9) | 0x10,
+ },
+ {
+ .freq_low = 1718000,
+ .freq_high = 1855999,
+ .bandselect = 0x20,
+ .VCOdivider = 2,
+ .VCOnumber = 6,
+ .progdata = (0 << 18) | (1 << 9) | 0x20,
+ },
+ {
+ .freq_low = 1856000,
+ .freq_high = 2035999,
+ .bandselect = 0x40,
+ .VCOdivider = 2,
+ .VCOnumber = 7,
+ .progdata = (0 << 18) | (1 << 9) | 0x40,
+ },
+ {
+ .freq_low = 2036000,
+ .freq_high = 2149999,
+ .bandselect = 0x80,
+ .VCOdivider = 2,
+ .VCOnumber = 8,
+ .progdata = (0 << 18) | (1 << 9) | 0x80,
+ },
+};
+
+static struct {
+ u8 reg;
+ u8 data;
+} cx24123_regdata[] =
+{
+ {0x00, 0x03}, /* Reset system */
+ {0x00, 0x00}, /* Clear reset */
+ {0x01, 0x3b}, /* Apply sensible defaults, from an i2c sniffer */
+ {0x03, 0x07},
+ {0x04, 0x10},
+ {0x05, 0x04},
+ {0x06, 0x31},
+ {0x0d, 0x02},
+ {0x0e, 0x03},
+ {0x0f, 0xfe},
+ {0x10, 0x01},
+ {0x14, 0x01},
+ {0x15, 0x98},
+ {0x16, 0x00},
+ {0x17, 0x01},
+ {0x1b, 0x05},
+ {0x1c, 0x80},
+ {0x1d, 0x00},
+ {0x1e, 0x00},
+ {0x20, 0x41},
+ {0x21, 0x15},
+ {0x27, 0x14},
+ {0x28, 0x46},
+ {0x29, 0x00},
+ {0x2a, 0xb0},
+ {0x2b, 0x73},
+ {0x2c, 0x00},
+ {0x2d, 0x00},
+ {0x2e, 0x00},
+ {0x2f, 0x00},
+ {0x30, 0x00},
+ {0x31, 0x00},
+ {0x32, 0x8c},
+ {0x33, 0x00},
+ {0x34, 0x00},
+ {0x35, 0x03},
+ {0x36, 0x02},
+ {0x37, 0x3a},
+ {0x3a, 0x00}, /* Enable AGC accumulator */
+ {0x44, 0x00},
+ {0x45, 0x00},
+ {0x46, 0x05},
+ {0x56, 0x41},
+ {0x57, 0xff},
+ {0x67, 0x83},
+};
+
+static int cx24123_writereg(struct cx24123_state* state, int reg, int 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) {
+ printk("%s: writereg error(err == %i, reg == 0x%02x,"
+ " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int cx24123_writelnbreg(struct cx24123_state* state, int reg, int data)
+{
+ u8 buf[] = { reg, data };
+ /* fixme: put the intersil addr int the config */
+ struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 2 };
+ int err;
+
+ if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+ printk("%s: writelnbreg error (err == %i, reg == 0x%02x,"
+ " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+ return -EREMOTEIO;
+ }
+
+ /* cache the write, no way to read back */
+ state->lnbreg = data;
+
+ return 0;
+}
+
+static int cx24123_readreg(struct cx24123_state* state, u8 reg)
+{
+ int ret;
+ u8 b0[] = { reg };
+ u8 b1[] = { 0 };
+ struct i2c_msg msg[] = {
+ { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+ };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2) {
+ printk("%s: reg=0x%x (error=%d)\n", __FUNCTION__, reg, ret);
+ return ret;
+ }
+
+ return b1[0];
+}
+
+static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg)
+{
+ return state->lnbreg;
+}
+
+static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
+{
+ switch (inversion) {
+ case INVERSION_OFF:
+ cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) & 0x7f);
+ cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80);
+ break;
+ case INVERSION_ON:
+ cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) | 0x80);
+ cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80);
+ break;
+ case INVERSION_AUTO:
+ cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) & 0x7f);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_inversion_t *inversion)
+{
+ u8 val;
+
+ val = cx24123_readreg(state, 0x1b) >> 7;
+
+ if (val == 0)
+ *inversion = INVERSION_OFF;
+ else
+ *inversion = INVERSION_ON;
+
+ return 0;
+}
+
+static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec)
+{
+ if ( (fec < FEC_NONE) || (fec > FEC_AUTO) )
+ fec = FEC_AUTO;
+
+ /* Hardware has 5/11 and 3/5 but are never unused */
+ switch (fec) {
+ case FEC_NONE:
+ return cx24123_writereg(state, 0x0f, 0x01);
+ case FEC_1_2:
+ return cx24123_writereg(state, 0x0f, 0x02);
+ case FEC_2_3:
+ return cx24123_writereg(state, 0x0f, 0x04);
+ case FEC_3_4:
+ return cx24123_writereg(state, 0x0f, 0x08);
+ case FEC_5_6:
+ return cx24123_writereg(state, 0x0f, 0x20);
+ case FEC_7_8:
+ return cx24123_writereg(state, 0x0f, 0x80);
+ case FEC_AUTO:
+ return cx24123_writereg(state, 0x0f, 0xae);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int cx24123_get_fec(struct cx24123_state* state, fe_code_rate_t *fec)
+{
+ int ret;
+ u8 val;
+
+ ret = cx24123_readreg (state, 0x1b);
+ if (ret < 0)
+ return ret;
+ val = ret & 0x07;
+ switch (val) {
+ case 1:
+ *fec = FEC_1_2;
+ break;
+ case 3:
+ *fec = FEC_2_3;
+ break;
+ case 4:
+ *fec = FEC_3_4;
+ break;
+ case 5:
+ *fec = FEC_4_5;
+ break;
+ case 6:
+ *fec = FEC_5_6;
+ break;
+ case 7:
+ *fec = FEC_7_8;
+ break;
+ case 2: /* *fec = FEC_3_5; break; */
+ case 0: /* *fec = FEC_5_11; break; */
+ *fec = FEC_AUTO;
+ break;
+ default:
+ *fec = FEC_NONE; // can't happen
+ }
+
+ return 0;
+}
+
+/* fixme: Symbol rates < 3MSps may not work because of precision loss */
+static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
+{
+ u32 val;
+
+ val = (srate / 1185) * 100;
+
+ /* Compensate for scaling up, by removing 17 symbols per 1Msps */
+ val = val - (17 * (srate / 1000000));
+
+ cx24123_writereg(state, 0x08, (val >> 16) & 0xff );
+ cx24123_writereg(state, 0x09, (val >> 8) & 0xff );
+ cx24123_writereg(state, 0x0a, (val ) & 0xff );
+
+ return 0;
+}
+
+/*
+ * Based on the required frequency and symbolrate, the tuner AGC has to be configured
+ * and the correct band selected. Calculate those values
+ */
+static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct cx24123_state *state = fe->demodulator_priv;
+ u32 ndiv = 0, adiv = 0, vco_div = 0;
+ int i = 0;
+
+ /* Defaults for low freq, low rate */
+ state->VCAarg = cx24123_AGC_vals[0].VCAprogdata;
+ state->VGAarg = cx24123_AGC_vals[0].VGAprogdata;
+ state->bandselectarg = cx24123_bandselect_vals[0].progdata;
+ vco_div = cx24123_bandselect_vals[0].VCOdivider;
+
+ /* For the given symbolerate, determine the VCA and VGA programming bits */
+ for (i = 0; i < sizeof(cx24123_AGC_vals) / sizeof(cx24123_AGC_vals[0]); i++)
+ {
+ if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) &&
+ (cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) {
+ state->VCAarg = cx24123_AGC_vals[i].VCAprogdata;
+ state->VGAarg = cx24123_AGC_vals[i].VGAprogdata;
+ }
+ }
+
+ /* For the given frequency, determine the bandselect programming bits */
+ for (i = 0; i < sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]); i++)
+ {
+ if ((cx24123_bandselect_vals[i].freq_low <= p->frequency) &&
+ (cx24123_bandselect_vals[i].freq_high >= p->frequency) ) {
+ state->bandselectarg = cx24123_bandselect_vals[i].progdata;
+ vco_div = cx24123_bandselect_vals[i].VCOdivider;
+ }
+ }
+
+ /* Determine the N/A dividers for the requested lband freq (in kHz). */
+ /* Note: 10111 (kHz) is the Crystal Freq and divider of 10. */
+ ndiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) / 32) & 0x1ff;
+ adiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) % 32) & 0x1f;
+
+ if (adiv == 0)
+ adiv++;
+
+ /* determine the correct pll frequency values. */
+ /* Command 11, refdiv 11, cpump polarity 1, cpump current 3mA 10. */
+ state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (2 << 14);
+ state->pllarg |= (ndiv << 5) | adiv;
+
+ return 0;
+}
+
+/*
+ * Tuner data is 21 bits long, must be left-aligned in data.
+ * Tuner cx24109 is written through a dedicated 3wire interface on the demod chip.
+ */
+static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_parameters *p, u32 data)
+{
+ struct cx24123_state *state = fe->demodulator_priv;
+ unsigned long timeout;
+
+ /* align the 21 bytes into to bit23 boundary */
+ data = data << 3;
+
+ /* Reset the demod pll word length to 0x15 bits */
+ cx24123_writereg(state, 0x21, 0x15);
+
+ /* write the msb 8 bits, wait for the send to be completed */
+ timeout = jiffies + msecs_to_jiffies(40);
+ cx24123_writereg(state, 0x22, (data >> 16) & 0xff);
+ while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
+ if (time_after(jiffies, timeout)) {
+ printk("%s: demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+ return -EREMOTEIO;
+ }
+ msleep(10);
+ }
+
+ /* send another 8 bytes, wait for the send to be completed */
+ timeout = jiffies + msecs_to_jiffies(40);
+ cx24123_writereg(state, 0x22, (data>>8) & 0xff );
+ while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
+ if (time_after(jiffies, timeout)) {
+ printk("%s: demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+ return -EREMOTEIO;
+ }
+ msleep(10);
+ }
+
+ /* send the lower 5 bits of this byte, padded with 3 LBB, wait for the send to be completed */
+ timeout = jiffies + msecs_to_jiffies(40);
+ cx24123_writereg(state, 0x22, (data) & 0xff );
+ while ((cx24123_readreg(state, 0x20) & 0x80)) {
+ if (time_after(jiffies, timeout)) {
+ printk("%s: demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+ return -EREMOTEIO;
+ }
+ msleep(10);
+ }
+
+ /* Trigger the demod to configure the tuner */
+ cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) | 2);
+ cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) & 0xfd);
+
+ return 0;
+}
+
+static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct cx24123_state *state = fe->demodulator_priv;
+
+ if (cx24123_pll_calculate(fe, p) != 0) {
+ printk("%s: cx24123_pll_calcutate failed\n",__FUNCTION__);
+ return -EINVAL;
+ }
+
+ /* Write the new VCO/VGA */
+ cx24123_pll_writereg(fe, p, state->VCAarg);
+ cx24123_pll_writereg(fe, p, state->VGAarg);
+
+ /* Write the new bandselect and pll args */
+ cx24123_pll_writereg(fe, p, state->bandselectarg);
+ cx24123_pll_writereg(fe, p, state->pllarg);
+
+ return 0;
+}
+
+static int cx24123_initfe(struct dvb_frontend* fe)
+{
+ struct cx24123_state *state = fe->demodulator_priv;
+ int i;
+
+ /* Configure the demod to a good set of defaults */
+ for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
+ cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
+
+ if (state->config->pll_init)
+ state->config->pll_init(fe);
+
+ /* Configure the LNB for 14V */
+ if (state->config->use_isl6421)
+ cx24123_writelnbreg(state, 0x0, 0x2a);
+
+ return 0;
+}
+
+static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+ struct cx24123_state *state = fe->demodulator_priv;
+ u8 val;
+
+ switch (state->config->use_isl6421) {
+
+ case 1:
+
+ val = cx24123_readlnbreg(state, 0x0);
+
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */
+ case SEC_VOLTAGE_18:
+ return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */
+ case SEC_VOLTAGE_OFF:
+ return cx24123_writelnbreg(state, 0x0, val & 0x30);
+ default:
+ return -EINVAL;
+ };
+
+ case 0:
+
+ val = cx24123_readreg(state, 0x29);
+
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ dprintk("%s: setting voltage 13V\n", __FUNCTION__);
+ if (state->config->enable_lnb_voltage)
+ state->config->enable_lnb_voltage(fe, 1);
+ return cx24123_writereg(state, 0x29, val | 0x80);
+ case SEC_VOLTAGE_18:
+ dprintk("%s: setting voltage 18V\n", __FUNCTION__);
+ if (state->config->enable_lnb_voltage)
+ state->config->enable_lnb_voltage(fe, 1);
+ return cx24123_writereg(state, 0x29, val & 0x7f);
+ case SEC_VOLTAGE_OFF:
+ dprintk("%s: setting voltage off\n", __FUNCTION__);
+ if (state->config->enable_lnb_voltage)
+ state->config->enable_lnb_voltage(fe, 0);
+ return 0;
+ default:
+ return -EINVAL;
+ };
+ }
+
+ return 0;
+}
+
+static int cx24123_send_diseqc_msg(struct dvb_frontend* fe,
+ struct dvb_diseqc_master_cmd *cmd)
+{
+ /* fixme: Implement diseqc */
+ printk("%s: No support yet\n",__FUNCTION__);
+
+ return -ENOTSUPP;
+}
+
+static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct cx24123_state *state = fe->demodulator_priv;
+
+ int sync = cx24123_readreg(state, 0x14);
+ int lock = cx24123_readreg(state, 0x20);
+
+ *status = 0;
+ if (lock & 0x01)
+ *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+ if (sync & 0x04)
+ *status |= FE_HAS_VITERBI;
+ if (sync & 0x08)
+ *status |= FE_HAS_CARRIER;
+ if (sync & 0x80)
+ *status |= FE_HAS_SYNC | FE_HAS_LOCK;
+
+ return 0;
+}
+
+/*
+ * Configured to return the measurement of errors in blocks, because no UCBLOCKS value
+ * is available, so this value doubles up to satisfy both measurements
+ */
+static int cx24123_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ struct cx24123_state *state = fe->demodulator_priv;
+
+ state->lastber =
+ ((cx24123_readreg(state, 0x1c) & 0x3f) << 16) |
+ (cx24123_readreg(state, 0x1d) << 8 |
+ cx24123_readreg(state, 0x1e));
+
+ /* Do the signal quality processing here, it's derived from the BER. */
+ /* Scale the BER from a 24bit to a SNR 16 bit where higher = better */
+ if (state->lastber < 5000)
+ state->snr = 655*100;
+ else if ( (state->lastber >= 5000) && (state->lastber < 55000) )
+ state->snr = 655*90;
+ else if ( (state->lastber >= 55000) && (state->lastber < 150000) )
+ state->snr = 655*80;
+ else if ( (state->lastber >= 150000) && (state->lastber < 250000) )
+ state->snr = 655*70;
+ else if ( (state->lastber >= 250000) && (state->lastber < 450000) )
+ state->snr = 655*65;
+ else
+ state->snr = 0;
+
+ *ber = state->lastber;
+
+ return 0;
+}
+
+static int cx24123_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+{
+ struct cx24123_state *state = fe->demodulator_priv;
+ *signal_strength = cx24123_readreg(state, 0x3b) << 8; /* larger = better */
+
+ return 0;
+}
+
+static int cx24123_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct cx24123_state *state = fe->demodulator_priv;
+ *snr = state->snr;
+
+ return 0;
+}
+
+static int cx24123_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct cx24123_state *state = fe->demodulator_priv;
+ *ucblocks = state->lastber;
+
+ return 0;
+}
+
+static int cx24123_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct cx24123_state *state = fe->demodulator_priv;
+
+ if (state->config->set_ts_params)
+ state->config->set_ts_params(fe, 0);
+
+ state->currentfreq=p->frequency;
+ state->currentsymbolrate = p->u.qpsk.symbol_rate;
+
+ cx24123_set_inversion(state, p->inversion);
+ cx24123_set_fec(state, p->u.qpsk.fec_inner);
+ cx24123_set_symbolrate(state, p->u.qpsk.symbol_rate);
+ cx24123_pll_tune(fe, p);
+
+ /* Enable automatic aquisition and reset cycle */
+ cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07));
+ cx24123_writereg(state, 0x00, 0x10);
+ cx24123_writereg(state, 0x00, 0);
+
+ return 0;
+}
+
+static int cx24123_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct cx24123_state *state = fe->demodulator_priv;
+
+ if (cx24123_get_inversion(state, &p->inversion) != 0) {
+ printk("%s: Failed to get inversion status\n",__FUNCTION__);
+ return -EREMOTEIO;
+ }
+ if (cx24123_get_fec(state, &p->u.qpsk.fec_inner) != 0) {
+ printk("%s: Failed to get fec status\n",__FUNCTION__);
+ return -EREMOTEIO;
+ }
+ p->frequency = state->currentfreq;
+ p->u.qpsk.symbol_rate = state->currentsymbolrate;
+
+ return 0;
+}
+
+static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct cx24123_state *state = fe->demodulator_priv;
+ u8 val;
+
+ switch (state->config->use_isl6421) {
+ case 1:
+
+ val = cx24123_readlnbreg(state, 0x0);
+
+ switch (tone) {
+ case SEC_TONE_ON:
+ return cx24123_writelnbreg(state, 0x0, val | 0x10);
+ case SEC_TONE_OFF:
+ return cx24123_writelnbreg(state, 0x0, val & 0x2f);
+ default:
+ printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+ return -EINVAL;
+ }
+
+ case 0:
+
+ val = cx24123_readreg(state, 0x29);
+
+ switch (tone) {
+ case SEC_TONE_ON:
+ dprintk("%s: setting tone on\n", __FUNCTION__);
+ return cx24123_writereg(state, 0x29, val | 0x10);
+ case SEC_TONE_OFF:
+ dprintk("%s: setting tone off\n",__FUNCTION__);
+ return cx24123_writereg(state, 0x29, val & 0xef);
+ default:
+ printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static void cx24123_release(struct dvb_frontend* fe)
+{
+ struct cx24123_state* state = fe->demodulator_priv;
+ dprintk("%s\n",__FUNCTION__);
+ kfree(state);
+}
+
+static struct dvb_frontend_ops cx24123_ops;
+
+struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
+ struct i2c_adapter* i2c)
+{
+ struct cx24123_state* state = NULL;
+ int ret;
+
+ dprintk("%s\n",__FUNCTION__);
+
+ /* allocate memory for the internal state */
+ state = kmalloc(sizeof(struct cx24123_state), GFP_KERNEL);
+ if (state == NULL) {
+ printk("Unable to kmalloc\n");
+ goto error;
+ }
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
+ state->lastber = 0;
+ state->snr = 0;
+ state->lnbreg = 0;
+ state->VCAarg = 0;
+ state->VGAarg = 0;
+ state->bandselectarg = 0;
+ state->pllarg = 0;
+ state->currentfreq = 0;
+ state->currentsymbolrate = 0;
+
+ /* check if the demod is there */
+ ret = cx24123_readreg(state, 0x00);
+ if ((ret != 0xd1) && (ret != 0xe1)) {
+ printk("Version != d1 or e1\n");
+ 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 cx24123_ops = {
+
+ .info = {
+ .name = "Conexant CX24123/CX24109",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 1011, /* kHz for QPSK frontends */
+ .frequency_tolerance = 29500,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_RECOVER
+ },
+
+ .release = cx24123_release,
+
+ .init = cx24123_initfe,
+ .set_frontend = cx24123_set_frontend,
+ .get_frontend = cx24123_get_frontend,
+ .read_status = cx24123_read_status,
+ .read_ber = cx24123_read_ber,
+ .read_signal_strength = cx24123_read_signal_strength,
+ .read_snr = cx24123_read_snr,
+ .read_ucblocks = cx24123_read_ucblocks,
+ .diseqc_send_master_cmd = cx24123_send_diseqc_msg,
+ .set_tone = cx24123_set_tone,
+ .set_voltage = cx24123_set_voltage,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24123/cx24109 hardware");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(cx24123_attach);
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
new file mode 100644
index 000000000000..0c922b5e9263
--- /dev/null
+++ b/drivers/media/dvb/frontends/cx24123.h
@@ -0,0 +1,51 @@
+/*
+ Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
+
+ Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef CX24123_H
+#define CX24123_H
+
+#include <linux/dvb/frontend.h>
+
+struct cx24123_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /*
+ cards like Hauppauge Nova-S Plus/Nova-SE2 use an Intersil ISL6421 chip
+ for LNB control, while KWorld DVB-S 100 use the LNBDC and LNBTone bits
+ from register 0x29 of the CX24123 demodulator
+ */
+ int use_isl6421;
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+
+ /* Need to set device param for start_dma */
+ int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+
+ void (*enable_lnb_voltage)(struct dvb_frontend* fe, int on);
+};
+
+extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
+ struct i2c_adapter* i2c);
+
+#endif /* CX24123_H */
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index f857b869616c..a3d57ce9dd12 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -107,18 +107,19 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = {
};
EXPORT_SYMBOL(dvb_pll_microtune_4042);
-struct dvb_pll_desc dvb_pll_thomson_dtt7611 = {
- .name = "Thomson dtt7611",
- .min = 44000000,
- .max = 958000000,
+struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
+ /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
+ .name = "Thomson dtt761x",
+ .min = 57000000,
+ .max = 863000000,
.count = 3,
.entries = {
- { 157250000, 44000000, 62500, 0x8e, 0x39 },
- { 454000000, 44000000, 62500, 0x8e, 0x3a },
+ { 147000000, 44000000, 62500, 0x8e, 0x39 },
+ { 417000000, 44000000, 62500, 0x8e, 0x3a },
{ 999999999, 44000000, 62500, 0x8e, 0x3c },
},
};
-EXPORT_SYMBOL(dvb_pll_thomson_dtt7611);
+EXPORT_SYMBOL(dvb_pll_thomson_dtt761x);
struct dvb_pll_desc dvb_pll_unknown_1 = {
.name = "unknown 1", /* used by dntv live dvb-t */
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 497d31dcf41e..24d4d2e9acd8 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -25,7 +25,7 @@ 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_thomson_dtt761x;
extern struct dvb_pll_desc dvb_pll_unknown_1;
extern struct dvb_pll_desc dvb_pll_tua6010xs;
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index cb5301865d07..9d214643b87a 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -27,6 +27,7 @@
* DViCO FusionHDTV 3 Gold-T
* DViCO FusionHDTV 5 Gold
* DViCO FusionHDTV 5 Lite
+ * DViCO FusionHDTV 5 USB Gold
* Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
*
* TODO:
@@ -402,6 +403,8 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
state->config->pll_set(fe, param);
/* Keep track of the new frequency */
+ /* FIXME this is the wrong way to do this... */
+ /* The tuner is shared with the video4linux analog API */
state->current_frequency = param->frequency;
lgdt330x_SwReset(state);
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
index 8d672283c93d..ec4e641acc64 100644
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb/frontends/mt312.c
@@ -501,7 +501,8 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
case ID_VP310:
// For now we will do this only for the VP310.
// It should be better for the mt312 as well, but tunning will be slower. ACCJr 09/29/03
- if ((ret = mt312_readreg(state, CONFIG, &config_val) < 0))
+ ret = mt312_readreg(state, CONFIG, &config_val);
+ if (ret < 0)
return ret;
if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz
{
diff --git a/drivers/media/dvb/frontends/nxt2002.c b/drivers/media/dvb/frontends/nxt2002.c
index 52c416043a62..4f263e65ba14 100644
--- a/drivers/media/dvb/frontends/nxt2002.c
+++ b/drivers/media/dvb/frontends/nxt2002.c
@@ -22,7 +22,8 @@
/*
* This driver needs external firmware. Please use the command
* "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
*/
#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
#define CRC_CCIT_MASK 0x1021
diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c
index a458a3bfff70..a16eeba0020d 100644
--- a/drivers/media/dvb/frontends/nxt6000.c
+++ b/drivers/media/dvb/frontends/nxt6000.c
@@ -574,11 +574,11 @@ static struct dvb_frontend_ops nxt6000_ops = {
.symbol_rate_max = 9360000, /* FIXME */
.symbol_rate_tolerance = 4000,
.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
- FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
- FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_HIERARCHY_AUTO,
+ FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+ FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
+ FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO,
},
.release = nxt6000_release,
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index 531f76246e5f..7c3aed1f546b 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -25,7 +25,8 @@
/*
* This driver needs external firmware. Please use the command
* "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
*/
#define OR51211_DEFAULT_FIRMWARE "dvb-fe-or51211.fw"
@@ -112,7 +113,7 @@ static int or51211_load_firmware (struct dvb_frontend* fe,
u8 tudata[585];
int i;
- dprintk("Firmware is %d bytes\n",fw->size);
+ dprintk("Firmware is %zd bytes\n",fw->size);
/* Get eprom data */
tudata[0] = 17;
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index 18715091aed8..d69477596921 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -521,8 +521,8 @@ static void s5h1420_setfec_inversion(struct s5h1420_state* state,
case FEC_3_4:
s5h1420_writereg(state, 0x30, 0x04);
- s5h1420_writereg(state, 0x31, 0x12 | inversion);
- break;
+ s5h1420_writereg(state, 0x31, 0x12 | inversion);
+ break;
case FEC_5_6:
s5h1420_writereg(state, 0x30, 0x08);
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c
index fc06cd6b46c3..73829e647e50 100644
--- a/drivers/media/dvb/frontends/sp8870.c
+++ b/drivers/media/dvb/frontends/sp8870.c
@@ -22,7 +22,8 @@
/*
* This driver needs external firmware. Please use the command
* "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
*/
#define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw"
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
index e3b665782243..eb8a602198ca 100644
--- a/drivers/media/dvb/frontends/sp887x.c
+++ b/drivers/media/dvb/frontends/sp887x.c
@@ -5,7 +5,8 @@
/*
* This driver needs external firmware. Please use the command
* "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
*/
#define SP887X_DEFAULT_FIRMWARE "dvb-fe-sp887x.fw"
@@ -581,7 +582,7 @@ static struct dvb_frontend_ops sp887x_ops = {
.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
- FE_CAN_RECOVER
+ FE_CAN_RECOVER
},
.release = sp887x_release,
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 177d71d56b67..5bcd00f792e6 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -131,6 +131,13 @@ static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len
return ret == 2 ? 0 : ret;
}
+int stv0299_enable_plli2c (struct dvb_frontend* fe)
+{
+ struct stv0299_state* state = fe->demodulator_priv;
+
+ return stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
+}
+
static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
{
dprintk ("%s\n", __FUNCTION__);
@@ -387,7 +394,7 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag
};
}
-static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
+static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long cmd)
{
struct stv0299_state* state = fe->demodulator_priv;
u8 reg0x08;
@@ -407,7 +414,7 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
cmd = cmd << 1;
if (debug_legacy_dish_switch)
- printk ("%s switch command: 0x%04x\n",__FUNCTION__, cmd);
+ printk ("%s switch command: 0x%04lx\n",__FUNCTION__, cmd);
do_gettimeofday (&nexttime);
if (debug_legacy_dish_switch)
@@ -717,5 +724,6 @@ MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
"Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy");
MODULE_LICENSE("GPL");
+EXPORT_SYMBOL(stv0299_enable_plli2c);
EXPORT_SYMBOL(stv0299_writereg);
EXPORT_SYMBOL(stv0299_attach);
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h
index 9af3d71c89db..32c87b4c2f13 100644
--- a/drivers/media/dvb/frontends/stv0299.h
+++ b/drivers/media/dvb/frontends/stv0299.h
@@ -94,6 +94,7 @@ struct stv0299_config
};
extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data);
+extern int stv0299_enable_plli2c (struct dvb_frontend* fe);
extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
struct i2c_adapter* i2c);
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 425cd19136fe..21255cac9793 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -95,7 +95,7 @@ static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
u8 b0 [] = { reg };
u8 b1 [] = { 0 };
struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
- { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+ { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
int ret;
ret = i2c_transfer (state->i2c, msg, 2);
@@ -434,7 +434,7 @@ static struct dvb_frontend_ops tda10021_ops = {
.frequency_max = 858000000,
.symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */
.symbol_rate_max = (XIN/2)/4, /* SACLK/4 */
- #if 0
+#if 0
.frequency_tolerance = ???,
.symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */
#endif
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index dd02aff467fe..c63e9a5084eb 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -23,7 +23,8 @@
* This driver needs external firmware. Please use the commands
* "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
* "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
- * download/extract them, and then copy them to /usr/lib/hotplug/firmware.
+ * download/extract them, and then copy them to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
*/
#define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw"
#define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw"
@@ -271,32 +272,57 @@ static int tda10045h_set_bandwidth(struct tda1004x_state *state,
static int tda10046h_set_bandwidth(struct tda1004x_state *state,
fe_bandwidth_t bandwidth)
{
- static u8 bandwidth_6mhz[] = { 0x80, 0x15, 0xfe, 0xab, 0x8e };
- static u8 bandwidth_7mhz[] = { 0x6e, 0x02, 0x53, 0xc8, 0x25 };
- static u8 bandwidth_8mhz[] = { 0x60, 0x12, 0xa8, 0xe4, 0xbd };
-
+ static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 };
+ static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f };
+ static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d };
+
+ static u8 bandwidth_6mhz_48M[] = { 0x70, 0x02, 0x49, 0x24, 0x92 };
+ static u8 bandwidth_7mhz_48M[] = { 0x60, 0x02, 0xaa, 0xaa, 0xab };
+ static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 };
+ int tda10046_clk53m;
+
+ if ((state->config->if_freq == TDA10046_FREQ_045) ||
+ (state->config->if_freq == TDA10046_FREQ_052))
+ tda10046_clk53m = 0;
+ else
+ tda10046_clk53m = 1;
switch (bandwidth) {
case BANDWIDTH_6_MHZ:
- tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz));
+ if (tda10046_clk53m)
+ tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M,
+ sizeof(bandwidth_6mhz_53M));
+ else
+ tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_48M,
+ sizeof(bandwidth_6mhz_48M));
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);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xab);
}
break;
case BANDWIDTH_7_MHZ:
- tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz));
+ if (tda10046_clk53m)
+ tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M,
+ sizeof(bandwidth_7mhz_53M));
+ else
+ tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_48M,
+ sizeof(bandwidth_7mhz_48M));
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);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
}
break;
case BANDWIDTH_8_MHZ:
- tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz));
+ if (tda10046_clk53m)
+ tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M,
+ sizeof(bandwidth_8mhz_53M));
+ else
+ tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_48M,
+ sizeof(bandwidth_8mhz_48M));
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);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x55);
}
break;
@@ -418,9 +444,22 @@ static int tda10045_fwupload(struct dvb_frontend* fe)
static void tda10046_init_plls(struct dvb_frontend* fe)
{
struct tda1004x_state* state = fe->demodulator_priv;
+ int tda10046_clk53m;
+
+ if ((state->config->if_freq == TDA10046_FREQ_045) ||
+ (state->config->if_freq == TDA10046_FREQ_052))
+ tda10046_clk53m = 0;
+ else
+ tda10046_clk53m = 1;
tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
- tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x0a); // PLL M = 10
+ if(tda10046_clk53m) {
+ printk(KERN_INFO "tda1004x: setting up plls for 53MHz sampling clock\n");
+ tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x08); // PLL M = 8
+ } else {
+ printk(KERN_INFO "tda1004x: setting up plls for 48MHz sampling clock\n");
+ tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3
+ }
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
@@ -428,26 +467,32 @@ static void tda10046_init_plls(struct dvb_frontend* fe)
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);
+ if(tda10046_clk53m)
+ tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x67);
+ else
+ tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x72);
+ /* Note clock frequency is handled implicitly */
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);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
break;
case TDA10046_FREQ_052:
- tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
- tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x06);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xc7);
+ break;
+ case TDA10046_FREQ_3617:
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x59);
+ break;
+ case TDA10046_FREQ_3613:
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f);
break;
}
tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
+ /* let the PLLs settle */
+ msleep(120);
}
static int tda10046_fwupload(struct dvb_frontend* fe)
@@ -462,13 +507,13 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
/* let the clocks recover from sleep */
msleep(5);
+ /* The PLLs need to be reprogrammed after sleep */
+ tda10046_init_plls(fe);
+
/* don't re-upload unless necessary */
if (tda1004x_check_upload_ok(state) == 0)
return 0;
- /* set parameters */
- 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");
@@ -484,7 +529,6 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
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);
@@ -606,10 +650,9 @@ static int tda10046_init(struct dvb_frontend* fe)
// tda setup
tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
- tda1004x_write_byteI(state, TDA1004X_AUTO, 7); // select HP stream
- tda1004x_write_byteI(state, TDA1004X_CONFC1, 8); // disable pulse killer
+ tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87); // 100 ppm crystal, 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
@@ -626,25 +669,22 @@ static int tda10046_init(struct dvb_frontend* fe)
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
+ tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
+ tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities
break;
}
+ tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
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_byteI(state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1
+ tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 0x12); // IF gain 2, TUN gain 1
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_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_byteI(state, TDA10046H_GPIO_SELECT, 8); // GPIO select
-
state->initialised = 1;
return 0;
}
@@ -686,9 +726,9 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
// Set standard params.. or put them to auto
if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) ||
- (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) ||
- (fe_params->u.ofdm.constellation == QAM_AUTO) ||
- (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) {
+ (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) ||
+ (fe_params->u.ofdm.constellation == QAM_AUTO) ||
+ (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) {
tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1); // enable auto
tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits
tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits
@@ -851,6 +891,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params)
{
struct tda1004x_state* state = fe->demodulator_priv;
+
dprintk("%s\n", __FUNCTION__);
// inversion status
@@ -875,16 +916,18 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete
break;
}
break;
-
case TDA1004X_DEMOD_TDA10046:
switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) {
- case 0x60:
+ case 0x5c:
+ case 0x54:
fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
break;
- case 0x6e:
+ case 0x6a:
+ case 0x60:
fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
break;
- case 0x80:
+ case 0x7b:
+ case 0x70:
fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
break;
}
diff --git a/drivers/media/dvb/pluto2/Kconfig b/drivers/media/dvb/pluto2/Kconfig
index f02842be0d60..84f8f9f52869 100644
--- a/drivers/media/dvb/pluto2/Kconfig
+++ b/drivers/media/dvb/pluto2/Kconfig
@@ -8,7 +8,7 @@ config DVB_PLUTO2
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
+ 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.
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index fa5034a9ecf5..5b2aadb8385c 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -18,9 +18,10 @@ config DVB_AV7110
This driver only supports the fullfeatured cards with
onboard MPEG2 decoder.
- This driver needs an external firmware. Please use the script
- "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to
- download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ This driver needs an external firmware. Please use the script
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to
+ download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ or /lib/firmware (depending on configuration of firmware hotplug).
Say Y if you own such a card and want to use it.
diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile
index 825ab1c38a4f..a690730ac39d 100644
--- a/drivers/media/dvb/ttpci/Makefile
+++ b/drivers/media/dvb/ttpci/Makefile
@@ -16,7 +16,7 @@ EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
hostprogs-y := fdump
ifdef CONFIG_DVB_AV7110_FIRMWARE
-$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h
+$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h
$(obj)/av7110_firm.h:
$(obj)/fdump $(CONFIG_DVB_AV7110_FIRMWARE_FILE) dvb_ttpci_fw $@
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 7dae91e5863c..8ce4146f55f1 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -133,7 +133,13 @@ static void init_av7110_av(struct av7110 *av7110)
/* remaining inits according to card and frontend type */
av7110->analog_tuner_flags = 0;
av7110->current_input = 0;
- if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
+ if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) {
+ printk("dvb-ttpci: MSP3415 audio DAC @ card %d\n",
+ av7110->dvb_adapter.num);
+ av7110->adac_type = DVB_ADAC_MSP34x5;
+ av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on
+ }
+ else if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n",
av7110->dvb_adapter.num);
av7110->adac_type = DVB_ADAC_CRYSTAL;
@@ -156,10 +162,10 @@ static void init_av7110_av(struct av7110 *av7110)
else {
av7110->adac_type = adac;
printk("dvb-ttpci: adac type set to %d @ card %d\n",
- av7110->dvb_adapter.num, av7110->adac_type);
+ av7110->adac_type, av7110->dvb_adapter.num);
}
- if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) {
+ if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP34x0) {
// switch DVB SCART on
ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);
if (ret < 0)
@@ -190,17 +196,15 @@ static void recover_arm(struct av7110 *av7110)
av7110_bootarm(av7110);
msleep(100);
- restart_feeds(av7110);
- av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
-}
-static void arm_error(struct av7110 *av7110)
-{
- dprintk(4, "%p\n",av7110);
+ init_av7110_av(av7110);
+
+ /* card-specific recovery */
+ if (av7110->recover)
+ av7110->recover(av7110);
- av7110->arm_errors++;
- av7110->arm_ready = 0;
- recover_arm(av7110);
+ restart_feeds(av7110);
+ av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
}
static void av7110_arm_sync(struct av7110 *av7110)
@@ -240,26 +244,22 @@ static int arm_thread(void *data)
if (down_interruptible(&av7110->dcomlock))
break;
-
newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
up(&av7110->dcomlock);
- if (newloops == av7110->arm_loops) {
+ if (newloops == av7110->arm_loops || av7110->arm_errors > 3) {
printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n",
av7110->dvb_adapter.num);
- arm_error(av7110);
- av7710_set_video_mode(av7110, vidmode);
-
- init_av7110_av(av7110);
+ recover_arm(av7110);
if (down_interruptible(&av7110->dcomlock))
break;
-
newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1;
up(&av7110->dcomlock);
}
av7110->arm_loops = newloops;
+ av7110->arm_errors = 0;
}
av7110->arm_thread = NULL;
@@ -510,10 +510,6 @@ static void gpioirq(unsigned long data)
iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
av7110->video_size.h = h_ar & 0xfff;
- dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",
- av7110->video_size.w,
- av7110->video_size.h,
- av7110->video_size.aspect_ratio);
event.type = VIDEO_EVENT_SIZE_CHANGED;
event.u.size.w = av7110->video_size.w;
@@ -535,6 +531,11 @@ static void gpioirq(unsigned long data)
event.u.size.aspect_ratio = VIDEO_FORMAT_4_3;
av7110->videostate.video_format = VIDEO_FORMAT_4_3;
}
+
+ dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",
+ av7110->video_size.w, av7110->video_size.h,
+ av7110->video_size.aspect_ratio);
+
dvb_video_add_event(av7110, &event);
break;
}
@@ -714,6 +715,8 @@ static struct dvb_device dvbdev_osd = {
static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
u16 subpid, u16 pcrpid)
{
+ u16 aflags = 0;
+
dprintk(4, "%p\n", av7110);
if (vpid == 0x1fff || apid == 0x1fff ||
@@ -725,8 +728,11 @@ static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
av7110->pids[DMX_PES_PCR] = 0;
}
- return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 5,
- pcrpid, vpid, apid, ttpid, subpid);
+ if (av7110->audiostate.bypass_mode)
+ aflags |= 0x8000;
+
+ return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 6,
+ pcrpid, vpid, apid, ttpid, subpid, aflags);
}
int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
@@ -1043,7 +1049,7 @@ static void restart_feeds(struct av7110 *av7110)
struct dvb_demux *dvbdmx = &av7110->demux;
struct dvb_demux_feed *feed;
int mode;
- int i;
+ int i, j;
dprintk(4, "%p\n", av7110);
@@ -1051,10 +1057,21 @@ static void restart_feeds(struct av7110 *av7110)
av7110->playing = 0;
av7110->rec_mode = 0;
- for (i = 0; i < dvbdmx->filternum; i++) {
+ for (i = 0; i < dvbdmx->feednum; i++) {
feed = &dvbdmx->feed[i];
- if (feed->state == DMX_STATE_GO)
+ if (feed->state == DMX_STATE_GO) {
+ if (feed->type == DMX_TYPE_SEC) {
+ for (j = 0; j < dvbdmx->filternum; j++) {
+ if (dvbdmx->filter[j].type != DMX_TYPE_SEC)
+ continue;
+ if (dvbdmx->filter[j].filter.parent != &feed->feed.sec)
+ continue;
+ if (dvbdmx->filter[j].state == DMX_STATE_GO)
+ dvbdmx->filter[j].state = DMX_STATE_READY;
+ }
+ }
av7110_start_feed(feed);
+ }
}
if (mode)
@@ -1483,9 +1500,9 @@ static int get_firmware(struct av7110* av7110)
if (ret == -ENOENT) {
printk(KERN_ERR "dvb-ttpci: could not load firmware,"
" file not found: dvb-ttpci-01.fw\n");
- printk(KERN_ERR "dvb-ttpci: usually this should be in"
- " /usr/lib/hotplug/firmware\n");
- printk(KERN_ERR "dvb-ttpci: and can be downloaded here"
+ printk(KERN_ERR "dvb-ttpci: usually this should be in "
+ "/usr/lib/hotplug/firmware or /lib/firmware\n");
+ printk(KERN_ERR "dvb-ttpci: and can be downloaded from"
" http://www.linuxtv.org/download/dvb/firmware/\n");
} else
printk(KERN_ERR "dvb-ttpci: cannot request firmware"
@@ -2110,8 +2127,10 @@ static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_p
struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
- if (!ret)
+ if (!ret) {
+ av7110->saved_fe_params = *params;
ret = av7110->fe_set_frontend(fe, params);
+ }
return ret;
}
@@ -2153,8 +2172,10 @@ static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe,
struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
- if (!ret)
+ if (!ret) {
+ av7110->saved_master_cmd = *cmd;
ret = av7110->fe_diseqc_send_master_cmd(fe, cmd);
+ }
return ret;
}
@@ -2163,8 +2184,10 @@ static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_
struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
- if (!ret)
+ if (!ret) {
+ av7110->saved_minicmd = minicmd;
ret = av7110->fe_diseqc_send_burst(fe, minicmd);
+ }
return ret;
}
@@ -2173,8 +2196,10 @@ static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
- if (!ret)
+ if (!ret) {
+ av7110->saved_tone = tone;
ret = av7110->fe_set_tone(fe, tone);
+ }
return ret;
}
@@ -2183,12 +2208,14 @@ static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t volta
struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
- if (!ret)
+ if (!ret) {
+ av7110->saved_voltage = voltage;
ret = av7110->fe_set_voltage(fe, voltage);
+ }
return ret;
}
-static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned int cmd)
+static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned long cmd)
{
struct av7110* av7110 = fe->dvb->priv;
@@ -2198,6 +2225,23 @@ static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, un
return ret;
}
+static void dvb_s_recover(struct av7110* av7110)
+{
+ av7110_fe_init(av7110->fe);
+
+ av7110_fe_set_voltage(av7110->fe, av7110->saved_voltage);
+ if (av7110->saved_master_cmd.msg_len) {
+ msleep(20);
+ av7110_fe_diseqc_send_master_cmd(av7110->fe, &av7110->saved_master_cmd);
+ }
+ msleep(20);
+ av7110_fe_diseqc_send_burst(av7110->fe, av7110->saved_minicmd);
+ msleep(20);
+ av7110_fe_set_tone(av7110->fe, av7110->saved_tone);
+
+ av7110_fe_set_frontend(av7110->fe, &av7110->saved_fe_params);
+}
+
static u8 read_pwm(struct av7110* av7110)
{
u8 b = 0xff;
@@ -2235,6 +2279,7 @@ static int frontend_init(struct av7110 *av7110)
av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->recover = dvb_s_recover;
break;
}
@@ -2244,15 +2289,17 @@ static int frontend_init(struct av7110 *av7110)
av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->recover = dvb_s_recover;
break;
}
// Try the grundig 29504-451
- av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
+ av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
if (av7110->fe) {
av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->recover = dvb_s_recover;
break;
}
@@ -2274,12 +2321,12 @@ static int frontend_init(struct av7110 *av7110)
case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X
// ALPS TDLB7
- av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
+ av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
break;
case 0x0002: // Hauppauge/TT DVB-C premium rev2.X
- av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
+ av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
break;
case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */
@@ -2289,6 +2336,7 @@ static int frontend_init(struct av7110 *av7110)
av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->recover = dvb_s_recover;
}
break;
@@ -2314,8 +2362,11 @@ static int frontend_init(struct av7110 *av7110)
case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */
/* ALPS BSBE1 */
av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap);
- if (av7110->fe)
+ if (av7110->fe) {
av7110->fe->ops->set_voltage = lnbp21_set_voltage;
+ av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
+ av7110->recover = dvb_s_recover;
+ }
break;
}
}
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index cce00ef293e9..6ea30df2e823 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -98,7 +98,8 @@ struct av7110 {
int adac_type; /* audio DAC type */
#define DVB_ADAC_TI 0
#define DVB_ADAC_CRYSTAL 1
-#define DVB_ADAC_MSP 2
+#define DVB_ADAC_MSP34x0 2
+#define DVB_ADAC_MSP34x5 3
#define DVB_ADAC_NONE -1
@@ -228,6 +229,9 @@ struct av7110 {
struct dvb_video_events video_events;
video_size_t video_size;
+ u16 wssMode;
+ u16 wssData;
+
u32 ir_config;
u32 ir_command;
void (*ir_handler)(struct av7110 *av7110, u32 ircom);
@@ -245,6 +249,15 @@ struct av7110 {
struct dvb_frontend* fe;
fe_status_t fe_status;
+
+ /* crash recovery */
+ void (*recover)(struct av7110* av7110);
+ struct dvb_frontend_parameters saved_fe_params;
+ fe_sec_voltage_t saved_voltage;
+ fe_sec_tone_mode_t saved_tone;
+ struct dvb_diseqc_master_cmd saved_master_cmd;
+ fe_sec_mini_cmd_t saved_minicmd;
+
int (*fe_init)(struct dvb_frontend* fe);
int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status);
int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe);
@@ -252,7 +265,7 @@ struct av7110 {
int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
- int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd);
+ int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
int (*fe_set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 0696a5a4f855..400facec7407 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -309,7 +309,7 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
i2c_writereg(av7110, 0x20, 0x04, volright);
return 0;
- case DVB_ADAC_MSP:
+ case DVB_ADAC_MSP34x0:
vol = (volleft > volright) ? volleft : volright;
val = (vol * 0x73 / 255) << 8;
if (vol > 0)
@@ -1256,7 +1256,9 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
break;
case AUDIO_SET_BYPASS_MODE:
- ret = -EINVAL;
+ if (FW_VERSION(av7110->arm_app) < 0x2621)
+ ret = -EINVAL;
+ av7110->audiostate.bypass_mode = (int)arg;
break;
case AUDIO_CHANNEL_SELECT:
@@ -1295,7 +1297,11 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
break;
case AUDIO_GET_CAPABILITIES:
- *(int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
+ if (FW_VERSION(av7110->arm_app) < 0x2621)
+ *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
+ else
+ *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_DTS | AUDIO_CAP_AC3 |
+ AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
break;
case AUDIO_CLEAR_BUFFER:
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 87106e8bf35b..cb377452b57d 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -230,6 +230,8 @@ int av7110_bootarm(struct av7110 *av7110)
dprintk(4, "%p\n", av7110);
+ av7110->arm_ready = 0;
+
saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
/* Disable DEBI and GPIO irq */
@@ -361,6 +363,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
break;
if (err) {
printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
+ av7110->arm_errors++;
return -ETIMEDOUT;
}
msleep(1);
@@ -1206,9 +1209,9 @@ int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
switch (cap->cmd) {
case OSD_CAP_MEMSIZE:
if (FW_4M_SDRAM(av7110->arm_app))
- cap->val = 1000000;
+ cap->val = 1000000;
else
- cap->val = 92000;
+ cap->val = 92000;
return 0;
default:
return -EINVAL;
diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h
index 2a5e87ba1052..84b83299b8be 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.h
+++ b/drivers/media/dvb/ttpci/av7110_hw.h
@@ -167,7 +167,8 @@ enum av7110_encoder_command {
LoadVidCode,
SetMonitorType,
SetPanScanType,
- SetFreezeMode
+ SetFreezeMode,
+ SetWSSConfig
};
enum av7110_rec_play_state {
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
index f5e59fc924af..9138132ad25f 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -17,6 +17,8 @@ static int av_cnt;
static struct av7110 *av_list[4];
static struct input_dev *input_dev;
+static u8 delay_timer_finished;
+
static u16 key_map [256] = {
KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO,
@@ -112,13 +114,16 @@ static void av7110_emit_key(unsigned long parm)
if (timer_pending(&keyup_timer)) {
del_timer(&keyup_timer);
if (keyup_timer.data != keycode || new_toggle != old_toggle) {
+ delay_timer_finished = 0;
input_event(input_dev, EV_KEY, keyup_timer.data, !!0);
input_event(input_dev, EV_KEY, keycode, !0);
} else
- input_event(input_dev, EV_KEY, keycode, 2);
-
- } else
+ if (delay_timer_finished)
+ input_event(input_dev, EV_KEY, keycode, 2);
+ } else {
+ delay_timer_finished = 0;
input_event(input_dev, EV_KEY, keycode, !0);
+ }
keyup_timer.expires = jiffies + UP_TIMEOUT;
keyup_timer.data = keycode;
@@ -145,7 +150,8 @@ static void input_register_keys(void)
static void input_repeat_key(unsigned long data)
{
- /* dummy routine to disable autorepeat in the input driver */
+ /* called by the input driver after rep[REP_DELAY] ms */
+ delay_timer_finished = 1;
}
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index b5aea4129fa7..94cf38c7e8a8 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -490,6 +490,58 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
break;
}
+ case VIDIOC_G_SLICED_VBI_CAP:
+ {
+ struct v4l2_sliced_vbi_cap *cap = arg;
+ dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
+ memset(cap, 0, sizeof *cap);
+ if (FW_VERSION(av7110->arm_app) >= 0x2623) {
+ cap->service_set = V4L2_SLICED_WSS_625;
+ cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
+ }
+ break;
+ }
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *f = arg;
+ dprintk(2, "VIDIOC_G_FMT:\n");
+ if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
+ FW_VERSION(av7110->arm_app) < 0x2623)
+ return -EAGAIN; /* handled by core driver */
+ memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+ if (av7110->wssMode) {
+ f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
+ f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+ f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
+ }
+ break;
+ }
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *f = arg;
+ dprintk(2, "VIDIOC_S_FMT\n");
+ if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
+ FW_VERSION(av7110->arm_app) < 0x2623)
+ return -EAGAIN; /* handled by core driver */
+ if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
+ f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
+ memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+ /* WSS controlled by firmware */
+ av7110->wssMode = 0;
+ av7110->wssData = 0;
+ return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
+ SetWSSConfig, 1, 0);
+ } else {
+ memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+ f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
+ f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+ f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
+ /* WSS controlled by userspace */
+ av7110->wssMode = 1;
+ av7110->wssData = 0;
+ }
+ break;
+ }
default:
printk("no such ioctl\n");
return -ENOIOCTLCMD;
@@ -497,6 +549,46 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
return 0;
}
+static int av7110_vbi_reset(struct inode *inode, struct file *file)
+{
+ struct saa7146_fh *fh = file->private_data;
+ struct saa7146_dev *dev = fh->dev;
+ struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+
+ dprintk(2, "%s\n", __FUNCTION__);
+ av7110->wssMode = 0;
+ av7110->wssData = 0;
+ if (FW_VERSION(av7110->arm_app) < 0x2623)
+ return 0;
+ else
+ return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
+}
+
+static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
+{
+ struct saa7146_fh *fh = file->private_data;
+ struct saa7146_dev *dev = fh->dev;
+ struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+ struct v4l2_sliced_vbi_data d;
+ int rc;
+
+ dprintk(2, "%s\n", __FUNCTION__);
+ if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d)
+ return -EINVAL;
+ if (copy_from_user(&d, data, count))
+ return -EFAULT;
+ if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23)
+ return -EINVAL;
+ if (d.id) {
+ av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0];
+ rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig,
+ 2, 1, av7110->wssData);
+ } else {
+ av7110->wssData = 0;
+ rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
+ }
+ return (rc < 0) ? rc : count;
+}
/****************************************************************************
* INITIALIZATION
@@ -512,6 +604,9 @@ static struct saa7146_extension_ioctls ioctls[] = {
{ VIDIOC_S_TUNER, SAA7146_EXCLUSIVE },
{ VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
{ VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
+ { VIDIOC_G_SLICED_VBI_CAP, SAA7146_EXCLUSIVE },
+ { VIDIOC_G_FMT, SAA7146_BEFORE },
+ { VIDIOC_S_FMT, SAA7146_BEFORE },
{ 0, 0 }
};
@@ -587,7 +682,7 @@ int av7110_init_analog_module(struct av7110 *av7110)
printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n",
av7110->dvb_adapter.num);
- av7110->adac_type = DVB_ADAC_MSP;
+ av7110->adac_type = DVB_ADAC_MSP34x0;
msleep(100); // the probing above resets the msp...
msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
@@ -692,12 +787,11 @@ int av7110_init_v4l(struct av7110 *av7110)
saa7146_vv_release(dev);
return -ENODEV;
}
- if (av7110->analog_tuner_flags) {
- if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
- ERR(("cannot register vbi v4l2 device. skipping.\n"));
- } else {
+ if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
+ ERR(("cannot register vbi v4l2 device. skipping.\n"));
+ } else {
+ if (av7110->analog_tuner_flags)
av7110->analog_tuner_flags |= ANALOG_TUNER_VBI;
- }
}
return 0;
}
@@ -778,7 +872,7 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
static struct saa7146_ext_vv av7110_vv_data_st = {
.inputs = 1,
.audios = 1,
- .capabilities = 0,
+ .capabilities = V4L2_CAP_SLICED_VBI_OUTPUT,
.flags = 0,
.stds = &standard[0],
@@ -787,12 +881,16 @@ static struct saa7146_ext_vv av7110_vv_data_st = {
.ioctls = &ioctls[0],
.ioctl = av7110_ioctl,
+
+ .vbi_fops.open = av7110_vbi_reset,
+ .vbi_fops.release = av7110_vbi_reset,
+ .vbi_fops.write = av7110_vbi_write,
};
static struct saa7146_ext_vv av7110_vv_data_c = {
.inputs = 1,
.audios = 1,
- .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
+ .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT,
.flags = SAA7146_USE_PORT_B_FOR_VBI,
.stds = &standard[0],
@@ -801,5 +899,9 @@ static struct saa7146_ext_vv av7110_vv_data_c = {
.ioctls = &ioctls[0],
.ioctl = av7110_ioctl,
+
+ .vbi_fops.open = av7110_vbi_reset,
+ .vbi_fops.release = av7110_vbi_reset,
+ .vbi_fops.write = av7110_vbi_write,
};
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 9f51bae7194c..f9d00452e639 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -127,7 +127,7 @@ static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int ad
saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
udelay(1);
- result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 0);
+ result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1);
if (result == -ETIMEDOUT)
budget_av->slot_status = 0;
@@ -145,7 +145,7 @@ static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int a
saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
udelay(1);
- result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 0);
+ result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1);
if (result == -ETIMEDOUT)
budget_av->slot_status = 0;
@@ -192,7 +192,7 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
{
struct budget_av *budget_av = (struct budget_av *) ca->data;
struct saa7146_dev *saa = budget_av->budget.dev;
- int timeout = 500; // 5 seconds (4.4.6 Ready)
+ int timeout = 50; // 5 seconds (4.4.6 Ready)
if (slot != 0)
return -EINVAL;
@@ -256,19 +256,37 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open
{
struct budget_av *budget_av = (struct budget_av *) ca->data;
struct saa7146_dev *saa = budget_av->budget.dev;
+ int cam_present = 0;
if (slot != 0)
return -EINVAL;
- if (!budget_av->slot_status) {
+ if (!budget_av->slot_status)
+ {
+ // first of all test the card detect line
saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
udelay(1);
if (saa7146_read(saa, PSR) & MASK_06)
{
+ cam_present = 1;
+ }
+ saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+
+ // that is unreliable however, so try and read from IO memory
+ if (!cam_present)
+ {
+ saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+ if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT)
+ {
+ cam_present = 1;
+ }
+ }
+
+ // did we find something?
+ if (cam_present) {
printk(KERN_INFO "budget-av: cam inserted\n");
budget_av->slot_status = 1;
}
- saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
} else if (!open) {
saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT)
@@ -484,6 +502,140 @@ static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
return 0;
}
+#define MIN2(a,b) ((a) < (b) ? (a) : (b))
+#define MIN3(a,b,c) MIN2(MIN2(a,b),c)
+
+static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct dvb_frontend_parameters *params)
+{
+ u8 reg0 [2] = { 0x00, 0x00 };
+ u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
+ u8 reg2 [3] = { 0x02, 0x00, 0x00 };
+ int _fband;
+ int first_ZF;
+ int R, A, N, P, M;
+ struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 };
+ int freq = params->frequency;
+
+ first_ZF = (freq) / 1000;
+
+ if (abs(MIN2(abs(first_ZF-1190),abs(first_ZF-1790))) <
+ abs(MIN3(abs(first_ZF-1202),abs(first_ZF-1542),abs(first_ZF-1890))))
+ _fband = 2;
+ else
+ _fband = 3;
+
+ if (_fband == 2) {
+ if (((first_ZF >= 950) && (first_ZF < 1350)) ||
+ ((first_ZF >= 1430) && (first_ZF < 1950)))
+ reg0[1] = 0x07;
+ else if (((first_ZF >= 1350) && (first_ZF < 1430)) ||
+ ((first_ZF >= 1950) && (first_ZF < 2150)))
+ reg0[1] = 0x0B;
+ }
+
+ if(_fband == 3) {
+ if (((first_ZF >= 950) && (first_ZF < 1350)) ||
+ ((first_ZF >= 1455) && (first_ZF < 1950)))
+ reg0[1] = 0x07;
+ else if (((first_ZF >= 1350) && (first_ZF < 1420)) ||
+ ((first_ZF >= 1950) && (first_ZF < 2150)))
+ reg0[1] = 0x0B;
+ else if ((first_ZF >= 1420) && (first_ZF < 1455))
+ reg0[1] = 0x0F;
+ }
+
+ if (first_ZF > 1525)
+ reg1[1] |= 0x80;
+ else
+ reg1[1] &= 0x7F;
+
+ if (_fband == 2) {
+ if (first_ZF > 1430) { /* 1430MHZ */
+ reg1[1] &= 0xCF; /* N2 */
+ reg2[1] &= 0xCF; /* R2 */
+ reg2[1] |= 0x10;
+ } else {
+ reg1[1] &= 0xCF; /* N2 */
+ reg1[1] |= 0x20;
+ reg2[1] &= 0xCF; /* R2 */
+ reg2[1] |= 0x10;
+ }
+ }
+
+ if (_fband == 3) {
+ if ((first_ZF >= 1455) &&
+ (first_ZF < 1630)) {
+ reg1[1] &= 0xCF; /* N2 */
+ reg1[1] |= 0x20;
+ reg2[1] &= 0xCF; /* R2 */
+ } else {
+ if (first_ZF < 1455) {
+ reg1[1] &= 0xCF; /* N2 */
+ reg1[1] |= 0x20;
+ reg2[1] &= 0xCF; /* R2 */
+ reg2[1] |= 0x10;
+ } else {
+ if (first_ZF >= 1630) {
+ reg1[1] &= 0xCF; /* N2 */
+ reg2[1] &= 0xCF; /* R2 */
+ reg2[1] |= 0x10;
+ }
+ }
+ }
+ }
+
+ /* set ports, enable P0 for symbol rates > 4Ms/s */
+ if (params->u.qpsk.symbol_rate >= 4000000)
+ reg1[1] |= 0x0c;
+ else
+ reg1[1] |= 0x04;
+
+ reg2[1] |= 0x0c;
+
+ R = 64;
+ A = 64;
+ P = 64; //32
+
+ M = (freq * R) / 4; /* in Mhz */
+ N = (M - A * 1000) / (P * 1000);
+
+ reg1[1] |= (N >> 9) & 0x03;
+ reg1[2] = (N >> 1) & 0xff;
+ reg1[3] = (N << 7) & 0x80;
+
+ reg2[1] |= (R >> 8) & 0x03;
+ reg2[2] = R & 0xFF; /* R */
+
+ reg1[3] |= A & 0x7f; /* A */
+
+ if (P == 64)
+ reg1[1] |= 0x40; /* Prescaler 64/65 */
+
+ reg0[1] |= 0x03;
+
+ /* already enabled - do not reenable i2c repeater or TX fails */
+ msg.buf = reg0;
+ msg.len = sizeof(reg0);
+ if (i2c_transfer(i2c, &msg, 1) != 1)
+ return -EIO;
+
+ stv0299_enable_plli2c(fe);
+ msg.buf = reg1;
+ msg.len = sizeof(reg1);
+ if (i2c_transfer(i2c, &msg, 1) != 1)
+ return -EIO;
+
+ stv0299_enable_plli2c(fe);
+ msg.buf = reg2;
+ msg.len = sizeof(reg2);
+ if (i2c_transfer(i2c, &msg, 1) != 1)
+ return -EIO;
+
+ return 0;
+}
+
static u8 typhoon_cinergy1200s_inittab[] = {
0x01, 0x15,
0x02, 0x30,
@@ -553,6 +705,18 @@ static struct stv0299_config cinergy_1200s_config = {
.pll_set = philips_su1278_ty_ci_pll_set,
};
+static struct stv0299_config cinergy_1200s_1894_0010_config = {
+ .demod_address = 0x68,
+ .inittab = typhoon_cinergy1200s_inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .skip_reinit = 0,
+ .lock_output = STV0229_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP0,
+ .min_delay_ms = 100,
+ .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
+ .pll_set = philips_su1278sh2_tua6100_pll_set,
+};
static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
@@ -749,6 +913,15 @@ static void frontend_init(struct budget_av *budget_av)
switch (saa->pci->subsystem_device) {
case SUBID_DVBS_KNC1:
+ if (saa->pci->subsystem_vendor == 0x1894) {
+ fe = stv0299_attach(&cinergy_1200s_1894_0010_config,
+ &budget_av->budget.i2c_adap);
+ } else {
+ fe = stv0299_attach(&typhoon_config,
+ &budget_av->budget.i2c_adap);
+ }
+ break;
+
case SUBID_DVBS_KNC1_PLUS:
case SUBID_DVBS_TYPHOON:
fe = stv0299_attach(&typhoon_config,
@@ -1003,6 +1176,7 @@ MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);
static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56),
MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010),
+ MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010),
MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),
MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index 017fcbccb8cc..633e68c341c8 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -404,9 +404,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
tasklet_init(&budget->vpe_tasklet, vpeirq, (unsigned long) budget);
/* frontend power on */
- if (bi->type == BUDGET_FS_ACTIVY)
- saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
- else
+ if (bi->type != BUDGET_FS_ACTIVY)
saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
if (budget_register(budget) == 0) {
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index fafe6407b3d0..238c77b52f89 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -112,6 +112,7 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long
* Routines for the Fujitsu Siemens Activy budget card
* 22 kHz tone and DiSEqC are handled by the frontend.
* Voltage must be set here.
+ * GPIO 1: LNBP EN, GPIO 2: LNBP VSEL
*/
static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
{
@@ -121,11 +122,16 @@ static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
switch (voltage) {
case SEC_VOLTAGE_13:
+ saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO);
break;
case SEC_VOLTAGE_18:
+ saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
break;
+ case SEC_VOLTAGE_OFF:
+ saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO);
+ break;
default:
return -EINVAL;
}
@@ -206,7 +212,7 @@ static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
return 0;
}
-static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, int arg)
+static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, long arg)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
u8 buf;
@@ -580,6 +586,7 @@ static void frontend_init(struct budget *budget)
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;
+ budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
if (lnbp21_init(budget)) {
printk("%s: No LNBP21 found!\n", __FUNCTION__);
goto error_out;
@@ -624,7 +631,7 @@ static void frontend_init(struct budget *budget)
budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
- break;
+ budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
}
break;
@@ -632,7 +639,7 @@ static void frontend_init(struct budget *budget)
budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
- break;
+ budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
}
break;
diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c
index 18aa22b5478d..1f31e91195b0 100644
--- a/drivers/media/dvb/ttpci/ttpci-eeprom.c
+++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c
@@ -13,7 +13,7 @@
Holger Waechtler Convergence
Copyright (C) 2002-2003 Ralph Metzler <rjkm@metzlerbros.de>
- Metzler Brothers Systementwicklung GbR
+ Metzler Brothers Systementwicklung GbR
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig
index c6c1d41a2efb..914587d52b57 100644
--- a/drivers/media/dvb/ttusb-budget/Kconfig
+++ b/drivers/media/dvb/ttusb-budget/Kconfig
@@ -10,7 +10,7 @@ config DVB_TTUSB_BUDGET
Support for external USB adapters designed by Technotrend and
produced by Hauppauge, shipped under the brand name 'Nova-USB'.
- These devices don't have a MPEG decoder built in, so you need
+ These devices don't have a MPEG decoder built in, so you need
an external software decoder to watch TV.
Say Y if you own such a device and want to use it.
diff --git a/drivers/media/dvb/ttusb-dec/Kconfig b/drivers/media/dvb/ttusb-dec/Kconfig
index c334526af66f..83611012ef34 100644
--- a/drivers/media/dvb/ttusb-dec/Kconfig
+++ b/drivers/media/dvb/ttusb-dec/Kconfig
@@ -8,14 +8,15 @@ config DVB_TTUSB_DEC
produced by Hauppauge, shipped under the brand name 'DEC2000-t'
and 'DEC3000-s'.
- Even if these devices have a MPEG decoder built in, they transmit
+ Even if these devices have a MPEG decoder built in, they transmit
only compressed MPEG data over the USB bus, so you need
an external software decoder to watch TV on your computer.
- This driver needs external firmware. Please use the commands
- "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2000t",
- "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2540t",
- "<kerneldir>/Documentation/dvb/get_dvb_firmware dec3000s",
- download/extract them, and then copy them to /usr/lib/hotplug/firmware.
+ This driver needs external firmware. Please use the commands
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2000t",
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2540t",
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware dec3000s",
+ download/extract them, and then copy them to /usr/lib/hotplug/firmware
+ or /lib/firmware (depending on configuration of firmware hotplug).
Say Y if you own such a device and want to use it.
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 8abc21890129..d8966d1d25ee 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -369,7 +369,7 @@ static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode,
static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data)
{
- struct ttusb_dec *dec = (struct ttusb_dec *)priv;
+ struct ttusb_dec *dec = priv;
dec->audio_filter->feed->cb.ts(data, 188, NULL, 0,
&dec->audio_filter->feed->feed.ts,
@@ -380,7 +380,7 @@ static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data)
static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data)
{
- struct ttusb_dec *dec = (struct ttusb_dec *)priv;
+ struct ttusb_dec *dec = priv;
dec->video_filter->feed->cb.ts(data, 188, NULL, 0,
&dec->video_filter->feed->feed.ts,
@@ -965,8 +965,8 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed)
case DMX_TS_PES_TELETEXT:
dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid;
- dprintk(" pes_type: DMX_TS_PES_TELETEXT\n");
- break;
+ dprintk(" pes_type: DMX_TS_PES_TELETEXT(not supported)\n");
+ return -ENOSYS;
case DMX_TS_PES_PCR:
dprintk(" pes_type: DMX_TS_PES_PCR\n");
@@ -975,8 +975,8 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed)
break;
case DMX_TS_PES_OTHER:
- dprintk(" pes_type: DMX_TS_PES_OTHER\n");
- break;
+ dprintk(" pes_type: DMX_TS_PES_OTHER(not supported)\n");
+ return -ENOSYS;
default:
dprintk(" pes_type: unknown (%d)\n", dvbdmxfeed->pes_type);
@@ -1182,7 +1182,7 @@ static void ttusb_dec_init_tasklet(struct ttusb_dec *dec)
(unsigned long)dec);
}
-static int ttusb_init_rc(struct ttusb_dec *dec)
+static int ttusb_init_rc( struct ttusb_dec *dec)
{
struct input_dev *input_dev;
u8 b[] = { 0x00, 0x01 };
@@ -1203,13 +1203,12 @@ static int ttusb_init_rc(struct ttusb_dec *dec)
input_dev->keycode = rc_keys;
for (i = 0; i < ARRAY_SIZE(rc_keys); i++)
- set_bit(rc_keys[i], input_dev->keybit);
+ set_bit(rc_keys[i], input_dev->keybit);
input_register_device(input_dev);
if (usb_submit_urb(dec->irq_urb, GFP_KERNEL))
printk("%s: usb_submit_urb failed\n",__FUNCTION__);
-
/* enable irq pipe */
ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL);
@@ -1395,6 +1394,7 @@ static int ttusb_dec_init_stb(struct ttusb_dec *dec)
/* We can't trust the USB IDs that some firmwares
give the box */
switch (model) {
+ case 0x00070001:
case 0x00070008:
case 0x0007000c:
ttusb_dec_set_model(dec, TTUSB_DEC3000S);
@@ -1588,7 +1588,7 @@ static int fe_send_command(struct dvb_frontend* fe, const u8 command,
int param_length, const u8 params[],
int *result_length, u8 cmd_result[])
{
- struct ttusb_dec* dec = (struct ttusb_dec*) fe->dvb->priv;
+ struct ttusb_dec* dec = fe->dvb->priv;
return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result);
}
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
index 725af3af5b27..a5a46175fa09 100644
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
@@ -42,8 +42,39 @@ struct ttusbdecfe_state {
static int ttusbdecfe_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
- *status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
- FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
+ struct ttusbdecfe_state* state = fe->demodulator_priv;
+ u8 b[] = { 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+ u8 result[4];
+ int len, ret;
+
+ *status=0;
+
+ ret=state->config->send_command(fe, 0x73, sizeof(b), b, &len, result);
+ if(ret)
+ return ret;
+
+ if(len != 4) {
+ printk(KERN_ERR "%s: unexpected reply\n", __FUNCTION__);
+ return -EIO;
+ }
+
+ switch(result[3]) {
+ case 1: /* not tuned yet */
+ case 2: /* no signal/no lock*/
+ break;
+ case 3: /* signal found and locked*/
+ *status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
+ FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
+ break;
+ case 4:
+ *status = FE_TIMEDOUT;
+ break;
+ default:
+ pr_info("%s: returned unknown value: %d\n",
+ __FUNCTION__, result[3]);
+ return -EIO;
+ }
return 0;
}
@@ -64,6 +95,16 @@ static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_fron
return 0;
}
+static int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe,
+ struct dvb_frontend_tune_settings* fesettings)
+{
+ fesettings->min_delay_ms = 1500;
+ /* Drift compensation makes no sense for DVB-T */
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
+ return 0;
+}
+
static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
@@ -212,6 +253,8 @@ static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = {
.set_frontend = ttusbdecfe_dvbt_set_frontend,
+ .get_tune_settings = ttusbdecfe_dvbt_get_tune_settings,
+
.read_status = ttusbdecfe_read_status,
};
@@ -223,11 +266,11 @@ static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = {
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 125,
+ .symbol_rate_min = 1000000, /* guessed */
+ .symbol_rate_max = 45000000, /* guessed */
.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_HIERARCHY_AUTO,
+ FE_CAN_QPSK
},
.release = ttusbdecfe_release,
diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c
index c2ebe8754a95..dc292da2605f 100644
--- a/drivers/media/radio/miropcm20-radio.c
+++ b/drivers/media/radio/miropcm20-radio.c
@@ -220,6 +220,7 @@ static struct file_operations pcm20_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = pcm20_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 877c770558e9..914deab4e044 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -299,6 +299,7 @@ static struct file_operations rtrack_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = rt_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 5319a9c9a979..523be820f9c6 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -256,6 +256,7 @@ static struct file_operations aztech_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = az_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 9b0406318f2d..f1b5ac81e9d2 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -490,6 +490,7 @@ static struct file_operations cadet_fops = {
.release = cadet_release,
.read = cadet_read,
.ioctl = cadet_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 630cc786d0a4..42c8fce04aa2 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -301,6 +301,7 @@ static struct file_operations gemtek_pci_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = gemtek_pci_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 6418f03b9ce4..47173be97b9f 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -233,6 +233,7 @@ static struct file_operations gemtek_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = gemtek_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index e5e2021a7312..c30effdf711f 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -72,6 +72,7 @@ static struct file_operations maestro_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = radio_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index 02d39a50d5ed..30869308332a 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -80,6 +80,7 @@ static struct file_operations maxiradio_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = radio_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
static struct video_device maxiradio_radio =
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index b2256d675b44..28a47c9e7a81 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -199,6 +199,7 @@ static struct file_operations rtrack2_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = rt_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 6f03ce4dd7b0..0229f792a059 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -225,6 +225,7 @@ static struct file_operations fmi_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = fmi_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 71971e9bb342..26632cead09a 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -356,6 +356,7 @@ static struct file_operations fmr2_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = fmr2_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index b03573c6840e..fcfde2e4f195 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -276,6 +276,7 @@ static struct file_operations terratec_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = tt_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index b300bedf7c74..5a099a50d4d0 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -255,6 +255,7 @@ static struct file_operations trust_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = tr_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index f304f3c14763..8ac9a8ef9094 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -261,6 +261,7 @@ static struct file_operations typhoon_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = typhoon_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index 4c6d6fb49034..d590e80c922e 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -313,6 +313,7 @@ static struct file_operations zoltrix_fops =
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = zol_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index fc87efc5049c..2fe260fff85d 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -7,6 +7,15 @@ menu "Video For Linux"
comment "Video Adapters"
+config VIDEO_ADV_DEBUG
+ bool "Enable advanced debug functionality"
+ depends on VIDEO_DEV
+ default n
+ ---help---
+ Say Y here to enable advanced debugging functionality on some
+ V4L devices.
+ In doubt, say N.
+
config VIDEO_BT848
tristate "BT848 Video For Linux"
depends on VIDEO_DEV && PCI && I2C
@@ -342,6 +351,6 @@ config VIDEO_DECODER
depends on VIDEO_DEV && I2C && EXPERIMENTAL
---help---
Say Y here to compile drivers for SAA7115, SAA7127 and CX25840
- video decoders.
+ video decoders.
endmenu
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 82060f9909d8..dd24896906fe 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -3,15 +3,19 @@
#
bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \
- bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o
+ bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \
+ bttv-input.o
zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o
zr36067-objs := zoran_procfs.o zoran_device.o \
zoran_driver.o zoran_card.o
tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o
-obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o
+
+msp3400-objs := msp3400-driver.o msp3400-kthreads.o
+
+obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o compat_ioctl32.o
obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \
- tda7432.o tda9875.o ir-kbd-i2c.o ir-kbd-gpio.o
+ tda7432.o tda9875.o ir-kbd-i2c.o
obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index 881cdcb1875d..7d5a068353f2 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -749,6 +749,7 @@ static struct file_operations ar_fops = {
.release = video_exclusive_release,
.read = ar_read,
.ioctl = ar_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c
index 1c3ff5f38a6d..dda4aa6bef27 100644
--- a/drivers/media/video/bt832.c
+++ b/drivers/media/video/bt832.c
@@ -30,8 +30,9 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/slab.h>
-
#include <media/audiochip.h>
+#include <media/v4l2-common.h>
+
#include "bttv.h"
#include "bt832.h"
@@ -42,9 +43,10 @@ static unsigned short normal_i2c[] = { I2C_BT832_ALT1>>1, I2C_BT832_ALT2>>1,
I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
-/* ---------------------------------------------------------------------- */
+int debug = 0; /* debug output */
+module_param(debug, int, 0644);
-#define dprintk if (debug) printk
+/* ---------------------------------------------------------------------- */
static int bt832_detach(struct i2c_client *client);
@@ -61,23 +63,26 @@ int bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf)
int i,rc;
buf[0]=0x80; // start at register 0 with auto-increment
if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
- printk("bt832: i2c i/o error: rc == %d (should be 1)\n",rc);
+ v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 1)\n",rc);
for(i=0;i<65;i++)
buf[i]=0;
if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
- printk("bt832: i2c i/o error: rc == %d (should be 65)\n",rc);
+ v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 65)\n",rc);
// Note: On READ the first byte is the current index
// (e.g. 0x80, what we just wrote)
- if(1) {
+ if(debug>1) {
int i;
- printk("BT832 hexdump:\n");
+ v4l_dbg(2,i2c_client_s,"hexdump:");
for(i=1;i<65;i++) {
if(i!=1) {
- if(((i-1)%8)==0) printk(" ");
- if(((i-1)%16)==0) printk("\n");
+ if(((i-1)%8)==0) printk(" ");
+ if(((i-1)%16)==0) {
+ printk("\n");
+ v4l_dbg(2,i2c_client_s,"hexdump:");
+ }
}
printk(" %02x",buf[i]);
}
@@ -96,56 +101,56 @@ int bt832_init(struct i2c_client *i2c_client_s)
bt832_hexdump(i2c_client_s,buf);
if(buf[0x40] != 0x31) {
- printk("bt832: this i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
+ v4l_err(i2c_client_s,"This i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
kfree(buf);
return 0;
}
- printk("Write 0 tp VPSTATUS\n");
+ v4l_err(i2c_client_s,"Write 0 tp VPSTATUS\n");
buf[0]=BT832_VP_STATUS; // Reg.52
buf[1]= 0x00;
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+ v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
bt832_hexdump(i2c_client_s,buf);
// Leave low power mode:
- printk("Bt832: leave low power mode.\n");
+ v4l_err(i2c_client_s,"leave low power mode.\n");
buf[0]=BT832_CAM_SETUP0; //0x39 57
buf[1]=0x08;
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- printk("bt832: i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
+ v4l_err(i2c_client_s,"i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
bt832_hexdump(i2c_client_s,buf);
- printk("Write 0 tp VPSTATUS\n");
+ v4l_info(i2c_client_s,"Write 0 tp VPSTATUS\n");
buf[0]=BT832_VP_STATUS; // Reg.52
buf[1]= 0x00;
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+ v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
bt832_hexdump(i2c_client_s,buf);
// Enable Output
- printk("Enable Output\n");
+ v4l_info(i2c_client_s,"Enable Output\n");
buf[0]=BT832_VP_CONTROL1; // Reg.40
buf[1]= 0x27 & (~0x01); // Default | !skip
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc);
+ v4l_err(i2c_client_s,"i2c i/o error EO: rc == %d (should be 2)\n",rc);
bt832_hexdump(i2c_client_s,buf);
// for testing (even works when no camera attached)
- printk("bt832: *** Generate NTSC M Bars *****\n");
+ v4l_info(i2c_client_s,"*** Generate NTSC M Bars *****\n");
buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
+ v4l_info(i2c_client_s,"i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
- printk("Bt832: Camera Present: %s\n",
+ v4l_info(i2c_client_s,"Camera Present: %s\n",
(buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");
bt832_hexdump(i2c_client_s,buf);
@@ -159,13 +164,9 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct bt832 *t;
- printk("bt832_attach\n");
-
client_template.adapter = adap;
client_template.addr = addr;
- printk("bt832: chip found @ 0x%x\n", addr<<1);
-
if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
return -ENOMEM;
memset(t,0,sizeof(*t));
@@ -173,6 +174,9 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
i2c_set_clientdata(&t->client, t);
i2c_attach_client(&t->client);
+ v4l_info(&t->client,"chip found @ 0x%x\n", addr<<1);
+
+
if(! bt832_init(&t->client)) {
bt832_detach(&t->client);
return -1;
@@ -183,13 +187,8 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
static int bt832_probe(struct i2c_adapter *adap)
{
-#ifdef I2C_CLASS_TV_ANALOG
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, bt832_attach);
-#else
- if (adap->id == I2C_HW_B_BT848)
- return i2c_probe(adap, &addr_data, bt832_attach);
-#endif
return 0;
}
@@ -197,7 +196,7 @@ static int bt832_detach(struct i2c_client *client)
{
struct bt832 *t = i2c_get_clientdata(client);
- printk("bt832: detach.\n");
+ v4l_info(&t->client,"dettach\n");
i2c_detach_client(client);
kfree(t);
return 0;
@@ -208,7 +207,8 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct bt832 *t = i2c_get_clientdata(client);
- printk("bt832: command %x\n",cmd);
+ if (debug>1)
+ v4l_i2c_print_ioctl(&t->client,cmd);
switch (cmd) {
case BT832_HEXDUMP: {
@@ -219,7 +219,7 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
}
break;
case BT832_REATTACH:
- printk("bt832: re-attach\n");
+ v4l_info(&t->client,"re-attach\n");
i2c_del_driver(&driver);
i2c_add_driver(&driver);
break;
@@ -231,9 +231,9 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
static struct i2c_driver driver = {
.driver = {
- .name = "i2c bt832 driver",
+ .name = "bt832",
},
- .id = -1, /* FIXME */
+ .id = 0, /* FIXME */
.attach_adapter = bt832_probe,
.detach_client = bt832_detach,
.command = bt832_command,
diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c
index 012be639aa18..1621ab133d23 100644
--- a/drivers/media/video/bttv-cards.c
+++ b/drivers/media/video/bttv-cards.c
@@ -38,6 +38,7 @@
#include <asm/io.h>
#include "bttvp.h"
+#include <media/v4l2-common.h>
/* fwd decl */
static void boot_msp34xx(struct bttv *btv, int pin);
@@ -292,6 +293,9 @@ static struct CARD {
/* likely broken, vendor id doesn't match the other magic views ...
* { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */
+ /* Duplicate PCI ID, reconfigure for this board during the eeprom read.
+ * { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB, "Hauppauge ImpactVCB" }, */
+
/* DVB cards (using pci function .1 for mpeg data xfer) */
{ 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
{ 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" },
@@ -2136,7 +2140,6 @@ struct tvcard bttv_tvcards[] = {
.has_remote = 1,
.gpiomask = 0x1b,
.no_gpioirq = 1,
- .any_irq = 1,
},
[BTTV_BOARD_PV143] = {
/* Jorge Boncompte - DTI2 <jorge@dti2.net> */
@@ -2817,6 +2820,22 @@ struct tvcard bttv_tvcards[] = {
.tuner_addr = ADDR_UNSET,
.has_radio = 1,
},
+ /* ---- card 0x8f ---------------------------------- */
+ [BTTV_BOARD_HAUPPAUGE_IMPACTVCB] = {
+ .name = "Hauppauge ImpactVCB (bt878)",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .gpiomask = 0x0f, /* old: 7 */
+ .muxsel = { 0, 1, 3, 2}, /* Composite 0-3 */
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
};
static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3037,26 +3056,33 @@ static void miro_pinnacle_gpio(struct bttv *btv)
switch (id) {
case 1:
info = "PAL / mono";
+ btv->tda9887_conf = TDA9887_INTERCARRIER;
break;
case 2:
info = "PAL+SECAM / stereo";
btv->has_radio = 1;
+ btv->tda9887_conf = TDA9887_QSS;
break;
case 3:
info = "NTSC / stereo";
btv->has_radio = 1;
+ btv->tda9887_conf = TDA9887_QSS;
break;
case 4:
info = "PAL+SECAM / mono";
+ btv->tda9887_conf = TDA9887_QSS;
break;
case 5:
info = "NTSC / mono";
+ btv->tda9887_conf = TDA9887_INTERCARRIER;
break;
case 6:
info = "NTSC / stereo";
+ btv->tda9887_conf = TDA9887_INTERCARRIER;
break;
case 7:
info = "PAL / stereo";
+ btv->tda9887_conf = TDA9887_INTERCARRIER;
break;
default:
info = "oops: unknown card";
@@ -3067,8 +3093,7 @@ static void miro_pinnacle_gpio(struct bttv *btv)
printk(KERN_INFO
"bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n",
btv->c.nr, id, info, btv->has_radio ? "yes" : "no");
- btv->tuner_type = 33;
- btv->pinnacle_id = id;
+ btv->tuner_type = TUNER_MT2032;
}
}
@@ -3370,9 +3395,9 @@ void __devinit bttv_init_card2(struct bttv *btv)
bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
}
- if (btv->pinnacle_id != UNSET) {
- bttv_call_i2c_clients(btv, AUDC_CONFIG_PINNACLE,
- &btv->pinnacle_id);
+ if (btv->tda9887_conf) {
+ bttv_call_i2c_clients(btv, TDA9887_SET_CONFIG,
+ &btv->tda9887_conf);
}
btv->svhs = bttv_tvcards[btv->c.type].svhs;
@@ -3387,8 +3412,6 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->has_remote=1;
if (!bttv_tvcards[btv->c.type].no_gpioirq)
btv->gpioirq=1;
- if (bttv_tvcards[btv->c.type].any_irq)
- btv->any_irq = 1;
if (bttv_tvcards[btv->c.type].audio_hook)
btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
@@ -3424,7 +3447,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
/* tuner modules */
tda9887 = 0;
- if (btv->pinnacle_id != UNSET)
+ if (btv->tda9887_conf)
tda9887 = 1;
if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb &&
bttv_I2CRead(btv, I2C_TDA9887, "TDA9887") >=0)
@@ -3471,6 +3494,21 @@ static void __devinit hauppauge_eeprom(struct bttv *btv)
tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data);
btv->tuner_type = tv.tuner_type;
btv->has_radio = tv.has_radio;
+
+ printk("bttv%d: Hauppauge eeprom indicates model#%d\n",
+ btv->c.nr, tv.model);
+
+ /*
+ * Some of the 878 boards have duplicate PCI IDs. Switch the board
+ * type based on model #.
+ */
+ if(tv.model == 64900) {
+ printk("bttv%d: Switching board type from %s to %s\n",
+ btv->c.nr,
+ bttv_tvcards[btv->c.type].name,
+ bttv_tvcards[BTTV_BOARD_HAUPPAUGE_IMPACTVCB].name);
+ btv->c.type = BTTV_BOARD_HAUPPAUGE_IMPACTVCB;
+ }
}
static int terratec_active_radio_upgrade(struct bttv *btv)
diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c
index 1ddf9ba613ef..0e6970346788 100644
--- a/drivers/media/video/bttv-driver.c
+++ b/drivers/media/video/bttv-driver.c
@@ -34,13 +34,14 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/kdev_t.h>
+#include "bttvp.h"
+#include <media/v4l2-common.h>
+
#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/byteorder.h>
-#include "bttvp.h"
-
#include "rds.h"
@@ -210,6 +211,9 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x20,
.vbipack = 255,
.sram = 0,
+ /* ITU-R frame line number of the first VBI line
+ we can capture, of the first and second field. */
+ .vbistart = { 7,320 },
},{
.v4l2_id = V4L2_STD_NTSC_M,
.name = "NTSC",
@@ -226,6 +230,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x1a,
.vbipack = 144,
.sram = 1,
+ .vbistart = { 10, 273 },
},{
.v4l2_id = V4L2_STD_SECAM,
.name = "SECAM",
@@ -242,6 +247,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x20,
.vbipack = 255,
.sram = 0, /* like PAL, correct? */
+ .vbistart = { 7, 320 },
},{
.v4l2_id = V4L2_STD_PAL_Nc,
.name = "PAL-Nc",
@@ -258,6 +264,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x1a,
.vbipack = 144,
.sram = -1,
+ .vbistart = { 7, 320 },
},{
.v4l2_id = V4L2_STD_PAL_M,
.name = "PAL-M",
@@ -274,6 +281,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x1a,
.vbipack = 144,
.sram = -1,
+ .vbistart = { 10, 273 },
},{
.v4l2_id = V4L2_STD_PAL_N,
.name = "PAL-N",
@@ -290,6 +298,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x20,
.vbipack = 144,
.sram = -1,
+ .vbistart = { 7, 320},
},{
.v4l2_id = V4L2_STD_NTSC_M_JP,
.name = "NTSC-JP",
@@ -306,6 +315,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x16,
.vbipack = 144,
.sram = -1,
+ .vbistart = {10, 273},
},{
/* that one hopefully works with the strange timing
* which video recorders produce when playing a NTSC
@@ -326,6 +336,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vbipack = 255,
.vtotal = 524,
.sram = -1,
+ .vbistart = { 10, 273 },
}
};
static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
@@ -1510,14 +1521,6 @@ static struct videobuf_queue_ops bttv_video_qops = {
.buf_release = buffer_release,
};
-static const char *v4l1_ioctls[] = {
- "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
- "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
- "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
- "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
- "SMICROCODE", "GVBIFMT", "SVBIFMT" };
-#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
-
static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
{
switch (cmd) {
@@ -2206,22 +2209,9 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
unsigned long flags;
int retval = 0;
- if (bttv_debug > 1) {
- switch (_IOC_TYPE(cmd)) {
- case 'v':
- printk("bttv%d: ioctl 0x%x (v4l1, VIDIOC%s)\n",
- btv->c.nr, cmd, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
- v4l1_ioctls[_IOC_NR(cmd)] : "???");
- break;
- case 'V':
- printk("bttv%d: ioctl 0x%x (v4l2, %s)\n",
- btv->c.nr, cmd, v4l2_ioctl_names[_IOC_NR(cmd)]);
- break;
- default:
- printk("bttv%d: ioctl 0x%x (???)\n",
- btv->c.nr, cmd);
- }
- }
+ if (bttv_debug > 1)
+ v4l_print_ioctl(btv->c.name, cmd);
+
if (btv->errors)
bttv_reinit_bt848(btv);
@@ -2570,10 +2560,10 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
fmt->count[0] = fmt2.fmt.vbi.count[0];
fmt->start[1] = fmt2.fmt.vbi.start[1];
fmt->count[1] = fmt2.fmt.vbi.count[1];
- if (fmt2.fmt.vbi.flags & VBI_UNSYNC)
- fmt->flags |= V4L2_VBI_UNSYNC;
- if (fmt2.fmt.vbi.flags & VBI_INTERLACED)
- fmt->flags |= V4L2_VBI_INTERLACED;
+ if (fmt2.fmt.vbi.flags & V4L2_VBI_UNSYNC)
+ fmt->flags |= VBI_UNSYNC;
+ if (fmt2.fmt.vbi.flags & V4L2_VBI_INTERLACED)
+ fmt->flags |= VBI_INTERLACED;
return 0;
}
case VIDIOCSVBIFMT:
@@ -3120,6 +3110,7 @@ static struct file_operations bttv_fops =
.open = bttv_open,
.release = bttv_release,
.ioctl = bttv_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
.read = bttv_read,
.mmap = bttv_mmap,
@@ -3229,6 +3220,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCSFREQ:
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
+ case VIDIOC_LOG_STATUS:
return bttv_common_ioctls(btv,cmd,arg);
default:
@@ -3701,8 +3693,8 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
btv=(struct bttv *)dev_id;
- if (btv->any_irq)
- handled = bttv_any_irq(&btv->c);
+ if (btv->custom_irq)
+ handled = btv->custom_irq(btv);
count=0;
while (1) {
@@ -3738,9 +3730,9 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
if (astat&BT848_INT_VSYNC)
btv->field_count++;
- if (astat & BT848_INT_GPINT) {
+ if ((astat & BT848_INT_GPINT) && btv->remote) {
wake_up(&btv->gpioq);
- bttv_gpio_irq(&btv->c);
+ bttv_input_irq(btv);
}
if (astat & BT848_INT_I2CDONE) {
@@ -3946,7 +3938,6 @@ static int __devinit bttv_probe(struct pci_dev *dev,
btv->i2c_rc = -1;
btv->tuner_type = UNSET;
- btv->pinnacle_id = UNSET;
btv->new_input = UNSET;
btv->has_radio=radio[btv->c.nr];
@@ -4065,11 +4056,11 @@ static int __devinit bttv_probe(struct pci_dev *dev,
}
/* add subdevices */
- if (btv->has_remote)
- bttv_sub_add_device(&btv->c, "remote");
if (bttv_tvcards[btv->c.type].has_dvb)
bttv_sub_add_device(&btv->c, "dvb");
+ bttv_input_init(btv);
+
/* everything is fine */
bttv_num++;
return 0;
@@ -4104,6 +4095,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
/* tell gpio modules we are leaving ... */
btv->shutdown=1;
wake_up(&btv->gpioq);
+ bttv_input_fini(btv);
bttv_sub_del_devices(&btv->c);
/* unregister i2c_bus + input */
@@ -4253,7 +4245,7 @@ static int bttv_init_module(void)
bttv_check_chipset();
bus_register(&bttv_sub_bus_type);
- return pci_module_init(&bttv_pci_driver);
+ return pci_register_driver(&bttv_pci_driver);
}
static void bttv_cleanup_module(void)
diff --git a/drivers/media/video/bttv-gpio.c b/drivers/media/video/bttv-gpio.c
index 616a5b7e510c..575ce8b8e714 100644
--- a/drivers/media/video/bttv-gpio.c
+++ b/drivers/media/video/bttv-gpio.c
@@ -113,24 +113,6 @@ void bttv_gpio_irq(struct bttv_core *core)
}
}
-int bttv_any_irq(struct bttv_core *core)
-{
- struct bttv_sub_driver *drv;
- struct bttv_sub_device *dev;
- struct list_head *item;
- int handled = 0;
-
- list_for_each(item,&core->subs) {
- dev = list_entry(item,struct bttv_sub_device,list);
- drv = to_bttv_sub_drv(dev->dev.driver);
- if (drv && drv->any_irq) {
- if (drv->any_irq(dev))
- handled = 1;
- }
- }
- return handled;
-}
-
/* ----------------------------------------------------------------------- */
/* external: sub-driver register/unregister */
diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c
index d6418c023d39..748d630c7fe4 100644
--- a/drivers/media/video/bttv-i2c.c
+++ b/drivers/media/video/bttv-i2c.c
@@ -28,10 +28,11 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/jiffies.h>
-#include <asm/io.h>
#include "bttvp.h"
+#include <media/v4l2-common.h>
+#include <linux/jiffies.h>
+#include <asm/io.h>
static struct i2c_algo_bit_data bttv_i2c_algo_bit_template;
static struct i2c_adapter bttv_i2c_adap_sw_template;
@@ -105,10 +106,8 @@ static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
static struct i2c_adapter bttv_i2c_adap_sw_template = {
.owner = THIS_MODULE,
-#ifdef I2C_CLASS_TV_ANALOG
.class = I2C_CLASS_TV_ANALOG,
-#endif
- .name = "bt848",
+ .name = "bttv",
.id = I2C_HW_B_BT848,
.client_register = attach_inform,
};
@@ -275,10 +274,8 @@ static struct i2c_algorithm bttv_algo = {
};
static struct i2c_adapter bttv_i2c_adap_hw_template = {
- .owner = THIS_MODULE,
-#ifdef I2C_CLASS_TV_ANALOG
+ .owner = THIS_MODULE,
.class = I2C_CLASS_TV_ANALOG,
-#endif
.name = "bt878",
.id = I2C_HW_B_BT848 /* FIXME */,
.algo = &bttv_algo,
@@ -441,12 +438,10 @@ int __devinit init_bttv_i2c(struct bttv *btv)
i2c_set_adapdata(&btv->c.i2c_adap, btv);
btv->i2c_client.adapter = &btv->c.i2c_adap;
-#ifdef I2C_CLASS_TV_ANALOG
if (bttv_tvcards[btv->c.type].no_video)
btv->c.i2c_adap.class &= ~I2C_CLASS_TV_ANALOG;
if (bttv_tvcards[btv->c.type].has_dvb)
btv->c.i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
-#endif
if (btv->use_i2c_hw) {
btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap);
diff --git a/drivers/media/video/ir-kbd-gpio.c b/drivers/media/video/bttv-input.c
index de1385e5d05e..12197f1b2757 100644
--- a/drivers/media/video/ir-kbd-gpio.c
+++ b/drivers/media/video/bttv-input.c
@@ -24,11 +24,9 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/input.h>
-#include <linux/pci.h>
-
-#include <media/ir-common.h>
#include "bttv.h"
+#include "bttvp.h"
/* ---------------------------------------------------------------------- */
@@ -156,9 +154,6 @@ static IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
/* ---------------------------------------------------------------------- */
-/* Ricardo Cerqueira <v4l@cerqueira.org> */
-/* Weird matching, since the remote has "uncommon" keys */
-
static IR_KEYTAB_TYPE ir_codes_conceptronic[IR_KEYTAB_SIZE] = {
[ 30 ] = KEY_POWER, // power
@@ -279,34 +274,6 @@ static IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = {
[0x36] = KEY_PC
};
-struct IR {
- struct bttv_sub_device *sub;
- struct input_dev *input;
- struct ir_input_state ir;
- char name[32];
- char phys[32];
-
- /* Usual gpio signalling */
-
- u32 mask_keycode;
- u32 mask_keydown;
- u32 mask_keyup;
- u32 polling;
- u32 last_gpio;
- struct work_struct work;
- struct timer_list timer;
-
- /* RC5 gpio */
- u32 rc5_gpio;
- struct timer_list timer_end; /* timer_end for code completion */
- struct timer_list timer_keyup; /* timer_end for key release */
- u32 last_rc5; /* last good rc5 code */
- u32 last_bit; /* last raw bit seen */
- u32 code; /* raw code under construction */
- struct timeval base_time; /* time of last seen code */
- int active; /* building raw code */
-};
-
static int debug;
module_param(debug, int, 0644); /* debug level (0,1,2) */
static int repeat_delay = 500;
@@ -314,31 +281,17 @@ module_param(repeat_delay, int, 0644);
static int repeat_period = 33;
module_param(repeat_period, int, 0644);
-#define DEVNAME "ir-kbd-gpio"
-#define dprintk(fmt, arg...) if (debug) \
- printk(KERN_DEBUG DEVNAME ": " fmt , ## arg)
-
-static void ir_irq(struct bttv_sub_device *sub);
-static int ir_probe(struct device *dev);
-static int ir_remove(struct device *dev);
-
-static struct bttv_sub_driver driver = {
- .drv = {
- .name = DEVNAME,
- .probe = ir_probe,
- .remove = ir_remove,
- },
- .gpio_irq = ir_irq,
-};
+#define DEVNAME "bttv-input"
/* ---------------------------------------------------------------------- */
-static void ir_handle_key(struct IR *ir)
+static void ir_handle_key(struct bttv *btv)
{
+ struct bttv_ir *ir = btv->remote;
u32 gpio,data;
/* read gpio value */
- gpio = bttv_gpio_read(ir->sub->core);
+ gpio = bttv_gpio_read(&btv->c);
if (ir->polling) {
if (ir->last_gpio == gpio)
return;
@@ -347,56 +300,36 @@ static void ir_handle_key(struct IR *ir)
/* extract data */
data = ir_extract_bits(gpio, ir->mask_keycode);
- dprintk(DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n",
+ dprintk(KERN_INFO DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n",
gpio, data,
ir->polling ? "poll" : "irq",
(gpio & ir->mask_keydown) ? " down" : "",
(gpio & ir->mask_keyup) ? " up" : "");
- if (ir->mask_keydown) {
- /* bit set on keydown */
- if (gpio & ir->mask_keydown) {
- ir_input_keydown(ir->input, &ir->ir, data, data);
- } else {
- ir_input_nokey(ir->input, &ir->ir);
- }
-
- } else if (ir->mask_keyup) {
- /* bit cleared on keydown */
- if (0 == (gpio & ir->mask_keyup)) {
- ir_input_keydown(ir->input, &ir->ir, data, data);
- } else {
- ir_input_nokey(ir->input, &ir->ir);
- }
-
+ if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
+ (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
+ ir_input_keydown(ir->dev,&ir->ir,data,data);
} else {
- /* can't disturgissh keydown/up :-/ */
- ir_input_keydown(ir->input, &ir->ir, data, data);
- ir_input_nokey(ir->input, &ir->ir);
+ ir_input_nokey(ir->dev,&ir->ir);
}
-}
-
-static void ir_irq(struct bttv_sub_device *sub)
-{
- struct IR *ir = dev_get_drvdata(&sub->dev);
- if (!ir->polling)
- ir_handle_key(ir);
}
-static void ir_timer(unsigned long data)
+void bttv_input_irq(struct bttv *btv)
{
- struct IR *ir = (struct IR*)data;
+ struct bttv_ir *ir = btv->remote;
- schedule_work(&ir->work);
+ if (!ir->polling)
+ ir_handle_key(btv);
}
-static void ir_work(void *data)
+static void bttv_input_timer(unsigned long data)
{
- struct IR *ir = data;
+ struct bttv *btv = (struct bttv*)data;
+ struct bttv_ir *ir = btv->remote;
unsigned long timeout;
- ir_handle_key(ir);
+ ir_handle_key(btv);
timeout = jiffies + (ir->polling * HZ / 1000);
mod_timer(&ir->timer, timeout);
}
@@ -435,26 +368,26 @@ static u32 rc5_decode(unsigned int code)
rc5 |= 1;
break;
case 3:
- dprintk("bad code: %x\n", org_code);
+ dprintk(KERN_WARNING "bad code: %x\n", org_code);
return 0;
}
}
- dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
+ dprintk(KERN_WARNING "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
"instr=%x\n", rc5, org_code, RC5_START(rc5),
RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
return rc5;
}
-static int ir_rc5_irq(struct bttv_sub_device *sub)
+static int bttv_rc5_irq(struct bttv *btv)
{
- struct IR *ir = dev_get_drvdata(&sub->dev);
+ struct bttv_ir *ir = btv->remote;
struct timeval tv;
u32 gpio;
u32 gap;
unsigned long current_jiffies, timeout;
/* read gpio port */
- gpio = bttv_gpio_read(ir->sub->core);
+ gpio = bttv_gpio_read(&btv->c);
/* remote IRQ? */
if (!(gpio & 0x20))
@@ -493,14 +426,15 @@ static int ir_rc5_irq(struct bttv_sub_device *sub)
}
/* toggle GPIO pin 4 to reset the irq */
- bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4));
- bttv_gpio_write(ir->sub->core, gpio | (1 << 4));
+ bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
+ bttv_gpio_write(&btv->c, gpio | (1 << 4));
return 1;
}
-static void ir_rc5_timer_end(unsigned long data)
+
+static void bttv_rc5_timer_end(unsigned long data)
{
- struct IR *ir = (struct IR *)data;
+ struct bttv_ir *ir = (struct bttv_ir *)data;
struct timeval tv;
unsigned long current_jiffies, timeout;
u32 gap;
@@ -519,20 +453,20 @@ static void ir_rc5_timer_end(unsigned long data)
/* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */
if (gap < 28000) {
- dprintk("spurious timer_end\n");
+ dprintk(KERN_WARNING "spurious timer_end\n");
return;
}
ir->active = 0;
if (ir->last_bit < 20) {
/* ignore spurious codes (caused by light/other remotes) */
- dprintk("short code: %x\n", ir->code);
+ dprintk(KERN_WARNING "short code: %x\n", ir->code);
} else {
u32 rc5 = rc5_decode(ir->code);
/* two start bits? */
if (RC5_START(rc5) != 3) {
- dprintk("rc5 start bits invalid: %u\n", RC5_START(rc5));
+ dprintk(KERN_WARNING "rc5 start bits invalid: %u\n", RC5_START(rc5));
/* right address? */
} else if (RC5_ADDR(rc5) == 0x0) {
@@ -542,10 +476,10 @@ static void ir_rc5_timer_end(unsigned long data)
/* Good code, decide if repeat/repress */
if (toggle != RC5_TOGGLE(ir->last_rc5) ||
instr != RC5_INSTR(ir->last_rc5)) {
- dprintk("instruction %x, toggle %x\n", instr,
+ dprintk(KERN_WARNING "instruction %x, toggle %x\n", instr,
toggle);
- ir_input_nokey(ir->input, &ir->ir);
- ir_input_keydown(ir->input, &ir->ir, instr,
+ ir_input_nokey(ir->dev, &ir->ir);
+ ir_input_keydown(ir->dev, &ir->ir, instr,
instr);
}
@@ -560,34 +494,37 @@ static void ir_rc5_timer_end(unsigned long data)
}
}
-static void ir_rc5_timer_keyup(unsigned long data)
+static void bttv_rc5_timer_keyup(unsigned long data)
{
- struct IR *ir = (struct IR *)data;
+ struct bttv_ir *ir = (struct bttv_ir *)data;
- dprintk("key released\n");
- ir_input_nokey(ir->input, &ir->ir);
+ dprintk(KERN_DEBUG "key released\n");
+ ir_input_nokey(ir->dev, &ir->ir);
}
/* ---------------------------------------------------------------------- */
-static int ir_probe(struct device *dev)
+int bttv_input_init(struct bttv *btv)
{
- struct bttv_sub_device *sub = to_bttv_sub_dev(dev);
- struct IR *ir;
- struct input_dev *input_dev;
+ struct bttv_ir *ir;
IR_KEYTAB_TYPE *ir_codes = NULL;
+ struct input_dev *input_dev;
int ir_type = IR_TYPE_OTHER;
- ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+ if (!btv->has_remote)
+ return -ENODEV;
+
+ ir = kzalloc(sizeof(*ir),GFP_KERNEL);
input_dev = input_allocate_device();
if (!ir || !input_dev) {
kfree(ir);
input_free_device(input_dev);
return -ENOMEM;
}
+ memset(ir,0,sizeof(*ir));
/* detect & configure */
- switch (sub->core->type) {
+ switch (btv->c.type) {
case BTTV_BOARD_AVERMEDIA:
case BTTV_BOARD_AVPHONE98:
case BTTV_BOARD_AVERMEDIA98:
@@ -643,12 +580,12 @@ static int ir_probe(struct device *dev)
break;
case BTTV_BOARD_NEBULA_DIGITV:
ir_codes = ir_codes_nebula;
- driver.any_irq = ir_rc5_irq;
- driver.gpio_irq = NULL;
+ btv->custom_irq = bttv_rc5_irq;
ir->rc5_gpio = 1;
break;
}
if (NULL == ir_codes) {
+ dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n",btv->c.type);
kfree(ir);
input_free_device(input_dev);
return -ENODEV;
@@ -657,109 +594,92 @@ static int ir_probe(struct device *dev)
if (ir->rc5_gpio) {
u32 gpio;
/* enable remote irq */
- bttv_gpio_inout(sub->core, (1 << 4), 1 << 4);
- gpio = bttv_gpio_read(sub->core);
- bttv_gpio_write(sub->core, gpio & ~(1 << 4));
- bttv_gpio_write(sub->core, gpio | (1 << 4));
+ bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4);
+ gpio = bttv_gpio_read(&btv->c);
+ bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
+ bttv_gpio_write(&btv->c, gpio | (1 << 4));
} else {
/* init hardware-specific stuff */
- bttv_gpio_inout(sub->core, ir->mask_keycode | ir->mask_keydown, 0);
+ bttv_gpio_inout(&btv->c, ir->mask_keycode | ir->mask_keydown, 0);
}
/* init input device */
+ ir->dev = input_dev;
+
snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)",
- sub->core->type);
+ btv->c.type);
snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
- pci_name(sub->core->pci));
+ pci_name(btv->c.pci));
ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
input_dev->name = ir->name;
input_dev->phys = ir->phys;
input_dev->id.bustype = BUS_PCI;
input_dev->id.version = 1;
- if (sub->core->pci->subsystem_vendor) {
- input_dev->id.vendor = sub->core->pci->subsystem_vendor;
- input_dev->id.product = sub->core->pci->subsystem_device;
+ if (btv->c.pci->subsystem_vendor) {
+ input_dev->id.vendor = btv->c.pci->subsystem_vendor;
+ input_dev->id.product = btv->c.pci->subsystem_device;
} else {
- input_dev->id.vendor = sub->core->pci->vendor;
- input_dev->id.product = sub->core->pci->device;
+ input_dev->id.vendor = btv->c.pci->vendor;
+ input_dev->id.product = btv->c.pci->device;
}
- input_dev->cdev.dev = &sub->core->pci->dev;
-
- ir->input = input_dev;
- ir->sub = sub;
+ input_dev->cdev.dev = &btv->c.pci->dev;
+ btv->remote = ir;
if (ir->polling) {
- INIT_WORK(&ir->work, ir_work, ir);
init_timer(&ir->timer);
- ir->timer.function = ir_timer;
- ir->timer.data = (unsigned long)ir;
- schedule_work(&ir->work);
+ ir->timer.function = bttv_input_timer;
+ ir->timer.data = (unsigned long)btv;
+ ir->timer.expires = jiffies + HZ;
+ add_timer(&ir->timer);
} else if (ir->rc5_gpio) {
/* set timer_end for code completion */
init_timer(&ir->timer_end);
- ir->timer_end.function = ir_rc5_timer_end;
+ ir->timer_end.function = bttv_rc5_timer_end;
ir->timer_end.data = (unsigned long)ir;
init_timer(&ir->timer_keyup);
- ir->timer_keyup.function = ir_rc5_timer_keyup;
+ ir->timer_keyup.function = bttv_rc5_timer_keyup;
ir->timer_keyup.data = (unsigned long)ir;
}
/* all done */
- dev_set_drvdata(dev, ir);
- input_register_device(ir->input);
+ input_register_device(btv->remote->dev);
+ printk(DEVNAME ": %s detected at %s\n",ir->name,ir->phys);
/* the remote isn't as bouncy as a keyboard */
- ir->input->rep[REP_DELAY] = repeat_delay;
- ir->input->rep[REP_PERIOD] = repeat_period;
+ ir->dev->rep[REP_DELAY] = repeat_delay;
+ ir->dev->rep[REP_PERIOD] = repeat_period;
return 0;
}
-static int ir_remove(struct device *dev)
+void bttv_input_fini(struct bttv *btv)
{
- struct IR *ir = dev_get_drvdata(dev);
+ if (btv->remote == NULL)
+ return;
- if (ir->polling) {
- del_timer(&ir->timer);
+ if (btv->remote->polling) {
+ del_timer_sync(&btv->remote->timer);
flush_scheduled_work();
}
- if (ir->rc5_gpio) {
+
+ if (btv->remote->rc5_gpio) {
u32 gpio;
- del_timer(&ir->timer_end);
+ del_timer_sync(&btv->remote->timer_end);
flush_scheduled_work();
- gpio = bttv_gpio_read(ir->sub->core);
- bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4));
+ gpio = bttv_gpio_read(&btv->c);
+ bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
}
- input_unregister_device(ir->input);
- kfree(ir);
- return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-MODULE_AUTHOR("Gerd Knorr, Pavel Machek");
-MODULE_DESCRIPTION("input driver for bt8x8 gpio IR remote controls");
-MODULE_LICENSE("GPL");
-
-static int ir_init(void)
-{
- return bttv_sub_register(&driver, "remote");
+ input_unregister_device(btv->remote->dev);
+ kfree(btv->remote);
+ btv->remote = NULL;
}
-static void ir_fini(void)
-{
- bttv_sub_unregister(&driver);
-}
-
-module_init(ir_init);
-module_exit(ir_fini);
-
/*
* Local variables:
diff --git a/drivers/media/video/bttv-vbi.c b/drivers/media/video/bttv-vbi.c
index f4f58c60f152..72afdd64b882 100644
--- a/drivers/media/video/bttv-vbi.c
+++ b/drivers/media/video/bttv-vbi.c
@@ -31,6 +31,12 @@
#include <asm/io.h>
#include "bttvp.h"
+/* Offset from line sync pulse leading edge (0H) in 1 / sampling_rate:
+ bt8x8 /HRESET pulse starts at 0H and has length 64 / fCLKx1 (E|O_VTC
+ HSFMT = 0). VBI_HDELAY (always 0) is an offset from the trailing edge
+ of /HRESET in 1 / fCLKx1, and the sampling_rate tvnorm->Fsc is fCLKx2. */
+#define VBI_OFFSET ((64 + 0) * 2)
+
#define VBI_DEFLINES 16
#define VBI_MAXLINES 32
@@ -163,40 +169,30 @@ void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines)
void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f)
{
const struct bttv_tvnorm *tvnorm;
- u32 start0,start1;
- s32 count0,count1,count;
+ s64 count0,count1,count;
tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
f->fmt.vbi.sampling_rate = tvnorm->Fsc;
f->fmt.vbi.samples_per_line = 2048;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- f->fmt.vbi.offset = 244;
+ f->fmt.vbi.offset = VBI_OFFSET;
f->fmt.vbi.flags = 0;
- switch (fh->btv->tvnorm) {
- case 1: /* NTSC */
- start0 = 10;
- start1 = 273;
- break;
- case 0: /* PAL */
- case 2: /* SECAM */
- default:
- start0 = 7;
- start1 = 320;
- }
- count0 = (f->fmt.vbi.start[0] + f->fmt.vbi.count[0]) - start0;
- count1 = (f->fmt.vbi.start[1] + f->fmt.vbi.count[1]) - start1;
- count = max(count0,count1);
- if (count > VBI_MAXLINES)
- count = VBI_MAXLINES;
- if (count < 1)
- count = 1;
+ /* s64 to prevent overflow. */
+ count0 = (s64) f->fmt.vbi.start[0] + f->fmt.vbi.count[0]
+ - tvnorm->vbistart[0];
+ count1 = (s64) f->fmt.vbi.start[1] + f->fmt.vbi.count[1]
+ - tvnorm->vbistart[1];
+ count = clamp (max (count0, count1), 1LL, (s64) VBI_MAXLINES);
- f->fmt.vbi.start[0] = start0;
- f->fmt.vbi.start[1] = start1;
+ f->fmt.vbi.start[0] = tvnorm->vbistart[0];
+ f->fmt.vbi.start[1] = tvnorm->vbistart[1];
f->fmt.vbi.count[0] = count;
f->fmt.vbi.count[1] = count;
+
+ f->fmt.vbi.reserved[0] = 0;
+ f->fmt.vbi.reserved[1] = 0;
}
void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
@@ -209,21 +205,12 @@ void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
f->fmt.vbi.sampling_rate = tvnorm->Fsc;
f->fmt.vbi.samples_per_line = 2048;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- f->fmt.vbi.offset = 244;
+ f->fmt.vbi.offset = VBI_OFFSET;
+ f->fmt.vbi.start[0] = tvnorm->vbistart[0];
+ f->fmt.vbi.start[1] = tvnorm->vbistart[1];
f->fmt.vbi.count[0] = fh->lines;
f->fmt.vbi.count[1] = fh->lines;
f->fmt.vbi.flags = 0;
- switch (fh->btv->tvnorm) {
- case 1: /* NTSC */
- f->fmt.vbi.start[0] = 10;
- f->fmt.vbi.start[1] = 273;
- break;
- case 0: /* PAL */
- case 2: /* SECAM */
- default:
- f->fmt.vbi.start[0] = 7;
- f->fmt.vbi.start[1] = 319;
- }
}
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h
index 93298f06e019..9feaa6bab207 100644
--- a/drivers/media/video/bttv.h
+++ b/drivers/media/video/bttv.h
@@ -16,6 +16,8 @@
#include <linux/videodev.h>
#include <linux/i2c.h>
+#include <media/ir-common.h>
+#include <media/ir-kbd-i2c.h>
/* ---------------------------------------------------------- */
/* exported by bttv-cards.c */
@@ -163,6 +165,7 @@
#define BTTV_BOARD_OSPREY440 0x8c
#define BTTV_BOARD_ASOUND_SKYEYE 0x8d
#define BTTV_BOARD_SABRENT_TVFM 0x8e
+#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f
/* i2c address list */
#define I2C_TSA5522 0xc2
@@ -210,6 +213,34 @@ struct bttv_core {
struct bttv;
+
+struct bttv_ir {
+ struct input_dev *dev;
+ struct ir_input_state ir;
+ char name[32];
+ char phys[32];
+
+ /* Usual gpio signalling */
+
+ u32 mask_keycode;
+ u32 mask_keydown;
+ u32 mask_keyup;
+ u32 polling;
+ u32 last_gpio;
+ struct work_struct work;
+ struct timer_list timer;
+
+ /* RC5 gpio */
+ u32 rc5_gpio;
+ struct timer_list timer_end; /* timer_end for code completion */
+ struct timer_list timer_keyup; /* timer_end for key release */
+ u32 last_rc5; /* last good rc5 code */
+ u32 last_bit; /* last raw bit seen */
+ u32 code; /* raw code under construction */
+ struct timeval base_time; /* time of last seen code */
+ int active; /* building raw code */
+};
+
struct tvcard
{
char *name;
@@ -235,7 +266,6 @@ struct tvcard
unsigned int has_dvb:1;
unsigned int has_remote:1;
unsigned int no_gpioirq:1;
- unsigned int any_irq:1;
/* other settings */
unsigned int pll;
@@ -335,7 +365,6 @@ struct bttv_sub_driver {
struct device_driver drv;
char wanted[BUS_ID_SIZE];
void (*gpio_irq)(struct bttv_sub_device *sub);
- int (*any_irq)(struct bttv_sub_device *sub);
};
#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
@@ -363,6 +392,10 @@ extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
unsigned char b2, int both);
extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr);
+extern int bttv_input_init(struct bttv *dev);
+extern void bttv_input_fini(struct bttv *dev);
+extern void bttv_input_irq(struct bttv *dev);
+
#endif /* _BTTV_H_ */
/*
* Local variables:
diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h
index 1e6a5632c3c7..dd00c20ab95e 100644
--- a/drivers/media/video/bttvp.h
+++ b/drivers/media/video/bttvp.h
@@ -73,6 +73,8 @@
#define UNSET (-1U)
+#define clamp(x, low, high) min (max (low, x), high)
+
/* ---------------------------------------------------------- */
struct bttv_tvnorm {
@@ -88,6 +90,9 @@ struct bttv_tvnorm {
u8 vbipack;
u16 vtotal;
int sram;
+ /* ITU-R frame line number of the first VBI line we can
+ capture, of the first and second field. */
+ u16 vbistart[2];
};
extern const struct bttv_tvnorm bttv_tvnorms[];
@@ -209,7 +214,6 @@ extern struct bus_type bttv_sub_bus_type;
int bttv_sub_add_device(struct bttv_core *core, char *name);
int bttv_sub_del_devices(struct bttv_core *core);
void bttv_gpio_irq(struct bttv_core *core);
-int bttv_any_irq(struct bttv_core *core);
/* ---------------------------------------------------------- */
@@ -270,12 +274,13 @@ struct bttv {
/* card configuration info */
unsigned int cardid; /* pci subsystem id (bt878 based ones) */
unsigned int tuner_type; /* tuner chip type */
- unsigned int pinnacle_id;
+ unsigned int tda9887_conf;
unsigned int svhs;
struct bttv_pll_info pll;
int triton1;
int gpioirq;
- int any_irq;
+ int (*custom_irq)(struct bttv *btv);
+
int use_i2c_hw;
/* old gpio interface */
@@ -300,7 +305,7 @@ struct bttv {
/* infrared remote */
int has_remote;
- struct bttv_input *remote;
+ struct bttv_ir *remote;
/* locking */
spinlock_t s_lock;
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 0065d0c240d1..6bad93ef969f 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -875,6 +875,7 @@ static struct file_operations qcam_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = qcam_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.read = qcam_read,
.llseek = no_llseek,
};
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 75442ec49f35..9976db4f6da8 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -687,6 +687,7 @@ static struct file_operations qcam_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = qcam_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.read = qcam_read,
.llseek = no_llseek,
};
diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c
new file mode 100644
index 000000000000..6194b0125576
--- /dev/null
+++ b/drivers/media/video/compat_ioctl32.c
@@ -0,0 +1,732 @@
+/*
+ * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
+ * Separated from fs stuff by Arnd Bergmann <arnd@arndb.de>
+ *
+ * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
+ * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
+ * Copyright (C) 2003 Pavel Machek (pavel@suse.cz)
+ * Copyright (C) 2005 Philippe De Muyter (phdm@macqel.be)
+ *
+ * These routines maintain argument size conversion between 32bit and 64bit
+ * ioctls.
+ */
+
+#include <linux/config.h>
+#include <linux/compat.h>
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+
+#ifdef CONFIG_COMPAT
+struct video_tuner32 {
+ compat_int_t tuner;
+ char name[32];
+ compat_ulong_t rangelow, rangehigh;
+ u32 flags; /* It is really u32 in videodev.h */
+ u16 mode, signal;
+};
+
+static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
+{
+ if(get_user(kp->tuner, &up->tuner))
+ return -EFAULT;
+ __copy_from_user(kp->name, up->name, 32);
+ __get_user(kp->rangelow, &up->rangelow);
+ __get_user(kp->rangehigh, &up->rangehigh);
+ __get_user(kp->flags, &up->flags);
+ __get_user(kp->mode, &up->mode);
+ __get_user(kp->signal, &up->signal);
+ return 0;
+}
+
+static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
+{
+ if(put_user(kp->tuner, &up->tuner))
+ return -EFAULT;
+ __copy_to_user(up->name, kp->name, 32);
+ __put_user(kp->rangelow, &up->rangelow);
+ __put_user(kp->rangehigh, &up->rangehigh);
+ __put_user(kp->flags, &up->flags);
+ __put_user(kp->mode, &up->mode);
+ __put_user(kp->signal, &up->signal);
+ return 0;
+}
+
+struct video_buffer32 {
+ compat_caddr_t base;
+ compat_int_t height, width, depth, bytesperline;
+};
+
+static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
+{
+ u32 tmp;
+
+ if (get_user(tmp, &up->base))
+ return -EFAULT;
+
+ /* This is actually a physical address stored
+ * as a void pointer.
+ */
+ kp->base = (void *)(unsigned long) tmp;
+
+ __get_user(kp->height, &up->height);
+ __get_user(kp->width, &up->width);
+ __get_user(kp->depth, &up->depth);
+ __get_user(kp->bytesperline, &up->bytesperline);
+ return 0;
+}
+
+static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
+{
+ u32 tmp = (u32)((unsigned long)kp->base);
+
+ if(put_user(tmp, &up->base))
+ return -EFAULT;
+ __put_user(kp->height, &up->height);
+ __put_user(kp->width, &up->width);
+ __put_user(kp->depth, &up->depth);
+ __put_user(kp->bytesperline, &up->bytesperline);
+ return 0;
+}
+
+struct video_clip32 {
+ s32 x, y, width, height; /* Its really s32 in videodev.h */
+ compat_caddr_t next;
+};
+
+struct video_window32 {
+ u32 x, y, width, height, chromakey, flags;
+ compat_caddr_t clips;
+ compat_int_t clipcount;
+};
+
+static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int ret = -ENOIOCTLCMD;
+
+ if (file->f_op->unlocked_ioctl)
+ ret = file->f_op->unlocked_ioctl(file, cmd, arg);
+ else if (file->f_op->ioctl) {
+ lock_kernel();
+ ret = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, arg);
+ unlock_kernel();
+ }
+
+ return ret;
+}
+
+
+/* You get back everything except the clips... */
+static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
+{
+ if(put_user(kp->x, &up->x))
+ return -EFAULT;
+ __put_user(kp->y, &up->y);
+ __put_user(kp->width, &up->width);
+ __put_user(kp->height, &up->height);
+ __put_user(kp->chromakey, &up->chromakey);
+ __put_user(kp->flags, &up->flags);
+ __put_user(kp->clipcount, &up->clipcount);
+ return 0;
+}
+
+struct v4l2_clip32
+{
+ struct v4l2_rect c;
+ compat_caddr_t next;
+};
+
+struct v4l2_window32
+{
+ struct v4l2_rect w;
+ enum v4l2_field field;
+ __u32 chromakey;
+ compat_caddr_t clips; /* actually struct v4l2_clip32 * */
+ __u32 clipcount;
+ compat_caddr_t bitmap;
+};
+
+static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+{
+ if (copy_from_user(&kp->w, &up->w, sizeof(up->w)))
+ return -EFAULT;
+ __get_user(kp->field, &up->field);
+ __get_user(kp->chromakey, &up->chromakey);
+ __get_user(kp->clipcount, &up->clipcount);
+ if (kp->clipcount > 2048)
+ return -EINVAL;
+ if (kp->clipcount) {
+ struct v4l2_clip32 *uclips = compat_ptr(up->clips);
+ struct v4l2_clip *kclips;
+ int n = kp->clipcount;
+
+ kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
+ kp->clips = kclips;
+ while (--n >= 0) {
+ copy_from_user(&kclips->c, &uclips->c, sizeof(uclips->c));
+ kclips->next = n ? kclips + 1 : 0;
+ uclips += 1;
+ kclips += 1;
+ }
+ } else
+ kp->clips = 0;
+ return 0;
+}
+
+static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+{
+ if (copy_to_user(&up->w, &kp->w, sizeof(up->w)))
+ return -EFAULT;
+ __put_user(kp->field, &up->field);
+ __put_user(kp->chromakey, &up->chromakey);
+ __put_user(kp->clipcount, &up->clipcount);
+ return 0;
+}
+
+static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
+{
+ return copy_from_user(kp, up, sizeof(struct v4l2_pix_format));
+}
+
+static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
+{
+ return copy_to_user(up, kp, sizeof(struct v4l2_pix_format));
+}
+
+static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
+{
+ return copy_from_user(kp, up, sizeof(struct v4l2_vbi_format));
+}
+
+static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
+{
+ return copy_to_user(up, kp, sizeof(struct v4l2_vbi_format));
+}
+
+struct v4l2_format32
+{
+ enum v4l2_buf_type type;
+ union
+ {
+ struct v4l2_pix_format pix; // V4L2_BUF_TYPE_VIDEO_CAPTURE
+ struct v4l2_window32 win; // V4L2_BUF_TYPE_VIDEO_OVERLAY
+ struct v4l2_vbi_format vbi; // V4L2_BUF_TYPE_VBI_CAPTURE
+ __u8 raw_data[200]; // user-defined
+ } fmt;
+};
+
+static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+{
+ if(get_user(kp->type, &up->type))
+ return -EFAULT;
+ switch (kp->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+ default:
+ printk("compat_ioctl : unexpected VIDIOC_FMT type %d\n",
+ kp->type);
+ return -ENXIO;
+ }
+}
+
+static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+{
+ if(put_user(kp->type, &up->type))
+ return -EFAULT;
+ switch (kp->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+ default:
+ return -ENXIO;
+ }
+}
+
+struct v4l2_standard32
+{
+ __u32 index;
+ __u32 id[2]; /* __u64 would get the alignment wrong */
+ __u8 name[24];
+ struct v4l2_fract frameperiod; /* Frames, not fields */
+ __u32 framelines;
+ __u32 reserved[4];
+};
+
+static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+{
+ /* other fields are not set by the user, nor used by the driver */
+ return get_user(kp->index, &up->index);
+}
+
+static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+{
+ if(put_user(kp->index, &up->index))
+ return -EFAULT;
+ __copy_to_user(up->id, &kp->id, sizeof(__u64));
+ __copy_to_user(up->name, kp->name, 24);
+ __put_user(kp->frameperiod, &up->frameperiod);
+ __put_user(kp->framelines, &up->framelines);
+ __copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32));
+ return 0;
+}
+
+struct v4l2_buffer32
+{
+ __u32 index;
+ enum v4l2_buf_type type;
+ __u32 bytesused;
+ __u32 flags;
+ enum v4l2_field field;
+ struct compat_timeval timestamp;
+ struct v4l2_timecode timecode;
+ __u32 sequence;
+
+ /* memory location */
+ enum v4l2_memory memory;
+ union {
+ __u32 offset;
+ compat_long_t userptr;
+ } m;
+ __u32 length;
+ __u32 input;
+ __u32 reserved;
+};
+
+static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
+{
+
+ if (get_user(kp->index, &up->index))
+ return -EFAULT;
+ __get_user(kp->type, &up->type);
+ __get_user(kp->flags, &up->flags);
+ __get_user(kp->memory, &up->memory);
+ __get_user(kp->input, &up->input);
+ switch(kp->memory) {
+ case V4L2_MEMORY_MMAP:
+ break;
+ case V4L2_MEMORY_USERPTR:
+ {
+ unsigned long tmp = (unsigned long)compat_ptr(up->m.userptr);
+
+ __get_user(kp->length, &up->length);
+ __get_user(kp->m.userptr, &tmp);
+ }
+ break;
+ case V4L2_MEMORY_OVERLAY:
+ __get_user(kp->m.offset, &up->m.offset);
+ break;
+ }
+ return 0;
+}
+
+static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
+{
+ if (put_user(kp->index, &up->index))
+ return -EFAULT;
+ __put_user(kp->type, &up->type);
+ __put_user(kp->flags, &up->flags);
+ __put_user(kp->memory, &up->memory);
+ __put_user(kp->input, &up->input);
+ switch(kp->memory) {
+ case V4L2_MEMORY_MMAP:
+ __put_user(kp->length, &up->length);
+ __put_user(kp->m.offset, &up->m.offset);
+ break;
+ case V4L2_MEMORY_USERPTR:
+ __put_user(kp->length, &up->length);
+ __put_user(kp->m.userptr, &up->m.userptr);
+ break;
+ case V4L2_MEMORY_OVERLAY:
+ __put_user(kp->m.offset, &up->m.offset);
+ break;
+ }
+ __put_user(kp->bytesused, &up->bytesused);
+ __put_user(kp->field, &up->field);
+ __put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec);
+ __put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec);
+ __copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode));
+ __put_user(kp->sequence, &up->sequence);
+ __put_user(kp->reserved, &up->reserved);
+ return 0;
+}
+
+struct v4l2_framebuffer32
+{
+ __u32 capability;
+ __u32 flags;
+ compat_caddr_t base;
+ struct v4l2_pix_format fmt;
+};
+
+static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
+{
+ u32 tmp;
+
+ if (get_user(tmp, &up->base))
+ return -EFAULT;
+ kp->base = compat_ptr(tmp);
+ __get_user(kp->capability, &up->capability);
+ __get_user(kp->flags, &up->flags);
+ get_v4l2_pix_format(&kp->fmt, &up->fmt);
+ return 0;
+}
+
+static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
+{
+ u32 tmp = (u32)((unsigned long)kp->base);
+
+ if(put_user(tmp, &up->base))
+ return -EFAULT;
+ __put_user(kp->capability, &up->capability);
+ __put_user(kp->flags, &up->flags);
+ put_v4l2_pix_format(&kp->fmt, &up->fmt);
+ return 0;
+}
+
+struct v4l2_input32 /* identical layout, but different size */
+{
+ __u32 index; /* Which input */
+ __u8 name[32]; /* Label */
+ __u32 type; /* Type of input */
+ __u32 audioset; /* Associated audios (bitfield) */
+ __u32 tuner; /* Associated tuner */
+ __u32 std[2]; /* __u64 would get the padding wrong */
+ __u32 status;
+ __u32 reserved[4];
+};
+
+#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32)
+#define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32)
+#define VIDIOCGWIN32 _IOR('v',9, struct video_window32)
+#define VIDIOCSWIN32 _IOW('v',10, struct video_window32)
+#define VIDIOCGFBUF32 _IOR('v',11, struct video_buffer32)
+#define VIDIOCSFBUF32 _IOW('v',12, struct video_buffer32)
+#define VIDIOCGFREQ32 _IOR('v',14, u32)
+#define VIDIOCSFREQ32 _IOW('v',15, u32)
+
+#define VIDIOC_G_FMT32 _IOWR ('V', 4, struct v4l2_format32)
+#define VIDIOC_S_FMT32 _IOWR ('V', 5, struct v4l2_format32)
+#define VIDIOC_QUERYBUF32 _IOWR ('V', 9, struct v4l2_buffer32)
+#define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32)
+#define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32)
+/* VIDIOC_OVERLAY is now _IOW, but was _IOWR */
+#define VIDIOC_OVERLAY32 _IOWR ('V', 14, compat_int_t)
+#define VIDIOC_QBUF32 _IOWR ('V', 15, struct v4l2_buffer32)
+#define VIDIOC_DQBUF32 _IOWR ('V', 17, struct v4l2_buffer32)
+#define VIDIOC_STREAMON32 _IOW ('V', 18, compat_int_t)
+#define VIDIOC_STREAMOFF32 _IOW ('V', 19, compat_int_t)
+#define VIDIOC_ENUMSTD32 _IOWR ('V', 25, struct v4l2_standard32)
+#define VIDIOC_ENUMINPUT32 _IOWR ('V', 26, struct v4l2_input32)
+/* VIDIOC_S_CTRL is now _IOWR, but was _IOW */
+#define VIDIOC_S_CTRL32 _IOW ('V', 28, struct v4l2_control)
+#define VIDIOC_G_INPUT32 _IOR ('V', 38, compat_int_t)
+#define VIDIOC_S_INPUT32 _IOWR ('V', 39, compat_int_t)
+#define VIDIOC_TRY_FMT32 _IOWR ('V', 64, struct v4l2_format32)
+
+enum {
+ MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip)
+};
+
+static int do_set_window(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct video_window32 __user *up = compat_ptr(arg);
+ struct video_window __user *vw;
+ struct video_clip __user *p;
+ int nclips;
+ u32 n;
+
+ if (get_user(nclips, &up->clipcount))
+ return -EFAULT;
+
+ /* Peculiar interface... */
+ if (nclips < 0)
+ nclips = VIDEO_CLIPMAP_SIZE;
+
+ if (nclips > MaxClips)
+ return -ENOMEM;
+
+ vw = compat_alloc_user_space(sizeof(struct video_window) +
+ nclips * sizeof(struct video_clip));
+
+ p = nclips ? (struct video_clip __user *)(vw + 1) : NULL;
+
+ if (get_user(n, &up->x) || put_user(n, &vw->x) ||
+ get_user(n, &up->y) || put_user(n, &vw->y) ||
+ get_user(n, &up->width) || put_user(n, &vw->width) ||
+ get_user(n, &up->height) || put_user(n, &vw->height) ||
+ get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) ||
+ get_user(n, &up->flags) || put_user(n, &vw->flags) ||
+ get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) ||
+ get_user(n, &up->clips) || put_user(p, &vw->clips))
+ return -EFAULT;
+
+ if (nclips) {
+ struct video_clip32 __user *u = compat_ptr(n);
+ int i;
+ if (!u)
+ return -EINVAL;
+ for (i = 0; i < nclips; i++, u++, p++) {
+ s32 v;
+ if (get_user(v, &u->x) ||
+ put_user(v, &p->x) ||
+ get_user(v, &u->y) ||
+ put_user(v, &p->y) ||
+ get_user(v, &u->width) ||
+ put_user(v, &p->width) ||
+ get_user(v, &u->height) ||
+ put_user(v, &p->height) ||
+ put_user(NULL, &p->next))
+ return -EFAULT;
+ }
+ }
+
+ return native_ioctl(file, VIDIOCSWIN, (unsigned long)vw);
+}
+
+static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ union {
+ struct video_tuner vt;
+ struct video_buffer vb;
+ struct video_window vw;
+ struct v4l2_format v2f;
+ struct v4l2_buffer v2b;
+ struct v4l2_framebuffer v2fb;
+ struct v4l2_standard v2s;
+ unsigned long vx;
+ } karg;
+ void __user *up = compat_ptr(arg);
+ int compatible_arg = 1;
+ int err = 0;
+
+ /* First, convert the command. */
+ switch(cmd) {
+ case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
+ case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
+ case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
+ case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
+ case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
+ case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
+ case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
+ case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
+ case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
+ case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
+ case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
+ case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
+ case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
+ case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
+ case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
+ case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
+ case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
+ case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
+ case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
+ case VIDIOC_S_CTRL32: cmd = VIDIOC_S_CTRL; break;
+ case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
+ case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
+ case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
+ };
+
+ switch(cmd) {
+ case VIDIOCSTUNER:
+ case VIDIOCGTUNER:
+ err = get_video_tuner32(&karg.vt, up);
+ compatible_arg = 0;
+
+ break;
+
+ case VIDIOCSFBUF:
+ err = get_video_buffer32(&karg.vb, up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOCSFREQ:
+ case VIDIOC_S_INPUT:
+ case VIDIOC_OVERLAY:
+ case VIDIOC_STREAMON:
+ case VIDIOC_STREAMOFF:
+ err = get_user(karg.vx, (u32 __user *)up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_S_FBUF:
+ err = get_v4l2_framebuffer32(&karg.v2fb, up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_G_FMT:
+ case VIDIOC_S_FMT:
+ case VIDIOC_TRY_FMT:
+ err = get_v4l2_format32(&karg.v2f, up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_QUERYBUF:
+ case VIDIOC_QBUF:
+ case VIDIOC_DQBUF:
+ err = get_v4l2_buffer32(&karg.v2b, up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_ENUMSTD:
+ err = get_v4l2_standard32(&karg.v2s, up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOCGWIN:
+ case VIDIOCGFBUF:
+ case VIDIOCGFREQ:
+ case VIDIOC_G_FBUF:
+ case VIDIOC_G_INPUT:
+ compatible_arg = 0;
+ };
+
+ if(err)
+ goto out;
+
+ if(compatible_arg)
+ err = native_ioctl(file, cmd, (unsigned long)up);
+ else {
+ mm_segment_t old_fs = get_fs();
+
+ set_fs(KERNEL_DS);
+ err = native_ioctl(file, cmd, (unsigned long)&karg);
+ set_fs(old_fs);
+ }
+ if(err == 0) {
+ switch(cmd) {
+ case VIDIOCGTUNER:
+ err = put_video_tuner32(&karg.vt, up);
+ break;
+
+ case VIDIOCGWIN:
+ err = put_video_window32(&karg.vw, up);
+ break;
+
+ case VIDIOCGFBUF:
+ err = put_video_buffer32(&karg.vb, up);
+ break;
+
+ case VIDIOC_G_FBUF:
+ err = put_v4l2_framebuffer32(&karg.v2fb, up);
+ break;
+
+ case VIDIOC_G_FMT:
+ case VIDIOC_S_FMT:
+ case VIDIOC_TRY_FMT:
+ err = put_v4l2_format32(&karg.v2f, up);
+ break;
+
+ case VIDIOC_QUERYBUF:
+ case VIDIOC_QBUF:
+ case VIDIOC_DQBUF:
+ err = put_v4l2_buffer32(&karg.v2b, up);
+ break;
+
+ case VIDIOC_ENUMSTD:
+ err = put_v4l2_standard32(&karg.v2s, up);
+ break;
+
+ case VIDIOCGFREQ:
+ case VIDIOC_G_INPUT:
+ err = put_user(((u32)karg.vx), (u32 __user *)up);
+ break;
+ };
+ }
+out:
+ return err;
+}
+
+long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int ret = -ENOIOCTLCMD;
+
+ if (!file->f_op->ioctl)
+ return ret;
+
+ switch (cmd) {
+ case VIDIOCSWIN32:
+ ret = do_set_window(file, cmd, arg);
+ break;
+ case VIDIOCGTUNER32:
+ case VIDIOCSTUNER32:
+ case VIDIOCGWIN32:
+ case VIDIOCGFBUF32:
+ case VIDIOCSFBUF32:
+ case VIDIOCGFREQ32:
+ case VIDIOCSFREQ32:
+ case VIDIOC_QUERYCAP:
+ case VIDIOC_ENUM_FMT:
+ case VIDIOC_G_FMT32:
+ case VIDIOC_S_FMT32:
+ case VIDIOC_REQBUFS:
+ case VIDIOC_QUERYBUF32:
+ case VIDIOC_G_FBUF32:
+ case VIDIOC_S_FBUF32:
+ case VIDIOC_OVERLAY32:
+ case VIDIOC_QBUF32:
+ case VIDIOC_DQBUF32:
+ case VIDIOC_STREAMON32:
+ case VIDIOC_STREAMOFF32:
+ case VIDIOC_G_PARM:
+ case VIDIOC_G_STD:
+ case VIDIOC_S_STD:
+ case VIDIOC_ENUMSTD32:
+ case VIDIOC_ENUMINPUT32:
+ case VIDIOC_G_CTRL:
+ case VIDIOC_S_CTRL32:
+ case VIDIOC_QUERYCTRL:
+ case VIDIOC_G_INPUT32:
+ case VIDIOC_S_INPUT32:
+ case VIDIOC_TRY_FMT32:
+ ret = do_video_ioctl(file, cmd, arg);
+ break;
+
+ /* Little v, the video4linux ioctls (conflict?) */
+ case VIDIOCGCAP:
+ case VIDIOCGCHAN:
+ case VIDIOCSCHAN:
+ case VIDIOCGPICT:
+ case VIDIOCSPICT:
+ case VIDIOCCAPTURE:
+ case VIDIOCKEY:
+ case VIDIOCGAUDIO:
+ case VIDIOCSAUDIO:
+ case VIDIOCSYNC:
+ case VIDIOCMCAPTURE:
+ case VIDIOCGMBUF:
+ case VIDIOCGUNIT:
+ case VIDIOCGCAPTURE:
+ case VIDIOCSCAPTURE:
+
+ /* BTTV specific... */
+ case _IOW('v', BASE_VIDIOCPRIVATE+0, char [256]):
+ case _IOR('v', BASE_VIDIOCPRIVATE+1, char [256]):
+ case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int):
+ case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */
+ case _IOR('v' , BASE_VIDIOCPRIVATE+4, int):
+ case _IOR('v' , BASE_VIDIOCPRIVATE+5, int):
+ case _IOR('v' , BASE_VIDIOCPRIVATE+6, int):
+ case _IOR('v' , BASE_VIDIOCPRIVATE+7, int):
+ ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+ break;
+ }
+ return ret;
+}
+#else
+long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ return -ENOIOCTLCMD;
+}
+#endif
+EXPORT_SYMBOL_GPL(v4l_compat_ioctl32);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index b7ec9bf45085..9f59541155d9 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -3807,6 +3807,7 @@ static struct file_operations cpia_fops = {
.read = cpia_read,
.mmap = cpia_mmap,
.ioctl = cpia_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
index 643ead1a87ee..b421068f7ea3 100644
--- a/drivers/media/video/cs53l32a.c
+++ b/drivers/media/video/cs53l32a.c
@@ -27,7 +27,7 @@
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/videodev.h>
-#include <media/audiochip.h>
+#include <media/v4l2-common.h>
MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
MODULE_AUTHOR("Martin Vaughan");
@@ -39,21 +39,6 @@ module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On");
-#define cs53l32a_dbg(fmt, arg...) \
- do { \
- if (debug) \
- printk(KERN_INFO "%s debug %d-%04x: " fmt, \
- client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); \
- } while (0)
-
-#define cs53l32a_err(fmt, arg...) do { \
- printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define cs53l32a_info(fmt, arg...) do { \
- printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
@@ -74,50 +59,59 @@ static int cs53l32a_read(struct i2c_client *client, u8 reg)
static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
void *arg)
{
- int *input = arg;
+ struct v4l2_audio *input = arg;
+ struct v4l2_control *ctrl = arg;
switch (cmd) {
- case AUDC_SET_INPUT:
- switch (*input) {
- case AUDIO_TUNER:
- cs53l32a_write(client, 0x01, 0x01);
- break;
- case AUDIO_EXTERN:
- cs53l32a_write(client, 0x01, 0x21);
- break;
- case AUDIO_MUTE:
- cs53l32a_write(client, 0x03, 0xF0);
- break;
- case AUDIO_UNMUTE:
- cs53l32a_write(client, 0x03, 0x30);
- break;
- default:
- cs53l32a_err("Invalid input %d.\n", *input);
+ case VIDIOC_S_AUDIO:
+ /* There are 2 physical inputs, but the second input can be
+ placed in two modes, the first mode bypasses the PGA (gain),
+ the second goes through the PGA. Hence there are three
+ possible inputs to choose from. */
+ if (input->index > 2) {
+ v4l_err(client, "Invalid input %d.\n", input->index);
return -EINVAL;
}
+ cs53l32a_write(client, 0x01, 0x01 + (input->index << 4));
+ break;
+
+ case VIDIOC_G_AUDIO:
+ memset(input, 0, sizeof(*input));
+ input->index = (cs53l32a_read(client, 0x01) >> 4) & 3;
+ break;
+
+ case VIDIOC_G_CTRL:
+ if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+ ctrl->value = (cs53l32a_read(client, 0x03) & 0xc0) != 0;
+ break;
+ }
+ if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+ return -EINVAL;
+ ctrl->value = (s8)cs53l32a_read(client, 0x04);
break;
case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
- return -EINVAL;
- if (ctrl->value > 12 || ctrl->value < -90)
- return -EINVAL;
- cs53l32a_write(client, 0x04, (u8) ctrl->value);
- cs53l32a_write(client, 0x05, (u8) ctrl->value);
+ if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+ cs53l32a_write(client, 0x03, ctrl->value ? 0xf0 : 0x30);
break;
}
+ if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+ return -EINVAL;
+ if (ctrl->value > 12 || ctrl->value < -96)
+ return -EINVAL;
+ cs53l32a_write(client, 0x04, (u8) ctrl->value);
+ cs53l32a_write(client, 0x05, (u8) ctrl->value);
+ break;
case VIDIOC_LOG_STATUS:
{
u8 v = cs53l32a_read(client, 0x01);
u8 m = cs53l32a_read(client, 0x03);
+ s8 vol = cs53l32a_read(client, 0x04);
- cs53l32a_info("Input: %s%s\n",
- v == 0x21 ? "external line in" : "tuner",
+ v4l_info(client, "Input: %d%s\n", (v >> 4) & 3,
(m & 0xC0) ? " (muted)" : "");
+ v4l_info(client, "Volume: %d dB\n", vol);
break;
}
@@ -157,12 +151,12 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
client->driver = &i2c_driver;
snprintf(client->name, sizeof(client->name) - 1, "cs53l32a");
- cs53l32a_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+ v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
for (i = 1; i <= 7; i++) {
u8 v = cs53l32a_read(client, i);
- cs53l32a_dbg("Read Reg %d %02x\n", i, v);
+ v4l_dbg(1, client, "Read Reg %d %02x\n", i, v);
}
/* Set cs53l32a internal register for Adaptec 2010/2410 setup */
@@ -180,7 +174,7 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
for (i = 1; i <= 7; i++) {
u8 v = cs53l32a_read(client, i);
- cs53l32a_dbg("Read Reg %d %02x\n", i, v);
+ v4l_dbg(1, client, "Read Reg %d %02x\n", i, v);
}
i2c_attach_client(client);
@@ -190,11 +184,7 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
static int cs53l32a_probe(struct i2c_adapter *adapter)
{
-#ifdef I2C_CLASS_TV_ANALOG
if (adapter->class & I2C_CLASS_TV_ANALOG)
-#else
- if (adapter->id == I2C_HW_B_BT848)
-#endif
return i2c_probe(adapter, &addr_data, cs53l32a_attach);
return 0;
}
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
index 740908f8027d..cb9a7981e408 100644
--- a/drivers/media/video/cx25840/cx25840-audio.c
+++ b/drivers/media/video/cx25840/cx25840-audio.c
@@ -23,11 +23,13 @@
#include "cx25840.h"
-inline static int set_audclk_freq(struct i2c_client *client,
- enum v4l2_audio_clock_freq freq)
+static int set_audclk_freq(struct i2c_client *client, u32 freq)
{
struct cx25840_state *state = i2c_get_clientdata(client);
+ if (freq != 32000 && freq != 44100 && freq != 48000)
+ return -EINVAL;
+
/* assert soft reset */
cx25840_and_or(client, 0x810, ~0x1, 0x01);
@@ -35,10 +37,9 @@ inline static int set_audclk_freq(struct i2c_client *client,
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
cx25840_write(client, 0x127, 0x50);
- switch (state->audio_input) {
- case AUDIO_TUNER:
+ if (state->aud_input != CX25840_AUDIO_SERIAL) {
switch (freq) {
- case V4L2_AUDCLK_32_KHZ:
+ case 32000:
/* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f040610);
@@ -51,7 +52,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
cx25840_write4(client, 0x90c, 0x7ff70108);
break;
- case V4L2_AUDCLK_441_KHZ:
+ case 44100:
/* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f040910);
@@ -64,7 +65,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
cx25840_write4(client, 0x90c, 0x596d0108);
break;
- case V4L2_AUDCLK_48_KHZ:
+ case 48000:
/* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f040a10);
@@ -77,14 +78,9 @@ inline static int set_audclk_freq(struct i2c_client *client,
cx25840_write4(client, 0x90c, 0xaa4f0108);
break;
}
- break;
-
- case AUDIO_EXTERN_1:
- case AUDIO_EXTERN_2:
- case AUDIO_INTERN:
- case AUDIO_RADIO:
+ } else {
switch (freq) {
- case V4L2_AUDCLK_32_KHZ:
+ case 32000:
/* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f04081e);
@@ -103,7 +99,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
cx25840_write(client, 0x127, 0x54);
break;
- case V4L2_AUDCLK_441_KHZ:
+ case 44100:
/* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f040918);
@@ -119,7 +115,7 @@ inline static int set_audclk_freq(struct i2c_client *client,
cx25840_write4(client, 0x90c, 0x85730108);
break;
- case V4L2_AUDCLK_48_KHZ:
+ case 48000:
/* VID_PLL and AUX_PLL */
cx25840_write4(client, 0x108, 0x0f040a18);
@@ -135,7 +131,6 @@ inline static int set_audclk_freq(struct i2c_client *client,
cx25840_write4(client, 0x90c, 0x55550108);
break;
}
- break;
}
/* deassert soft reset */
@@ -146,51 +141,36 @@ inline static int set_audclk_freq(struct i2c_client *client,
return 0;
}
-static int set_input(struct i2c_client *client, int audio_input)
+void cx25840_audio_set_path(struct i2c_client *client)
{
struct cx25840_state *state = i2c_get_clientdata(client);
- cx25840_dbg("set audio input (%d)\n", audio_input);
-
/* stop microcontroller */
cx25840_and_or(client, 0x803, ~0x10, 0);
/* Mute everything to prevent the PFFT! */
cx25840_write(client, 0x8d3, 0x1f);
- switch (audio_input) {
- case AUDIO_TUNER:
- /* Set Path1 to Analog Demod Main Channel */
- cx25840_write4(client, 0x8d0, 0x7038061f);
-
- /* When the microcontroller detects the
- * audio format, it will unmute the lines */
- cx25840_and_or(client, 0x803, ~0x10, 0x10);
- break;
-
- case AUDIO_EXTERN_1:
- case AUDIO_EXTERN_2:
- case AUDIO_INTERN:
- case AUDIO_RADIO:
+ if (state->aud_input == CX25840_AUDIO_SERIAL) {
/* Set Path1 to Serial Audio Input */
cx25840_write4(client, 0x8d0, 0x12100101);
/* The microcontroller should not be started for the
* non-tuner inputs: autodetection is specific for
* TV audio. */
- break;
+ } else {
+ /* Set Path1 to Analog Demod Main Channel */
+ cx25840_write4(client, 0x8d0, 0x7038061f);
- default:
- cx25840_dbg("Invalid audio input selection %d\n", audio_input);
- return -EINVAL;
+ /* When the microcontroller detects the
+ * audio format, it will unmute the lines */
+ cx25840_and_or(client, 0x803, ~0x10, 0x10);
}
- state->audio_input = audio_input;
-
- return set_audclk_freq(client, state->audclk_freq);
+ set_audclk_freq(client, state->audclk_freq);
}
-inline static int get_volume(struct i2c_client *client)
+static int get_volume(struct i2c_client *client)
{
/* Volume runs +18dB to -96dB in 1/2dB steps
* change to fit the msp3400 -114dB to +12dB range */
@@ -201,7 +181,7 @@ inline static int get_volume(struct i2c_client *client)
return vol << 9;
}
-inline static void set_volume(struct i2c_client *client, int volume)
+static void set_volume(struct i2c_client *client, int volume)
{
/* First convert the volume to msp3400 values (0-127) */
int vol = volume >> 9;
@@ -218,7 +198,7 @@ inline static void set_volume(struct i2c_client *client, int volume)
cx25840_write(client, 0x8d4, 228 - (vol * 2));
}
-inline static int get_bass(struct i2c_client *client)
+static int get_bass(struct i2c_client *client)
{
/* bass is 49 steps +12dB to -12dB */
@@ -228,13 +208,13 @@ inline static int get_bass(struct i2c_client *client)
return bass;
}
-inline static void set_bass(struct i2c_client *client, int bass)
+static void set_bass(struct i2c_client *client, int bass)
{
/* PATH1_EQ_BASS_VOL */
cx25840_and_or(client, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
}
-inline static int get_treble(struct i2c_client *client)
+static int get_treble(struct i2c_client *client)
{
/* treble is 49 steps +12dB to -12dB */
@@ -244,13 +224,13 @@ inline static int get_treble(struct i2c_client *client)
return treble;
}
-inline static void set_treble(struct i2c_client *client, int treble)
+static void set_treble(struct i2c_client *client, int treble)
{
/* PATH1_EQ_TREBLE_VOL */
cx25840_and_or(client, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
}
-inline static int get_balance(struct i2c_client *client)
+static int get_balance(struct i2c_client *client)
{
/* balance is 7 bit, 0 to -96dB */
@@ -264,7 +244,7 @@ inline static int get_balance(struct i2c_client *client)
return balance << 8;
}
-inline static void set_balance(struct i2c_client *client, int balance)
+static void set_balance(struct i2c_client *client, int balance)
{
int bal = balance >> 8;
if (bal > 0x80) {
@@ -280,17 +260,17 @@ inline static void set_balance(struct i2c_client *client, int balance)
}
}
-inline static int get_mute(struct i2c_client *client)
+static int get_mute(struct i2c_client *client)
{
/* check SRC1_MUTE_EN */
return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0;
}
-inline static void set_mute(struct i2c_client *client, int mute)
+static void set_mute(struct i2c_client *client, int mute)
{
struct cx25840_state *state = i2c_get_clientdata(client);
- if (state->audio_input == AUDIO_TUNER) {
+ if (state->aud_input != CX25840_AUDIO_SERIAL) {
/* Must turn off microcontroller in order to mute sound.
* Not sure if this is the best method, but it does work.
* If the microcontroller is running, then it will undo any
@@ -314,10 +294,9 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
struct v4l2_control *ctrl = arg;
switch (cmd) {
- case AUDC_SET_INPUT:
- return set_input(client, *(int *)arg);
case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- return set_audclk_freq(client, *(enum v4l2_audio_clock_freq *)arg);
+ return set_audclk_freq(client, *(u32 *)arg);
+
case VIDIOC_G_CTRL:
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
@@ -339,6 +318,7 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
return -EINVAL;
}
break;
+
case VIDIOC_S_CTRL:
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
@@ -360,6 +340,7 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
return -EINVAL;
}
break;
+
default:
return -EINVAL;
}
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 3b09f46dddf6..d45237d508c4 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -43,11 +43,11 @@ MODULE_LICENSE("GPL");
static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
-int cx25840_debug = 0;
+int debug = 0;
-module_param(cx25840_debug, bool, 0644);
+module_param(debug, bool, 0644);
-MODULE_PARM_DESC(cx25840_debug, "Debugging messages [0=Off (default) 1=On]");
+MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]");
I2C_CLIENT_INSMOD;
@@ -115,13 +115,13 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask,
/* ----------------------------------------------------------------------- */
-static int set_input(struct i2c_client *, enum cx25840_input);
-static void input_change(struct i2c_client *);
+static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
+ enum cx25840_audio_input aud_input);
static void log_status(struct i2c_client *client);
/* ----------------------------------------------------------------------- */
-static inline void init_dll1(struct i2c_client *client)
+static void init_dll1(struct i2c_client *client)
{
/* This is the Hauppauge sequence used to
* initialize the Delay Lock Loop 1 (ADC DLL). */
@@ -135,7 +135,7 @@ static inline void init_dll1(struct i2c_client *client)
cx25840_write(client, 0x15b, 0x10);
}
-static inline void init_dll2(struct i2c_client *client)
+static void init_dll2(struct i2c_client *client)
{
/* This is the Hauppauge sequence used to
* initialize the Delay Lock Loop 2 (ADC DLL). */
@@ -195,10 +195,8 @@ static void cx25840_initialize(struct i2c_client *client, int loadfw)
/* AC97 shift */
cx25840_write(client, 0x8cf, 0x0f);
- /* (re)set video input */
- set_input(client, state->input);
- /* (re)set audio input */
- cx25840_audio(client, AUDC_SET_INPUT, &state->audio_input);
+ /* (re)set input */
+ set_input(client, state->vid_input, state->aud_input);
/* start microcontroller */
cx25840_and_or(client, 0x803, ~0x10, 0x10);
@@ -223,7 +221,7 @@ static void input_change(struct i2c_client *client)
cx25840_write(client, 0x80b, 0x10);
} else if (std & V4L2_STD_NTSC) {
/* NTSC */
- if (state->cardtype == CARDTYPE_PVR150_WORKAROUND) {
+ if (state->pvr150_workaround) {
/* Certain Hauppauge PVR150 models have a hardware bug
that causes audio to drop out. For these models the
audio standard must be set explicitly.
@@ -259,72 +257,68 @@ static void input_change(struct i2c_client *client)
}
}
-static int set_input(struct i2c_client *client, enum cx25840_input input)
+static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
+ enum cx25840_audio_input aud_input)
{
struct cx25840_state *state = i2c_get_clientdata(client);
+ u8 is_composite = (vid_input >= CX25840_COMPOSITE1 &&
+ vid_input <= CX25840_COMPOSITE8);
+ u8 reg;
- cx25840_dbg("decoder set input (%d)\n", input);
+ v4l_dbg(1, client, "decoder set video input %d, audio input %d\n",
+ vid_input, aud_input);
- switch (input) {
- case CX25840_TUNER:
- cx25840_dbg("now setting Tuner input\n");
-
- if (state->cardtype == CARDTYPE_PVR150 ||
- state->cardtype == CARDTYPE_PVR150_WORKAROUND) {
- /* CH_SEL_ADC2=1 */
- cx25840_and_or(client, 0x102, ~0x2, 0x02);
- }
-
- /* Video Input Control */
- if (state->cardtype == CARDTYPE_PG600) {
- cx25840_write(client, 0x103, 0x11);
- } else {
- cx25840_write(client, 0x103, 0x46);
- }
-
- /* INPUT_MODE=0 */
- cx25840_and_or(client, 0x401, ~0x6, 0x00);
- break;
-
- case CX25840_COMPOSITE0:
- case CX25840_COMPOSITE1:
- cx25840_dbg("now setting Composite input\n");
+ if (is_composite) {
+ reg = 0xf0 + (vid_input - CX25840_COMPOSITE1);
+ } else {
+ int luma = vid_input & 0xf0;
+ int chroma = vid_input & 0xf00;
- /* Video Input Control */
- if (state->cardtype == CARDTYPE_PG600) {
- cx25840_write(client, 0x103, 0x00);
- } else {
- cx25840_write(client, 0x103, 0x02);
+ if ((vid_input & ~0xff0) ||
+ luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 ||
+ chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) {
+ v4l_err(client, "0x%04x is not a valid video input!\n", vid_input);
+ return -EINVAL;
}
-
- /* INPUT_MODE=0 */
- cx25840_and_or(client, 0x401, ~0x6, 0x00);
- break;
-
- case CX25840_SVIDEO0:
- case CX25840_SVIDEO1:
- cx25840_dbg("now setting S-Video input\n");
-
- /* CH_SEL_ADC2=0 */
- cx25840_and_or(client, 0x102, ~0x2, 0x00);
-
- /* Video Input Control */
- if (state->cardtype == CARDTYPE_PG600) {
- cx25840_write(client, 0x103, 0x02);
+ reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4);
+ if (chroma >= CX25840_SVIDEO_CHROMA7) {
+ reg &= 0x3f;
+ reg |= (chroma - CX25840_SVIDEO_CHROMA7) >> 2;
} else {
- cx25840_write(client, 0x103, 0x10);
+ reg &= 0xcf;
+ reg |= (chroma - CX25840_SVIDEO_CHROMA4) >> 4;
}
+ }
- /* INPUT_MODE=1 */
- cx25840_and_or(client, 0x401, ~0x6, 0x02);
+ switch (aud_input) {
+ case CX25840_AUDIO_SERIAL:
+ /* do nothing, use serial audio input */
break;
+ case CX25840_AUDIO4: reg &= ~0x30; break;
+ case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
+ case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
+ case CX25840_AUDIO7: reg &= ~0xc0; break;
+ case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
default:
- cx25840_err("%d is not a valid input!\n", input);
+ v4l_err(client, "0x%04x is not a valid audio input!\n", aud_input);
return -EINVAL;
}
- state->input = input;
+ cx25840_write(client, 0x103, reg);
+ /* Set INPUT_MODE to Composite (0) or S-Video (1) */
+ cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
+ /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
+ cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
+ /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
+ if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
+ cx25840_and_or(client, 0x102, ~0x4, 4);
+ else
+ cx25840_and_or(client, 0x102, ~0x4, 0);
+
+ state->vid_input = vid_input;
+ state->aud_input = aud_input;
+ cx25840_audio_set_path(client);
input_change(client);
return 0;
}
@@ -395,23 +389,14 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
struct cx25840_state *state = i2c_get_clientdata(client);
switch (ctrl->id) {
- case CX25840_CID_CARDTYPE:
- switch (ctrl->value) {
- case CARDTYPE_PVR150:
- case CARDTYPE_PVR150_WORKAROUND:
- case CARDTYPE_PG600:
- state->cardtype = ctrl->value;
- break;
- default:
- return -ERANGE;
- }
-
- set_input(client, state->input);
+ case CX25840_CID_ENABLE_PVR150_WORKAROUND:
+ state->pvr150_workaround = ctrl->value;
+ set_input(client, state->vid_input, state->aud_input);
break;
case V4L2_CID_BRIGHTNESS:
if (ctrl->value < 0 || ctrl->value > 255) {
- cx25840_err("invalid brightness setting %d\n",
+ v4l_err(client, "invalid brightness setting %d\n",
ctrl->value);
return -ERANGE;
}
@@ -421,7 +406,7 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
case V4L2_CID_CONTRAST:
if (ctrl->value < 0 || ctrl->value > 127) {
- cx25840_err("invalid contrast setting %d\n",
+ v4l_err(client, "invalid contrast setting %d\n",
ctrl->value);
return -ERANGE;
}
@@ -431,7 +416,7 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
case V4L2_CID_SATURATION:
if (ctrl->value < 0 || ctrl->value > 127) {
- cx25840_err("invalid saturation setting %d\n",
+ v4l_err(client, "invalid saturation setting %d\n",
ctrl->value);
return -ERANGE;
}
@@ -442,7 +427,7 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
case V4L2_CID_HUE:
if (ctrl->value < -127 || ctrl->value > 127) {
- cx25840_err("invalid hue setting %d\n", ctrl->value);
+ v4l_err(client, "invalid hue setting %d\n", ctrl->value);
return -ERANGE;
}
@@ -455,6 +440,9 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_MUTE:
return cx25840_audio(client, VIDIOC_S_CTRL, ctrl);
+
+ default:
+ return -EINVAL;
}
return 0;
@@ -465,11 +453,11 @@ static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
struct cx25840_state *state = i2c_get_clientdata(client);
switch (ctrl->id) {
- case CX25840_CID_CARDTYPE:
- ctrl->value = state->cardtype;
+ case CX25840_CID_ENABLE_PVR150_WORKAROUND:
+ ctrl->value = state->pvr150_workaround;
break;
case V4L2_CID_BRIGHTNESS:
- ctrl->value = cx25840_read(client, 0x414) + 128;
+ ctrl->value = (s8)cx25840_read(client, 0x414) + 128;
break;
case V4L2_CID_CONTRAST:
ctrl->value = cx25840_read(client, 0x415) >> 1;
@@ -478,7 +466,7 @@ static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
ctrl->value = cx25840_read(client, 0x420) >> 1;
break;
case V4L2_CID_HUE:
- ctrl->value = cx25840_read(client, 0x422);
+ ctrl->value = (s8)cx25840_read(client, 0x422);
break;
case V4L2_CID_AUDIO_VOLUME:
case V4L2_CID_AUDIO_BASS:
@@ -527,7 +515,7 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
(Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
- cx25840_err("%dx%d is not a valid size!\n",
+ v4l_err(client, "%dx%d is not a valid size!\n",
pix->width, pix->height);
return -ERANGE;
}
@@ -545,7 +533,7 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
else
filter = 3;
- cx25840_dbg("decoder set size %dx%d -> scale %ux%u\n",
+ v4l_dbg(1, client, "decoder set size %dx%d -> scale %ux%u\n",
pix->width, pix->height, HSC, VSC);
/* HSCALE=HSC */
@@ -574,17 +562,98 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
/* ----------------------------------------------------------------------- */
+static struct v4l2_queryctrl cx25840_qctrl[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 128,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 64,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 64,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535/100,
+ .default_value = 58880,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_AUDIO_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Balance",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535/100,
+ .default_value = 32768,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_AUDIO_BASS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Bass",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535/100,
+ .default_value = 32768,
+ }, {
+ .id = V4L2_CID_AUDIO_TREBLE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Treble",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535/100,
+ .default_value = 32768,
+ },
+};
+
+/* ----------------------------------------------------------------------- */
+
static int cx25840_command(struct i2c_client *client, unsigned int cmd,
void *arg)
{
struct cx25840_state *state = i2c_get_clientdata(client);
struct v4l2_tuner *vt = arg;
- int result = 0;
switch (cmd) {
- case 0:
- break;
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
/* ioctls to allow direct access to the
* cx25840 registers for testing */
@@ -615,18 +684,16 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
return cx25840_vbi(client, cmd, arg);
case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- case AUDC_SET_INPUT:
- result = cx25840_audio(client, cmd, arg);
- break;
+ return cx25840_audio(client, cmd, arg);
case VIDIOC_STREAMON:
- cx25840_dbg("enable output\n");
+ v4l_dbg(1, client, "enable output\n");
cx25840_write(client, 0x115, 0x8c);
cx25840_write(client, 0x116, 0x07);
break;
case VIDIOC_STREAMOFF:
- cx25840_dbg("disable output\n");
+ v4l_dbg(1, client, "disable output\n");
cx25840_write(client, 0x115, 0x00);
cx25840_write(client, 0x116, 0x00);
break;
@@ -636,28 +703,58 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
break;
case VIDIOC_G_CTRL:
- result = get_v4lctrl(client, (struct v4l2_control *)arg);
- break;
+ return get_v4lctrl(client, (struct v4l2_control *)arg);
case VIDIOC_S_CTRL:
- result = set_v4lctrl(client, (struct v4l2_control *)arg);
- break;
+ return set_v4lctrl(client, (struct v4l2_control *)arg);
+
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cx25840_qctrl); i++)
+ if (qc->id && qc->id == cx25840_qctrl[i].id) {
+ memcpy(qc, &cx25840_qctrl[i], sizeof(*qc));
+ return 0;
+ }
+ return -EINVAL;
+ }
case VIDIOC_G_STD:
*(v4l2_std_id *)arg = cx25840_get_v4lstd(client);
break;
case VIDIOC_S_STD:
- result = set_v4lstd(client, *(v4l2_std_id *)arg);
+ state->radio = 0;
+ return set_v4lstd(client, *(v4l2_std_id *)arg);
+
+ case AUDC_SET_RADIO:
+ state->radio = 1;
break;
case VIDIOC_G_INPUT:
- *(int *)arg = state->input;
+ *(int *)arg = state->vid_input;
break;
case VIDIOC_S_INPUT:
- result = set_input(client, *(int *)arg);
+ return set_input(client, *(enum cx25840_video_input *)arg, state->aud_input);
+
+ case VIDIOC_S_AUDIO:
+ {
+ struct v4l2_audio *input = arg;
+
+ return set_input(client, state->vid_input, input->index);
+ }
+
+ case VIDIOC_G_AUDIO:
+ {
+ struct v4l2_audio *input = arg;
+
+ memset(input, 0, sizeof(*input));
+ input->index = state->aud_input;
break;
+ }
case VIDIOC_S_FREQUENCY:
input_change(client);
@@ -670,6 +767,9 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
u8 vpres = cx25840_read(client, 0x80a) & 0x10;
int val = 0;
+ if (state->radio)
+ break;
+
vt->capability |=
V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
@@ -724,12 +824,10 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
break;
case VIDIOC_G_FMT:
- result = get_v4lfmt(client, (struct v4l2_format *)arg);
- break;
+ return get_v4lfmt(client, (struct v4l2_format *)arg);
case VIDIOC_S_FMT:
- result = set_v4lfmt(client, (struct v4l2_format *)arg);
- break;
+ return set_v4lfmt(client, (struct v4l2_format *)arg);
case VIDIOC_INT_RESET:
cx25840_initialize(client, 0);
@@ -741,11 +839,10 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
break;
default:
- cx25840_err("invalid ioctl %x\n", cmd);
return -EINVAL;
}
- return result;
+ return 0;
}
/* ----------------------------------------------------------------------- */
@@ -775,7 +872,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
client->driver = &i2c_driver_cx25840;
snprintf(client->name, sizeof(client->name) - 1, "cx25840");
- cx25840_dbg("detecting cx25840 client on address 0x%x\n", address << 1);
+ v4l_dbg(1, client, "detecting cx25840 client on address 0x%x\n", address << 1);
device_id = cx25840_read(client, 0x101) << 8;
device_id |= cx25840_read(client, 0x100);
@@ -783,12 +880,12 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
/* The high byte of the device ID should be
* 0x84 if chip is present */
if ((device_id & 0xff00) != 0x8400) {
- cx25840_dbg("cx25840 not found\n");
+ v4l_dbg(1, client, "cx25840 not found\n");
kfree(client);
return 0;
}
- cx25840_info("cx25%3x-2%x found @ 0x%x (%s)\n",
+ v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
(device_id & 0xfff0) >> 4,
(device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3,
address << 1, adapter->name);
@@ -801,10 +898,10 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
i2c_set_clientdata(client, state);
memset(state, 0, sizeof(struct cx25840_state));
- state->input = CX25840_TUNER;
- state->audclk_freq = V4L2_AUDCLK_48_KHZ;
- state->audio_input = AUDIO_TUNER;
- state->cardtype = CARDTYPE_PVR150;
+ state->vid_input = CX25840_COMPOSITE7;
+ state->aud_input = CX25840_AUDIO8;
+ state->audclk_freq = 48000;
+ state->pvr150_workaround = 0;
cx25840_initialize(client, 1);
@@ -815,11 +912,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
static int cx25840_attach_adapter(struct i2c_adapter *adapter)
{
-#ifdef I2C_CLASS_TV_ANALOG
if (adapter->class & I2C_CLASS_TV_ANALOG)
-#else
- if (adapter->id == I2C_HW_B_BT848)
-#endif
return i2c_probe(adapter, &addr_data, &cx25840_detect_client);
return 0;
}
@@ -846,9 +939,7 @@ static struct i2c_driver i2c_driver_cx25840 = {
.driver = {
.name = "cx25840",
},
-
.id = I2C_DRIVERID_CX25840,
-
.attach_adapter = cx25840_attach_adapter,
.detach_client = cx25840_detach_client,
.command = cx25840_command,
@@ -892,11 +983,13 @@ static void log_status(struct i2c_client *client)
u8 pref_mode = cx25840_read(client, 0x809);
u8 afc0 = cx25840_read(client, 0x80b);
u8 mute_ctl = cx25840_read(client, 0x8d3);
+ int vid_input = state->vid_input;
+ int aud_input = state->aud_input;
char *p;
- cx25840_info("Video signal: %spresent\n",
+ v4l_info(client, "Video signal: %spresent\n",
(microctrl_vidfmt & 0x10) ? "" : "not ");
- cx25840_info("Detected format: %s\n",
+ v4l_info(client, "Detected format: %s\n",
fmt_strs[gen_stat1 & 0xf]);
switch (mod_det_stat0) {
@@ -911,7 +1004,7 @@ static void log_status(struct i2c_client *client)
case 0xfe: p = "forced mode"; break;
default: p = "not defined";
}
- cx25840_info("Detected audio mode: %s\n", p);
+ v4l_info(client, "Detected audio mode: %s\n", p);
switch (mod_det_stat1) {
case 0x00: p = "not defined"; break;
@@ -937,10 +1030,10 @@ static void log_status(struct i2c_client *client)
case 0xff: p = "no detected audio standard"; break;
default: p = "not defined";
}
- cx25840_info("Detected audio standard: %s\n", p);
- cx25840_info("Audio muted: %s\n",
+ v4l_info(client, "Detected audio standard: %s\n", p);
+ v4l_info(client, "Audio muted: %s\n",
(mute_ctl & 0x2) ? "yes" : "no");
- cx25840_info("Audio microcontroller: %s\n",
+ v4l_info(client, "Audio microcontroller: %s\n",
(download_ctl & 0x10) ? "running" : "stopped");
switch (audio_config >> 4) {
@@ -962,7 +1055,7 @@ static void log_status(struct i2c_client *client)
case 0x0f: p = "automatic detection"; break;
default: p = "undefined";
}
- cx25840_info("Configured audio standard: %s\n", p);
+ v4l_info(client, "Configured audio standard: %s\n", p);
if ((audio_config >> 4) < 0xF) {
switch (audio_config & 0xF) {
@@ -979,7 +1072,7 @@ static void log_status(struct i2c_client *client)
case 0x0a: p = "SAP"; break;
default: p = "undefined";
}
- cx25840_info("Configured audio mode: %s\n", p);
+ v4l_info(client, "Configured audio mode: %s\n", p);
} else {
switch (audio_config & 0xF) {
case 0x00: p = "BG"; break;
@@ -995,30 +1088,27 @@ static void log_status(struct i2c_client *client)
case 0x0f: p = "automatic standard and mode detection"; break;
default: p = "undefined";
}
- cx25840_info("Configured audio system: %s\n", p);
+ v4l_info(client, "Configured audio system: %s\n", p);
}
- cx25840_info("Specified standard: %s\n",
+ v4l_info(client, "Specified standard: %s\n",
vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
- switch (state->input) {
- case CX25840_COMPOSITE0: p = "Composite 0"; break;
- case CX25840_COMPOSITE1: p = "Composite 1"; break;
- case CX25840_SVIDEO0: p = "S-Video 0"; break;
- case CX25840_SVIDEO1: p = "S-Video 1"; break;
- case CX25840_TUNER: p = "Tuner"; break;
+ if (vid_input >= CX25840_COMPOSITE1 &&
+ vid_input <= CX25840_COMPOSITE8) {
+ v4l_info(client, "Specified video input: Composite %d\n",
+ vid_input - CX25840_COMPOSITE1 + 1);
+ } else {
+ v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n",
+ (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
}
- cx25840_info("Specified input: %s\n", p);
- cx25840_info("Specified audio input: %s\n",
- state->audio_input == 0 ? "Tuner" : "External");
-
- switch (state->audclk_freq) {
- case V4L2_AUDCLK_441_KHZ: p = "44.1 kHz"; break;
- case V4L2_AUDCLK_48_KHZ: p = "48 kHz"; break;
- case V4L2_AUDCLK_32_KHZ: p = "32 kHz"; break;
- default: p = "undefined";
+ if (aud_input) {
+ v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input);
+ } else {
+ v4l_info(client, "Specified audio input: External\n");
}
- cx25840_info("Specified audioclock freq: %s\n", p);
+
+ v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
switch (pref_mode & 0xf) {
case 0: p = "mono/language A"; break;
@@ -1031,7 +1121,7 @@ static void log_status(struct i2c_client *client)
case 7: p = "language AB"; break;
default: p = "undefined";
}
- cx25840_info("Preferred audio mode: %s\n", p);
+ v4l_info(client, "Preferred audio mode: %s\n", p);
if ((audio_config & 0xf) == 0xf) {
switch ((afc0 >> 3) & 0x3) {
@@ -1040,7 +1130,7 @@ static void log_status(struct i2c_client *client)
case 2: p = "autodetect"; break;
default: p = "undefined";
}
- cx25840_info("Selected 65 MHz format: %s\n", p);
+ v4l_info(client, "Selected 65 MHz format: %s\n", p);
switch (afc0 & 0x7) {
case 0: p = "chroma"; break;
@@ -1050,6 +1140,6 @@ static void log_status(struct i2c_client *client)
case 4: p = "autodetect"; break;
default: p = "undefined";
}
- cx25840_info("Selected 45 MHz format: %s\n", p);
+ v4l_info(client, "Selected 45 MHz format: %s\n", p);
}
}
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c
index df9d50a75542..e1a7823d82cd 100644
--- a/drivers/media/video/cx25840/cx25840-firmware.c
+++ b/drivers/media/video/cx25840/cx25840-firmware.c
@@ -15,7 +15,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
@@ -38,7 +37,7 @@ module_param(firmware, charp, 0444);
MODULE_PARM_DESC(fastfw, "Load firmware fast [0=100MHz 1=333MHz (default)]");
MODULE_PARM_DESC(firmware, "Firmware image [default: " FWFILE "]");
-static inline void set_i2c_delay(struct i2c_client *client, int delay)
+static void set_i2c_delay(struct i2c_client *client, int delay)
{
struct i2c_algo_bit_data *algod = client->adapter->algo_data;
@@ -52,7 +51,7 @@ static inline void set_i2c_delay(struct i2c_client *client, int delay)
}
}
-static inline void start_fw_load(struct i2c_client *client)
+static void start_fw_load(struct i2c_client *client)
{
/* DL_ADDR_LB=0 DL_ADDR_HB=0 */
cx25840_write(client, 0x800, 0x00);
@@ -66,7 +65,7 @@ static inline void start_fw_load(struct i2c_client *client)
set_i2c_delay(client, 3);
}
-static inline void end_fw_load(struct i2c_client *client)
+static void end_fw_load(struct i2c_client *client)
{
if (fastfw)
set_i2c_delay(client, 10);
@@ -77,38 +76,47 @@ static inline void end_fw_load(struct i2c_client *client)
cx25840_write(client, 0x803, 0x03);
}
-static inline int check_fw_load(struct i2c_client *client, int size)
+static int check_fw_load(struct i2c_client *client, int size)
{
/* DL_ADDR_HB DL_ADDR_LB */
int s = cx25840_read(client, 0x801) << 8;
s |= cx25840_read(client, 0x800);
if (size != s) {
- cx25840_err("firmware %s load failed\n", firmware);
+ v4l_err(client, "firmware %s load failed\n", firmware);
return -EINVAL;
}
- cx25840_info("loaded %s firmware (%d bytes)\n", firmware, size);
+ v4l_info(client, "loaded %s firmware (%d bytes)\n", firmware, size);
return 0;
}
-static inline int fw_write(struct i2c_client *client, u8 * data, int size)
+static int fw_write(struct i2c_client *client, u8 * data, int size)
{
- if (i2c_master_send(client, data, size) < size) {
+ int sent;
+
+ if ((sent = i2c_master_send(client, data, size)) < size) {
if (fastfw) {
- cx25840_err("333MHz i2c firmware load failed\n");
+ v4l_err(client, "333MHz i2c firmware load failed\n");
fastfw = 0;
set_i2c_delay(client, 10);
+ if (sent > 2) {
+ u16 dl_addr = cx25840_read(client, 0x801) << 8;
+ dl_addr |= cx25840_read(client, 0x800);
+ dl_addr -= sent - 2;
+ cx25840_write(client, 0x801, dl_addr >> 8);
+ cx25840_write(client, 0x800, dl_addr & 0xff);
+ }
+
if (i2c_master_send(client, data, size) < size) {
- cx25840_err
- ("100MHz i2c firmware load failed\n");
+ v4l_err(client, "100MHz i2c firmware load failed\n");
return -ENOSYS;
}
} else {
- cx25840_err("firmware load i2c failure\n");
+ v4l_err(client, "firmware load i2c failure\n");
return -ENOSYS;
}
@@ -124,7 +132,7 @@ int cx25840_loadfw(struct i2c_client *client)
int size, send, retval;
if (request_firmware(&fw, firmware, FWDEV(client)) != 0) {
- cx25840_err("unable to open firmware %s\n", firmware);
+ v4l_err(client, "unable to open firmware %s\n", firmware);
return -EINVAL;
}
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index 13ba4e15ddea..04d879da7d63 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -22,7 +22,7 @@
#include "cx25840.h"
-static inline int odd_parity(u8 c)
+static int odd_parity(u8 c)
{
c ^= (c >> 4);
c ^= (c >> 2);
@@ -31,7 +31,7 @@ static inline int odd_parity(u8 c)
return c & 1;
}
-static inline int decode_vps(u8 * dst, u8 * p)
+static int decode_vps(u8 * dst, u8 * p)
{
static const u8 biphase_tbl[] = {
0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
diff --git a/drivers/media/video/cx25840/cx25840.h b/drivers/media/video/cx25840/cx25840.h
index 40aa59f9c525..fd22f30dcc1b 100644
--- a/drivers/media/video/cx25840/cx25840.h
+++ b/drivers/media/video/cx25840/cx25840.h
@@ -24,48 +24,60 @@
#include <linux/videodev2.h>
#include <linux/i2c.h>
-extern int cx25840_debug;
-
-#define cx25840_dbg(fmt, arg...) do { if (cx25840_debug) \
- printk(KERN_INFO "%s debug %d-%04x: " fmt, \
- client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
-#define cx25840_err(fmt, arg...) do { \
- printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
-#define cx25840_info(fmt, arg...) do { \
- printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
-#define CX25840_CID_CARDTYPE (V4L2_CID_PRIVATE_BASE+0)
-
-/* The CARDTYPE_PVR150_WORKAROUND cardtype activates a workaround for a
- hardware bug that is present in PVR150 (and possible PVR500) cards that
- have certain NTSC tuners (tveeprom model numbers 85, 99 and 112). The
+/* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is
+ present in Hauppauge PVR-150 (and possibly PVR-500) cards that have
+ certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The
audio autodetect fails on some channels for these models and the workaround
is to select the audio standard explicitly. Many thanks to Hauppauge for
providing this information. */
-enum cx25840_cardtype {
- CARDTYPE_PVR150,
- CARDTYPE_PG600,
- CARDTYPE_PVR150_WORKAROUND,
+#define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0)
+
+enum cx25840_video_input {
+ /* Composite video inputs In1-In8 */
+ CX25840_COMPOSITE1 = 1,
+ CX25840_COMPOSITE2,
+ CX25840_COMPOSITE3,
+ CX25840_COMPOSITE4,
+ CX25840_COMPOSITE5,
+ CX25840_COMPOSITE6,
+ CX25840_COMPOSITE7,
+ CX25840_COMPOSITE8,
+
+ /* S-Video inputs consist of one luma input (In1-In4) ORed with one
+ chroma input (In5-In8) */
+ CX25840_SVIDEO_LUMA1 = 0x10,
+ CX25840_SVIDEO_LUMA2 = 0x20,
+ CX25840_SVIDEO_LUMA3 = 0x30,
+ CX25840_SVIDEO_LUMA4 = 0x40,
+ CX25840_SVIDEO_CHROMA4 = 0x400,
+ CX25840_SVIDEO_CHROMA5 = 0x500,
+ CX25840_SVIDEO_CHROMA6 = 0x600,
+ CX25840_SVIDEO_CHROMA7 = 0x700,
+ CX25840_SVIDEO_CHROMA8 = 0x800,
+
+ /* S-Video aliases for common luma/chroma combinations */
+ CX25840_SVIDEO1 = 0x510,
+ CX25840_SVIDEO2 = 0x620,
+ CX25840_SVIDEO3 = 0x730,
+ CX25840_SVIDEO4 = 0x840,
};
-enum cx25840_input {
- CX25840_TUNER,
- CX25840_COMPOSITE0,
- CX25840_COMPOSITE1,
- CX25840_SVIDEO0,
- CX25840_SVIDEO1
+enum cx25840_audio_input {
+ /* Audio inputs: serial or In4-In8 */
+ CX25840_AUDIO_SERIAL,
+ CX25840_AUDIO4 = 4,
+ CX25840_AUDIO5,
+ CX25840_AUDIO6,
+ CX25840_AUDIO7,
+ CX25840_AUDIO8,
};
struct cx25840_state {
- enum cx25840_cardtype cardtype;
- enum cx25840_input input;
- int audio_input;
- enum v4l2_audio_clock_freq audclk_freq;
+ int pvr150_workaround;
+ int radio;
+ enum cx25840_video_input vid_input;
+ enum cx25840_audio_input aud_input;
+ u32 audclk_freq;
};
/* ----------------------------------------------------------------------- */
@@ -84,6 +96,7 @@ int cx25840_loadfw(struct i2c_client *client);
/* ----------------------------------------------------------------------- */
/* cx25850-audio.c */
int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg);
+void cx25840_audio_set_path(struct i2c_client *client);
/* ----------------------------------------------------------------------- */
/* cx25850-vbi.c */
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 85ba4106dc79..76fcb4e995c9 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -29,6 +29,21 @@ config VIDEO_CX88_DVB
You must also select one or more DVB/ATSC demodulators.
If you are unsure which you need, choose all of them.
+config VIDEO_CX88_ALSA
+ tristate "ALSA DMA audio support"
+ depends on VIDEO_CX88 && SND
+ select SND_PCM_OSS
+ ---help---
+ This is a video4linux driver for direct (DMA) audio on
+ Conexant 2388x based TV cards.
+ It only works with boards with function 01 enabled.
+ To check if your board supports, use lspci -n.
+ If supported, you should see 1471:8801 or 1471:8811
+ PCI device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx88-alsa.
+
config VIDEO_CX88_DVB_ALL_FRONTENDS
bool "Build all supported frontends for cx2388x based TV cards"
default y
@@ -38,6 +53,7 @@ config VIDEO_CX88_DVB_ALL_FRONTENDS
select DVB_CX22702
select DVB_LGDT330X
select DVB_NXT200X
+ select DVB_CX24123
---help---
This builds cx88-dvb with all currently supported frontend
demodulators. If you wish to tweak your configuration, and
@@ -89,3 +105,12 @@ config VIDEO_CX88_DVB_NXT200X
---help---
This adds ATSC 8VSB and QAM64/256 support for cards based on the
Connexant 2388x chip and the NXT2002/NXT2004 demodulator.
+
+config VIDEO_CX88_DVB_CX24123
+ bool "Conexant CX24123 DVB-S Support"
+ default y
+ depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+ select DVB_CX24123
+ ---help---
+ This adds DVB-S support for cards based on the
+ Connexant 2388x chip and the CX24123 demodulator.
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
index 54401b02b7ce..e4b2134fe567 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -4,7 +4,7 @@ cx8800-objs := cx88-video.o cx88-vbi.o
cx8802-objs := cx88-mpeg.o
obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o cx8802.o cx88-blackbird.o
-obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
+obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o cx88-vp3054-i2c.o
EXTRA_CFLAGS += -I$(src)/..
EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
@@ -16,5 +16,7 @@ extra-cflags-$(CONFIG_DVB_OR51132) += -DHAVE_OR51132=1
extra-cflags-$(CONFIG_DVB_LGDT330X) += -DHAVE_LGDT330X=1
extra-cflags-$(CONFIG_DVB_MT352) += -DHAVE_MT352=1
extra-cflags-$(CONFIG_DVB_NXT200X) += -DHAVE_NXT200X=1
+extra-cflags-$(CONFIG_DVB_CX24123) += -DHAVE_CX24123=1
+extra-cflags-$(CONFIG_VIDEO_CX88_DVB)+= -DHAVE_VP3054_I2C=1
EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
new file mode 100644
index 000000000000..7695b521eb35
--- /dev/null
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -0,0 +1,848 @@
+/*
+ *
+ * Support for audio capture
+ * PCI function #1 of the cx2388x.
+ *
+ * (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>
+ * (c) 2005 Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ * Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
+ * Based on dummy.c by Jaroslav Kysela <perex@suse.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <asm/delay.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+
+#include "cx88.h"
+#include "cx88-reg.h"
+
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+ printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg)
+
+#define dprintk_core(level,fmt, arg...) if (debug >= level) \
+ printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg)
+
+
+/****************************************************************************
+ Data type declarations - Can be moded to a header file later
+ ****************************************************************************/
+
+/* These can be replaced after done */
+#define MIXER_ADDR_LAST MAX_CX88_INPUT
+
+struct cx88_audio_dev {
+ struct cx88_core *core;
+ struct cx88_dmaqueue q;
+
+ /* pci i/o */
+ struct pci_dev *pci;
+ unsigned char pci_rev,pci_lat;
+
+ /* audio controls */
+ int irq;
+
+ snd_card_t *card;
+
+ spinlock_t reg_lock;
+
+ unsigned int dma_size;
+ unsigned int period_size;
+ unsigned int num_periods;
+
+ struct videobuf_dmabuf dma_risc;
+
+ int mixer_volume[MIXER_ADDR_LAST+1][2];
+ int capture_source[MIXER_ADDR_LAST+1][2];
+
+ long int read_count;
+ long int read_offset;
+
+ struct cx88_buffer *buf;
+
+ long opened;
+ snd_pcm_substream_t *substream;
+
+};
+typedef struct cx88_audio_dev snd_cx88_card_t;
+
+
+
+/****************************************************************************
+ Module global static vars
+ ****************************************************************************/
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
+static snd_card_t *snd_cx88_cards[SNDRV_CARDS];
+
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled.");
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s).");
+
+
+/****************************************************************************
+ Module macros
+ ****************************************************************************/
+
+MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");
+MODULE_AUTHOR("Ricardo Cerqueira");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@brturbo.com.br>");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Conexant,23881},"
+ "{{Conexant,23882},"
+ "{{Conexant,23883}");
+static unsigned int debug = 0;
+module_param(debug,int,0644);
+MODULE_PARM_DESC(debug,"enable debug messages");
+
+/****************************************************************************
+ Module specific funtions
+ ****************************************************************************/
+
+/*
+ * BOARD Specific: Sets audio DMA
+ */
+
+int _cx88_start_audio_dma(snd_cx88_card_t *chip)
+{
+ struct cx88_buffer *buf = chip->buf;
+ struct cx88_core *core=chip->core;
+ struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
+
+
+ dprintk(1, "Starting audio DMA for %i bytes/line and %i (%i) lines at address %08x\n",buf->bpl, chip->num_periods, audio_ch->fifo_size / buf->bpl, audio_ch->fifo_start);
+
+ /* setup fifo + format - out channel */
+ cx88_sram_channel_setup(chip->core, &cx88_sram_channels[SRAM_CH25],
+ buf->bpl, buf->risc.dma);
+
+ /* sets bpl size */
+ cx_write(MO_AUDD_LNGTH, buf->bpl);
+
+ /* reset counter */
+ cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET);
+
+ dprintk(1,"Enabling IRQ, setting mask from 0x%x to 0x%x\n",chip->core->pci_irqmask,(chip->core->pci_irqmask | 0x02));
+ /* enable irqs */
+ cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | 0x02);
+
+
+ /* Enables corresponding bits at AUD_INT_STAT */
+ cx_write(MO_AUD_INTMSK,
+ (1<<16)|
+ (1<<12)|
+ (1<<4)|
+ (1<<0)
+ );
+
+ /* start dma */
+ cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */
+ cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */
+
+ if (debug)
+ cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
+
+ return 0;
+}
+
+/*
+ * BOARD Specific: Resets audio DMA
+ */
+int _cx88_stop_audio_dma(snd_cx88_card_t *chip)
+{
+ struct cx88_core *core=chip->core;
+ dprintk(1, "Stopping audio DMA\n");
+
+ /* stop dma */
+ cx_clear(MO_AUD_DMACNTRL, 0x11);
+
+ /* disable irqs */
+ cx_clear(MO_PCI_INTMSK, 0x02);
+ cx_clear(MO_AUD_INTMSK,
+ (1<<16)|
+ (1<<12)|
+ (1<<4)|
+ (1<<0)
+ );
+
+ if (debug)
+ cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
+
+ return 0;
+}
+
+#define MAX_IRQ_LOOP 10
+
+/*
+ * BOARD Specific: IRQ dma bits
+ */
+static char *cx88_aud_irqs[32] = {
+ "dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */
+ NULL, /* reserved */
+ "dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */
+ NULL, /* reserved */
+ "dnf_of", "upf_uf", "rds_dnf_uf", /* 8-10 */
+ NULL, /* reserved */
+ "dn_sync", "up_sync", "rds_dn_sync", /* 12-14 */
+ NULL, /* reserved */
+ "opc_err", "par_err", "rip_err", /* 16-18 */
+ "pci_abort", "ber_irq", "mchg_irq" /* 19-21 */
+};
+
+/*
+ * BOARD Specific: Threats IRQ audio specific calls
+ */
+static void cx8801_aud_irq(snd_cx88_card_t *chip)
+{
+ struct cx88_core *core = chip->core;
+ u32 status, mask;
+ u32 count;
+
+ status = cx_read(MO_AUD_INTSTAT);
+ mask = cx_read(MO_AUD_INTMSK);
+ if (0 == (status & mask)) {
+ spin_unlock(&chip->reg_lock);
+ return;
+ }
+ cx_write(MO_AUD_INTSTAT, status);
+ if (debug > 1 || (status & mask & ~0xff))
+ cx88_print_irqbits(core->name, "irq aud",
+ cx88_aud_irqs, status, mask);
+ /* risc op code error */
+ if (status & (1 << 16)) {
+ printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name);
+ cx_clear(MO_AUD_DMACNTRL, 0x11);
+ cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]);
+ }
+
+ /* risc1 downstream */
+ if (status & 0x01) {
+ spin_lock(&chip->reg_lock);
+ count = cx_read(MO_AUDD_GPCNT);
+ spin_unlock(&chip->reg_lock);
+ if (chip->read_count == 0)
+ chip->read_count += chip->dma_size;
+ }
+
+ if (chip->read_count >= chip->period_size) {
+ dprintk(2, "Elapsing period\n");
+ snd_pcm_period_elapsed(chip->substream);
+ }
+
+ dprintk(3,"Leaving audio IRQ handler...\n");
+
+ /* FIXME: Any other status should deserve a special handling? */
+}
+
+/*
+ * BOARD Specific: Handles IRQ calls
+ */
+static irqreturn_t cx8801_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ snd_cx88_card_t *chip = dev_id;
+ struct cx88_core *core = chip->core;
+ u32 status;
+ int loop, handled = 0;
+
+ for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
+ status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x02);
+ if (0 == status)
+ goto out;
+ dprintk( 3, "cx8801_irq\n" );
+ dprintk( 3, " loop: %d/%d\n", loop, MAX_IRQ_LOOP );
+ dprintk( 3, " status: %d\n", status );
+ handled = 1;
+ cx_write(MO_PCI_INTSTAT, status);
+
+ if (status & 0x02)
+ {
+ dprintk( 2, " ALSA IRQ handling\n" );
+ cx8801_aud_irq(chip);
+ }
+ };
+
+ if (MAX_IRQ_LOOP == loop) {
+ dprintk( 0, "clearing mask\n" );
+ dprintk(1,"%s/0: irq loop -- clearing mask\n",
+ core->name);
+ cx_clear(MO_PCI_INTMSK,0x02);
+ }
+
+ out:
+ return IRQ_RETVAL(handled);
+}
+
+
+static int dsp_buffer_free(snd_cx88_card_t *chip)
+{
+ BUG_ON(!chip->dma_size);
+
+ dprintk(2,"Freeing buffer\n");
+ videobuf_dma_pci_unmap(chip->pci, &chip->dma_risc);
+ videobuf_dma_free(&chip->dma_risc);
+ btcx_riscmem_free(chip->pci,&chip->buf->risc);
+ kfree(chip->buf);
+
+ chip->dma_size = 0;
+
+ return 0;
+}
+
+/****************************************************************************
+ ALSA PCM Interface
+ ****************************************************************************/
+
+/*
+ * Digital hardware definition
+ */
+static snd_pcm_hardware_t snd_cx88_digital_hw = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = (2*2048),
+ .period_bytes_min = 256,
+ .period_bytes_max = 2048,
+ .periods_min = 2,
+ .periods_max = 16,
+};
+
+/*
+ * audio pcm capture runtime free
+ */
+static void snd_card_cx88_runtime_free(snd_pcm_runtime_t *runtime)
+{
+}
+/*
+ * audio pcm capture open callback
+ */
+static int snd_cx88_pcm_open(snd_pcm_substream_t *substream)
+{
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ int err;
+
+ if (test_and_set_bit(0, &chip->opened))
+ return -EBUSY;
+
+ err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ if (err < 0)
+ goto _error;
+
+ chip->substream = substream;
+
+ chip->read_count = 0;
+ chip->read_offset = 0;
+
+ runtime->private_free = snd_card_cx88_runtime_free;
+ runtime->hw = snd_cx88_digital_hw;
+
+ return 0;
+_error:
+ dprintk(1,"Error opening PCM!\n");
+ clear_bit(0, &chip->opened);
+ smp_mb__after_clear_bit();
+ return err;
+}
+
+/*
+ * audio close callback
+ */
+static int snd_cx88_close(snd_pcm_substream_t *substream)
+{
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+
+ clear_bit(0, &chip->opened);
+ smp_mb__after_clear_bit();
+
+ return 0;
+}
+
+/*
+ * hw_params callback
+ */
+static int snd_cx88_hw_params(snd_pcm_substream_t * substream,
+ snd_pcm_hw_params_t * hw_params)
+{
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+ struct cx88_buffer *buf;
+
+ if (substream->runtime->dma_area) {
+ dsp_buffer_free(chip);
+ substream->runtime->dma_area = NULL;
+ }
+
+
+ chip->period_size = params_period_bytes(hw_params);
+ chip->num_periods = params_periods(hw_params);
+ chip->dma_size = chip->period_size * params_periods(hw_params);
+
+ BUG_ON(!chip->dma_size);
+
+ dprintk(1,"Setting buffer\n");
+
+ buf = kmalloc(sizeof(*buf),GFP_KERNEL);
+ if (NULL == buf)
+ return -ENOMEM;
+ memset(buf,0,sizeof(*buf));
+
+
+ buf->vb.memory = V4L2_MEMORY_MMAP;
+ buf->vb.width = chip->period_size;
+ buf->vb.height = chip->num_periods;
+ buf->vb.size = chip->dma_size;
+ buf->vb.field = V4L2_FIELD_NONE;
+
+ videobuf_dma_init(&buf->vb.dma);
+ videobuf_dma_init_kernel(&buf->vb.dma,PCI_DMA_FROMDEVICE,
+ (PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT));
+
+ videobuf_dma_pci_map(chip->pci,&buf->vb.dma);
+
+
+ cx88_risc_databuffer(chip->pci, &buf->risc,
+ buf->vb.dma.sglist,
+ buf->vb.width, buf->vb.height);
+
+ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+ buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+
+ buf->vb.state = STATE_PREPARED;
+
+ buf->bpl = chip->period_size;
+ chip->buf = buf;
+ chip->dma_risc = buf->vb.dma;
+
+ dprintk(1,"Buffer ready at %u\n",chip->dma_risc.nr_pages);
+ substream->runtime->dma_area = chip->dma_risc.vmalloc;
+ return 0;
+}
+
+/*
+ * hw free callback
+ */
+static int snd_cx88_hw_free(snd_pcm_substream_t * substream)
+{
+
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+
+ if (substream->runtime->dma_area) {
+ dsp_buffer_free(chip);
+ substream->runtime->dma_area = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * prepare callback
+ */
+static int snd_cx88_prepare(snd_pcm_substream_t *substream)
+{
+ return 0;
+}
+
+
+/*
+ * trigger callback
+ */
+static int snd_cx88_card_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+ int err;
+
+ spin_lock(&chip->reg_lock);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ err=_cx88_start_audio_dma(chip);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ err=_cx88_stop_audio_dma(chip);
+ break;
+ default:
+ err=-EINVAL;
+ break;
+ }
+
+ spin_unlock(&chip->reg_lock);
+
+ return err;
+}
+
+/*
+ * pointer callback
+ */
+static snd_pcm_uframes_t snd_cx88_pointer(snd_pcm_substream_t *substream)
+{
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+
+ if (chip->read_count) {
+ chip->read_count -= snd_pcm_lib_period_bytes(substream);
+ chip->read_offset += snd_pcm_lib_period_bytes(substream);
+ if (chip->read_offset == chip->dma_size)
+ chip->read_offset = 0;
+ }
+
+ dprintk(2, "Pointer time, will return %li, read %li\n",chip->read_offset,chip->read_count);
+ return bytes_to_frames(runtime, chip->read_offset);
+
+}
+
+/*
+ * operators
+ */
+static snd_pcm_ops_t snd_cx88_pcm_ops = {
+ .open = snd_cx88_pcm_open,
+ .close = snd_cx88_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_cx88_hw_params,
+ .hw_free = snd_cx88_hw_free,
+ .prepare = snd_cx88_prepare,
+ .trigger = snd_cx88_card_trigger,
+ .pointer = snd_cx88_pointer,
+};
+
+/*
+ * create a PCM device
+ */
+static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, char *name)
+{
+ int err;
+ snd_pcm_t *pcm;
+
+ err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
+ if (err < 0)
+ return err;
+ pcm->private_data = chip;
+ strcpy(pcm->name, name);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx88_pcm_ops);
+
+ return 0;
+}
+
+/****************************************************************************
+ CONTROL INTERFACE
+ ****************************************************************************/
+static int snd_cx88_capture_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *info)
+{
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 1;
+ info->value.integer.min = 0;
+ info->value.integer.max = 0x3f;
+
+ return 0;
+}
+
+/* OK - TODO: test it */
+static int snd_cx88_capture_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+{
+ snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+ struct cx88_core *core=chip->core;
+
+ value->value.integer.value[0] = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f);
+
+ return 0;
+}
+
+/* OK - TODO: test it */
+static int snd_cx88_capture_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+{
+ snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+ struct cx88_core *core=chip->core;
+ int v;
+ u32 old_control;
+
+ spin_lock_irq(&chip->reg_lock);
+ old_control = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f);
+ v = 0x3f - (value->value.integer.value[0] & 0x3f);
+ cx_andor(AUD_VOL_CTL, 0x3f, v);
+ spin_unlock_irq(&chip->reg_lock);
+
+ return v != old_control;
+}
+
+static snd_kcontrol_new_t snd_cx88_capture_volume = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Volume",
+ .info = snd_cx88_capture_volume_info,
+ .get = snd_cx88_capture_volume_get,
+ .put = snd_cx88_capture_volume_put,
+};
+
+
+/****************************************************************************
+ Basic Flow for Sound Devices
+ ****************************************************************************/
+
+/*
+ * PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio
+ * Only boards with eeprom and byte 1 at eeprom=1 have it
+ */
+
+struct pci_device_id cx88_audio_pci_tbl[] = {
+ {0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+ {0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+ {0, }
+};
+MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl);
+
+/*
+ * Chip-specific destructor
+ */
+
+static int snd_cx88_free(snd_cx88_card_t *chip)
+{
+
+ if (chip->irq >= 0){
+ synchronize_irq(chip->irq);
+ free_irq(chip->irq, chip);
+ }
+
+ cx88_core_put(chip->core,chip->pci);
+
+ pci_disable_device(chip->pci);
+ return 0;
+}
+
+/*
+ * Component Destructor
+ */
+static void snd_cx88_dev_free(snd_card_t * card)
+{
+ snd_cx88_card_t *chip = card->private_data;
+
+ snd_cx88_free(chip);
+}
+
+
+/*
+ * Alsa Constructor - Component probe
+ */
+
+static int devno=0;
+static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci,
+ snd_cx88_card_t **rchip)
+{
+ snd_cx88_card_t *chip;
+ struct cx88_core *core;
+ int err;
+
+ *rchip = NULL;
+
+ err = pci_enable_device(pci);
+ if (err < 0)
+ return err;
+
+ pci_set_master(pci);
+
+ chip = (snd_cx88_card_t *) card->private_data;
+
+ core = cx88_core_get(pci);
+
+ if (!pci_dma_supported(pci,0xffffffff)) {
+ dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
+ err = -EIO;
+ cx88_core_put(core,pci);
+ return err;
+ }
+
+
+ /* pci init */
+ chip->card = card;
+ chip->pci = pci;
+ chip->irq = -1;
+ spin_lock_init(&chip->reg_lock);
+
+ cx88_reset(core);
+ if (NULL == core) {
+ err = -EINVAL;
+ kfree (chip);
+ return err;
+ }
+ chip->core = core;
+
+ /* get irq */
+ err = request_irq(chip->pci->irq, cx8801_irq,
+ SA_SHIRQ | SA_INTERRUPT, chip->core->name, chip);
+ if (err < 0) {
+ dprintk(0, "%s: can't get IRQ %d\n",
+ chip->core->name, chip->pci->irq);
+ return err;
+ }
+
+ /* print pci info */
+ pci_read_config_byte(pci, PCI_CLASS_REVISION, &chip->pci_rev);
+ pci_read_config_byte(pci, PCI_LATENCY_TIMER, &chip->pci_lat);
+
+ dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, "
+ "latency: %d, mmio: 0x%lx\n", core->name, devno,
+ pci_name(pci), chip->pci_rev, pci->irq,
+ chip->pci_lat,pci_resource_start(pci,0));
+
+ chip->irq = pci->irq;
+ synchronize_irq(chip->irq);
+
+ snd_card_set_dev(card, &pci->dev);
+
+ *rchip = chip;
+
+ return 0;
+}
+
+static int __devinit cx88_audio_initdev(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
+{
+ snd_card_t *card;
+ snd_cx88_card_t *chip;
+ int err;
+
+ if (devno >= SNDRV_CARDS)
+ return (-ENODEV);
+
+ if (!enable[devno]) {
+ ++devno;
+ return (-ENOENT);
+ }
+
+ card = snd_card_new(index[devno], id[devno], THIS_MODULE, sizeof(snd_cx88_card_t));
+ if (!card)
+ return (-ENOMEM);
+
+ card->private_free = snd_cx88_dev_free;
+
+ err = snd_cx88_create(card, pci, &chip);
+ if (err < 0)
+ return (err);
+
+ err = snd_cx88_pcm(chip, 0, "CX88 Digital");
+
+ if (err < 0) {
+ snd_card_free(card);
+ return (err);
+ }
+
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_capture_volume, chip));
+ if (err < 0) {
+ snd_card_free(card);
+ return (err);
+ }
+
+ strcpy (card->driver, "CX88x");
+ sprintf(card->shortname, "Conexant CX%x", pci->device);
+ sprintf(card->longname, "%s at %#lx",
+ card->shortname, pci_resource_start(pci, 0));
+ strcpy (card->mixername, "CX88");
+
+ dprintk (0, "%s/%i: ALSA support for cx2388x boards\n",
+ card->driver,devno);
+
+ err = snd_card_register(card);
+ if (err < 0) {
+ snd_card_free(card);
+ return (err);
+ }
+ snd_cx88_cards[devno] = card;
+
+ pci_set_drvdata(pci,card);
+
+ devno++;
+ return 0;
+}
+/*
+ * ALSA destructor
+ */
+static void __devexit cx88_audio_finidev(struct pci_dev *pci)
+{
+ struct cx88_audio_dev *card = pci_get_drvdata(pci);
+
+ snd_card_free((void *)card);
+
+ pci_set_drvdata(pci, NULL);
+
+ devno--;
+}
+
+/*
+ * PCI driver definition
+ */
+
+static struct pci_driver cx88_audio_pci_driver = {
+ .name = "cx88_audio",
+ .id_table = cx88_audio_pci_tbl,
+ .probe = cx88_audio_initdev,
+ .remove = cx88_audio_finidev,
+ SND_PCI_PM_CALLBACKS
+};
+
+/****************************************************************************
+ LINUX MODULE INIT
+ ****************************************************************************/
+
+/*
+ * module init
+ */
+static int cx88_audio_init(void)
+{
+ printk(KERN_INFO "cx2388x alsa driver version %d.%d.%d loaded\n",
+ (CX88_VERSION_CODE >> 16) & 0xff,
+ (CX88_VERSION_CODE >> 8) & 0xff,
+ CX88_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+ printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
+ SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
+#endif
+ return pci_register_driver(&cx88_audio_pci_driver);
+}
+
+/*
+ * module remove
+ */
+static void cx88_audio_fini(void)
+{
+
+ pci_unregister_driver(&cx88_audio_pci_driver);
+}
+
+module_init(cx88_audio_init);
+module_exit(cx88_audio_fini);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index 74e57a53116f..a49062119313 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -32,10 +32,10 @@
#include <linux/firmware.h>
#include "cx88.h"
+#include <media/v4l2-common.h>
MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards");
-MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>");
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
static unsigned int mpegbufs = 32;
@@ -1375,7 +1375,7 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
struct cx88_core *core = dev->core;
if (debug > 1)
- cx88_print_ioctl(core->name,cmd);
+ v4l_print_ioctl(core->name,cmd);
switch (cmd) {
@@ -1689,6 +1689,18 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev,
memcpy(&dev->params,&default_mpeg_params,sizeof(default_mpeg_params));
memcpy(&dev->dnr_params,&default_dnr_params,sizeof(default_dnr_params));
+ if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN) {
+
+ if (core->tuner_formats & V4L2_STD_525_60) {
+ dev->height = 480;
+ dev->params.vi_frame_rate = 30;
+ } else {
+ dev->height = 576;
+ dev->params.vi_frame_rate = 25;
+ }
+
+ }
+
err = cx8802_init_common(dev);
if (0 != err)
goto fail_free;
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 951709aa88ba..a76d54503b6f 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -611,12 +611,12 @@ struct cx88_board cx88_boards[] = {
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
- .gpio0 = 0xed12, /* internal decoder */
+ .gpio0 = 0xed1a,
.gpio2 = 0x00ff,
},{
.type = CX88_VMUX_DEBUG,
.vmux = 0,
- .gpio0 = 0xff01, /* mono from tuner chip */
+ .gpio0 = 0xff01,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
@@ -708,7 +708,7 @@ struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = {
.name = "DViCO FusionHDTV 3 Gold-T",
- .tuner_type = TUNER_THOMSON_DTT7611,
+ .tuner_type = TUNER_THOMSON_DTT761X,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -897,6 +897,158 @@ struct cx88_board cx88_boards[] = {
.gpio3 = 0x0000,
}},
},
+ [CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1] = {
+ .name = "Hauppauge Nova-S-Plus DVB-S",
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ }},
+ .dvb = 1,
+ },
+ [CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = {
+ .name = "Hauppauge Nova-SE2 DVB-S",
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ }},
+ .dvb = 1,
+ },
+ [CX88_BOARD_KWORLD_DVBS_100] = {
+ .name = "KWorld DVB-S 100",
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ }},
+ .dvb = 1,
+ },
+ [CX88_BOARD_HAUPPAUGE_HVR1100] = {
+ .name = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid",
+ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ }},
+ /* fixme: Add radio support */
+ .dvb = 1,
+ },
+ [CX88_BOARD_HAUPPAUGE_HVR1100LP] = {
+ .name = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)",
+ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ }},
+ /* fixme: Add radio support */
+ .dvb = 1,
+ },
+ [CX88_BOARD_DNTV_LIVE_DVB_T_PRO] = {
+ .name = "digitalnow DNTV Live! DVB-T Pro",
+ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
+ TDA9887_PORT2_ACTIVE,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0xf80808,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0xf80808,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0xf80808,
+ }},
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0xf80808,
+ },
+ .dvb = 1,
+ },
+ [CX88_BOARD_KWORLD_DVB_T_CX22702] = {
+ /* Kworld V-stream Xpert DVB-T with Thomson tuner */
+ /* DTT 7579 Conexant CX22702-19 Conexant CX2388x */
+ /* Manenti Marco <marco_manenti@colman.it> */
+ .name = "KWorld/VStream XPert DVB-T with cx22702",
+ .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_DVICO_FUSIONHDTV_DVB_T_DUAL] = {
+ .name = "DViCO FusionHDTV DVB-T Dual Digital",
+ .tuner_type = TUNER_ABSENT, /* No analog tuner */
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x000027df,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x000027df,
+ }},
+ .dvb = 1,
+ },
+
};
const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
@@ -1044,6 +1196,54 @@ struct cx88_subid cx88_subids[] = {
.subvendor = 0x1461,
.subdevice = 0x000a,
.card = CX88_BOARD_AVERTV_303,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x9200,
+ .card = CX88_BOARD_HAUPPAUGE_NOVASE2_S1,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x9201,
+ .card = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x9202,
+ .card = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
+ },{
+ .subvendor = 0x17de,
+ .subdevice = 0x08b2,
+ .card = CX88_BOARD_KWORLD_DVBS_100,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x9400,
+ .card = CX88_BOARD_HAUPPAUGE_HVR1100,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x9402,
+ .card = CX88_BOARD_HAUPPAUGE_HVR1100,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x9800,
+ .card = CX88_BOARD_HAUPPAUGE_HVR1100LP,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x9802,
+ .card = CX88_BOARD_HAUPPAUGE_HVR1100LP,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x9001,
+ .card = CX88_BOARD_HAUPPAUGE_DVB_T1,
+ },{
+ .subvendor = 0x1822,
+ .subdevice = 0x0025,
+ .card = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
+ },{
+ .subvendor = 0x17de,
+ .subdevice = 0x08a1,
+ .card = CX88_BOARD_KWORLD_DVB_T_CX22702,
+ },{
+ .subvendor = 0x18ac,
+ .subdevice = 0xdb50,
+ .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL,
},
};
const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -1075,20 +1275,19 @@ static void __devinit leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data)
core->name, core->tuner_type, eeprom_data[0]);
}
-
-/* ----------------------------------------------------------------------- */
-
static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
{
struct tveeprom tv;
tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data);
core->tuner_type = tv.tuner_type;
+ core->tuner_formats = tv.tuner_formats;
core->has_radio = tv.has_radio;
/* Make sure we support the board model */
switch (tv.model)
{
+ case 28552: /* WinTV-PVR 'Roslyn' (No IR) */
case 90002: /* Nova-T-PCI (9002) */
case 92001: /* Nova-S-Plus (Video and IR) */
case 92002: /* Nova-S-Plus (Video and IR) */
@@ -1096,7 +1295,9 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
case 90500: /* Nova-T-PCI (oem) */
case 90501: /* Nova-T-PCI (oem/IR) */
case 92000: /* Nova-SE2 (OEM, No Video or IR) */
-
+ case 94009: /* WinTV-HVR1100 (Video and IR Retail) */
+ case 94501: /* WinTV-HVR1100 (Video and IR OEM) */
+ case 98559: /* WinTV-HVR1100LP (Video no IR, Retail - Low Profile) */
/* known */
break;
default:
@@ -1211,12 +1412,21 @@ void cx88_card_setup(struct cx88_core *core)
if (0 == core->i2c_rc)
leadtek_eeprom(core,eeprom);
break;
+ case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+ case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
case CX88_BOARD_HAUPPAUGE_DVB_T1:
+ case CX88_BOARD_HAUPPAUGE_HVR1100:
+ case CX88_BOARD_HAUPPAUGE_HVR1100LP:
if (0 == core->i2c_rc)
hauppauge_eeprom(core,eeprom);
break;
+ case CX88_BOARD_KWORLD_DVBS_100:
+ cx_write(MO_GP0_IO, 0x000007f8);
+ cx_write(MO_GP1_IO, 0x00000001);
+ break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
/* GPIO0:0 is hooked to mt352 reset pin */
cx_set(MO_GP0_IO, 0x00000101);
cx_clear(MO_GP0_IO, 0x00000001);
@@ -1232,6 +1442,9 @@ void cx88_card_setup(struct cx88_core *core)
cx_clear(MO_GP0_IO, 0x00000007);
cx_set(MO_GP2_IO, 0x00000101);
break;
+ case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
+ cx_write(MO_GP0_IO, 0x00080808);
+ break;
case CX88_BOARD_ATI_HDTVWONDER:
if (0 == core->i2c_rc) {
/* enable tuner */
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index bb6eb54e19ce..9975be1aca38 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -34,6 +34,7 @@
#include <linux/videodev2.h>
#include "cx88.h"
+#include <media/v4l2-common.h>
MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -76,60 +77,6 @@ static unsigned int cx88_devcount;
static LIST_HEAD(cx88_devlist);
static DECLARE_MUTEX(devlist);
-/* ------------------------------------------------------------------ */
-/* debug help functions */
-
-static const char *v4l1_ioctls[] = {
- "0", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
- "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
- "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
- "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
- "SMICROCODE", "GVBIFMT", "SVBIFMT" };
-#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
-
-static const char *v4l2_ioctls[] = {
- "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
- "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
- "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
- "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
- "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
- "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
- "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
- "44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
- "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
- "S_MODULATOR"
-};
-#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
-
-void cx88_print_ioctl(char *name, unsigned int cmd)
-{
- char *dir;
-
- switch (_IOC_DIR(cmd)) {
- case _IOC_NONE: dir = "--"; break;
- case _IOC_READ: dir = "r-"; break;
- case _IOC_WRITE: dir = "-w"; break;
- case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
- default: dir = "??"; break;
- }
- switch (_IOC_TYPE(cmd)) {
- case 'v':
- printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n",
- name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
- v4l1_ioctls[_IOC_NR(cmd)] : "???");
- break;
- case 'V':
- printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n",
- name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ?
- v4l2_ioctls[_IOC_NR(cmd)] : "???");
- break;
- default:
- printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
- name, cmd, dir, _IOC_NR(cmd));
- }
-}
-
-/* ------------------------------------------------------------------ */
#define NO_SYNC_LINE (-1U)
static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
@@ -291,9 +238,9 @@ cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf)
* channel 22 (u video) - 2.0k
* channel 23 (v video) - 2.0k
* channel 24 (vbi) - 4.0k
- * channels 25+26 (audio) - 0.5k
+ * channels 25+26 (audio) - 4.0k
* channel 28 (mpeg) - 4.0k
- * TOTAL = 25.5k
+ * TOTAL = 29.0k
*
* Every channel has 160 bytes control data (64 bytes instruction
* queue and 6 CDT entries), which is close to 2k total.
@@ -359,7 +306,7 @@ struct sram_channel cx88_sram_channels[] = {
.ctrl_start = 0x180680,
.cdt = 0x180680 + 64,
.fifo_start = 0x185400,
- .fifo_size = 0x000200,
+ .fifo_size = 0x001000,
.ptr1_reg = MO_DMA25_PTR1,
.ptr2_reg = MO_DMA25_PTR2,
.cnt1_reg = MO_DMA25_CNT1,
@@ -371,7 +318,7 @@ struct sram_channel cx88_sram_channels[] = {
.ctrl_start = 0x180720,
.cdt = 0x180680 + 64, /* same as audio IN */
.fifo_start = 0x185400, /* same as audio IN */
- .fifo_size = 0x000200, /* same as audio IN */
+ .fifo_size = 0x001000, /* same as audio IN */
.ptr1_reg = MO_DMA26_PTR1,
.ptr2_reg = MO_DMA26_PTR2,
.cnt1_reg = MO_DMA26_CNT1,
@@ -382,7 +329,7 @@ struct sram_channel cx88_sram_channels[] = {
.cmds_start = 0x180200,
.ctrl_start = 0x1807C0,
.cdt = 0x1807C0 + 64,
- .fifo_start = 0x185600,
+ .fifo_start = 0x186400,
.fifo_size = 0x001000,
.ptr1_reg = MO_DMA28_PTR1,
.ptr2_reg = MO_DMA28_PTR2,
@@ -848,7 +795,6 @@ int cx88_start_audio_dma(struct cx88_core *core)
/* start dma */
cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */
-
return 0;
}
@@ -1208,7 +1154,6 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
/* ------------------------------------------------------------------ */
-EXPORT_SYMBOL(cx88_print_ioctl);
EXPORT_SYMBOL(cx88_print_irqbits);
EXPORT_SYMBOL(cx88_core_irq);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 99ea955f5987..42c012aaa849 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -3,7 +3,7 @@
* device driver for Conexant 2388x based TV cards
* MPEG Transport Stream (DVB) routines
*
- * (c) 2004 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+ * (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
* (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
*
* This program is free software; you can redistribute it and/or modify
@@ -31,10 +31,14 @@
#include "cx88.h"
#include "dvb-pll.h"
+#include <media/v4l2-common.h>
#ifdef HAVE_MT352
# include "mt352.h"
# include "mt352_priv.h"
+# ifdef HAVE_VP3054_I2C
+# include "cx88-vp3054-i2c.h"
+# endif
#endif
#ifdef HAVE_CX22702
# include "cx22702.h"
@@ -48,6 +52,9 @@
#ifdef HAVE_NXT200X
# include "nxt200x.h"
#endif
+#ifdef HAVE_CX24123
+# include "cx24123.h"
+#endif
MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -125,6 +132,27 @@ static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
return 0;
}
+static int dvico_dual_demod_init(struct dvb_frontend *fe)
+{
+ static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x38 };
+ static u8 reset [] = { RESET, 0x80 };
+ static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+ static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 };
+ static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
+ static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(200);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+ return 0;
+}
+
static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
{
static u8 clock_config [] = { 0x89, 0x38, 0x39 };
@@ -172,6 +200,98 @@ static struct mt352_config dntv_live_dvbt_config = {
.demod_init = dntv_live_dvbt_demod_init,
.pll_set = mt352_pll_set,
};
+
+static struct mt352_config dvico_fusionhdtv_dual = {
+ .demod_address = 0x0F,
+ .demod_init = dvico_dual_demod_init,
+ .pll_set = mt352_pll_set,
+};
+
+#ifdef HAVE_VP3054_I2C
+static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
+{
+ static u8 clock_config [] = { 0x89, 0x38, 0x38 };
+ static u8 reset [] = { 0x50, 0x80 };
+ static u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+ static u8 agc_cfg [] = { 0x67, 0x10, 0x20, 0x00, 0xFF, 0xFF,
+ 0x00, 0xFF, 0x00, 0x40, 0x40 };
+ static u8 dntv_extra[] = { 0xB5, 0x7A };
+ static u8 capt_range_cfg[] = { 0x75, 0x32 };
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(2000);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ udelay(2000);
+ mt352_write(fe, dntv_extra, sizeof(dntv_extra));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+ return 0;
+}
+
+static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+
+ /* this message is to set up ATC and ALC */
+ static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
+ struct i2c_msg msg =
+ { .addr = dev->core->pll_addr, .flags = 0,
+ .buf = fmd1216_init, .len = sizeof(fmd1216_init) };
+ int err;
+
+ if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
+ if (err < 0)
+ return err;
+ else
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int dntv_live_dvbt_pro_pll_set(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params,
+ u8* pllbuf)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ struct i2c_msg msg =
+ { .addr = dev->core->pll_addr, .flags = 0,
+ .buf = pllbuf+1, .len = 4 };
+ int err;
+
+ /* Switch PLL to DVB mode */
+ err = philips_fmd1216_pll_init(fe);
+ if (err)
+ return err;
+
+ /* Tune PLL */
+ pllbuf[0] = dev->core->pll_addr << 1;
+ dvb_pll_configure(dev->core->pll_desc, pllbuf+1,
+ params->frequency,
+ params->u.ofdm.bandwidth);
+ if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
+ printk(KERN_WARNING "cx88-dvb: %s error "
+ "(addr %02x <- %02x, err = %i)\n",
+ __FUNCTION__, pllbuf[0], pllbuf[1], err);
+ if (err < 0)
+ return err;
+ else
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static struct mt352_config dntv_live_dvbt_pro_config = {
+ .demod_address = 0x0f,
+ .no_tuner = 1,
+ .demod_init = dntv_live_dvbt_pro_demod_init,
+ .pll_set = dntv_live_dvbt_pro_pll_set,
+};
+#endif
#endif
#ifdef HAVE_CX22702
@@ -188,6 +308,12 @@ static struct cx22702_config hauppauge_novat_config = {
.pll_address = 0x61,
.pll_desc = &dvb_pll_thomson_dtt759x,
};
+static struct cx22702_config hauppauge_hvr1100_config = {
+ .demod_address = 0x63,
+ .output_mode = CX22702_SERIAL_OUTPUT,
+ .pll_address = 0x61,
+ .pll_desc = &dvb_pll_fmd1216me,
+};
#endif
#ifdef HAVE_OR51132
@@ -314,6 +440,40 @@ static struct nxt200x_config ati_hdtvwonder = {
};
#endif
+#ifdef HAVE_CX24123
+static int cx24123_set_ts_param(struct dvb_frontend* fe,
+ int is_punctured)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ dev->ts_gen_cntrl = 0x2;
+ return 0;
+}
+
+static void cx24123_enable_lnb_voltage(struct dvb_frontend* fe, int on)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+
+ if (on)
+ cx_write(MO_GP0_IO, 0x000006f9);
+ else
+ cx_write(MO_GP0_IO, 0x000006fB);
+}
+
+static struct cx24123_config hauppauge_novas_config = {
+ .demod_address = 0x55,
+ .use_isl6421 = 1,
+ .set_ts_params = cx24123_set_ts_param,
+};
+
+static struct cx24123_config kworld_dvbs_100_config = {
+ .demod_address = 0x15,
+ .use_isl6421 = 0,
+ .set_ts_params = cx24123_set_ts_param,
+ .enable_lnb_voltage = cx24123_enable_lnb_voltage,
+};
+#endif
+
static int dvb_register(struct cx8802_dev *dev)
{
/* init struct videobuf_dvb */
@@ -329,10 +489,16 @@ static int dvb_register(struct cx8802_dev *dev)
break;
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
case CX88_BOARD_CONEXANT_DVB_T1:
+ case CX88_BOARD_KWORLD_DVB_T_CX22702:
case CX88_BOARD_WINFAST_DTV1000:
dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
&dev->core->i2c_adap);
break;
+ case CX88_BOARD_HAUPPAUGE_HVR1100:
+ case CX88_BOARD_HAUPPAUGE_HVR1100LP:
+ dev->dvb.frontend = cx22702_attach(&hauppauge_hvr1100_config,
+ &dev->core->i2c_adap);
+ break;
#endif
#ifdef HAVE_MT352
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
@@ -355,6 +521,24 @@ static int dvb_register(struct cx8802_dev *dev)
dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config,
&dev->core->i2c_adap);
break;
+ case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
+#ifdef HAVE_VP3054_I2C
+ dev->core->pll_addr = 0x61;
+ dev->core->pll_desc = &dvb_pll_fmd1216me;
+ dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_pro_config,
+ &((struct vp3054_i2c_state *)dev->card_priv)->adap);
+#else
+ printk("%s: built without vp3054 support\n", dev->core->name);
+#endif
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+ /* The tin box says DEE1601, but it seems to be DTT7579
+ * compatible, with a slightly different MT352 AGC gain. */
+ dev->core->pll_addr = 0x61;
+ dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
+ dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dual,
+ &dev->core->i2c_adap);
+ break;
#endif
#ifdef HAVE_OR51132
case CX88_BOARD_PCHDTV_HD3000:
@@ -393,7 +577,7 @@ static int dvb_register(struct cx8802_dev *dev)
cx_set(MO_GP0_IO, 9);
mdelay(200);
dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_thomson_dtt7611;
+ dev->core->pll_desc = &dvb_pll_thomson_dtt761x;
dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
&dev->core->i2c_adap);
}
@@ -421,6 +605,17 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
break;
#endif
+#ifdef HAVE_CX24123
+ case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+ case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+ dev->dvb.frontend = cx24123_attach(&hauppauge_novas_config,
+ &dev->core->i2c_adap);
+ break;
+ case CX88_BOARD_KWORLD_DVBS_100:
+ dev->dvb.frontend = cx24123_attach(&kworld_dvbs_100_config,
+ &dev->core->i2c_adap);
+ break;
+#endif
default:
printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
dev->core->name);
@@ -473,6 +668,12 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev,
if (0 != err)
goto fail_free;
+#ifdef HAVE_VP3054_I2C
+ err = vp3054_i2c_probe(dev);
+ if (0 != err)
+ goto fail_free;
+#endif
+
/* dvb stuff */
printk("%s/2: cx2388x based dvb card\n", core->name);
videobuf_queue_init(&dev->dvb.dvbq, &dvb_qops,
@@ -484,6 +685,9 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev,
err = dvb_register(dev);
if (0 != err)
goto fail_fini;
+
+ /* Maintain a reference to cx88-video can query the 8802 device. */
+ core->dvbdev = dev;
return 0;
fail_fini:
@@ -499,9 +703,16 @@ static void __devexit dvb_remove(struct pci_dev *pci_dev)
{
struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+ /* Destroy any 8802 reference. */
+ dev->core->dvbdev = NULL;
+
/* dvb */
videobuf_dvb_unregister(&dev->dvb);
+#ifdef HAVE_VP3054_I2C
+ vp3054_i2c_remove(dev);
+#endif
+
/* common */
cx8802_fini_common(dev);
cx88_core_put(dev->core,dev->pci);
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 4a8fb161b16a..f720901e9638 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -30,6 +30,7 @@
#include <asm/io.h>
#include "cx88.h"
+#include <media/v4l2-common.h>
static unsigned int i2c_debug = 0;
module_param(i2c_debug, int, 0644);
@@ -135,7 +136,17 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
{
if (0 != core->i2c_rc)
return;
- i2c_clients_command(&core->i2c_adap, cmd, arg);
+
+ if (core->dvbdev) {
+ if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
+ core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
+
+ i2c_clients_command(&core->i2c_adap, cmd, arg);
+
+ if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
+ core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
+ } else
+ i2c_clients_command(&core->i2c_adap, cmd, arg);
}
static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index 461019dca901..286c85b6bdf9 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -5,7 +5,7 @@
*
* Copyright (c) 2003 Pavel Machek
* Copyright (c) 2004 Gerd Knorr
- * Copyright (c) 2004 Chris Pascoe
+ * Copyright (c) 2004, 2005 Chris Pascoe
*
* 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
@@ -29,9 +29,8 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <media/ir-common.h>
-
#include "cx88.h"
+#include <media/ir-common.h>
/* ---------------------------------------------------------------------- */
@@ -258,6 +257,114 @@ static IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = {
/* ---------------------------------------------------------------------- */
+/* AVERTV STUDIO 303 Remote */
+static IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE] = {
+ [ 0x2a ] = KEY_KP1,
+ [ 0x32 ] = KEY_KP2,
+ [ 0x3a ] = KEY_KP3,
+ [ 0x4a ] = KEY_KP4,
+ [ 0x52 ] = KEY_KP5,
+ [ 0x5a ] = KEY_KP6,
+ [ 0x6a ] = KEY_KP7,
+ [ 0x72 ] = KEY_KP8,
+ [ 0x7a ] = KEY_KP9,
+ [ 0x0e ] = KEY_KP0,
+
+ [ 0x02 ] = KEY_POWER,
+ [ 0x22 ] = KEY_VIDEO,
+ [ 0x42 ] = KEY_AUDIO,
+ [ 0x62 ] = KEY_ZOOM,
+ [ 0x0a ] = KEY_TV,
+ [ 0x12 ] = KEY_CD,
+ [ 0x1a ] = KEY_TEXT,
+
+ [ 0x16 ] = KEY_SUBTITLE,
+ [ 0x1e ] = KEY_REWIND,
+ [ 0x06 ] = KEY_PRINT,
+
+ [ 0x2e ] = KEY_SEARCH,
+ [ 0x36 ] = KEY_SLEEP,
+ [ 0x3e ] = KEY_SHUFFLE,
+ [ 0x26 ] = KEY_MUTE,
+
+ [ 0x4e ] = KEY_RECORD,
+ [ 0x56 ] = KEY_PAUSE,
+ [ 0x5e ] = KEY_STOP,
+ [ 0x46 ] = KEY_PLAY,
+
+ [ 0x6e ] = KEY_RED,
+ [ 0x0b ] = KEY_GREEN,
+ [ 0x66 ] = KEY_YELLOW,
+ [ 0x03 ] = KEY_BLUE,
+
+ [ 0x76 ] = KEY_LEFT,
+ [ 0x7e ] = KEY_RIGHT,
+ [ 0x13 ] = KEY_DOWN,
+ [ 0x1b ] = KEY_UP,
+};
+
+/* ---------------------------------------------------------------------- */
+
+/* DigitalNow DNTV Live! DVB-T Pro Remote */
+static IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE] = {
+ [ 0x16 ] = KEY_POWER,
+ [ 0x5b ] = KEY_HOME,
+
+ [ 0x55 ] = KEY_TV, /* live tv */
+ [ 0x58 ] = KEY_TUNER, /* digital Radio */
+ [ 0x5a ] = KEY_RADIO, /* FM radio */
+ [ 0x59 ] = KEY_DVD, /* dvd menu */
+ [ 0x03 ] = KEY_1,
+ [ 0x01 ] = KEY_2,
+ [ 0x06 ] = KEY_3,
+ [ 0x09 ] = KEY_4,
+ [ 0x1d ] = KEY_5,
+ [ 0x1f ] = KEY_6,
+ [ 0x0d ] = KEY_7,
+ [ 0x19 ] = KEY_8,
+ [ 0x1b ] = KEY_9,
+ [ 0x0c ] = KEY_CANCEL,
+ [ 0x15 ] = KEY_0,
+ [ 0x4a ] = KEY_CLEAR,
+ [ 0x13 ] = KEY_BACK,
+ [ 0x00 ] = KEY_TAB,
+ [ 0x4b ] = KEY_UP,
+ [ 0x4e ] = KEY_LEFT,
+ [ 0x4f ] = KEY_OK,
+ [ 0x52 ] = KEY_RIGHT,
+ [ 0x51 ] = KEY_DOWN,
+ [ 0x1e ] = KEY_VOLUMEUP,
+ [ 0x0a ] = KEY_VOLUMEDOWN,
+ [ 0x02 ] = KEY_CHANNELDOWN,
+ [ 0x05 ] = KEY_CHANNELUP,
+ [ 0x11 ] = KEY_RECORD,
+ [ 0x14 ] = KEY_PLAY,
+ [ 0x4c ] = KEY_PAUSE,
+ [ 0x1a ] = KEY_STOP,
+ [ 0x40 ] = KEY_REWIND,
+ [ 0x12 ] = KEY_FASTFORWARD,
+ [ 0x41 ] = KEY_PREVIOUSSONG, /* replay |< */
+ [ 0x42 ] = KEY_NEXTSONG, /* skip >| */
+ [ 0x54 ] = KEY_CAMERA, /* capture */
+ [ 0x50 ] = KEY_LANGUAGE, /* sap */
+ [ 0x47 ] = KEY_TV2, /* pip */
+ [ 0x4d ] = KEY_SCREEN,
+ [ 0x43 ] = KEY_SUBTITLE,
+ [ 0x10 ] = KEY_MUTE,
+ [ 0x49 ] = KEY_AUDIO, /* l/r */
+ [ 0x07 ] = KEY_SLEEP,
+ [ 0x08 ] = KEY_VIDEO, /* a/v */
+ [ 0x0e ] = KEY_PREVIOUS, /* recall */
+ [ 0x45 ] = KEY_ZOOM, /* zoom + */
+ [ 0x46 ] = KEY_ANGLE, /* zoom - */
+ [ 0x56 ] = KEY_RED,
+ [ 0x57 ] = KEY_GREEN,
+ [ 0x5c ] = KEY_YELLOW,
+ [ 0x5d ] = KEY_BLUE,
+};
+
+/* ---------------------------------------------------------------------- */
+
struct cx88_IR {
struct cx88_core *core;
struct input_dev *input;
@@ -266,7 +373,7 @@ struct cx88_IR {
char phys[32];
/* sample from gpio pin 16 */
- int sampling;
+ u32 sampling;
u32 samples[16];
int scount;
unsigned long release;
@@ -384,10 +491,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
ir_codes = ir_codes_cinergy_1400;
ir_type = IR_TYPE_PD;
- ir->sampling = 1;
+ ir->sampling = 0xeb04; /* address */
break;
case CX88_BOARD_HAUPPAUGE:
case CX88_BOARD_HAUPPAUGE_DVB_T1:
+ case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+ case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+ case CX88_BOARD_HAUPPAUGE_HVR1100:
ir_codes = ir_codes_hauppauge_new;
ir_type = IR_TYPE_RC5;
ir->sampling = 1;
@@ -427,6 +537,19 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir->mask_keyup = 0x40;
ir->polling = 1; /* ms */
break;
+ case CX88_BOARD_AVERTV_303:
+ case CX88_BOARD_AVERTV_STUDIO_303:
+ ir_codes = ir_codes_avertv_303;
+ ir->gpio_addr = MO_GP2_IO;
+ ir->mask_keycode = 0xfb;
+ ir->mask_keydown = 0x02;
+ ir->polling = 50; /* ms */
+ break;
+ case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
+ ir_codes = ir_codes_dntv_live_dvbt_pro;
+ ir_type = IR_TYPE_PD;
+ ir->sampling = 0xff00; /* address */
+ break;
}
if (NULL == ir_codes) {
@@ -484,6 +607,10 @@ int cx88_ir_fini(struct cx88_core *core)
if (NULL == ir)
return 0;
+ if (ir->sampling) {
+ cx_write(MO_DDSCFG_IO, 0x0);
+ core->pci_irqmask &= ~(1 << 18);
+ }
if (ir->polling) {
del_timer(&ir->timer);
flush_scheduled_work();
@@ -535,6 +662,7 @@ void cx88_ir_irq(struct cx88_core *core)
/* decode it */
switch (core->board) {
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
+ case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
ircode = ir_decode_pulsedistance(ir->samples, ir->scount, 1, 4);
if (ircode == 0xffffffff) { /* decoding error */
@@ -550,7 +678,7 @@ void cx88_ir_irq(struct cx88_core *core)
break;
}
- if ((ircode & 0xffff) != 0xeb04) { /* wrong address */
+ if ((ircode & 0xffff) != (ir->sampling & 0xffff)) { /* wrong address */
ir_dprintk("pulse distance decoded wrong address\n");
break;
}
@@ -567,6 +695,8 @@ void cx88_ir_irq(struct cx88_core *core)
break;
case CX88_BOARD_HAUPPAUGE:
case CX88_BOARD_HAUPPAUGE_DVB_T1:
+ case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+ case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
ir_dprintk("biphase decoded: %x\n", ircode);
if ((ircode & 0xfffff000) != 0x3000)
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 35e6d0c2b872..c79cc1d2bf8b 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -78,6 +78,11 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
cx_write(TS_SOP_STAT, 1<<13);
break;
+ case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+ case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+ cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */
+ udelay(100);
+ break;
default:
cx_write(TS_SOP_STAT, 0x00);
break;
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index a1b120c8a9b5..24118e43e73a 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -132,14 +132,22 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
{
u32 volume;
+#ifndef USING_CX88_ALSA
/* restart dma; This avoids buzz in NICAM and is good in others */
cx88_stop_audio_dma(core);
+#endif
cx_write(AUD_RATE_THRES_DMD, 0x000000C0);
+#ifndef USING_CX88_ALSA
cx88_start_audio_dma(core);
+#endif
if (cx88_boards[core->board].blackbird) {
/* sets sound input from external adc */
- cx_set(AUD_CTL, EN_I2SIN_ENABLE);
+ if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN)
+ cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
+ else
+ cx_set(AUD_CTL, EN_I2SIN_ENABLE);
+
cx_write(AUD_I2SINPUTCNTL, 4);
cx_write(AUD_BAUDRATE, 1);
/* 'pass-thru mode': this enables the i2s output to the mpeg encoder */
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 24a48f8a48c1..9a02515fe18b 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -33,6 +33,7 @@
#include <asm/div64.h>
#include "cx88.h"
+#include <media/v4l2-common.h>
/* Include V4L1 specific functions. Should be removed soon */
#include <linux/videodev.h>
@@ -240,7 +241,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
.minimum = 0,
.maximum = 0xff,
.step = 1,
- .default_value = 0,
+ .default_value = 0x3f,
.type = V4L2_CTRL_TYPE_INTEGER,
},
.off = 0,
@@ -271,7 +272,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
.minimum = 0,
.maximum = 0xff,
.step = 1,
- .default_value = 0,
+ .default_value = 0x7f,
.type = V4L2_CTRL_TYPE_INTEGER,
},
.off = 0,
@@ -285,6 +286,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
.name = "Mute",
.minimum = 0,
.maximum = 1,
+ .default_value = 1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
},
.reg = AUD_VOL_CTL,
@@ -298,7 +300,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
.minimum = 0,
.maximum = 0x3f,
.step = 1,
- .default_value = 0,
+ .default_value = 0x1f,
.type = V4L2_CTRL_TYPE_INTEGER,
},
.reg = AUD_VOL_CTL,
@@ -917,6 +919,9 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl)
ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift;
break;
}
+ printk("get_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
+ ctl->id, c->reg, ctl->value,
+ c->mask, c->sreg ? " [shadowed]" : "");
return 0;
}
@@ -925,13 +930,13 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
{
/* struct cx88_core *core = dev->core; */
struct cx88_ctrl *c = NULL;
- u32 v_sat_value;
- u32 value;
+ u32 value,mask;
int i;
-
- for (i = 0; i < CX8800_CTLS; i++)
- if (cx8800_ctls[i].v.id == ctl->id)
+ for (i = 0; i < CX8800_CTLS; i++) {
+ if (cx8800_ctls[i].v.id == ctl->id) {
c = &cx8800_ctls[i];
+ }
+ }
if (NULL == c)
return -EINVAL;
@@ -939,6 +944,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
ctl->value = c->v.minimum;
if (ctl->value > c->v.maximum)
ctl->value = c->v.maximum;
+ mask=c->mask;
switch (ctl->id) {
case V4L2_CID_AUDIO_BALANCE:
value = (ctl->value < 0x40) ? (0x40 - ctl->value) : ctl->value;
@@ -948,56 +954,44 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
break;
case V4L2_CID_SATURATION:
/* special v_sat handling */
- v_sat_value = ctl->value - (0x7f - 0x5a);
- if (v_sat_value > 0xff)
- v_sat_value = 0xff;
- if (v_sat_value < 0x00)
- v_sat_value = 0x00;
- cx_andor(MO_UV_SATURATION, 0xff00, v_sat_value << 8);
- /* fall through to default route for u_sat */
+
+ value = ((ctl->value - c->off) << c->shift) & c->mask;
+
+ if (core->tvnorm->id & V4L2_STD_SECAM) {
+ /* For SECAM, both U and V sat should be equal */
+ value=value<<8|value;
+ } else {
+ /* Keeps U Saturation proportional to V Sat */
+ value=(value*0x5a)/0x7f<<8|value;
+ }
+ mask=0xffff;
+ break;
default:
value = ((ctl->value - c->off) << c->shift) & c->mask;
break;
}
- dprintk(1,"set_control id=0x%X reg=0x%x val=0x%x%s\n",
- ctl->id, c->reg, value, c->sreg ? " [shadowed]" : "");
+ printk("set_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
+ ctl->id, c->reg, value,
+ mask, c->sreg ? " [shadowed]" : "");
if (c->sreg) {
- cx_sandor(c->sreg, c->reg, c->mask, value);
+ cx_sandor(c->sreg, c->reg, mask, value);
} else {
- cx_andor(c->reg, c->mask, value);
+ cx_andor(c->reg, mask, value);
}
return 0;
}
-/* static void init_controls(struct cx8800_dev *dev) */
static void init_controls(struct cx88_core *core)
{
- static struct v4l2_control mute = {
- .id = V4L2_CID_AUDIO_MUTE,
- .value = 1,
- };
- static struct v4l2_control volume = {
- .id = V4L2_CID_AUDIO_VOLUME,
- .value = 0x3f,
- };
- static struct v4l2_control hue = {
- .id = V4L2_CID_HUE,
- .value = 0x80,
- };
- static struct v4l2_control contrast = {
- .id = V4L2_CID_CONTRAST,
- .value = 0x80,
- };
- static struct v4l2_control brightness = {
- .id = V4L2_CID_BRIGHTNESS,
- .value = 0x80,
- };
+ struct v4l2_control ctrl;
+ int i;
- set_control(core,&mute);
- set_control(core,&volume);
- set_control(core,&hue);
- set_control(core,&contrast);
- set_control(core,&brightness);
+ for (i = 0; i < CX8800_CTLS; i++) {
+ ctrl.id=cx8800_ctls[i].v.id;
+ ctrl.value=cx8800_ctls[i].v.default_value
+ +cx8800_ctls[i].off;
+ set_control(core, &ctrl);
+ }
}
/* ------------------------------------------------------------------ */
@@ -1125,7 +1119,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
int err;
if (video_debug > 1)
- cx88_print_ioctl(core->name,cmd);
+ v4l_print_ioctl(core->name,cmd);
switch (cmd) {
/* --- capabilities ------------------------------------------ */
@@ -1261,7 +1255,7 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
dprintk( 1, "CORE IOCTL: 0x%x\n", cmd );
if (video_debug > 1)
- cx88_print_ioctl(core->name,cmd);
+ v4l_print_ioctl(core->name,cmd);
switch (cmd) {
/* ---------- tv norms ---------- */
@@ -1481,7 +1475,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
struct cx88_core *core = dev->core;
if (video_debug > 1)
- cx88_print_ioctl(core->name,cmd);
+ v4l_print_ioctl(core->name,cmd);
switch (cmd) {
case VIDIOC_QUERYCAP:
@@ -1740,6 +1734,7 @@ static struct file_operations video_fops =
.poll = video_poll,
.mmap = video_mmap,
.ioctl = video_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
@@ -1767,6 +1762,7 @@ static struct file_operations radio_fops =
.open = video_open,
.release = video_release,
.ioctl = radio_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
@@ -1928,8 +1924,8 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
/* initial device configuration */
down(&core->lock);
- init_controls(core);
cx88_set_tvnorm(core,tvnorms);
+ init_controls(core);
video_mux(core,0);
up(&core->lock);
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c
new file mode 100644
index 000000000000..372cd29cedbd
--- /dev/null
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c
@@ -0,0 +1,173 @@
+/*
+
+ cx88-vp3054-i2c.c -- support for the secondary I2C bus of the
+ DNTV Live! DVB-T Pro (VP-3054), wired as:
+ GPIO[0] -> SCL, GPIO[1] -> SDA
+
+ (c) 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "cx88.h"
+#include "cx88-vp3054-i2c.h"
+
+
+/* ----------------------------------------------------------------------- */
+
+static void vp3054_bit_setscl(void *data, int state)
+{
+ struct cx8802_dev *dev = data;
+ struct cx88_core *core = dev->core;
+ struct vp3054_i2c_state *vp3054_i2c = dev->card_priv;
+
+ if (state) {
+ vp3054_i2c->state |= 0x0001; /* SCL high */
+ vp3054_i2c->state &= ~0x0100; /* external pullup */
+ } else {
+ vp3054_i2c->state &= ~0x0001; /* SCL low */
+ vp3054_i2c->state |= 0x0100; /* drive pin */
+ }
+ cx_write(MO_GP0_IO, 0x010000 | vp3054_i2c->state);
+ cx_read(MO_GP0_IO);
+}
+
+static void vp3054_bit_setsda(void *data, int state)
+{
+ struct cx8802_dev *dev = data;
+ struct cx88_core *core = dev->core;
+ struct vp3054_i2c_state *vp3054_i2c = dev->card_priv;
+
+ if (state) {
+ vp3054_i2c->state |= 0x0002; /* SDA high */
+ vp3054_i2c->state &= ~0x0200; /* tristate pin */
+ } else {
+ vp3054_i2c->state &= ~0x0002; /* SDA low */
+ vp3054_i2c->state |= 0x0200; /* drive pin */
+ }
+ cx_write(MO_GP0_IO, 0x020000 | vp3054_i2c->state);
+ cx_read(MO_GP0_IO);
+}
+
+static int vp3054_bit_getscl(void *data)
+{
+ struct cx8802_dev *dev = data;
+ struct cx88_core *core = dev->core;
+ u32 state;
+
+ state = cx_read(MO_GP0_IO);
+ return (state & 0x01) ? 1 : 0;
+}
+
+static int vp3054_bit_getsda(void *data)
+{
+ struct cx8802_dev *dev = data;
+ struct cx88_core *core = dev->core;
+ u32 state;
+
+ state = cx_read(MO_GP0_IO);
+ return (state & 0x02) ? 1 : 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_algo_bit_data vp3054_i2c_algo_template = {
+ .setsda = vp3054_bit_setsda,
+ .setscl = vp3054_bit_setscl,
+ .getsda = vp3054_bit_getsda,
+ .getscl = vp3054_bit_getscl,
+ .udelay = 16,
+ .mdelay = 10,
+ .timeout = 200,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_adapter vp3054_i2c_adap_template = {
+ .name = "cx2388x",
+ .owner = THIS_MODULE,
+ .id = I2C_HW_B_CX2388x,
+};
+
+static struct i2c_client vp3054_i2c_client_template = {
+ .name = "VP-3054",
+};
+
+int vp3054_i2c_probe(struct cx8802_dev *dev)
+{
+ struct cx88_core *core = dev->core;
+ struct vp3054_i2c_state *vp3054_i2c;
+ int rc;
+
+ if (core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
+ return 0;
+
+ dev->card_priv = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL);
+ if (dev->card_priv == NULL)
+ return -ENOMEM;
+ vp3054_i2c = dev->card_priv;
+
+ memcpy(&vp3054_i2c->adap, &vp3054_i2c_adap_template,
+ sizeof(vp3054_i2c->adap));
+ memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template,
+ sizeof(vp3054_i2c->algo));
+ memcpy(&vp3054_i2c->client, &vp3054_i2c_client_template,
+ sizeof(vp3054_i2c->client));
+
+ vp3054_i2c->adap.class |= I2C_CLASS_TV_DIGITAL;
+
+ vp3054_i2c->adap.dev.parent = &dev->pci->dev;
+ strlcpy(vp3054_i2c->adap.name, core->name,
+ sizeof(vp3054_i2c->adap.name));
+ vp3054_i2c->algo.data = dev;
+ i2c_set_adapdata(&vp3054_i2c->adap, dev);
+ vp3054_i2c->adap.algo_data = &vp3054_i2c->algo;
+ vp3054_i2c->client.adapter = &vp3054_i2c->adap;
+
+ vp3054_bit_setscl(dev,1);
+ vp3054_bit_setsda(dev,1);
+
+ rc = i2c_bit_add_bus(&vp3054_i2c->adap);
+ if (0 != rc) {
+ printk("%s: vp3054_i2c register FAILED\n", core->name);
+
+ kfree(dev->card_priv);
+ dev->card_priv = NULL;
+ }
+
+ return rc;
+}
+
+void vp3054_i2c_remove(struct cx8802_dev *dev)
+{
+ struct vp3054_i2c_state *vp3054_i2c = dev->card_priv;
+
+ if (vp3054_i2c == NULL ||
+ dev->core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
+ return;
+
+ i2c_bit_del_bus(&vp3054_i2c->adap);
+ kfree(vp3054_i2c);
+}
+
+EXPORT_SYMBOL(vp3054_i2c_probe);
+EXPORT_SYMBOL(vp3054_i2c_remove);
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.h b/drivers/media/video/cx88/cx88-vp3054-i2c.h
new file mode 100644
index 000000000000..b7a0a04d2423
--- /dev/null
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.h
@@ -0,0 +1,35 @@
+/*
+
+ cx88-vp3054-i2c.h -- support for the secondary I2C bus of the
+ DNTV Live! DVB-T Pro (VP-3054), wired as:
+ GPIO[0] -> SCL, GPIO[1] -> SDA
+
+ (c) 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+
+ 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.
+
+*/
+
+/* ----------------------------------------------------------------------- */
+struct vp3054_i2c_state {
+ struct i2c_adapter adap;
+ struct i2c_algo_bit_data algo;
+ struct i2c_client client;
+ u32 state;
+};
+
+/* ----------------------------------------------------------------------- */
+int vp3054_i2c_probe(struct cx8802_dev *dev);
+void vp3054_i2c_remove(struct cx8802_dev *dev);
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 77beafc5c327..e9fd55b57fa6 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -179,6 +179,14 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_ATI_HDTVWONDER 34
#define CX88_BOARD_WINFAST_DTV1000 35
#define CX88_BOARD_AVERTV_303 36
+#define CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1 37
+#define CX88_BOARD_HAUPPAUGE_NOVASE2_S1 38
+#define CX88_BOARD_KWORLD_DVBS_100 39
+#define CX88_BOARD_HAUPPAUGE_HVR1100 40
+#define CX88_BOARD_HAUPPAUGE_HVR1100LP 41
+#define CX88_BOARD_DNTV_LIVE_DVB_T_PRO 42
+#define CX88_BOARD_KWORLD_DVB_T_CX22702 43
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
@@ -280,6 +288,9 @@ struct cx88_core {
unsigned int tda9887_conf;
unsigned int has_radio;
+ /* Supported V4L _STD_ tuner formats */
+ unsigned int tuner_formats;
+
/* config info -- dvb */
struct dvb_pll_desc *pll_desc;
unsigned int pll_addr;
@@ -301,6 +312,9 @@ struct cx88_core {
/* various v4l controls */
u32 freq;
+
+ /* cx88-video needs to access cx8802 for hybrid tuner pll access. */
+ struct cx8802_dev *dvbdev;
};
struct cx8800_dev;
@@ -411,6 +425,8 @@ struct cx8802_dev {
struct videobuf_dvb dvb;
void* fe_handle;
int (*fe_release)(void *handle);
+
+ void *card_priv;
/* for switching modulation types */
unsigned char ts_gen_cntrl;
@@ -447,7 +463,6 @@ struct cx8802_dev {
extern void cx88_print_irqbits(char *name, char *tag, char **strings,
u32 bits, u32 mask);
-extern void cx88_print_ioctl(char *name, unsigned int cmd);
extern int cx88_core_irq(struct cx88_core *core, u32 status);
extern void cx88_wakeup(struct cx88_core *core,
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 57779e63f35d..58f7b4194a0d 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -30,6 +30,7 @@
#include <media/tuner.h>
#include <media/audiochip.h>
#include <media/tveeprom.h>
+#include <media/v4l2-common.h>
#include "msp3400.h"
#include "em28xx.h"
@@ -261,7 +262,6 @@ void em28xx_card_setup(struct em28xx *dev)
/* request some modules */
if (dev->model == EM2820_BOARD_HAUPPAUGE_WINTV_USB_2) {
struct tveeprom tv;
- struct v4l2_audioout ao;
#ifdef CONFIG_MODULES
request_module("tveeprom");
request_module("ir-kbd-i2c");
@@ -274,12 +274,8 @@ void em28xx_card_setup(struct em28xx *dev)
dev->tuner_type= tv.tuner_type;
if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
+ dev->i2s_speed=2048000;
dev->has_msp34xx=1;
- memset (&ao,0,sizeof(ao));
-
- ao.index=2;
- ao.mode=V4L2_AUDMODE_32BITS;
- em28xx_i2c_call_clients(dev, VIDIOC_S_AUDOUT, &ao);
} else
dev->has_msp34xx=0;
}
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 0cfe75416ec6..dff3893f32fd 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -32,7 +32,7 @@
/* #define ENABLE_DEBUG_ISOC_FRAMES */
-static unsigned int core_debug;
+static unsigned int core_debug = 0;
module_param(core_debug,int,0644);
MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
@@ -41,7 +41,7 @@ MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
printk(KERN_INFO "%s %s :"fmt, \
dev->name, __FUNCTION__ , ##arg); } while (0)
-static unsigned int reg_debug;
+static unsigned int reg_debug = 0;
module_param(reg_debug,int,0644);
MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]");
@@ -50,7 +50,7 @@ MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]");
printk(KERN_INFO "%s %s :"fmt, \
dev->name, __FUNCTION__ , ##arg); } while (0)
-static unsigned int isoc_debug;
+static unsigned int isoc_debug = 0;
module_param(isoc_debug,int,0644);
MODULE_PARM_DESC(isoc_debug,"enable debug messages [isoc transfers]");
@@ -63,59 +63,6 @@ static int alt = EM28XX_PINOUT;
module_param(alt, int, 0644);
MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
-/* ------------------------------------------------------------------ */
-/* debug help functions */
-
-static const char *v4l1_ioctls[] = {
- "0", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
- "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
- "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
- "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
- "SMICROCODE", "GVBIFMT", "SVBIFMT" };
-#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
-
-static const char *v4l2_ioctls[] = {
- "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
- "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
- "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
- "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
- "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
- "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
- "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
- "44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
- "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
- "S_MODULATOR"
-};
-#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
-
-void em28xx_print_ioctl(char *name, unsigned int cmd)
-{
- char *dir;
-
- switch (_IOC_DIR(cmd)) {
- case _IOC_NONE: dir = "--"; break;
- case _IOC_READ: dir = "r-"; break;
- case _IOC_WRITE: dir = "-w"; break;
- case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
- default: dir = "??"; break;
- }
- switch (_IOC_TYPE(cmd)) {
- case 'v':
- printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n",
- name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
- v4l1_ioctls[_IOC_NR(cmd)] : "???");
- break;
- case 'V':
- printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n",
- name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ?
- v4l2_ioctls[_IOC_NR(cmd)] : "???");
- break;
- default:
- printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
- name, cmd, dir, _IOC_NR(cmd));
- }
-}
-
/*
* em28xx_request_buffers()
@@ -126,7 +73,7 @@ u32 em28xx_request_buffers(struct em28xx *dev, u32 count)
const size_t imagesize = PAGE_ALIGN(dev->frame_size); /*needs to be page aligned cause the buffers can be mapped individually! */
void *buff = NULL;
u32 i;
- em28xx_coredbg("requested %i buffers with size %zd", count, imagesize);
+ em28xx_coredbg("requested %i buffers with size %zi", count, imagesize);
if (count > EM28XX_NUM_FRAMES)
count = EM28XX_NUM_FRAMES;
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index d14bcf4ceaea..0591a705b7a1 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -28,6 +28,7 @@
#include <linux/video_decoder.h>
#include "em28xx.h"
+#include <media/v4l2-common.h>
#include <media/tuner.h>
/* ----------------------------------------------------------- */
@@ -486,9 +487,7 @@ static struct i2c_adapter em28xx_adap_template = {
.inc_use = inc_use,
.dec_use = dec_use,
#endif
-#ifdef I2C_CLASS_TV_ANALOG
.class = I2C_CLASS_TV_ANALOG,
-#endif
.name = "em28xx",
.id = I2C_HW_B_EM28XX,
.algo = &em28xx_algo,
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 3a56120397ae..fdc255918dde 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -32,6 +32,7 @@
#include "em28xx.h"
#include <media/tuner.h>
+#include <media/v4l2-common.h>
#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
"Markus Rechberger <mrechberger@gmail.com>, " \
@@ -106,8 +107,32 @@ static const unsigned char saa7114_i2c_init[] = {
#define TVNORMS ARRAY_SIZE(tvnorms)
/* supported controls */
+/* Common to all boards */
static struct v4l2_queryctrl em28xx_qctrl[] = {
{
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Volume",
+ .minimum = 0x0,
+ .maximum = 0x1f,
+ .step = 0x1,
+ .default_value = 0x1f,
+ .flags = 0,
+ },{
+ .id = V4L2_CID_AUDIO_MUTE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ .flags = 0,
+ }
+};
+
+/* FIXME: These are specific to saa711x - should be moved to its code */
+static struct v4l2_queryctrl saa711x_qctrl[] = {
+ {
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Brightness",
@@ -135,24 +160,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
.default_value = 0x10,
.flags = 0,
},{
- .id = V4L2_CID_AUDIO_VOLUME,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Volume",
- .minimum = 0x0,
- .maximum = 0x1f,
- .step = 0x1,
- .default_value = 0x1f,
- .flags = 0,
- },{
- .id = V4L2_CID_AUDIO_MUTE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- .flags = 0,
- },{
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Red chroma balance",
@@ -179,7 +186,7 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
.step = 0x1,
.default_value = 0x20,
.flags = 0,
- }
+ }
};
static struct usb_driver em28xx_usb_driver;
@@ -280,6 +287,8 @@ static void video_mux(struct em28xx *dev, int index)
em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
if (dev->has_msp34xx) {
+ if (dev->i2s_speed)
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
em28xx_i2c_call_clients(dev, VIDIOC_S_AUDIO, &dev->ctl_ainput);
ainput = EM28XX_AUDIO_SRC_TUNER;
em28xx_audio_source(dev, ainput);
@@ -674,7 +683,6 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
*/
static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
{
- s32 tmp;
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
ctrl->value = dev->mute;
@@ -682,6 +690,16 @@ static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
case V4L2_CID_AUDIO_VOLUME:
ctrl->value = dev->volume;
return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/*FIXME: should be moved to saa711x */
+static int saa711x_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
+{
+ s32 tmp;
+ switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
if ((tmp = em28xx_brightness_get(dev)) < 0)
return -EIO;
@@ -731,6 +749,15 @@ static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
case V4L2_CID_AUDIO_VOLUME:
dev->volume = ctrl->value;
return em28xx_audio_analog_set(dev);
+ default:
+ return -EINVAL;
+ }
+}
+
+/*FIXME: should be moved to saa711x */
+static int saa711x_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+{
+ switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
return em28xx_brightness_set(dev, ctrl->value);
case V4L2_CID_CONTRAST:
@@ -994,14 +1021,34 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *qc = arg;
- u8 i, n;
- n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
- for (i = 0; i < n; i++)
- if (qc->id && qc->id == em28xx_qctrl[i].id) {
- memcpy(qc, &(em28xx_qctrl[i]),
+ int i, id=qc->id;
+
+ memset(qc,0,sizeof(*qc));
+ qc->id=id;
+
+ if (!dev->has_msp34xx) {
+ for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+ if (qc->id && qc->id == em28xx_qctrl[i].id) {
+ memcpy(qc, &(em28xx_qctrl[i]),
+ sizeof(*qc));
+ return 0;
+ }
+ }
+ }
+ if (dev->decoder == EM28XX_TVP5150) {
+ em28xx_i2c_call_clients(dev,cmd,qc);
+ if (qc->type)
+ return 0;
+ else
+ return -EINVAL;
+ }
+ for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) {
+ if (qc->id && qc->id == saa711x_qctrl[i].id) {
+ memcpy(qc, &(saa711x_qctrl[i]),
sizeof(*qc));
return 0;
}
+ }
return -EINVAL;
}
@@ -1009,29 +1056,64 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
case VIDIOC_G_CTRL:
{
struct v4l2_control *ctrl = arg;
+ int retval=-EINVAL;
+ if (!dev->has_msp34xx)
+ retval=em28xx_get_ctrl(dev, ctrl);
+ if (retval==-EINVAL) {
+ if (dev->decoder == EM28XX_TVP5150) {
+ em28xx_i2c_call_clients(dev,cmd,arg);
+ return 0;
+ }
- return em28xx_get_ctrl(dev, ctrl);
+ return saa711x_get_ctrl(dev, ctrl);
+ } else return retval;
}
- case VIDIOC_S_CTRL_OLD: /* ??? */
case VIDIOC_S_CTRL:
{
struct v4l2_control *ctrl = arg;
- u8 i, n;
-
-
- n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
- for (i = 0; i < n; i++)
- if (ctrl->id == em28xx_qctrl[i].id) {
- if (ctrl->value <
- em28xx_qctrl[i].minimum
- || ctrl->value >
- em28xx_qctrl[i].maximum)
- return -ERANGE;
+ u8 i;
+
+ if (!dev->has_msp34xx){
+ for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+ if (ctrl->id == em28xx_qctrl[i].id) {
+ if (ctrl->value <
+ em28xx_qctrl[i].minimum
+ || ctrl->value >
+ em28xx_qctrl[i].maximum)
+ return -ERANGE;
+ return em28xx_set_ctrl(dev, ctrl);
+ }
+ }
+ }
- return em28xx_set_ctrl(dev, ctrl);
+ if (dev->decoder == EM28XX_TVP5150) {
+ em28xx_i2c_call_clients(dev,cmd,arg);
+ return 0;
+ } else if (!dev->has_msp34xx) {
+ for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+ if (ctrl->id == em28xx_qctrl[i].id) {
+ if (ctrl->value <
+ em28xx_qctrl[i].minimum
+ || ctrl->value >
+ em28xx_qctrl[i].maximum)
+ return -ERANGE;
+ return em28xx_set_ctrl(dev, ctrl);
+ }
}
+ for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) {
+ if (ctrl->id == saa711x_qctrl[i].id) {
+ if (ctrl->value <
+ saa711x_qctrl[i].minimum
+ || ctrl->value >
+ saa711x_qctrl[i].maximum)
+ return -ERANGE;
+ return saa711x_set_ctrl(dev, ctrl);
+ }
+ }
+ }
+
return -EINVAL;
}
@@ -1187,7 +1269,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
return -ENODEV;
if (video_debug > 1)
- em28xx_print_ioctl(dev->name,cmd);
+ v4l_print_ioctl(dev->name,cmd);
switch (cmd) {
@@ -1564,6 +1646,8 @@ static struct file_operations em28xx_v4l_fops = {
.poll = em28xx_v4l2_poll,
.mmap = em28xx_v4l2_mmap,
.llseek = no_llseek,
+ .compat_ioctl = v4l_compat_ioctl32,
+
};
/******************************** usb interface *****************************************/
@@ -1848,9 +1932,12 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
struct em28xx *dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
+/*FIXME: IR should be disconnected */
+
if (!dev)
return;
+
down_write(&em28xx_disconnect);
down(&dev->lock);
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 5c7a41ce69f3..33de9d846af5 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -1,5 +1,5 @@
/*
- em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+ em28xx.h - driver for Empia EM2800/EM2820/2840 USB video capture devices
Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
Ludovico Cavedon <cavedon@sssup.it>
@@ -216,6 +216,8 @@ struct em28xx {
unsigned int has_msp34xx:1;
unsigned int has_tda9887:1;
+ u32 i2s_speed; /* I2S speed for audio digital stream */
+
enum em28xx_decoder decoder;
int tuner_type; /* type of the tuner */
@@ -293,8 +295,6 @@ void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir);
/* Provided by em28xx-core.c */
-void em28xx_print_ioctl(char *name, unsigned int cmd);
-
u32 em28xx_request_buffers(struct em28xx *dev, u32 count);
void em28xx_queue_unusedframes(struct em28xx *dev);
void em28xx_release_buffers(struct em28xx *dev);
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 3cc1d6a6019b..58b0e6982822 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -279,7 +279,7 @@ static int ir_probe(struct i2c_adapter *adap);
static struct i2c_driver driver = {
.driver = {
- .name = "ir remote kbd driver",
+ .name = "ir-kbd-i2c",
},
.id = I2C_DRIVERID_INFRARED,
.attach_adapter = ir_probe,
@@ -304,18 +304,20 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL);
input_dev = input_allocate_device();
if (!ir || !input_dev) {
- kfree(ir);
input_free_device(input_dev);
+ kfree(ir);
return -ENOMEM;
}
+ memset(ir,0,sizeof(*ir));
ir->c = client_template;
ir->input = input_dev;
- i2c_set_clientdata(&ir->c, ir);
ir->c.adapter = adap;
ir->c.addr = addr;
+ i2c_set_clientdata(&ir->c, ir);
+
switch(addr) {
case 0x64:
name = "Pixelview";
@@ -378,13 +380,15 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
ir->c.dev.bus_id);
/* init + register input device */
- ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
- input_dev->id.bustype = BUS_I2C;
- input_dev->name = ir->c.name;
- input_dev->phys = ir->phys;
+ ir_input_init(input_dev,&ir->ir,ir_type,ir->ir_codes);
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->name = ir->c.name;
+ input_dev->phys = ir->phys;
/* register event device */
input_register_device(ir->input);
+ printk(DEVNAME ": %s detected at %s [%s]\n",
+ ir->input->name,ir->input->phys,adap->name);
/* start polling via eventd */
INIT_WORK(&ir->work, ir_work, ir);
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 3f2a882bc20a..2869464aee0d 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -1754,6 +1754,7 @@ static struct file_operations meye_fops = {
.release = meye_release,
.mmap = meye_mmap,
.ioctl = meye_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.poll = meye_poll,
.llseek = no_llseek,
};
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
new file mode 100644
index 000000000000..aa8c556b6ba1
--- /dev/null
+++ b/drivers/media/video/msp3400-driver.c
@@ -0,0 +1,1274 @@
+/*
+ * Programming the mspx4xx sound processor family
+ *
+ * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org>
+ *
+ * what works and what doesn't:
+ *
+ * AM-Mono
+ * Support for Hauppauge cards added (decoding handled by tuner) added by
+ * Frederic Crozat <fcrozat@mail.dotcom.fr>
+ *
+ * FM-Mono
+ * should work. The stereo modes are backward compatible to FM-mono,
+ * therefore FM-Mono should be allways available.
+ *
+ * FM-Stereo (B/G, used in germany)
+ * should work, with autodetect
+ *
+ * FM-Stereo (satellite)
+ * should work, no autodetect (i.e. default is mono, but you can
+ * switch to stereo -- untested)
+ *
+ * NICAM (B/G, L , used in UK, Scandinavia, Spain and France)
+ * should work, with autodetect. Support for NICAM was added by
+ * Pekka Pietikainen <pp@netppl.fi>
+ *
+ * TODO:
+ * - better SAT support
+ *
+ * 980623 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * using soundcore instead of OSS
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/audiochip.h>
+#include <linux/kthread.h>
+#include <linux/suspend.h>
+#include "msp3400.h"
+
+/* ---------------------------------------------------------------------- */
+
+MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
+MODULE_AUTHOR("Gerd Knorr");
+MODULE_LICENSE("GPL");
+
+/* module parameters */
+static int opmode = OPMODE_AUTO;
+int debug = 0; /* debug output */
+int once = 0; /* no continous stereo monitoring */
+int amsound = 0; /* hard-wire AM sound at 6.5 Hz (france),
+ the autoscan seems work well only with FM... */
+int standard = 1; /* Override auto detect of audio standard, if needed. */
+int dolby = 0;
+
+int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual
+ (msp34xxg only) 0x00a0-0x03c0 */
+
+/* read-only */
+module_param(opmode, int, 0444);
+
+/* read-write */
+module_param(once, bool, 0644);
+module_param(debug, int, 0644);
+module_param(stereo_threshold, int, 0644);
+module_param(standard, int, 0644);
+module_param(amsound, bool, 0644);
+module_param(dolby, bool, 0644);
+
+MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect");
+MODULE_PARM_DESC(once, "No continuous stereo monitoring");
+MODULE_PARM_DESC(debug, "Enable debug messages [0-3]");
+MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo");
+MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect");
+MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan");
+MODULE_PARM_DESC(dolby, "Activates Dolby processsing");
+
+/* ---------------------------------------------------------------------- */
+
+/* control subaddress */
+#define I2C_MSP_CONTROL 0x00
+/* demodulator unit subaddress */
+#define I2C_MSP_DEM 0x10
+/* DSP unit subaddress */
+#define I2C_MSP_DSP 0x12
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x80 >> 1, 0x88 >> 1, I2C_CLIENT_END };
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+/* functions for talking to the MSP3400C Sound processor */
+
+int msp_reset(struct i2c_client *client)
+{
+ /* reset and read revision code */
+ static u8 reset_off[3] = { I2C_MSP_CONTROL, 0x80, 0x00 };
+ static u8 reset_on[3] = { I2C_MSP_CONTROL, 0x00, 0x00 };
+ static u8 write[3] = { I2C_MSP_DSP + 1, 0x00, 0x1e };
+ u8 read[2];
+ struct i2c_msg reset[2] = {
+ { client->addr, I2C_M_IGNORE_NAK, 3, reset_off },
+ { client->addr, I2C_M_IGNORE_NAK, 3, reset_on },
+ };
+ struct i2c_msg test[2] = {
+ { client->addr, 0, 3, write },
+ { client->addr, I2C_M_RD, 2, read },
+ };
+
+ v4l_dbg(3, client, "msp_reset\n");
+ if (i2c_transfer(client->adapter, &reset[0], 1) != 1 ||
+ i2c_transfer(client->adapter, &reset[1], 1) != 1 ||
+ i2c_transfer(client->adapter, test, 2) != 2) {
+ v4l_err(client, "chip reset failed\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int msp_read(struct i2c_client *client, int dev, int addr)
+{
+ int err, retval;
+ u8 write[3];
+ u8 read[2];
+ struct i2c_msg msgs[2] = {
+ { client->addr, 0, 3, write },
+ { client->addr, I2C_M_RD, 2, read }
+ };
+
+ write[0] = dev + 1;
+ write[1] = addr >> 8;
+ write[2] = addr & 0xff;
+
+ for (err = 0; err < 3; err++) {
+ if (i2c_transfer(client->adapter, msgs, 2) == 2)
+ break;
+ v4l_warn(client, "I/O error #%d (read 0x%02x/0x%02x)\n", err,
+ dev, addr);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(msecs_to_jiffies(10));
+ }
+ if (err == 3) {
+ v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
+ msp_reset(client);
+ return -1;
+ }
+ retval = read[0] << 8 | read[1];
+ v4l_dbg(3, client, "msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval);
+ return retval;
+}
+
+int msp_read_dem(struct i2c_client *client, int addr)
+{
+ return msp_read(client, I2C_MSP_DEM, addr);
+}
+
+int msp_read_dsp(struct i2c_client *client, int addr)
+{
+ return msp_read(client, I2C_MSP_DSP, addr);
+}
+
+static int msp_write(struct i2c_client *client, int dev, int addr, int val)
+{
+ int err;
+ u8 buffer[5];
+
+ buffer[0] = dev;
+ buffer[1] = addr >> 8;
+ buffer[2] = addr & 0xff;
+ buffer[3] = val >> 8;
+ buffer[4] = val & 0xff;
+
+ v4l_dbg(3, client, "msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val);
+ for (err = 0; err < 3; err++) {
+ if (i2c_master_send(client, buffer, 5) == 5)
+ break;
+ v4l_warn(client, "I/O error #%d (write 0x%02x/0x%02x)\n", err,
+ dev, addr);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(msecs_to_jiffies(10));
+ }
+ if (err == 3) {
+ v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
+ msp_reset(client);
+ return -1;
+ }
+ return 0;
+}
+
+int msp_write_dem(struct i2c_client *client, int addr, int val)
+{
+ return msp_write(client, I2C_MSP_DEM, addr, val);
+}
+
+int msp_write_dsp(struct i2c_client *client, int addr, int val)
+{
+ return msp_write(client, I2C_MSP_DSP, addr, val);
+}
+
+/* ----------------------------------------------------------------------- *
+ * bits 9 8 5 - SCART DSP input Select:
+ * 0 0 0 - SCART 1 to DSP input (reset position)
+ * 0 1 0 - MONO to DSP input
+ * 1 0 0 - SCART 2 to DSP input
+ * 1 1 1 - Mute DSP input
+ *
+ * bits 11 10 6 - SCART 1 Output Select:
+ * 0 0 0 - undefined (reset position)
+ * 0 1 0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS)
+ * 1 0 0 - MONO input to SCART 1 Output
+ * 1 1 0 - SCART 1 DA to SCART 1 Output
+ * 0 0 1 - SCART 2 DA to SCART 1 Output
+ * 0 1 1 - SCART 1 Input to SCART 1 Output
+ * 1 1 1 - Mute SCART 1 Output
+ *
+ * bits 13 12 7 - SCART 2 Output Select (for devices with 2 Output SCART):
+ * 0 0 0 - SCART 1 DA to SCART 2 Output (reset position)
+ * 0 1 0 - SCART 1 Input to SCART 2 Output
+ * 1 0 0 - MONO input to SCART 2 Output
+ * 0 0 1 - SCART 2 DA to SCART 2 Output
+ * 0 1 1 - SCART 2 Input to SCART 2 Output
+ * 1 1 0 - Mute SCART 2 Output
+ *
+ * Bits 4 to 0 should be zero.
+ * ----------------------------------------------------------------------- */
+
+static int scarts[3][9] = {
+ /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */
+ /* SCART DSP Input select */
+ { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 },
+ /* SCART1 Output select */
+ { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
+ /* SCART2 Output select */
+ { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
+};
+
+static char *scart_names[] = {
+ "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute"
+};
+
+void msp_set_scart(struct i2c_client *client, int in, int out)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+
+ state->in_scart=in;
+
+ if (in >= 1 && in <= 8 && out >= 0 && out <= 2) {
+ if (-1 == scarts[out][in])
+ return;
+
+ state->acb &= ~scarts[out][SCART_MASK];
+ state->acb |= scarts[out][in];
+ } else
+ state->acb = 0xf60; /* Mute Input and SCART 1 Output */
+
+ v4l_dbg(1, client, "scart switch: %s => %d (ACB=0x%04x)\n",
+ scart_names[in], out, state->acb);
+ msp_write_dsp(client, 0x13, state->acb);
+
+ /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */
+ msp_write_dem(client, 0x40, state->i2s_mode);
+}
+
+void msp_set_mute(struct i2c_client *client)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+
+ v4l_dbg(1, client, "mute audio\n");
+ msp_write_dsp(client, 0x0000, 0);
+ msp_write_dsp(client, 0x0007, 1);
+ if (state->has_scart2_out_volume)
+ msp_write_dsp(client, 0x0040, 1);
+ if (state->has_headphones)
+ msp_write_dsp(client, 0x0006, 0);
+}
+
+void msp_set_audio(struct i2c_client *client)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+ int bal = 0, bass, treble, loudness;
+ int val = 0;
+
+ if (!state->muted)
+ val = (state->volume * 0x7f / 65535) << 8;
+
+ v4l_dbg(1, client, "mute=%s volume=%d\n",
+ state->muted ? "on" : "off", state->volume);
+
+ msp_write_dsp(client, 0x0000, val);
+ msp_write_dsp(client, 0x0007, state->muted ? 0x1 : (val | 0x1));
+ if (state->has_scart2_out_volume)
+ msp_write_dsp(client, 0x0040, state->muted ? 0x1 : (val | 0x1));
+ if (state->has_headphones)
+ msp_write_dsp(client, 0x0006, val);
+ if (!state->has_sound_processing)
+ return;
+
+ if (val)
+ bal = (u8)((state->balance / 256) - 128);
+ bass = ((state->bass - 32768) * 0x60 / 65535) << 8;
+ treble = ((state->treble - 32768) * 0x60 / 65535) << 8;
+ loudness = state->loudness ? ((5 * 4) << 8) : 0;
+
+ v4l_dbg(1, client, "balance=%d bass=%d treble=%d loudness=%d\n",
+ state->balance, state->bass, state->treble, state->loudness);
+
+ msp_write_dsp(client, 0x0001, bal << 8);
+ msp_write_dsp(client, 0x0002, bass);
+ msp_write_dsp(client, 0x0003, treble);
+ msp_write_dsp(client, 0x0004, loudness);
+ if (!state->has_headphones)
+ return;
+ msp_write_dsp(client, 0x0030, bal << 8);
+ msp_write_dsp(client, 0x0031, bass);
+ msp_write_dsp(client, 0x0032, treble);
+ msp_write_dsp(client, 0x0033, loudness);
+}
+
+int msp_modus(struct i2c_client *client)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+
+ if (state->radio) {
+ v4l_dbg(1, client, "video mode selected to Radio\n");
+ return 0x0003;
+ }
+
+ if (state->v4l2_std & V4L2_STD_PAL) {
+ v4l_dbg(1, client, "video mode selected to PAL\n");
+
+#if 1
+ /* experimental: not sure this works with all chip versions */
+ return 0x7003;
+#else
+ /* previous value, try this if it breaks ... */
+ return 0x1003;
+#endif
+ }
+ if (state->v4l2_std & V4L2_STD_NTSC) {
+ v4l_dbg(1, client, "video mode selected to NTSC\n");
+ return 0x2003;
+ }
+ if (state->v4l2_std & V4L2_STD_SECAM) {
+ v4l_dbg(1, client, "video mode selected to SECAM\n");
+ return 0x0003;
+ }
+ return 0x0003;
+}
+
+/* ------------------------------------------------------------------------ */
+
+
+static void msp_wake_thread(struct i2c_client *client)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+
+ if (NULL == state->kthread)
+ return;
+ msp_set_mute(client);
+ state->watch_stereo = 0;
+ state->restart = 1;
+ wake_up_interruptible(&state->wq);
+}
+
+int msp_sleep(struct msp_state *state, int timeout)
+{
+ DECLARE_WAITQUEUE(wait, current);
+
+ add_wait_queue(&state->wq, &wait);
+ if (!kthread_should_stop()) {
+ if (timeout < 0) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ } else {
+ schedule_timeout_interruptible
+ (msecs_to_jiffies(timeout));
+ }
+ }
+
+ remove_wait_queue(&state->wq, &wait);
+ try_to_freeze();
+ return state->restart;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int msp_mode_v4l2_to_v4l1(int rxsubchans)
+{
+ int mode = 0;
+
+ if (rxsubchans & V4L2_TUNER_SUB_STEREO)
+ mode |= VIDEO_SOUND_STEREO;
+ if (rxsubchans & V4L2_TUNER_SUB_LANG2)
+ mode |= VIDEO_SOUND_LANG2;
+ if (rxsubchans & V4L2_TUNER_SUB_LANG1)
+ mode |= VIDEO_SOUND_LANG1;
+ if (mode == 0)
+ mode |= VIDEO_SOUND_MONO;
+ return mode;
+}
+
+static int msp_mode_v4l1_to_v4l2(int mode)
+{
+ if (mode & VIDEO_SOUND_STEREO)
+ return V4L2_TUNER_MODE_STEREO;
+ if (mode & VIDEO_SOUND_LANG2)
+ return V4L2_TUNER_MODE_LANG2;
+ if (mode & VIDEO_SOUND_LANG1)
+ return V4L2_TUNER_MODE_LANG1;
+ return V4L2_TUNER_MODE_MONO;
+}
+
+static void msp_any_detect_stereo(struct i2c_client *client)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+
+ switch (state->opmode) {
+ case OPMODE_MANUAL:
+ case OPMODE_AUTODETECT:
+ autodetect_stereo(client);
+ break;
+ case OPMODE_AUTOSELECT:
+ msp34xxg_detect_stereo(client);
+ break;
+ }
+}
+
+static struct v4l2_queryctrl msp_qctrl_std[] = {
+ {
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535/100,
+ .default_value = 58880,
+ .flags = 0,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },{
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ .flags = 0,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },
+};
+
+static struct v4l2_queryctrl msp_qctrl_sound_processing[] = {
+ {
+ .id = V4L2_CID_AUDIO_BALANCE,
+ .name = "Balance",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535/100,
+ .default_value = 32768,
+ .flags = 0,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },{
+ .id = V4L2_CID_AUDIO_BASS,
+ .name = "Bass",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535/100,
+ .default_value = 32768,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },{
+ .id = V4L2_CID_AUDIO_TREBLE,
+ .name = "Treble",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535/100,
+ .default_value = 32768,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },{
+ .id = V4L2_CID_AUDIO_LOUDNESS,
+ .name = "Loudness",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ .flags = 0,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },
+};
+
+
+static void msp_any_set_audmode(struct i2c_client *client, int audmode)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+
+ switch (state->opmode) {
+ case OPMODE_MANUAL:
+ case OPMODE_AUTODETECT:
+ state->watch_stereo = 0;
+ msp3400c_setstereo(client, audmode);
+ break;
+ case OPMODE_AUTOSELECT:
+ msp34xxg_set_audmode(client, audmode);
+ break;
+ }
+}
+
+static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value = state->volume;
+ break;
+
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value = state->muted;
+ break;
+
+ case V4L2_CID_AUDIO_BALANCE:
+ if (!state->has_sound_processing)
+ return -EINVAL;
+ ctrl->value = state->balance;
+ break;
+
+ case V4L2_CID_AUDIO_BASS:
+ if (!state->has_sound_processing)
+ return -EINVAL;
+ ctrl->value = state->bass;
+ break;
+
+ case V4L2_CID_AUDIO_TREBLE:
+ if (!state->has_sound_processing)
+ return -EINVAL;
+ ctrl->value = state->treble;
+ break;
+
+ case V4L2_CID_AUDIO_LOUDNESS:
+ if (!state->has_sound_processing)
+ return -EINVAL;
+ ctrl->value = state->loudness;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ state->volume = ctrl->value;
+ if (state->volume == 0)
+ state->balance = 32768;
+ break;
+
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value < 0 || ctrl->value >= 2)
+ return -ERANGE;
+ state->muted = ctrl->value;
+ break;
+
+ case V4L2_CID_AUDIO_BASS:
+ if (!state->has_sound_processing)
+ return -EINVAL;
+ state->bass = ctrl->value;
+ break;
+
+ case V4L2_CID_AUDIO_TREBLE:
+ if (!state->has_sound_processing)
+ return -EINVAL;
+ state->treble = ctrl->value;
+ break;
+
+ case V4L2_CID_AUDIO_LOUDNESS:
+ if (!state->has_sound_processing)
+ return -EINVAL;
+ state->loudness = ctrl->value;
+ break;
+
+ case V4L2_CID_AUDIO_BALANCE:
+ if (!state->has_sound_processing)
+ return -EINVAL;
+ state->balance = ctrl->value;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ msp_set_audio(client);
+ return 0;
+}
+
+static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+ u16 *sarg = arg;
+ int scart = 0;
+
+ if (debug >= 2)
+ v4l_i2c_print_ioctl(client, cmd);
+
+ switch (cmd) {
+ case AUDC_SET_INPUT:
+ if (*sarg == state->input)
+ break;
+ state->input = *sarg;
+ switch (*sarg) {
+ case AUDIO_RADIO:
+ /* Hauppauge uses IN2 for the radio */
+ state->mode = MSP_MODE_FM_RADIO;
+ scart = SCART_IN2;
+ break;
+ case AUDIO_EXTERN_1:
+ /* IN1 is often used for external input ... */
+ state->mode = MSP_MODE_EXTERN;
+ scart = SCART_IN1;
+ break;
+ case AUDIO_EXTERN_2:
+ /* ... sometimes it is IN2 through ;) */
+ state->mode = MSP_MODE_EXTERN;
+ scart = SCART_IN2;
+ break;
+ case AUDIO_TUNER:
+ state->mode = -1;
+ break;
+ default:
+ if (*sarg & AUDIO_MUTE)
+ msp_set_scart(client, SCART_MUTE, 0);
+ break;
+ }
+ if (scart) {
+ state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ state->audmode = V4L2_TUNER_MODE_STEREO;
+ msp_set_scart(client, scart, 0);
+ msp_write_dsp(client, 0x000d, 0x1900);
+ if (state->opmode != OPMODE_AUTOSELECT)
+ msp3400c_setstereo(client, state->audmode);
+ }
+ msp_wake_thread(client);
+ break;
+
+ case AUDC_SET_RADIO:
+ if (state->radio)
+ return 0;
+ state->radio = 1;
+ v4l_dbg(1, client, "switching to radio mode\n");
+ state->watch_stereo = 0;
+ switch (state->opmode) {
+ case OPMODE_MANUAL:
+ /* set msp3400 to FM radio mode */
+ msp3400c_setmode(client, MSP_MODE_FM_RADIO);
+ msp3400c_setcarrier(client, MSP_CARRIER(10.7),
+ MSP_CARRIER(10.7));
+ msp_set_audio(client);
+ break;
+ case OPMODE_AUTODETECT:
+ case OPMODE_AUTOSELECT:
+ /* the thread will do for us */
+ msp_wake_thread(client);
+ break;
+ }
+ break;
+
+ /* --- v4l ioctls --- */
+ /* take care: bttv does userspace copying, we'll get a
+ kernel pointer here... */
+ case VIDIOCGAUDIO:
+ {
+ struct video_audio *va = arg;
+
+ va->flags |= VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_MUTABLE;
+ if (state->has_sound_processing)
+ va->flags |= VIDEO_AUDIO_BALANCE |
+ VIDEO_AUDIO_BASS |
+ VIDEO_AUDIO_TREBLE;
+ if (state->muted)
+ va->flags |= VIDEO_AUDIO_MUTE;
+ va->volume = state->volume;
+ va->balance = state->volume ? state->balance : 32768;
+ va->bass = state->bass;
+ va->treble = state->treble;
+
+ if (state->radio)
+ break;
+ if (state->opmode == OPMODE_AUTOSELECT)
+ msp_any_detect_stereo(client);
+ va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans);
+ break;
+ }
+
+ case VIDIOCSAUDIO:
+ {
+ struct video_audio *va = arg;
+
+ state->muted = (va->flags & VIDEO_AUDIO_MUTE);
+ state->volume = va->volume;
+ state->balance = va->balance;
+ state->bass = va->bass;
+ state->treble = va->treble;
+ msp_set_audio(client);
+
+ if (va->mode != 0 && state->radio == 0)
+ msp_any_set_audmode(client, msp_mode_v4l1_to_v4l2(va->mode));
+ break;
+ }
+
+ case VIDIOCSCHAN:
+ {
+ struct video_channel *vc = arg;
+ int update = 0;
+ v4l2_std_id std;
+
+ if (state->radio)
+ update = 1;
+ state->radio = 0;
+ if (vc->norm == VIDEO_MODE_PAL)
+ std = V4L2_STD_PAL;
+ else if (vc->norm == VIDEO_MODE_SECAM)
+ std = V4L2_STD_SECAM;
+ else
+ std = V4L2_STD_NTSC;
+ if (std != state->v4l2_std) {
+ state->v4l2_std = std;
+ update = 1;
+ }
+ if (update)
+ msp_wake_thread(client);
+ break;
+ }
+
+ case VIDIOCSFREQ:
+ case VIDIOC_S_FREQUENCY:
+ {
+ /* new channel -- kick audio carrier scan */
+ msp_wake_thread(client);
+ break;
+ }
+
+ /* msp34xx specific */
+ case MSP_SET_MATRIX:
+ {
+ struct msp_matrix *mspm = arg;
+
+ msp_set_scart(client, mspm->input, mspm->output);
+ break;
+ }
+
+ /* --- v4l2 ioctls --- */
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id *id = arg;
+ int update = state->radio || state->v4l2_std != *id;
+
+ state->v4l2_std = *id;
+ state->radio = 0;
+ if (update)
+ msp_wake_thread(client);
+ return 0;
+ }
+
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *i = arg;
+
+ if (i->index != 0)
+ return -EINVAL;
+
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ switch (i->index) {
+ case AUDIO_RADIO:
+ strcpy(i->name, "Radio");
+ break;
+ case AUDIO_EXTERN_1:
+ strcpy(i->name, "Extern 1");
+ break;
+ case AUDIO_EXTERN_2:
+ strcpy(i->name, "Extern 2");
+ break;
+ case AUDIO_TUNER:
+ strcpy(i->name, "Television");
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ case VIDIOC_G_AUDIO:
+ {
+ struct v4l2_audio *a = arg;
+
+ memset(a, 0, sizeof(*a));
+
+ switch (a->index) {
+ case AUDIO_RADIO:
+ strcpy(a->name, "Radio");
+ break;
+ case AUDIO_EXTERN_1:
+ strcpy(a->name, "Extern 1");
+ break;
+ case AUDIO_EXTERN_2:
+ strcpy(a->name, "Extern 2");
+ break;
+ case AUDIO_TUNER:
+ strcpy(a->name, "Television");
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ msp_any_detect_stereo(client);
+ if (state->audmode == V4L2_TUNER_MODE_STEREO) {
+ a->capability = V4L2_AUDCAP_STEREO;
+ }
+
+ break;
+ }
+
+ case VIDIOC_S_AUDIO:
+ {
+ struct v4l2_audio *sarg = arg;
+
+ switch (sarg->index) {
+ case AUDIO_RADIO:
+ /* Hauppauge uses IN2 for the radio */
+ state->mode = MSP_MODE_FM_RADIO;
+ scart = SCART_IN2;
+ break;
+ case AUDIO_EXTERN_1:
+ /* IN1 is often used for external input ... */
+ state->mode = MSP_MODE_EXTERN;
+ scart = SCART_IN1;
+ break;
+ case AUDIO_EXTERN_2:
+ /* ... sometimes it is IN2 through ;) */
+ state->mode = MSP_MODE_EXTERN;
+ scart = SCART_IN2;
+ break;
+ case AUDIO_TUNER:
+ state->mode = -1;
+ break;
+ }
+ if (scart) {
+ state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ state->audmode = V4L2_TUNER_MODE_STEREO;
+ msp_set_scart(client, scart, 0);
+ msp_write_dsp(client, 0x000d, 0x1900);
+ }
+ if (sarg->capability == V4L2_AUDCAP_STEREO) {
+ state->audmode = V4L2_TUNER_MODE_STEREO;
+ } else {
+ state->audmode &= ~V4L2_TUNER_MODE_STEREO;
+ }
+ msp_any_set_audmode(client, state->audmode);
+ msp_wake_thread(client);
+ break;
+ }
+
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *vt = arg;
+
+ if (state->radio)
+ break;
+ if (state->opmode == OPMODE_AUTOSELECT)
+ msp_any_detect_stereo(client);
+ vt->audmode = state->audmode;
+ vt->rxsubchans = state->rxsubchans;
+ vt->capability = V4L2_TUNER_CAP_STEREO |
+ V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+ break;
+ }
+
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
+
+ if (state->radio)
+ break;
+ /* only set audmode */
+ if (vt->audmode != -1 && vt->audmode != 0)
+ msp_any_set_audmode(client, vt->audmode);
+ break;
+ }
+
+ case VIDIOC_G_AUDOUT:
+ {
+ struct v4l2_audioout *a = (struct v4l2_audioout *)arg;
+ int idx = a->index;
+
+ memset(a, 0, sizeof(*a));
+
+ switch (idx) {
+ case 0:
+ strcpy(a->name, "Scart1 Out");
+ break;
+ case 1:
+ strcpy(a->name, "Scart2 Out");
+ break;
+ case 2:
+ strcpy(a->name, "I2S Out");
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ }
+
+ case VIDIOC_S_AUDOUT:
+ {
+ struct v4l2_audioout *a = (struct v4l2_audioout *)arg;
+
+ if (a->index < 0 || a->index > 2)
+ return -EINVAL;
+
+ v4l_dbg(1, client, "Setting audio out on msp34xx to input %i\n", a->index);
+ msp_set_scart(client, state->in_scart, a->index + 1);
+
+ break;
+ }
+
+ case VIDIOC_INT_I2S_CLOCK_FREQ:
+ {
+ u32 *a = (u32 *)arg;
+
+ v4l_dbg(1, client, "Setting I2S speed to %d\n", *a);
+
+ switch (*a) {
+ case 1024000:
+ state->i2s_mode = 0;
+ break;
+ case 2048000:
+ state->i2s_mode = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ }
+
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(msp_qctrl_std); i++)
+ if (qc->id && qc->id == msp_qctrl_std[i].id) {
+ memcpy(qc, &msp_qctrl_std[i], sizeof(*qc));
+ return 0;
+ }
+ if (!state->has_sound_processing)
+ return -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(msp_qctrl_sound_processing); i++)
+ if (qc->id && qc->id == msp_qctrl_sound_processing[i].id) {
+ memcpy(qc, &msp_qctrl_sound_processing[i], sizeof(*qc));
+ return 0;
+ }
+ return -EINVAL;
+ }
+
+ case VIDIOC_G_CTRL:
+ return msp_get_ctrl(client, arg);
+
+ case VIDIOC_S_CTRL:
+ return msp_set_ctrl(client, arg);
+
+ case VIDIOC_LOG_STATUS:
+ {
+ const char *p;
+
+ if (state->opmode == OPMODE_AUTOSELECT)
+ msp_any_detect_stereo(client);
+ v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n",
+ client->name, state->rev1, state->rev2);
+ v4l_info(client, "Audio: volume %d%s\n",
+ state->volume, state->muted ? " (muted)" : "");
+ if (state->has_sound_processing) {
+ v4l_info(client, "Audio: balance %d bass %d treble %d loudness %s\n",
+ state->balance, state->bass, state->treble,
+ state->loudness ? "on" : "off");
+ }
+ switch (state->mode) {
+ case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break;
+ case MSP_MODE_FM_RADIO: p = "FM Radio"; break;
+ case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono + FM-stereo"; break;
+ case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break;
+ case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break;
+ case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break;
+ case MSP_MODE_AM_NICAM: p = "NICAM/AM (L)"; break;
+ case MSP_MODE_BTSC: p = "BTSC"; break;
+ case MSP_MODE_EXTERN: p = "External input"; break;
+ default: p = "unknown"; break;
+ }
+ if (state->opmode == OPMODE_MANUAL) {
+ v4l_info(client, "Mode: %s (%s%s)\n", p,
+ (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
+ (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
+ } else {
+ v4l_info(client, "Mode: %s\n", p);
+ v4l_info(client, "Standard: %s (%s%s)\n",
+ msp_standard_std_name(state->std),
+ (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
+ (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
+ }
+ v4l_info(client, "ACB: 0x%04x\n", state->acb);
+ break;
+ }
+
+ default:
+ /* nothing */
+ break;
+ }
+ return 0;
+}
+
+static int msp_suspend(struct device * dev, pm_message_t state)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ v4l_dbg(1, client, "suspend\n");
+ msp_reset(client);
+ return 0;
+}
+
+static int msp_resume(struct device * dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ v4l_dbg(1, client, "resume\n");
+ msp_wake_thread(client);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver;
+
+static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct msp_state *state;
+ int (*thread_func)(void *data) = NULL;
+ int msp_hard;
+ int msp_family;
+ int msp_revision;
+ int msp_product, msp_prod_hi, msp_prod_lo;
+ int msp_rom;
+
+ client = kmalloc(sizeof(*client), GFP_KERNEL);
+ if (client == NULL)
+ return -ENOMEM;
+ memset(client, 0, sizeof(*client));
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver;
+ snprintf(client->name, sizeof(client->name) - 1, "msp3400");
+
+ if (msp_reset(client) == -1) {
+ v4l_dbg(1, client, "msp3400 not found\n");
+ kfree(client);
+ return -1;
+ }
+
+ state = kmalloc(sizeof(*state), GFP_KERNEL);
+ if (state == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ i2c_set_clientdata(client, state);
+
+ memset(state, 0, sizeof(*state));
+ state->v4l2_std = V4L2_STD_NTSC;
+ state->volume = 58880; /* 0db gain */
+ state->balance = 32768; /* 0db gain */
+ state->bass = 32768;
+ state->treble = 32768;
+ state->loudness = 0;
+ state->input = -1;
+ state->muted = 0;
+ state->i2s_mode = 0;
+ init_waitqueue_head(&state->wq);
+
+ state->rev1 = msp_read_dsp(client, 0x1e);
+ if (state->rev1 != -1)
+ state->rev2 = msp_read_dsp(client, 0x1f);
+ v4l_dbg(1, client, "rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2);
+ if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) {
+ v4l_dbg(1, client, "not an msp3400 (cannot read chip version)\n");
+ kfree(state);
+ kfree(client);
+ return -1;
+ }
+
+ msp_set_audio(client);
+
+ msp_family = ((state->rev1 >> 4) & 0x0f) + 3;
+ msp_product = (state->rev2 >> 8) & 0xff;
+ msp_prod_hi = msp_product / 10;
+ msp_prod_lo = msp_product % 10;
+ msp_revision = (state->rev1 & 0x0f) + '@';
+ msp_hard = ((state->rev1 >> 8) & 0xff) + '@';
+ msp_rom = state->rev2 & 0x1f;
+ snprintf(client->name, sizeof(client->name), "MSP%d4%02d%c-%c%d",
+ msp_family, msp_product,
+ msp_revision, msp_hard, msp_rom);
+
+ /* Has NICAM support: all mspx41x and mspx45x products have NICAM */
+ state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5;
+ /* Has radio support: was added with revision G */
+ state->has_radio = msp_revision >= 'G';
+ /* Has headphones output: not for stripped down products */
+ state->has_headphones = msp_prod_lo < 5;
+ /* Has scart4 input: not in pre D revisions, not in stripped D revs */
+ state->has_scart4 = msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5);
+ /* Has scart2 and scart3 inputs and scart2 output: not in stripped
+ down products of the '3' family */
+ state->has_scart23_in_scart2_out = msp_family >= 4 || msp_prod_lo < 5;
+ /* Has scart2 a volume control? Not in pre-D revisions. */
+ state->has_scart2_out_volume = msp_revision > 'C' && state->has_scart23_in_scart2_out;
+ /* Has a configurable i2s out? */
+ state->has_i2s_conf = msp_revision >= 'G' && msp_prod_lo < 7;
+ /* Has subwoofer output: not in pre-D revs and not in stripped down products */
+ state->has_subwoofer = msp_revision >= 'D' && msp_prod_lo < 5;
+ /* Has soundprocessing (bass/treble/balance/loudness/equalizer): not in
+ stripped down products */
+ state->has_sound_processing = msp_prod_lo < 7;
+ /* Has Virtual Dolby Surround: only in msp34x1 */
+ state->has_virtual_dolby_surround = msp_revision == 'G' && msp_prod_lo == 1;
+ /* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */
+ state->has_dolby_pro_logic = msp_revision == 'G' && msp_prod_lo == 2;
+
+ state->opmode = opmode;
+ if (state->opmode == OPMODE_AUTO) {
+ /* MSP revision G and up have both autodetect and autoselect */
+ if (msp_revision >= 'G')
+ state->opmode = OPMODE_AUTOSELECT;
+ /* MSP revision D and up have autodetect */
+ else if (msp_revision >= 'D')
+ state->opmode = OPMODE_AUTODETECT;
+ else
+ state->opmode = OPMODE_MANUAL;
+ }
+
+ /* hello world :-) */
+ v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name);
+ v4l_info(client, "%s ", client->name);
+ if (state->has_nicam && state->has_radio)
+ printk("supports nicam and radio, ");
+ else if (state->has_nicam)
+ printk("supports nicam, ");
+ else if (state->has_radio)
+ printk("supports radio, ");
+ printk("mode is ");
+
+ /* version-specific initialization */
+ switch (state->opmode) {
+ case OPMODE_MANUAL:
+ printk("manual");
+ thread_func = msp3400c_thread;
+ break;
+ case OPMODE_AUTODETECT:
+ printk("autodetect");
+ thread_func = msp3410d_thread;
+ break;
+ case OPMODE_AUTOSELECT:
+ printk("autodetect and autoselect");
+ thread_func = msp34xxg_thread;
+ break;
+ }
+ printk("\n");
+
+ /* startup control thread if needed */
+ if (thread_func) {
+ state->kthread = kthread_run(thread_func, client, "msp34xx");
+
+ if (state->kthread == NULL)
+ v4l_warn(client, "kernel_thread() failed\n");
+ msp_wake_thread(client);
+ }
+
+ /* done */
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+static int msp_probe(struct i2c_adapter *adapter)
+{
+ if (adapter->class & I2C_CLASS_TV_ANALOG)
+ return i2c_probe(adapter, &addr_data, msp_attach);
+ return 0;
+}
+
+static int msp_detach(struct i2c_client *client)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+ int err;
+
+ /* shutdown control thread */
+ if (state->kthread) {
+ state->restart = 1;
+ kthread_stop(state->kthread);
+ }
+ msp_reset(client);
+
+ err = i2c_detach_client(client);
+ if (err) {
+ return err;
+ }
+
+ kfree(state);
+ kfree(client);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver = {
+ .id = I2C_DRIVERID_MSP3400,
+ .attach_adapter = msp_probe,
+ .detach_client = msp_detach,
+ .command = msp_command,
+ .driver = {
+ .name = "msp3400",
+ .suspend = msp_suspend,
+ .resume = msp_resume,
+ },
+};
+
+static int __init msp3400_init_module(void)
+{
+ return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit msp3400_cleanup_module(void)
+{
+ i2c_del_driver(&i2c_driver);
+}
+
+module_init(msp3400_init_module);
+module_exit(msp3400_cleanup_module);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
new file mode 100644
index 000000000000..2b59b6847535
--- /dev/null
+++ b/drivers/media/video/msp3400-kthreads.c
@@ -0,0 +1,1010 @@
+/*
+ * Programming the mspx4xx sound processor family
+ *
+ * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/audiochip.h>
+#include <linux/kthread.h>
+#include <linux/suspend.h>
+#include "msp3400.h"
+
+/* this one uses the automatic sound standard detection of newer msp34xx
+ chip versions */
+static struct {
+ int retval;
+ int main, second;
+ char *name;
+} msp_stdlist[] = {
+ { 0x0000, 0, 0, "could not detect sound standard" },
+ { 0x0001, 0, 0, "autodetect start" },
+ { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72 M Dual FM-Stereo" },
+ { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74 B/G Dual FM-Stereo" },
+ { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" },
+ { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" },
+ { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" },
+ { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" },
+ { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" },
+ { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" },
+ { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" },
+ { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" },
+ { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" },
+ { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" },
+ { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" },
+ { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7 FM-Stereo Radio" },
+ { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 SAT-Mono" },
+ { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20 SAT-Stereo" },
+ { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2 SAT ADR" },
+ { -1, 0, 0, NULL }, /* EOF */
+};
+
+static struct msp3400c_init_data_dem {
+ int fir1[6];
+ int fir2[6];
+ int cdo1;
+ int cdo2;
+ int ad_cv;
+ int mode_reg;
+ int dsp_src;
+ int dsp_matrix;
+} msp3400c_init_data[] = {
+ { /* AM (for carrier detect / msp3400) */
+ {75, 19, 36, 35, 39, 40},
+ {75, 19, 36, 35, 39, 40},
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 0x00d0, 0x0500, 0x0020, 0x3000
+ },{ /* AM (for carrier detect / msp3410) */
+ {-1, -1, -8, 2, 59, 126},
+ {-1, -1, -8, 2, 59, 126},
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 0x00d0, 0x0100, 0x0020, 0x3000
+ },{ /* FM Radio */
+ {-8, -8, 4, 6, 78, 107},
+ {-8, -8, 4, 6, 78, 107},
+ MSP_CARRIER(10.7), MSP_CARRIER(10.7),
+ 0x00d0, 0x0480, 0x0020, 0x3000
+ },{ /* Terrestial FM-mono + FM-stereo */
+ {3, 18, 27, 48, 66, 72},
+ {3, 18, 27, 48, 66, 72},
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 0x00d0, 0x0480, 0x0030, 0x3000
+ },{ /* Sat FM-mono */
+ { 1, 9, 14, 24, 33, 37},
+ { 3, 18, 27, 48, 66, 72},
+ MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+ 0x00c6, 0x0480, 0x0000, 0x3000
+ },{ /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */
+ {-2, -8, -10, 10, 50, 86},
+ {3, 18, 27, 48, 66, 72},
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 0x00d0, 0x0040, 0x0120, 0x3000
+ },{ /* NICAM/FM -- I (6.0/6.552) */
+ {2, 4, -6, -4, 40, 94},
+ {3, 18, 27, 48, 66, 72},
+ MSP_CARRIER(6.0), MSP_CARRIER(6.0),
+ 0x00d0, 0x0040, 0x0120, 0x3000
+ },{ /* NICAM/AM -- L (6.5/5.85) */
+ {-2, -8, -10, 10, 50, 86},
+ {-4, -12, -9, 23, 79, 126},
+ MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+ 0x00c6, 0x0140, 0x0120, 0x7c03
+ },
+};
+
+struct msp3400c_carrier_detect {
+ int cdo;
+ char *name;
+};
+
+static struct msp3400c_carrier_detect msp3400c_carrier_detect_main[] = {
+ /* main carrier */
+ { MSP_CARRIER(4.5), "4.5 NTSC" },
+ { MSP_CARRIER(5.5), "5.5 PAL B/G" },
+ { MSP_CARRIER(6.0), "6.0 PAL I" },
+ { MSP_CARRIER(6.5), "6.5 PAL D/K + SAT + SECAM" }
+};
+
+static struct msp3400c_carrier_detect msp3400c_carrier_detect_55[] = {
+ /* PAL B/G */
+ { MSP_CARRIER(5.7421875), "5.742 PAL B/G FM-stereo" },
+ { MSP_CARRIER(5.85), "5.85 PAL B/G NICAM" }
+};
+
+static struct msp3400c_carrier_detect msp3400c_carrier_detect_65[] = {
+ /* PAL SAT / SECAM */
+ { MSP_CARRIER(5.85), "5.85 PAL D/K + SECAM NICAM" },
+ { MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" },
+ { MSP_CARRIER(6.7421875), "6.74 PAL D/K2 FM-stereo" },
+ { MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" },
+ { MSP_CARRIER(7.20), "7.20 PAL SAT FM-stereo s" },
+ { MSP_CARRIER(7.38), "7.38 PAL SAT FM-stereo b" },
+};
+
+/* ------------------------------------------------------------------------ */
+
+const char *msp_standard_std_name(int std)
+{
+ int i;
+
+ for (i = 0; msp_stdlist[i].name != NULL; i++)
+ if (msp_stdlist[i].retval == std)
+ return msp_stdlist[i].name;
+ return "unknown";
+}
+
+void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2)
+{
+ msp_write_dem(client, 0x0093, cdo1 & 0xfff);
+ msp_write_dem(client, 0x009b, cdo1 >> 12);
+ msp_write_dem(client, 0x00a3, cdo2 & 0xfff);
+ msp_write_dem(client, 0x00ab, cdo2 >> 12);
+ msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/
+}
+
+void msp3400c_setmode(struct i2c_client *client, int type)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+ int i;
+
+ v4l_dbg(1, client, "setmode: %d\n", type);
+ state->mode = type;
+ state->audmode = V4L2_TUNER_MODE_MONO;
+ state->rxsubchans = V4L2_TUNER_SUB_MONO;
+
+ msp_write_dem(client, 0x00bb, msp3400c_init_data[type].ad_cv);
+
+ for (i = 5; i >= 0; i--) /* fir 1 */
+ msp_write_dem(client, 0x0001, msp3400c_init_data[type].fir1[i]);
+
+ msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */
+ msp_write_dem(client, 0x0005, 0x0040);
+ msp_write_dem(client, 0x0005, 0x0000);
+ for (i = 5; i >= 0; i--)
+ msp_write_dem(client, 0x0005, msp3400c_init_data[type].fir2[i]);
+
+ msp_write_dem(client, 0x0083, msp3400c_init_data[type].mode_reg);
+
+ msp3400c_setcarrier(client, msp3400c_init_data[type].cdo1,
+ msp3400c_init_data[type].cdo2);
+
+ msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/
+
+ if (dolby) {
+ msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */
+ msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */
+ msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src);
+ } else {
+ msp_write_dsp(client, 0x0008, msp3400c_init_data[type].dsp_src);
+ msp_write_dsp(client, 0x0009, msp3400c_init_data[type].dsp_src);
+ msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src);
+ }
+ msp_write_dsp(client, 0x000a, msp3400c_init_data[type].dsp_src);
+ msp_write_dsp(client, 0x000e, msp3400c_init_data[type].dsp_matrix);
+
+ if (state->has_nicam) {
+ /* nicam prescale */
+ msp_write_dsp(client, 0x0010, 0x5a00); /* was: 0x3000 */
+ }
+}
+
+/* turn on/off nicam + stereo */
+void msp3400c_setstereo(struct i2c_client *client, int mode)
+{
+ static char *strmode[] = { "mono", "stereo", "lang2", "lang1" };
+ struct msp_state *state = i2c_get_clientdata(client);
+ int nicam = 0; /* channel source: FM/AM or nicam */
+ int src = 0;
+
+ if (state->opmode == OPMODE_AUTOSELECT) {
+ /* this method would break everything, let's make sure
+ * it's never called
+ */
+ v4l_dbg(1, client, "setstereo called with mode=%d instead of set_source (ignored)\n",
+ mode);
+ return;
+ }
+
+ /* switch demodulator */
+ switch (state->mode) {
+ case MSP_MODE_FM_TERRA:
+ v4l_dbg(1, client, "FM setstereo: %s\n", strmode[mode]);
+ msp3400c_setcarrier(client, state->second, state->main);
+ switch (mode) {
+ case V4L2_TUNER_MODE_STEREO:
+ msp_write_dsp(client, 0x000e, 0x3001);
+ break;
+ case V4L2_TUNER_MODE_MONO:
+ case V4L2_TUNER_MODE_LANG1:
+ case V4L2_TUNER_MODE_LANG2:
+ msp_write_dsp(client, 0x000e, 0x3000);
+ break;
+ }
+ break;
+ case MSP_MODE_FM_SAT:
+ v4l_dbg(1, client, "SAT setstereo: %s\n", strmode[mode]);
+ switch (mode) {
+ case V4L2_TUNER_MODE_MONO:
+ msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
+ break;
+ case V4L2_TUNER_MODE_LANG1:
+ msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+ break;
+ }
+ break;
+ case MSP_MODE_FM_NICAM1:
+ case MSP_MODE_FM_NICAM2:
+ case MSP_MODE_AM_NICAM:
+ v4l_dbg(1, client, "NICAM setstereo: %s\n",strmode[mode]);
+ msp3400c_setcarrier(client,state->second,state->main);
+ if (state->nicam_on)
+ nicam=0x0100;
+ break;
+ case MSP_MODE_BTSC:
+ v4l_dbg(1, client, "BTSC setstereo: %s\n",strmode[mode]);
+ nicam=0x0300;
+ break;
+ case MSP_MODE_EXTERN:
+ v4l_dbg(1, client, "extern setstereo: %s\n",strmode[mode]);
+ nicam = 0x0200;
+ break;
+ case MSP_MODE_FM_RADIO:
+ v4l_dbg(1, client, "FM-Radio setstereo: %s\n",strmode[mode]);
+ break;
+ default:
+ v4l_dbg(1, client, "mono setstereo\n");
+ return;
+ }
+
+ /* switch audio */
+ switch (mode) {
+ case V4L2_TUNER_MODE_STEREO:
+ src = 0x0020 | nicam;
+ break;
+ case V4L2_TUNER_MODE_MONO:
+ if (state->mode == MSP_MODE_AM_NICAM) {
+ v4l_dbg(1, client, "switching to AM mono\n");
+ /* AM mono decoding is handled by tuner, not MSP chip */
+ /* SCART switching control register */
+ msp_set_scart(client, SCART_MONO, 0);
+ src = 0x0200;
+ break;
+ }
+ case V4L2_TUNER_MODE_LANG1:
+ src = 0x0000 | nicam;
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ src = 0x0010 | nicam;
+ break;
+ }
+ v4l_dbg(1, client, "setstereo final source/matrix = 0x%x\n", src);
+
+ if (dolby) {
+ msp_write_dsp(client, 0x0008, 0x0520);
+ msp_write_dsp(client, 0x0009, 0x0620);
+ msp_write_dsp(client, 0x000a, src);
+ msp_write_dsp(client, 0x000b, src);
+ } else {
+ msp_write_dsp(client, 0x0008, src);
+ msp_write_dsp(client, 0x0009, src);
+ msp_write_dsp(client, 0x000a, src);
+ msp_write_dsp(client, 0x000b, src);
+ msp_write_dsp(client, 0x000c, src);
+ if (state->has_scart23_in_scart2_out)
+ msp_write_dsp(client, 0x0041, src);
+ }
+}
+
+static void msp3400c_print_mode(struct i2c_client *client)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+
+ if (state->main == state->second) {
+ v4l_dbg(1, client, "mono sound carrier: %d.%03d MHz\n",
+ state->main / 910000, (state->main / 910) % 1000);
+ } else {
+ v4l_dbg(1, client, "main sound carrier: %d.%03d MHz\n",
+ state->main / 910000, (state->main / 910) % 1000);
+ }
+ if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2)
+ v4l_dbg(1, client, "NICAM/FM carrier : %d.%03d MHz\n",
+ state->second / 910000, (state->second/910) % 1000);
+ if (state->mode == MSP_MODE_AM_NICAM)
+ v4l_dbg(1, client, "NICAM/AM carrier : %d.%03d MHz\n",
+ state->second / 910000, (state->second / 910) % 1000);
+ if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) {
+ v4l_dbg(1, client, "FM-stereo carrier : %d.%03d MHz\n",
+ state->second / 910000, (state->second / 910) % 1000);
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+int autodetect_stereo(struct i2c_client *client)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+ int val;
+ int rxsubchans = state->rxsubchans;
+ int newnicam = state->nicam_on;
+ int update = 0;
+
+ switch (state->mode) {
+ case MSP_MODE_FM_TERRA:
+ val = msp_read_dsp(client, 0x18);
+ if (val > 32767)
+ val -= 65536;
+ v4l_dbg(2, client, "stereo detect register: %d\n", val);
+ if (val > 4096) {
+ rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
+ } else if (val < -4096) {
+ rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+ } else {
+ rxsubchans = V4L2_TUNER_SUB_MONO;
+ }
+ newnicam = 0;
+ break;
+ case MSP_MODE_FM_NICAM1:
+ case MSP_MODE_FM_NICAM2:
+ case MSP_MODE_AM_NICAM:
+ val = msp_read_dem(client, 0x23);
+ v4l_dbg(2, client, "nicam sync=%d, mode=%d\n",
+ val & 1, (val & 0x1e) >> 1);
+
+ if (val & 1) {
+ /* nicam synced */
+ switch ((val & 0x1e) >> 1) {
+ case 0:
+ case 8:
+ rxsubchans = V4L2_TUNER_SUB_STEREO;
+ break;
+ case 1:
+ case 9:
+ rxsubchans = V4L2_TUNER_SUB_MONO
+ | V4L2_TUNER_SUB_LANG1;
+ break;
+ case 2:
+ case 10:
+ rxsubchans = V4L2_TUNER_SUB_MONO
+ | V4L2_TUNER_SUB_LANG1
+ | V4L2_TUNER_SUB_LANG2;
+ break;
+ default:
+ rxsubchans = V4L2_TUNER_SUB_MONO;
+ break;
+ }
+ newnicam = 1;
+ } else {
+ newnicam = 0;
+ rxsubchans = V4L2_TUNER_SUB_MONO;
+ }
+ break;
+ case MSP_MODE_BTSC:
+ val = msp_read_dem(client, 0x200);
+ v4l_dbg(2, client, "status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
+ val,
+ (val & 0x0002) ? "no" : "yes",
+ (val & 0x0004) ? "no" : "yes",
+ (val & 0x0040) ? "stereo" : "mono",
+ (val & 0x0080) ? ", nicam 2nd mono" : "",
+ (val & 0x0100) ? ", bilingual/SAP" : "");
+ rxsubchans = V4L2_TUNER_SUB_MONO;
+ if (val & 0x0040) rxsubchans |= V4L2_TUNER_SUB_STEREO;
+ if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1;
+ break;
+ }
+ if (rxsubchans != state->rxsubchans) {
+ update = 1;
+ v4l_dbg(1, client, "watch: rxsubchans %d => %d\n",
+ state->rxsubchans,rxsubchans);
+ state->rxsubchans = rxsubchans;
+ }
+ if (newnicam != state->nicam_on) {
+ update = 1;
+ v4l_dbg(1, client, "watch: nicam %d => %d\n",
+ state->nicam_on,newnicam);
+ state->nicam_on = newnicam;
+ }
+ return update;
+}
+
+/*
+ * A kernel thread for msp3400 control -- we don't want to block the
+ * in the ioctl while doing the sound carrier & stereo detect
+ */
+/* stereo/multilang monitoring */
+static void watch_stereo(struct i2c_client *client)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+
+ if (autodetect_stereo(client)) {
+ if (state->rxsubchans & V4L2_TUNER_SUB_STEREO)
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO);
+ else if (state->rxsubchans & V4L2_TUNER_SUB_LANG1)
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1);
+ else
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+ }
+
+ if (once)
+ state->watch_stereo = 0;
+}
+
+int msp3400c_thread(void *data)
+{
+ struct i2c_client *client = data;
+ struct msp_state *state = i2c_get_clientdata(client);
+ struct msp3400c_carrier_detect *cd;
+ int count, max1,max2,val1,val2, val,this;
+
+
+ v4l_dbg(1, client, "msp3400 daemon started\n");
+ for (;;) {
+ v4l_dbg(2, client, "msp3400 thread: sleep\n");
+ msp_sleep(state, -1);
+ v4l_dbg(2, client, "msp3400 thread: wakeup\n");
+
+ restart:
+ v4l_dbg(1, client, "thread: restart scan\n");
+ state->restart = 0;
+ if (kthread_should_stop())
+ break;
+
+ if (state->radio || MSP_MODE_EXTERN == state->mode) {
+ /* no carrier scan, just unmute */
+ v4l_dbg(1, client, "thread: no carrier scan\n");
+ msp_set_audio(client);
+ continue;
+ }
+
+ /* mute */
+ msp_set_mute(client);
+ msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
+ val1 = val2 = 0;
+ max1 = max2 = -1;
+ state->watch_stereo = 0;
+
+ /* some time for the tuner to sync */
+ if (msp_sleep(state,200))
+ goto restart;
+
+ /* carrier detect pass #1 -- main carrier */
+ cd = msp3400c_carrier_detect_main;
+ count = ARRAY_SIZE(msp3400c_carrier_detect_main);
+
+ if (amsound && (state->v4l2_std & V4L2_STD_SECAM)) {
+ /* autodetect doesn't work well with AM ... */
+ max1 = 3;
+ count = 0;
+ v4l_dbg(1, client, "AM sound override\n");
+ }
+
+ for (this = 0; this < count; this++) {
+ msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
+ if (msp_sleep(state,100))
+ goto restart;
+ val = msp_read_dsp(client, 0x1b);
+ if (val > 32767)
+ val -= 65536;
+ if (val1 < val)
+ val1 = val, max1 = this;
+ v4l_dbg(1, client, "carrier1 val: %5d / %s\n", val,cd[this].name);
+ }
+
+ /* carrier detect pass #2 -- second (stereo) carrier */
+ switch (max1) {
+ case 1: /* 5.5 */
+ cd = msp3400c_carrier_detect_55;
+ count = ARRAY_SIZE(msp3400c_carrier_detect_55);
+ break;
+ case 3: /* 6.5 */
+ cd = msp3400c_carrier_detect_65;
+ count = ARRAY_SIZE(msp3400c_carrier_detect_65);
+ break;
+ case 0: /* 4.5 */
+ case 2: /* 6.0 */
+ default:
+ cd = NULL;
+ count = 0;
+ break;
+ }
+
+ if (amsound && (state->v4l2_std & V4L2_STD_SECAM)) {
+ /* autodetect doesn't work well with AM ... */
+ cd = NULL;
+ count = 0;
+ max2 = 0;
+ }
+ for (this = 0; this < count; this++) {
+ msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
+ if (msp_sleep(state,100))
+ goto restart;
+ val = msp_read_dsp(client, 0x1b);
+ if (val > 32767)
+ val -= 65536;
+ if (val2 < val)
+ val2 = val, max2 = this;
+ v4l_dbg(1, client, "carrier2 val: %5d / %s\n", val,cd[this].name);
+ }
+
+ /* program the msp3400 according to the results */
+ state->main = msp3400c_carrier_detect_main[max1].cdo;
+ switch (max1) {
+ case 1: /* 5.5 */
+ if (max2 == 0) {
+ /* B/G FM-stereo */
+ state->second = msp3400c_carrier_detect_55[max2].cdo;
+ msp3400c_setmode(client, MSP_MODE_FM_TERRA);
+ state->nicam_on = 0;
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+ state->watch_stereo = 1;
+ } else if (max2 == 1 && state->has_nicam) {
+ /* B/G NICAM */
+ state->second = msp3400c_carrier_detect_55[max2].cdo;
+ msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
+ state->nicam_on = 1;
+ msp3400c_setcarrier(client, state->second, state->main);
+ state->watch_stereo = 1;
+ } else {
+ goto no_second;
+ }
+ break;
+ case 2: /* 6.0 */
+ /* PAL I NICAM */
+ state->second = MSP_CARRIER(6.552);
+ msp3400c_setmode(client, MSP_MODE_FM_NICAM2);
+ state->nicam_on = 1;
+ msp3400c_setcarrier(client, state->second, state->main);
+ state->watch_stereo = 1;
+ break;
+ case 3: /* 6.5 */
+ if (max2 == 1 || max2 == 2) {
+ /* D/K FM-stereo */
+ state->second = msp3400c_carrier_detect_65[max2].cdo;
+ msp3400c_setmode(client, MSP_MODE_FM_TERRA);
+ state->nicam_on = 0;
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+ state->watch_stereo = 1;
+ } else if (max2 == 0 && (state->v4l2_std & V4L2_STD_SECAM)) {
+ /* L NICAM or AM-mono */
+ state->second = msp3400c_carrier_detect_65[max2].cdo;
+ msp3400c_setmode(client, MSP_MODE_AM_NICAM);
+ state->nicam_on = 0;
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+ msp3400c_setcarrier(client, state->second, state->main);
+ /* volume prescale for SCART (AM mono input) */
+ msp_write_dsp(client, 0x000d, 0x1900);
+ state->watch_stereo = 1;
+ } else if (max2 == 0 && state->has_nicam) {
+ /* D/K NICAM */
+ state->second = msp3400c_carrier_detect_65[max2].cdo;
+ msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
+ state->nicam_on = 1;
+ msp3400c_setcarrier(client, state->second, state->main);
+ state->watch_stereo = 1;
+ } else {
+ goto no_second;
+ }
+ break;
+ case 0: /* 4.5 */
+ default:
+ no_second:
+ state->second = msp3400c_carrier_detect_main[max1].cdo;
+ msp3400c_setmode(client, MSP_MODE_FM_TERRA);
+ state->nicam_on = 0;
+ msp3400c_setcarrier(client, state->second, state->main);
+ state->rxsubchans = V4L2_TUNER_SUB_MONO;
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+ break;
+ }
+
+ /* unmute */
+ msp_set_audio(client);
+
+ if (debug)
+ msp3400c_print_mode(client);
+
+ /* monitor tv audio mode */
+ while (state->watch_stereo) {
+ if (msp_sleep(state,5000))
+ goto restart;
+ watch_stereo(client);
+ }
+ }
+ v4l_dbg(1, client, "thread: exit\n");
+ return 0;
+}
+
+
+int msp3410d_thread(void *data)
+{
+ struct i2c_client *client = data;
+ struct msp_state *state = i2c_get_clientdata(client);
+ int val, i, std;
+
+ v4l_dbg(1, client, "msp3410 daemon started\n");
+
+ for (;;) {
+ v4l_dbg(2, client, "msp3410 thread: sleep\n");
+ msp_sleep(state,-1);
+ v4l_dbg(2, client, "msp3410 thread: wakeup\n");
+
+ restart:
+ v4l_dbg(1, client, "thread: restart scan\n");
+ state->restart = 0;
+ if (kthread_should_stop())
+ break;
+
+ if (state->mode == MSP_MODE_EXTERN) {
+ /* no carrier scan needed, just unmute */
+ v4l_dbg(1, client, "thread: no carrier scan\n");
+ msp_set_audio(client);
+ continue;
+ }
+
+ /* put into sane state (and mute) */
+ msp_reset(client);
+
+ /* some time for the tuner to sync */
+ if (msp_sleep(state,200))
+ goto restart;
+
+ /* start autodetect */
+ if (state->radio)
+ std = 0x40;
+ else
+ std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1;
+ state->watch_stereo = 0;
+
+ if (debug)
+ v4l_dbg(1, client, "setting standard: %s (0x%04x)\n",
+ msp_standard_std_name(std), std);
+
+ if (std != 1) {
+ /* programmed some specific mode */
+ val = std;
+ } else {
+ /* triggered autodetect */
+ msp_write_dem(client, 0x20, std);
+ for (;;) {
+ if (msp_sleep(state, 100))
+ goto restart;
+
+ /* check results */
+ val = msp_read_dem(client, 0x7e);
+ if (val < 0x07ff)
+ break;
+ v4l_dbg(1, client, "detection still in progress\n");
+ }
+ }
+ for (i = 0; msp_stdlist[i].name != NULL; i++)
+ if (msp_stdlist[i].retval == val)
+ break;
+ v4l_dbg(1, client, "current standard: %s (0x%04x)\n",
+ msp_standard_std_name(val), val);
+ state->main = msp_stdlist[i].main;
+ state->second = msp_stdlist[i].second;
+ state->std = val;
+
+ if (amsound && !state->radio && (state->v4l2_std & V4L2_STD_SECAM) &&
+ (val != 0x0009)) {
+ /* autodetection has failed, let backup */
+ v4l_dbg(1, client, "autodetection failed,"
+ " switching to backup standard: %s (0x%04x)\n",
+ msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val);
+ val = 0x0009;
+ msp_write_dem(client, 0x20, val);
+ }
+
+ /* set various prescales */
+ msp_write_dsp(client, 0x0d, 0x1900); /* scart */
+ msp_write_dsp(client, 0x0e, 0x2403); /* FM */
+ msp_write_dsp(client, 0x10, 0x5a00); /* nicam */
+
+ /* set stereo */
+ switch (val) {
+ case 0x0008: /* B/G NICAM */
+ case 0x000a: /* I NICAM */
+ if (val == 0x0008)
+ state->mode = MSP_MODE_FM_NICAM1;
+ else
+ state->mode = MSP_MODE_FM_NICAM2;
+ /* just turn on stereo */
+ state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ state->nicam_on = 1;
+ state->watch_stereo = 1;
+ msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
+ break;
+ case 0x0009:
+ state->mode = MSP_MODE_AM_NICAM;
+ state->rxsubchans = V4L2_TUNER_SUB_MONO;
+ state->nicam_on = 1;
+ msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO);
+ state->watch_stereo = 1;
+ break;
+ case 0x0020: /* BTSC */
+ /* just turn on stereo */
+ state->mode = MSP_MODE_BTSC;
+ state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ state->nicam_on = 0;
+ state->watch_stereo = 1;
+ msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
+ break;
+ case 0x0040: /* FM radio */
+ state->mode = MSP_MODE_FM_RADIO;
+ state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ state->audmode = V4L2_TUNER_MODE_STEREO;
+ state->nicam_on = 0;
+ state->watch_stereo = 0;
+ /* not needed in theory if we have radio, but
+ short programming enables carrier mute */
+ msp3400c_setmode(client, MSP_MODE_FM_RADIO);
+ msp3400c_setcarrier(client, MSP_CARRIER(10.7),
+ MSP_CARRIER(10.7));
+ /* scart routing */
+ msp_set_scart(client,SCART_IN2,0);
+ /* msp34xx does radio decoding */
+ msp_write_dsp(client, 0x08, 0x0020);
+ msp_write_dsp(client, 0x09, 0x0020);
+ msp_write_dsp(client, 0x0b, 0x0020);
+ break;
+ case 0x0003:
+ case 0x0004:
+ case 0x0005:
+ state->mode = MSP_MODE_FM_TERRA;
+ state->rxsubchans = V4L2_TUNER_SUB_MONO;
+ state->audmode = V4L2_TUNER_MODE_MONO;
+ state->nicam_on = 0;
+ state->watch_stereo = 1;
+ break;
+ }
+
+ /* unmute, restore misc registers */
+ msp_set_audio(client);
+ msp_write_dsp(client, 0x13, state->acb);
+ if (state->has_i2s_conf)
+ msp_write_dem(client, 0x40, state->i2s_mode);
+
+ /* monitor tv audio mode */
+ while (state->watch_stereo) {
+ if (msp_sleep(state,5000))
+ goto restart;
+ watch_stereo(client);
+ }
+ }
+ v4l_dbg(1, client, "thread: exit\n");
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* msp34xxG + (autoselect no-thread) */
+/* this one uses both automatic standard detection and automatic sound */
+/* select which are available in the newer G versions */
+/* struct msp: only norm, acb and source are really used in this mode */
+
+/* set the same 'source' for the loudspeaker, scart and quasi-peak detector
+ * the value for source is the same as bit 15:8 of DSP registers 0x08,
+ * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B
+ *
+ * this function replaces msp3400c_setstereo
+ */
+static void msp34xxg_set_source(struct i2c_client *client, int source)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+
+ /* fix matrix mode to stereo and let the msp choose what
+ * to output according to 'source', as recommended
+ * for MONO (source==0) downmixing set bit[7:0] to 0x30
+ */
+ int value = (source & 0x07) << 8 | (source == 0 ? 0x30 : 0x20);
+
+ v4l_dbg(1, client, "set source to %d (0x%x)\n", source, value);
+ /* Loudspeaker Output */
+ msp_write_dsp(client, 0x08, value);
+ /* SCART1 DA Output */
+ msp_write_dsp(client, 0x0a, value);
+ /* Quasi-peak detector */
+ msp_write_dsp(client, 0x0c, value);
+ /*
+ * set identification threshold. Personally, I
+ * I set it to a higher value that the default
+ * of 0x190 to ignore noisy stereo signals.
+ * this needs tuning. (recommended range 0x00a0-0x03c0)
+ * 0x7f0 = forced mono mode
+ */
+ /* a2 threshold for stereo/bilingual */
+ msp_write_dem(client, 0x22, stereo_threshold);
+ state->source = source;
+}
+
+/* (re-)initialize the msp34xxg, according to the current norm in state->norm
+ * return 0 if it worked, -1 if it failed
+ */
+static int msp34xxg_reset(struct i2c_client *client)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+ int modus, std;
+
+ if (msp_reset(client))
+ return -1;
+
+ /* make sure that input/output is muted (paranoid mode) */
+ /* ACB, mute DSP input, mute SCART 1 */
+ if (msp_write_dsp(client, 0x13, 0x0f20))
+ return -1;
+
+ if (state->has_i2s_conf)
+ msp_write_dem(client, 0x40, state->i2s_mode);
+
+ /* step-by-step initialisation, as described in the manual */
+ modus = msp_modus(client);
+ if (state->radio)
+ std = 0x40;
+ else
+ std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1;
+ modus &= ~0x03; /* STATUS_CHANGE = 0 */
+ modus |= 0x01; /* AUTOMATIC_SOUND_DETECTION = 1 */
+ if (msp_write_dem(client, 0x30, modus))
+ return -1;
+ if (msp_write_dem(client, 0x20, std))
+ return -1;
+
+ /* write the dsps that may have an influence on
+ standard/audio autodetection right now */
+ msp34xxg_set_source(client, state->source);
+
+ /* AM/FM Prescale [15:8] 75khz deviation */
+ if (msp_write_dsp(client, 0x0e, 0x3000))
+ return -1;
+
+ /* NICAM Prescale 9db gain (as recommended) */
+ if (msp_write_dsp(client, 0x10, 0x5a00))
+ return -1;
+
+ return 0;
+}
+
+int msp34xxg_thread(void *data)
+{
+ struct i2c_client *client = data;
+ struct msp_state *state = i2c_get_clientdata(client);
+ int val, std, i;
+
+ v4l_dbg(1, client, "msp34xxg daemon started\n");
+
+ state->source = 1; /* default */
+ for (;;) {
+ v4l_dbg(2, client, "msp34xxg thread: sleep\n");
+ msp_sleep(state, -1);
+ v4l_dbg(2, client, "msp34xxg thread: wakeup\n");
+
+ restart:
+ v4l_dbg(1, client, "thread: restart scan\n");
+ state->restart = 0;
+ if (kthread_should_stop())
+ break;
+
+ /* setup the chip*/
+ msp34xxg_reset(client);
+ std = standard;
+ if (std != 0x01)
+ goto unmute;
+
+ /* watch autodetect */
+ v4l_dbg(1, client, "triggered autodetect, waiting for result\n");
+ for (i = 0; i < 10; i++) {
+ if (msp_sleep(state, 100))
+ goto restart;
+
+ /* check results */
+ val = msp_read_dem(client, 0x7e);
+ if (val < 0x07ff) {
+ std = val;
+ break;
+ }
+ v4l_dbg(2, client, "detection still in progress\n");
+ }
+ if (std == 1) {
+ v4l_dbg(1, client, "detection still in progress after 10 tries. giving up.\n");
+ continue;
+ }
+
+ unmute:
+ state->std = std;
+ v4l_dbg(1, client, "current standard: %s (0x%04x)\n",
+ msp_standard_std_name(std), std);
+
+ /* unmute: dispatch sound to scart output, set scart volume */
+ msp_set_audio(client);
+
+ /* restore ACB */
+ if (msp_write_dsp(client, 0x13, state->acb))
+ return -1;
+
+ msp_write_dem(client, 0x40, state->i2s_mode);
+ }
+ v4l_dbg(1, client, "thread: exit\n");
+ return 0;
+}
+
+void msp34xxg_detect_stereo(struct i2c_client *client)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+
+ int status = msp_read_dem(client, 0x0200);
+ int is_bilingual = status & 0x100;
+ int is_stereo = status & 0x40;
+
+ state->rxsubchans = 0;
+ if (is_stereo)
+ state->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+ else
+ state->rxsubchans |= V4L2_TUNER_SUB_MONO;
+ if (is_bilingual) {
+ state->rxsubchans |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+ /* I'm supposed to check whether it's SAP or not
+ * and set only LANG2/SAP in this case. Yet, the MSP
+ * does a lot of work to hide this and handle everything
+ * the same way. I don't want to work around it so unless
+ * this is a problem, I'll handle SAP just like lang1/lang2.
+ */
+ }
+ v4l_dbg(1, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
+ status, is_stereo, is_bilingual, state->rxsubchans);
+}
+
+void msp34xxg_set_audmode(struct i2c_client *client, int audmode)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+ int source;
+
+ switch (audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ source = 0; /* mono only */
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ source = 1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */
+ /* problem: that could also mean 2 (scart input) */
+ break;
+ case V4L2_TUNER_MODE_LANG1:
+ source = 3; /* stereo or A */
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ source = 4; /* stereo or B */
+ break;
+ default:
+ audmode = 0;
+ source = 1;
+ break;
+ }
+ state->audmode = audmode;
+ msp34xxg_set_source(client, source);
+}
+
diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c
deleted file mode 100644
index 183253e2dd91..000000000000
--- a/drivers/media/video/msp3400.c
+++ /dev/null
@@ -1,2229 +0,0 @@
-/*
- * programming the msp34* sound processor family
- *
- * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org>
- *
- * what works and what doesn't:
- *
- * AM-Mono
- * Support for Hauppauge cards added (decoding handled by tuner) added by
- * Frederic Crozat <fcrozat@mail.dotcom.fr>
- *
- * FM-Mono
- * should work. The stereo modes are backward compatible to FM-mono,
- * therefore FM-Mono should be allways available.
- *
- * FM-Stereo (B/G, used in germany)
- * should work, with autodetect
- *
- * FM-Stereo (satellite)
- * should work, no autodetect (i.e. default is mono, but you can
- * switch to stereo -- untested)
- *
- * NICAM (B/G, L , used in UK, Scandinavia, Spain and France)
- * should work, with autodetect. Support for NICAM was added by
- * Pekka Pietikainen <pp@netppl.fi>
- *
- *
- * TODO:
- * - better SAT support
- *
- *
- * 980623 Thomas Sailer (sailer@ife.ee.ethz.ch)
- * using soundcore instead of OSS
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/videodev.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/kthread.h>
-#include <linux/suspend.h>
-#include <asm/semaphore.h>
-#include <asm/pgtable.h>
-
-#include <media/audiochip.h>
-#include "msp3400.h"
-
-#define msp3400_dbg(fmt, arg...) \
- do { \
- if (debug) \
- printk(KERN_INFO "%s debug %d-%04x: " fmt, \
- client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); \
- } while (0)
-
-/* Medium volume debug. */
-#define msp3400_dbg_mediumvol(fmt, arg...) \
- do { \
- if (debug >= 2) \
- printk(KERN_INFO "%s debug %d-%04x: " fmt, \
- client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); \
- } while (0)
-
-/* High volume debug. Use with care. */
-#define msp3400_dbg_highvol(fmt, arg...) \
- do { \
- if (debug >= 16) \
- printk(KERN_INFO "%s debug %d-%04x: " fmt, \
- client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); \
- } while (0)
-
-#define msp3400_err(fmt, arg...) do { \
- printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define msp3400_warn(fmt, arg...) do { \
- printk(KERN_WARNING "%s %d-%04x: " fmt, client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define msp3400_info(fmt, arg...) do { \
- printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
-#define OPMODE_AUTO -1
-#define OPMODE_MANUAL 0
-#define OPMODE_SIMPLE 1 /* use short programming (>= msp3410 only) */
-#define OPMODE_SIMPLER 2 /* use shorter programming (>= msp34xxG) */
-
-/* insmod parameters */
-static int opmode = OPMODE_AUTO;
-static int debug = 0; /* debug output */
-static int once = 0; /* no continous stereo monitoring */
-static int amsound = 0; /* hard-wire AM sound at 6.5 Hz (france),
- the autoscan seems work well only with FM... */
-static int standard = 1; /* Override auto detect of audio standard, if needed. */
-static int dolby = 0;
-
-static int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual
- (msp34xxg only) 0x00a0-0x03c0 */
-#define DFP_COUNT 0x41
-static const int bl_dfp[] = {
- 0x00, 0x01, 0x02, 0x03, 0x06, 0x08, 0x09, 0x0a,
- 0x0b, 0x0d, 0x0e, 0x10
-};
-
-#define IS_MSP34XX_G(msp) ((msp)->opmode==2)
-
-struct msp3400c {
- int rev1,rev2;
-
- int opmode;
- int nicam;
- int mode;
- int norm;
- int stereo;
- int nicam_on;
- int acb;
- int in_scart;
- int i2s_mode;
- int main, second; /* sound carrier */
- int input;
- int source; /* see msp34xxg_set_source */
-
- /* v4l2 */
- int audmode;
- int rxsubchans;
-
- int muted;
- int left, right; /* volume */
- int bass, treble;
-
- /* shadow register set */
- int dfp_regs[DFP_COUNT];
-
- /* thread */
- struct task_struct *kthread;
- wait_queue_head_t wq;
- int restart:1;
- int watch_stereo:1;
-};
-
-#define MIN(a,b) (((a)>(b))?(b):(a))
-#define MAX(a,b) (((a)>(b))?(a):(b))
-#define HAVE_NICAM(msp) (((msp->rev2>>8) & 0xff) != 00)
-#define HAVE_SIMPLE(msp) ((msp->rev1 & 0xff) >= 'D'-'@')
-#define HAVE_SIMPLER(msp) ((msp->rev1 & 0xff) >= 'G'-'@')
-#define HAVE_RADIO(msp) ((msp->rev1 & 0xff) >= 'G'-'@')
-
-#define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */
-
-/* ---------------------------------------------------------------------- */
-
-/* read-only */
-module_param(opmode, int, 0444);
-
-/* read-write */
-module_param(once, int, 0644);
-module_param(debug, int, 0644);
-module_param(stereo_threshold, int, 0644);
-module_param(standard, int, 0644);
-module_param(amsound, int, 0644);
-module_param(dolby, int, 0644);
-
-MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Simple, 2=Simpler");
-MODULE_PARM_DESC(once, "No continuous stereo monitoring");
-MODULE_PARM_DESC(debug, "Enable debug messages");
-MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo");
-MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect");
-MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan");
-MODULE_PARM_DESC(dolby, "Activates Dolby processsing");
-
-/* ---------------------------------------------------------------------- */
-
-#define I2C_MSP3400C 0x80
-#define I2C_MSP3400C_ALT 0x88
-
-#define I2C_MSP3400C_DEM 0x10
-#define I2C_MSP3400C_DFP 0x12
-
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {
- I2C_MSP3400C >> 1,
- I2C_MSP3400C_ALT >> 1,
- I2C_CLIENT_END
-};
-I2C_CLIENT_INSMOD;
-
-MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("GPL");
-
-/* ----------------------------------------------------------------------- */
-/* functions for talking to the MSP3400C Sound processor */
-
-static int msp3400c_reset(struct i2c_client *client)
-{
- /* reset and read revision code */
- static char reset_off[3] = { 0x00, 0x80, 0x00 };
- static char reset_on[3] = { 0x00, 0x00, 0x00 };
- static char write[3] = { I2C_MSP3400C_DFP + 1, 0x00, 0x1e };
- char read[2];
- struct i2c_msg reset[2] = {
- { client->addr, I2C_M_IGNORE_NAK, 3, reset_off },
- { client->addr, I2C_M_IGNORE_NAK, 3, reset_on },
- };
- struct i2c_msg test[2] = {
- { client->addr, 0, 3, write },
- { client->addr, I2C_M_RD, 2, read },
- };
-
- msp3400_dbg_highvol("msp3400c_reset\n");
- if ( (1 != i2c_transfer(client->adapter,&reset[0],1)) ||
- (1 != i2c_transfer(client->adapter,&reset[1],1)) ||
- (2 != i2c_transfer(client->adapter,test,2)) ) {
- msp3400_err("chip reset failed\n");
- return -1;
- }
- return 0;
-}
-
-static int msp3400c_read(struct i2c_client *client, int dev, int addr)
-{
- int err,retval;
-
- unsigned char write[3];
- unsigned char read[2];
- struct i2c_msg msgs[2] = {
- { client->addr, 0, 3, write },
- { client->addr, I2C_M_RD, 2, read }
- };
-
- write[0] = dev+1;
- write[1] = addr >> 8;
- write[2] = addr & 0xff;
-
- for (err = 0; err < 3;) {
- if (2 == i2c_transfer(client->adapter,msgs,2))
- break;
- err++;
- msp3400_warn("I/O error #%d (read 0x%02x/0x%02x)\n", err,
- dev, addr);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(msecs_to_jiffies(10));
- }
- if (3 == err) {
- msp3400_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n");
- msp3400c_reset(client);
- return -1;
- }
- retval = read[0] << 8 | read[1];
- msp3400_dbg_highvol("msp3400c_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval);
- return retval;
-}
-
-static int msp3400c_write(struct i2c_client *client, int dev, int addr, int val)
-{
- int err;
- unsigned char buffer[5];
-
- buffer[0] = dev;
- buffer[1] = addr >> 8;
- buffer[2] = addr & 0xff;
- buffer[3] = val >> 8;
- buffer[4] = val & 0xff;
-
- msp3400_dbg_highvol("msp3400c_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val);
- for (err = 0; err < 3;) {
- if (5 == i2c_master_send(client, buffer, 5))
- break;
- err++;
- msp3400_warn("I/O error #%d (write 0x%02x/0x%02x)\n", err,
- dev, addr);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(msecs_to_jiffies(10));
- }
- if (3 == err) {
- msp3400_warn("giving up, reseting chip. Sound will go off, sorry folks :-|\n");
- msp3400c_reset(client);
- return -1;
- }
- return 0;
-}
-
-/* ------------------------------------------------------------------------ */
-
-/* This macro is allowed for *constants* only, gcc must calculate it
- at compile time. Remember -- no floats in kernel mode */
-#define MSP_CARRIER(freq) ((int)((float)(freq/18.432)*(1<<24)))
-
-#define MSP_MODE_AM_DETECT 0
-#define MSP_MODE_FM_RADIO 2
-#define MSP_MODE_FM_TERRA 3
-#define MSP_MODE_FM_SAT 4
-#define MSP_MODE_FM_NICAM1 5
-#define MSP_MODE_FM_NICAM2 6
-#define MSP_MODE_AM_NICAM 7
-#define MSP_MODE_BTSC 8
-#define MSP_MODE_EXTERN 9
-
-static struct MSP_INIT_DATA_DEM {
- int fir1[6];
- int fir2[6];
- int cdo1;
- int cdo2;
- int ad_cv;
- int mode_reg;
- int dfp_src;
- int dfp_matrix;
-} msp_init_data[] = {
- { /* AM (for carrier detect / msp3400) */
- {75, 19, 36, 35, 39, 40},
- {75, 19, 36, 35, 39, 40},
- MSP_CARRIER(5.5), MSP_CARRIER(5.5),
- 0x00d0, 0x0500, 0x0020, 0x3000
- },{ /* AM (for carrier detect / msp3410) */
- {-1, -1, -8, 2, 59, 126},
- {-1, -1, -8, 2, 59, 126},
- MSP_CARRIER(5.5), MSP_CARRIER(5.5),
- 0x00d0, 0x0100, 0x0020, 0x3000
- },{ /* FM Radio */
- {-8, -8, 4, 6, 78, 107},
- {-8, -8, 4, 6, 78, 107},
- MSP_CARRIER(10.7), MSP_CARRIER(10.7),
- 0x00d0, 0x0480, 0x0020, 0x3000
- },{ /* Terrestial FM-mono + FM-stereo */
- {3, 18, 27, 48, 66, 72},
- {3, 18, 27, 48, 66, 72},
- MSP_CARRIER(5.5), MSP_CARRIER(5.5),
- 0x00d0, 0x0480, 0x0030, 0x3000
- },{ /* Sat FM-mono */
- { 1, 9, 14, 24, 33, 37},
- { 3, 18, 27, 48, 66, 72},
- MSP_CARRIER(6.5), MSP_CARRIER(6.5),
- 0x00c6, 0x0480, 0x0000, 0x3000
- },{ /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */
- {-2, -8, -10, 10, 50, 86},
- {3, 18, 27, 48, 66, 72},
- MSP_CARRIER(5.5), MSP_CARRIER(5.5),
- 0x00d0, 0x0040, 0x0120, 0x3000
- },{ /* NICAM/FM -- I (6.0/6.552) */
- {2, 4, -6, -4, 40, 94},
- {3, 18, 27, 48, 66, 72},
- MSP_CARRIER(6.0), MSP_CARRIER(6.0),
- 0x00d0, 0x0040, 0x0120, 0x3000
- },{ /* NICAM/AM -- L (6.5/5.85) */
- {-2, -8, -10, 10, 50, 86},
- {-4, -12, -9, 23, 79, 126},
- MSP_CARRIER(6.5), MSP_CARRIER(6.5),
- 0x00c6, 0x0140, 0x0120, 0x7c03
- },
-};
-
-struct CARRIER_DETECT {
- int cdo;
- char *name;
-};
-
-static struct CARRIER_DETECT carrier_detect_main[] = {
- /* main carrier */
- { MSP_CARRIER(4.5), "4.5 NTSC" },
- { MSP_CARRIER(5.5), "5.5 PAL B/G" },
- { MSP_CARRIER(6.0), "6.0 PAL I" },
- { MSP_CARRIER(6.5), "6.5 PAL D/K + SAT + SECAM" }
-};
-
-static struct CARRIER_DETECT carrier_detect_55[] = {
- /* PAL B/G */
- { MSP_CARRIER(5.7421875), "5.742 PAL B/G FM-stereo" },
- { MSP_CARRIER(5.85), "5.85 PAL B/G NICAM" }
-};
-
-static struct CARRIER_DETECT carrier_detect_65[] = {
- /* PAL SAT / SECAM */
- { MSP_CARRIER(5.85), "5.85 PAL D/K + SECAM NICAM" },
- { MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" },
- { MSP_CARRIER(6.7421875), "6.74 PAL D/K2 FM-stereo" },
- { MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" },
- { MSP_CARRIER(7.20), "7.20 PAL SAT FM-stereo s" },
- { MSP_CARRIER(7.38), "7.38 PAL SAT FM-stereo b" },
-};
-
-#define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT))
-
-/* ----------------------------------------------------------------------- *
- * bits 9 8 5 - SCART DSP input Select:
- * 0 0 0 - SCART 1 to DSP input (reset position)
- * 0 1 0 - MONO to DSP input
- * 1 0 0 - SCART 2 to DSP input
- * 1 1 1 - Mute DSP input
- *
- * bits 11 10 6 - SCART 1 Output Select:
- * 0 0 0 - undefined (reset position)
- * 0 1 0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS)
- * 1 0 0 - MONO input to SCART 1 Output
- * 1 1 0 - SCART 1 DA to SCART 1 Output
- * 0 0 1 - SCART 2 DA to SCART 1 Output
- * 0 1 1 - SCART 1 Input to SCART 1 Output
- * 1 1 1 - Mute SCART 1 Output
- *
- * bits 13 12 7 - SCART 2 Output Select (for devices with 2 Output SCART):
- * 0 0 0 - SCART 1 DA to SCART 2 Output (reset position)
- * 0 1 0 - SCART 1 Input to SCART 2 Output
- * 1 0 0 - MONO input to SCART 2 Output
- * 0 0 1 - SCART 2 DA to SCART 2 Output
- * 0 1 1 - SCART 2 Input to SCART 2 Output
- * 1 1 0 - Mute SCART 2 Output
- *
- * Bits 4 to 0 should be zero.
- * ----------------------------------------------------------------------- */
-
-static int scarts[3][9] = {
- /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */
- /* SCART DSP Input select */
- { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 },
- /* SCART1 Output select */
- { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
- /* SCART2 Output select */
- { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
-};
-
-static char *scart_names[] = {
- "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute"
-};
-
-static void msp3400c_set_scart(struct i2c_client *client, int in, int out)
-{
- struct msp3400c *msp = i2c_get_clientdata(client);
-
- msp->in_scart=in;
-
- if (in >= 1 && in <= 8 && out >= 0 && out <= 2) {
- if (-1 == scarts[out][in])
- return;
-
- msp->acb &= ~scarts[out][SCART_MASK];
- msp->acb |= scarts[out][in];
- } else
- msp->acb = 0xf60; /* Mute Input and SCART 1 Output */
-
- msp3400_dbg("scart switch: %s => %d (ACB=0x%04x)\n",
- scart_names[in], out, msp->acb);
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x13, msp->acb);
-
- /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */
- msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
-}
-
-/* ------------------------------------------------------------------------ */
-
-static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2)
-{
- msp3400c_write(client,I2C_MSP3400C_DEM, 0x0093, cdo1 & 0xfff);
- msp3400c_write(client,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12);
- msp3400c_write(client,I2C_MSP3400C_DEM, 0x00a3, cdo2 & 0xfff);
- msp3400c_write(client,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12);
- msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/
-}
-
-static void msp3400c_setvolume(struct i2c_client *client,
- int muted, int left, int right)
- {
- int vol = 0, val = 0, balance = 0;
-
- if (!muted) {
- /* 0x7f instead if 0x73 here has sound quality issues,
- * probably due to overmodulation + clipping ... */
- vol = (left > right) ? left : right;
- val = (vol * 0x73 / 65535) << 8;
- }
- if (vol > 0) {
- balance = ((right - left) * 127) / vol;
- }
-
- msp3400_dbg("setvolume: mute=%s %d:%d v=0x%02x b=0x%02x\n",
- muted ? "on" : "off", left, right, val >> 8, balance);
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007,
- muted ? 0x1 : (val | 0x1));
- msp3400c_write(client, I2C_MSP3400C_DFP, 0x0001, balance << 8);
-}
-
-static void msp3400c_setbass(struct i2c_client *client, int bass)
-{
- int val = ((bass-32768) * 0x60 / 65535) << 8;
-
- msp3400_dbg("setbass: %d 0x%02x\n", bass, val >> 8);
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */
-}
-
-static void msp3400c_settreble(struct i2c_client *client, int treble)
-{
- int val = ((treble-32768) * 0x60 / 65535) << 8;
-
- msp3400_dbg("settreble: %d 0x%02x\n",treble, val>>8);
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */
-}
-
-static void msp3400c_setmode(struct i2c_client *client, int type)
-{
- struct msp3400c *msp = i2c_get_clientdata(client);
- int i;
-
- msp3400_dbg("setmode: %d\n",type);
- msp->mode = type;
- msp->audmode = V4L2_TUNER_MODE_MONO;
- msp->rxsubchans = V4L2_TUNER_SUB_MONO;
-
- msp3400c_write(client,I2C_MSP3400C_DEM, 0x00bb, /* ad_cv */
- msp_init_data[type].ad_cv);
-
- for (i = 5; i >= 0; i--) /* fir 1 */
- msp3400c_write(client,I2C_MSP3400C_DEM, 0x0001,
- msp_init_data[type].fir1[i]);
-
- msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */
- msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0040);
- msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0000);
- for (i = 5; i >= 0; i--)
- msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005,
- msp_init_data[type].fir2[i]);
-
- msp3400c_write(client,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */
- msp_init_data[type].mode_reg);
-
- msp3400c_setcarrier(client, msp_init_data[type].cdo1,
- msp_init_data[type].cdo2);
-
- msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/
-
- if (dolby) {
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,
- 0x0520); /* I2S1 */
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,
- 0x0620); /* I2S2 */
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,
- msp_init_data[type].dfp_src);
- } else {
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,
- msp_init_data[type].dfp_src);
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,
- msp_init_data[type].dfp_src);
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,
- msp_init_data[type].dfp_src);
- }
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,
- msp_init_data[type].dfp_src);
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e,
- msp_init_data[type].dfp_matrix);
-
- if (HAVE_NICAM(msp)) {
- /* nicam prescale */
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x5a00); /* was: 0x3000 */
- }
-}
-
-/* given a bitmask of VIDEO_SOUND_XXX returns the "best" in the bitmask */
-static int best_video_sound(int rxsubchans)
-{
- if (rxsubchans & V4L2_TUNER_SUB_STEREO)
- return V4L2_TUNER_MODE_STEREO;
- if (rxsubchans & V4L2_TUNER_SUB_LANG1)
- return V4L2_TUNER_MODE_LANG1;
- if (rxsubchans & V4L2_TUNER_SUB_LANG2)
- return V4L2_TUNER_MODE_LANG2;
- return V4L2_TUNER_MODE_MONO;
-}
-
-/* turn on/off nicam + stereo */
-static void msp3400c_setstereo(struct i2c_client *client, int mode)
-{
- static char *strmode[] = { "0", "mono", "stereo", "3",
- "lang1", "5", "6", "7", "lang2"
- };
- struct msp3400c *msp = i2c_get_clientdata(client);
- int nicam = 0; /* channel source: FM/AM or nicam */
- int src = 0;
-
- if (IS_MSP34XX_G(msp)) {
- /* this method would break everything, let's make sure
- * it's never called
- */
- msp3400_dbg
- ("DEBUG WARNING setstereo called with mode=%d instead of set_source (ignored)\n",
- mode);
- return;
- }
-
- /* switch demodulator */
- switch (msp->mode) {
- case MSP_MODE_FM_TERRA:
- msp3400_dbg("FM setstereo: %s\n", strmode[mode]);
- msp3400c_setcarrier(client,msp->second,msp->main);
- switch (mode) {
- case V4L2_TUNER_MODE_STEREO:
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3001);
- break;
- case V4L2_TUNER_MODE_MONO:
- case V4L2_TUNER_MODE_LANG1:
- case V4L2_TUNER_MODE_LANG2:
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3000);
- break;
- }
- break;
- case MSP_MODE_FM_SAT:
- msp3400_dbg("SAT setstereo: %s\n", strmode[mode]);
- switch (mode) {
- case V4L2_TUNER_MODE_MONO:
- msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
- break;
- case V4L2_TUNER_MODE_STEREO:
- msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
- break;
- case V4L2_TUNER_MODE_LANG1:
- msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
- break;
- case V4L2_TUNER_MODE_LANG2:
- msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
- break;
- }
- break;
- case MSP_MODE_FM_NICAM1:
- case MSP_MODE_FM_NICAM2:
- case MSP_MODE_AM_NICAM:
- msp3400_dbg("NICAM setstereo: %s\n",strmode[mode]);
- msp3400c_setcarrier(client,msp->second,msp->main);
- if (msp->nicam_on)
- nicam=0x0100;
- break;
- case MSP_MODE_BTSC:
- msp3400_dbg("BTSC setstereo: %s\n",strmode[mode]);
- nicam=0x0300;
- break;
- case MSP_MODE_EXTERN:
- msp3400_dbg("extern setstereo: %s\n",strmode[mode]);
- nicam = 0x0200;
- break;
- case MSP_MODE_FM_RADIO:
- msp3400_dbg("FM-Radio setstereo: %s\n",strmode[mode]);
- break;
- default:
- msp3400_dbg("mono setstereo\n");
- return;
- }
-
- /* switch audio */
- switch (best_video_sound(mode)) {
- case V4L2_TUNER_MODE_STEREO:
- src = 0x0020 | nicam;
- break;
- case V4L2_TUNER_MODE_MONO:
- if (msp->mode == MSP_MODE_AM_NICAM) {
- msp3400_dbg("switching to AM mono\n");
- /* AM mono decoding is handled by tuner, not MSP chip */
- /* SCART switching control register */
- msp3400c_set_scart(client,SCART_MONO,0);
- src = 0x0200;
- break;
- }
- case V4L2_TUNER_MODE_LANG1:
- src = 0x0000 | nicam;
- break;
- case V4L2_TUNER_MODE_LANG2:
- src = 0x0010 | nicam;
- break;
- }
- msp3400_dbg("setstereo final source/matrix = 0x%x\n", src);
-
- if (dolby) {
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520);
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,0x0620);
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src);
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src);
- } else {
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,src);
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,src);
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src);
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src);
- }
-}
-
-static void
-msp3400c_print_mode(struct i2c_client *client)
-{
- struct msp3400c *msp = i2c_get_clientdata(client);
-
- if (msp->main == msp->second) {
- msp3400_dbg("mono sound carrier: %d.%03d MHz\n",
- msp->main/910000,(msp->main/910)%1000);
- } else {
- msp3400_dbg("main sound carrier: %d.%03d MHz\n",
- msp->main/910000,(msp->main/910)%1000);
- }
- if (msp->mode == MSP_MODE_FM_NICAM1 || msp->mode == MSP_MODE_FM_NICAM2)
- msp3400_dbg("NICAM/FM carrier : %d.%03d MHz\n",
- msp->second/910000,(msp->second/910)%1000);
- if (msp->mode == MSP_MODE_AM_NICAM)
- msp3400_dbg("NICAM/AM carrier : %d.%03d MHz\n",
- msp->second/910000,(msp->second/910)%1000);
- if (msp->mode == MSP_MODE_FM_TERRA &&
- msp->main != msp->second) {
- msp3400_dbg("FM-stereo carrier : %d.%03d MHz\n",
- msp->second/910000,(msp->second/910)%1000);
- }
-}
-
-#define MSP3400_MAX 4
-static struct i2c_client *msps[MSP3400_MAX];
-static void msp3400c_restore_dfp(struct i2c_client *client)
-{
- struct msp3400c *msp = i2c_get_clientdata(client);
- int i;
-
- for (i = 0; i < DFP_COUNT; i++) {
- if (-1 == msp->dfp_regs[i])
- continue;
- msp3400c_write(client, I2C_MSP3400C_DFP, i, msp->dfp_regs[i]);
- }
-}
-
-/* if the dfp_regs is set, set what's in there. Otherwise, set the default value */
-static int msp3400c_write_dfp_with_default(struct i2c_client *client,
- int addr, int default_value)
-{
- struct msp3400c *msp = i2c_get_clientdata(client);
- int value = default_value;
- if (addr < DFP_COUNT && -1 != msp->dfp_regs[addr])
- value = msp->dfp_regs[addr];
- return msp3400c_write(client, I2C_MSP3400C_DFP, addr, value);
-}
-
-/* ----------------------------------------------------------------------- */
-
-struct REGISTER_DUMP {
- int addr;
- char *name;
-};
-
-struct REGISTER_DUMP d1[] = {
- {0x007e, "autodetect"},
- {0x0023, "C_AD_BITS "},
- {0x0038, "ADD_BITS "},
- {0x003e, "CIB_BITS "},
- {0x0057, "ERROR_RATE"},
-};
-
-static int autodetect_stereo(struct i2c_client *client)
-{
- struct msp3400c *msp = i2c_get_clientdata(client);
- int val;
- int rxsubchans = msp->rxsubchans;
- int newnicam = msp->nicam_on;
- int update = 0;
-
- switch (msp->mode) {
- case MSP_MODE_FM_TERRA:
- val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18);
- if (val > 32767)
- val -= 65536;
- msp3400_dbg("stereo detect register: %d\n",val);
- if (val > 4096) {
- rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
- } else if (val < -4096) {
- rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
- } else {
- rxsubchans = V4L2_TUNER_SUB_MONO;
- }
- newnicam = 0;
- break;
- case MSP_MODE_FM_NICAM1:
- case MSP_MODE_FM_NICAM2:
- case MSP_MODE_AM_NICAM:
- val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23);
- msp3400_dbg("nicam sync=%d, mode=%d\n",
- val & 1, (val & 0x1e) >> 1);
-
- if (val & 1) {
- /* nicam synced */
- switch ((val & 0x1e) >> 1) {
- case 0:
- case 8:
- rxsubchans = V4L2_TUNER_SUB_STEREO;
- break;
- case 1:
- case 9:
- rxsubchans = V4L2_TUNER_SUB_MONO
- | V4L2_TUNER_SUB_LANG1;
- break;
- case 2:
- case 10:
- rxsubchans = V4L2_TUNER_SUB_MONO
- | V4L2_TUNER_SUB_LANG1
- | V4L2_TUNER_SUB_LANG2;
- break;
- default:
- rxsubchans = V4L2_TUNER_SUB_MONO;
- break;
- }
- newnicam=1;
- } else {
- newnicam = 0;
- rxsubchans = V4L2_TUNER_SUB_MONO;
- }
- break;
- case MSP_MODE_BTSC:
- val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200);
- msp3400_dbg("status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
- val,
- (val & 0x0002) ? "no" : "yes",
- (val & 0x0004) ? "no" : "yes",
- (val & 0x0040) ? "stereo" : "mono",
- (val & 0x0080) ? ", nicam 2nd mono" : "",
- (val & 0x0100) ? ", bilingual/SAP" : "");
- rxsubchans = V4L2_TUNER_SUB_MONO;
- if (val & 0x0040) rxsubchans |= V4L2_TUNER_SUB_STEREO;
- if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1;
- break;
- }
- if (rxsubchans != msp->rxsubchans) {
- update = 1;
- msp3400_dbg("watch: rxsubchans %d => %d\n",
- msp->rxsubchans,rxsubchans);
- msp->rxsubchans = rxsubchans;
- }
- if (newnicam != msp->nicam_on) {
- update = 1;
- msp3400_dbg("watch: nicam %d => %d\n",
- msp->nicam_on,newnicam);
- msp->nicam_on = newnicam;
- }
- return update;
-}
-
-/*
- * A kernel thread for msp3400 control -- we don't want to block the
- * in the ioctl while doing the sound carrier & stereo detect
- */
-
-static int msp34xx_sleep(struct msp3400c *msp, int timeout)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(&msp->wq, &wait);
- if (!kthread_should_stop()) {
- if (timeout < 0) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- } else {
- schedule_timeout_interruptible
- (msecs_to_jiffies(timeout));
- }
- }
-
- remove_wait_queue(&msp->wq, &wait);
- try_to_freeze();
- return msp->restart;
-}
-
-/* stereo/multilang monitoring */
-static void watch_stereo(struct i2c_client *client)
-{
- struct msp3400c *msp = i2c_get_clientdata(client);
-
- if (autodetect_stereo(client)) {
- if (msp->stereo & V4L2_TUNER_MODE_STEREO)
- msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO);
- else if (msp->stereo & VIDEO_SOUND_LANG1)
- msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1);
- else
- msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
- }
-
- if (once)
- msp->watch_stereo = 0;
-}
-
-
-static int msp3400c_thread(void *data)
-{
- struct i2c_client *client = data;
- struct msp3400c *msp = i2c_get_clientdata(client);
- struct CARRIER_DETECT *cd;
- int count, max1,max2,val1,val2, val,this;
-
-
- msp3400_info("msp3400 daemon started\n");
- for (;;) {
- msp3400_dbg_mediumvol("msp3400 thread: sleep\n");
- msp34xx_sleep(msp,-1);
- msp3400_dbg_mediumvol("msp3400 thread: wakeup\n");
-
- restart:
- msp3400_dbg("thread: restart scan\n");
- msp->restart = 0;
- if (kthread_should_stop())
- break;
-
- if (VIDEO_MODE_RADIO == msp->norm ||
- MSP_MODE_EXTERN == msp->mode) {
- /* no carrier scan, just unmute */
- msp3400_info("thread: no carrier scan\n");
- msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
- continue;
- }
-
- /* mute */
- msp3400c_setvolume(client, msp->muted, 0, 0);
- msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
- val1 = val2 = 0;
- max1 = max2 = -1;
- msp->watch_stereo = 0;
-
- /* some time for the tuner to sync */
- if (msp34xx_sleep(msp,200))
- goto restart;
-
- /* carrier detect pass #1 -- main carrier */
- cd = carrier_detect_main;
- count = CARRIER_COUNT(carrier_detect_main);
-
- if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
- /* autodetect doesn't work well with AM ... */
- max1 = 3;
- count = 0;
- msp3400_dbg("AM sound override\n");
- }
-
- for (this = 0; this < count; this++) {
- msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
- if (msp34xx_sleep(msp,100))
- goto restart;
- val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b);
- if (val > 32767)
- val -= 65536;
- if (val1 < val)
- val1 = val, max1 = this;
- msp3400_dbg("carrier1 val: %5d / %s\n", val,cd[this].name);
- }
-
- /* carrier detect pass #2 -- second (stereo) carrier */
- switch (max1) {
- case 1: /* 5.5 */
- cd = carrier_detect_55;
- count = CARRIER_COUNT(carrier_detect_55);
- break;
- case 3: /* 6.5 */
- cd = carrier_detect_65;
- count = CARRIER_COUNT(carrier_detect_65);
- break;
- case 0: /* 4.5 */
- case 2: /* 6.0 */
- default:
- cd = NULL;
- count = 0;
- break;
- }
-
- if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
- /* autodetect doesn't work well with AM ... */
- cd = NULL;
- count = 0;
- max2 = 0;
- }
- for (this = 0; this < count; this++) {
- msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
- if (msp34xx_sleep(msp,100))
- goto restart;
- val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b);
- if (val > 32767)
- val -= 65536;
- if (val2 < val)
- val2 = val, max2 = this;
- msp3400_dbg("carrier2 val: %5d / %s\n", val,cd[this].name);
- }
-
- /* programm the msp3400 according to the results */
- msp->main = carrier_detect_main[max1].cdo;
- switch (max1) {
- case 1: /* 5.5 */
- if (max2 == 0) {
- /* B/G FM-stereo */
- msp->second = carrier_detect_55[max2].cdo;
- msp3400c_setmode(client, MSP_MODE_FM_TERRA);
- msp->nicam_on = 0;
- msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
- msp->watch_stereo = 1;
- } else if (max2 == 1 && HAVE_NICAM(msp)) {
- /* B/G NICAM */
- msp->second = carrier_detect_55[max2].cdo;
- msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
- msp->nicam_on = 1;
- msp3400c_setcarrier(client, msp->second, msp->main);
- msp->watch_stereo = 1;
- } else {
- goto no_second;
- }
- break;
- case 2: /* 6.0 */
- /* PAL I NICAM */
- msp->second = MSP_CARRIER(6.552);
- msp3400c_setmode(client, MSP_MODE_FM_NICAM2);
- msp->nicam_on = 1;
- msp3400c_setcarrier(client, msp->second, msp->main);
- msp->watch_stereo = 1;
- break;
- case 3: /* 6.5 */
- if (max2 == 1 || max2 == 2) {
- /* D/K FM-stereo */
- msp->second = carrier_detect_65[max2].cdo;
- msp3400c_setmode(client, MSP_MODE_FM_TERRA);
- msp->nicam_on = 0;
- msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
- msp->watch_stereo = 1;
- } else if (max2 == 0 &&
- msp->norm == VIDEO_MODE_SECAM) {
- /* L NICAM or AM-mono */
- msp->second = carrier_detect_65[max2].cdo;
- msp3400c_setmode(client, MSP_MODE_AM_NICAM);
- msp->nicam_on = 0;
- msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
- msp3400c_setcarrier(client, msp->second, msp->main);
- /* volume prescale for SCART (AM mono input) */
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900);
- msp->watch_stereo = 1;
- } else if (max2 == 0 && HAVE_NICAM(msp)) {
- /* D/K NICAM */
- msp->second = carrier_detect_65[max2].cdo;
- msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
- msp->nicam_on = 1;
- msp3400c_setcarrier(client, msp->second, msp->main);
- msp->watch_stereo = 1;
- } else {
- goto no_second;
- }
- break;
- case 0: /* 4.5 */
- default:
- no_second:
- msp->second = carrier_detect_main[max1].cdo;
- msp3400c_setmode(client, MSP_MODE_FM_TERRA);
- msp->nicam_on = 0;
- msp3400c_setcarrier(client, msp->second, msp->main);
- msp->rxsubchans = V4L2_TUNER_SUB_MONO;
- msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
- break;
- }
-
- /* unmute */
- msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
- msp3400c_restore_dfp(client);
-
- if (debug)
- msp3400c_print_mode(client);
-
- /* monitor tv audio mode */
- while (msp->watch_stereo) {
- if (msp34xx_sleep(msp,5000))
- goto restart;
- watch_stereo(client);
- }
- }
- msp3400_dbg("thread: exit\n");
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-/* this one uses the automatic sound standard detection of newer */
-/* msp34xx chip versions */
-
-static struct MODES {
- int retval;
- int main, second;
- char *name;
-} modelist[] = {
- { 0x0000, 0, 0, "ERROR" },
- { 0x0001, 0, 0, "autodetect start" },
- { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72 M Dual FM-Stereo" },
- { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74 B/G Dual FM-Stereo" },
- { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" },
- { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" },
- { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" },
- { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" },
- { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" },
- { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" },
- { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" },
- { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" },
- { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" },
- { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" },
- { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" },
- { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7 FM-Stereo Radio" },
- { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 SAT-Mono" },
- { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20 SAT-Stereo" },
- { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2 SAT ADR" },
- { -1, 0, 0, NULL }, /* EOF */
-};
-
-static inline const char *msp34xx_standard_mode_name(int mode)
-{
- int i;
- for (i = 0; modelist[i].name != NULL; i++)
- if (modelist[i].retval == mode)
- return modelist[i].name;
- return "unknown";
-}
-
-static int msp34xx_modus(struct i2c_client *client, int norm)
-{
- switch (norm) {
- case VIDEO_MODE_PAL:
- msp3400_dbg("video mode selected to PAL\n");
-
-#if 1
- /* experimental: not sure this works with all chip versions */
- return 0x7003;
-#else
- /* previous value, try this if it breaks ... */
- return 0x1003;
-#endif
- case VIDEO_MODE_NTSC: /* BTSC */
- msp3400_dbg("video mode selected to NTSC\n");
- return 0x2003;
- case VIDEO_MODE_SECAM:
- msp3400_dbg("video mode selected to SECAM\n");
- return 0x0003;
- case VIDEO_MODE_RADIO:
- msp3400_dbg("video mode selected to Radio\n");
- return 0x0003;
- case VIDEO_MODE_AUTO:
- msp3400_dbg("video mode selected to Auto\n");
- return 0x2003;
- default:
- return 0x0003;
- }
-}
-
-static int msp34xx_standard(int norm)
-{
- switch (norm) {
- case VIDEO_MODE_PAL:
- return 1;
- case VIDEO_MODE_NTSC: /* BTSC */
- return 0x0020;
- case VIDEO_MODE_SECAM:
- return 1;
- case VIDEO_MODE_RADIO:
- return 0x0040;
- default:
- return 1;
- }
-}
-
-static int msp3410d_thread(void *data)
-{
- struct i2c_client *client = data;
- struct msp3400c *msp = i2c_get_clientdata(client);
- int mode,val,i,std;
-
- msp3400_info("msp3410 daemon started\n");
-
- for (;;) {
- msp3400_dbg_mediumvol("msp3410 thread: sleep\n");
- msp34xx_sleep(msp,-1);
- msp3400_dbg_mediumvol("msp3410 thread: wakeup\n");
-
- restart:
- msp3400_dbg("thread: restart scan\n");
- msp->restart = 0;
- if (kthread_should_stop())
- break;
-
- if (msp->mode == MSP_MODE_EXTERN) {
- /* no carrier scan needed, just unmute */
- msp3400_dbg("thread: no carrier scan\n");
- msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
- continue;
- }
-
- /* put into sane state (and mute) */
- msp3400c_reset(client);
-
- /* some time for the tuner to sync */
- if (msp34xx_sleep(msp,200))
- goto restart;
-
- /* start autodetect */
- mode = msp34xx_modus(client, msp->norm);
- std = msp34xx_standard(msp->norm);
- msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode);
- msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std);
- msp->watch_stereo = 0;
-
- if (debug)
- msp3400_dbg("setting mode: %s (0x%04x)\n",
- msp34xx_standard_mode_name(std) ,std);
-
- if (std != 1) {
- /* programmed some specific mode */
- val = std;
- } else {
- /* triggered autodetect */
- for (;;) {
- if (msp34xx_sleep(msp,100))
- goto restart;
-
- /* check results */
- val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);
- if (val < 0x07ff)
- break;
- msp3400_dbg("detection still in progress\n");
- }
- }
- for (i = 0; modelist[i].name != NULL; i++)
- if (modelist[i].retval == val)
- break;
- msp3400_dbg("current mode: %s (0x%04x)\n",
- modelist[i].name ? modelist[i].name : "unknown",
- val);
- msp->main = modelist[i].main;
- msp->second = modelist[i].second;
-
- if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) {
- /* autodetection has failed, let backup */
- msp3400_dbg("autodetection failed,"
- " switching to backup mode: %s (0x%04x)\n",
- modelist[8].name ? modelist[8].name : "unknown",val);
- val = 0x0009;
- msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val);
- }
-
- /* set various prescales */
- msp3400c_write(client, I2C_MSP3400C_DFP, 0x0d, 0x1900); /* scart */
- msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */
- msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* nicam */
-
- /* set stereo */
- switch (val) {
- case 0x0008: /* B/G NICAM */
- case 0x000a: /* I NICAM */
- if (val == 0x0008)
- msp->mode = MSP_MODE_FM_NICAM1;
- else
- msp->mode = MSP_MODE_FM_NICAM2;
- /* just turn on stereo */
- msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
- msp->nicam_on = 1;
- msp->watch_stereo = 1;
- msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
- break;
- case 0x0009:
- msp->mode = MSP_MODE_AM_NICAM;
- msp->rxsubchans = V4L2_TUNER_SUB_MONO;
- msp->nicam_on = 1;
- msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO);
- msp->watch_stereo = 1;
- break;
- case 0x0020: /* BTSC */
- /* just turn on stereo */
- msp->mode = MSP_MODE_BTSC;
- msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
- msp->nicam_on = 0;
- msp->watch_stereo = 1;
- msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
- break;
- case 0x0040: /* FM radio */
- msp->mode = MSP_MODE_FM_RADIO;
- msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
- msp->audmode = V4L2_TUNER_MODE_STEREO;
- msp->nicam_on = 0;
- msp->watch_stereo = 0;
- /* not needed in theory if HAVE_RADIO(), but
- short programming enables carrier mute */
- msp3400c_setmode(client,MSP_MODE_FM_RADIO);
- msp3400c_setcarrier(client, MSP_CARRIER(10.7),
- MSP_CARRIER(10.7));
- /* scart routing */
- msp3400c_set_scart(client,SCART_IN2,0);
- /* msp34xx does radio decoding */
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0020);
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0020);
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0020);
- break;
- case 0x0003:
- case 0x0004:
- case 0x0005:
- msp->mode = MSP_MODE_FM_TERRA;
- msp->rxsubchans = V4L2_TUNER_SUB_MONO;
- msp->audmode = V4L2_TUNER_MODE_MONO;
- msp->nicam_on = 0;
- msp->watch_stereo = 1;
- break;
- }
-
- /* unmute, restore misc registers */
- msp3400c_setbass(client, msp->bass);
- msp3400c_settreble(client, msp->treble);
- msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
- msp3400c_write(client, I2C_MSP3400C_DFP, 0x13, msp->acb);
- msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
- msp3400c_restore_dfp(client);
-
- /* monitor tv audio mode */
- while (msp->watch_stereo) {
- if (msp34xx_sleep(msp,5000))
- goto restart;
- watch_stereo(client);
- }
- }
- msp3400_dbg("thread: exit\n");
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-/* msp34xxG + (simpler no-thread) */
-/* this one uses both automatic standard detection and automatic sound */
-/* select which are available in the newer G versions */
-/* struct msp: only norm, acb and source are really used in this mode */
-
-static void msp34xxg_set_source(struct i2c_client *client, int source);
-
-/* (re-)initialize the msp34xxg, according to the current norm in msp->norm
- * return 0 if it worked, -1 if it failed
- */
-static int msp34xxg_reset(struct i2c_client *client)
-{
- struct msp3400c *msp = i2c_get_clientdata(client);
- int modus,std;
-
- if (msp3400c_reset(client))
- return -1;
-
- /* make sure that input/output is muted (paranoid mode) */
- if (msp3400c_write(client,
- I2C_MSP3400C_DFP,
- 0x13, /* ACB */
- 0x0f20 /* mute DSP input, mute SCART 1 */))
- return -1;
-
- msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
-
- /* step-by-step initialisation, as described in the manual */
- modus = msp34xx_modus(client, msp->norm);
- std = msp34xx_standard(msp->norm);
- modus &= ~0x03; /* STATUS_CHANGE=0 */
- modus |= 0x01; /* AUTOMATIC_SOUND_DETECTION=1 */
- if (msp3400c_write(client,
- I2C_MSP3400C_DEM,
- 0x30/*MODUS*/,
- modus))
- return -1;
- if (msp3400c_write(client,
- I2C_MSP3400C_DEM,
- 0x20/*standard*/,
- std))
- return -1;
-
- /* write the dfps that may have an influence on
- standard/audio autodetection right now */
- msp34xxg_set_source(client, msp->source);
-
- if (msp3400c_write_dfp_with_default(client, 0x0e, /* AM/FM Prescale */
- 0x3000
- /* default: [15:8] 75khz deviation */
- ))
- return -1;
-
- if (msp3400c_write_dfp_with_default(client, 0x10, /* NICAM Prescale */
- 0x5a00
- /* default: 9db gain (as recommended) */
- ))
- return -1;
-
- return 0;
-}
-
-static int msp34xxg_thread(void *data)
-{
- struct i2c_client *client = data;
- struct msp3400c *msp = i2c_get_clientdata(client);
- int val, std, i;
-
- msp3400_info("msp34xxg daemon started\n");
-
- msp->source = 1; /* default */
- for (;;) {
- msp3400_dbg_mediumvol("msp34xxg thread: sleep\n");
- msp34xx_sleep(msp,-1);
- msp3400_dbg_mediumvol("msp34xxg thread: wakeup\n");
-
- restart:
- msp3400_dbg("thread: restart scan\n");
- msp->restart = 0;
- if (kthread_should_stop())
- break;
-
- /* setup the chip*/
- msp34xxg_reset(client);
- std = standard;
- if (std != 0x01)
- goto unmute;
-
- /* watch autodetect */
- msp3400_dbg("triggered autodetect, waiting for result\n");
- for (i = 0; i < 10; i++) {
- if (msp34xx_sleep(msp,100))
- goto restart;
-
- /* check results */
- val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);
- if (val < 0x07ff) {
- std = val;
- break;
- }
- msp3400_dbg("detection still in progress\n");
- }
- if (0x01 == std) {
- msp3400_dbg("detection still in progress after 10 tries. giving up.\n");
- continue;
- }
-
- unmute:
- msp3400_dbg("current mode: %s (0x%04x)\n",
- msp34xx_standard_mode_name(std), std);
-
- /* unmute: dispatch sound to scart output, set scart volume */
- msp3400_dbg("unmute\n");
-
- msp3400c_setbass(client, msp->bass);
- msp3400c_settreble(client, msp->treble);
- msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-
- /* restore ACB */
- if (msp3400c_write(client,
- I2C_MSP3400C_DFP,
- 0x13, /* ACB */
- msp->acb))
- return -1;
-
- msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
- }
- msp3400_dbg("thread: exit\n");
- return 0;
-}
-
-/* set the same 'source' for the loudspeaker, scart and quasi-peak detector
- * the value for source is the same as bit 15:8 of DFP registers 0x08,
- * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B
- *
- * this function replaces msp3400c_setstereo
- */
-static void msp34xxg_set_source(struct i2c_client *client, int source)
-{
- struct msp3400c *msp = i2c_get_clientdata(client);
-
- /* fix matrix mode to stereo and let the msp choose what
- * to output according to 'source', as recommended
- * for MONO (source==0) downmixing set bit[7:0] to 0x30
- */
- int value = (source&0x07)<<8|(source==0 ? 0x30:0x20);
- msp3400_dbg("set source to %d (0x%x)\n", source, value);
- msp3400c_write(client,
- I2C_MSP3400C_DFP,
- 0x08, /* Loudspeaker Output */
- value);
- msp3400c_write(client,
- I2C_MSP3400C_DFP,
- 0x0a, /* SCART1 DA Output */
- value);
- msp3400c_write(client,
- I2C_MSP3400C_DFP,
- 0x0c, /* Quasi-peak detector */
- value);
- /*
- * set identification threshold. Personally, I
- * I set it to a higher value that the default
- * of 0x190 to ignore noisy stereo signals.
- * this needs tuning. (recommended range 0x00a0-0x03c0)
- * 0x7f0 = forced mono mode
- */
- msp3400c_write(client,
- I2C_MSP3400C_DEM,
- 0x22, /* a2 threshold for stereo/bilingual */
- stereo_threshold);
- msp->source=source;
-}
-
-static void msp34xxg_detect_stereo(struct i2c_client *client)
-{
- struct msp3400c *msp = i2c_get_clientdata(client);
-
- int status = msp3400c_read(client,
- I2C_MSP3400C_DEM,
- 0x0200 /* STATUS */);
- int is_bilingual = status&0x100;
- int is_stereo = status&0x40;
-
- msp->rxsubchans = 0;
- if (is_stereo)
- msp->rxsubchans |= V4L2_TUNER_SUB_STEREO;
- else
- msp->rxsubchans |= V4L2_TUNER_SUB_MONO;
- if (is_bilingual) {
- msp->rxsubchans |= V4L2_TUNER_SUB_LANG1|V4L2_TUNER_SUB_LANG2;
- /* I'm supposed to check whether it's SAP or not
- * and set only LANG2/SAP in this case. Yet, the MSP
- * does a lot of work to hide this and handle everything
- * the same way. I don't want to work around it so unless
- * this is a problem, I'll handle SAP just like lang1/lang2.
- */
- }
- msp3400_dbg("status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
- status, is_stereo, is_bilingual, msp->rxsubchans);
-}
-
-static void msp34xxg_set_audmode(struct i2c_client *client, int audmode)
-{
- struct msp3400c *msp = i2c_get_clientdata(client);
- int source;
-
- switch (audmode) {
- case V4L2_TUNER_MODE_MONO:
- source=0; /* mono only */
- break;
- case V4L2_TUNER_MODE_STEREO:
- source=1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */
- /* problem: that could also mean 2 (scart input) */
- break;
- case V4L2_TUNER_MODE_LANG1:
- source=3; /* stereo or A */
- break;
- case V4L2_TUNER_MODE_LANG2:
- source=4; /* stereo or B */
- break;
- default:
- audmode = 0;
- source = 1;
- break;
- }
- msp->audmode = audmode;
- msp34xxg_set_source(client, source);
-}
-
-
-/* ----------------------------------------------------------------------- */
-
-static int msp_attach(struct i2c_adapter *adap, int addr, int kind);
-static int msp_detach(struct i2c_client *client);
-static int msp_probe(struct i2c_adapter *adap);
-static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg);
-
-static int msp_suspend(struct device * dev, pm_message_t state);
-static int msp_resume(struct device * dev);
-
-static void msp_wake_thread(struct i2c_client *client);
-
-static struct i2c_driver driver = {
- .id = I2C_DRIVERID_MSP3400,
- .attach_adapter = msp_probe,
- .detach_client = msp_detach,
- .command = msp_command,
- .driver = {
- .name = "i2c msp3400 driver",
- .suspend = msp_suspend,
- .resume = msp_resume,
- },
-};
-
-static struct i2c_client client_template =
-{
- .name = "(unset)",
- .driver = &driver,
-};
-
-static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
-{
- struct msp3400c *msp;
- struct i2c_client *client = &client_template;
- int (*thread_func)(void *data) = NULL;
- int i;
-
- client_template.adapter = adap;
- client_template.addr = addr;
-
- if (-1 == msp3400c_reset(&client_template)) {
- msp3400_dbg("no chip found\n");
- return -1;
- }
-
- if (NULL == (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
- return -ENOMEM;
- memcpy(client,&client_template,sizeof(struct i2c_client));
- if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) {
- kfree(client);
- return -ENOMEM;
- }
-
- memset(msp,0,sizeof(struct msp3400c));
- msp->norm = VIDEO_MODE_NTSC;
- msp->left = 58880; /* 0db gain */
- msp->right = 58880; /* 0db gain */
- msp->bass = 32768;
- msp->treble = 32768;
- msp->input = -1;
- msp->muted = 0;
- msp->i2s_mode = 0;
- for (i = 0; i < DFP_COUNT; i++)
- msp->dfp_regs[i] = -1;
-
- i2c_set_clientdata(client, msp);
- init_waitqueue_head(&msp->wq);
-
- if (-1 == msp3400c_reset(client)) {
- kfree(msp);
- kfree(client);
- msp3400_dbg("no chip found\n");
- return -1;
- }
-
- msp->rev1 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1e);
- if (-1 != msp->rev1)
- msp->rev2 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1f);
- if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) {
- kfree(msp);
- kfree(client);
- msp3400_dbg("error while reading chip version\n");
- return -1;
- }
- msp3400_dbg("rev1=0x%04x, rev2=0x%04x\n", msp->rev1, msp->rev2);
-
- msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-
- snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d",
- ((msp->rev1>>4)&0x0f) + '3',
- (msp->rev2>>8)&0xff, (msp->rev1&0x0f)+'@',
- ((msp->rev1>>8)&0xff)+'@', msp->rev2&0x1f);
-
- msp->opmode = opmode;
- if (OPMODE_AUTO == msp->opmode) {
- if (HAVE_SIMPLER(msp))
- msp->opmode = OPMODE_SIMPLER;
- else if (HAVE_SIMPLE(msp))
- msp->opmode = OPMODE_SIMPLE;
- else
- msp->opmode = OPMODE_MANUAL;
- }
-
- /* hello world :-) */
- msp3400_info("chip=%s", client->name);
- if (HAVE_NICAM(msp))
- printk(" +nicam");
- if (HAVE_SIMPLE(msp))
- printk(" +simple");
- if (HAVE_SIMPLER(msp))
- printk(" +simpler");
- if (HAVE_RADIO(msp))
- printk(" +radio");
-
- /* version-specific initialization */
- switch (msp->opmode) {
- case OPMODE_MANUAL:
- printk(" mode=manual");
- thread_func = msp3400c_thread;
- break;
- case OPMODE_SIMPLE:
- printk(" mode=simple");
- thread_func = msp3410d_thread;
- break;
- case OPMODE_SIMPLER:
- printk(" mode=simpler");
- thread_func = msp34xxg_thread;
- break;
- }
- printk("\n");
-
- /* startup control thread if needed */
- if (thread_func) {
- msp->kthread = kthread_run(thread_func, client, "msp34xx");
-
- if (NULL == msp->kthread)
- msp3400_warn("kernel_thread() failed\n");
- msp_wake_thread(client);
- }
-
- /* done */
- i2c_attach_client(client);
-
- /* update our own array */
- for (i = 0; i < MSP3400_MAX; i++) {
- if (NULL == msps[i]) {
- msps[i] = client;
- break;
- }
- }
-
- return 0;
-}
-
-static int msp_detach(struct i2c_client *client)
-{
- struct msp3400c *msp = i2c_get_clientdata(client);
- int i;
-
- /* shutdown control thread */
- if (msp->kthread) {
- msp->restart = 1;
- kthread_stop(msp->kthread);
- }
- msp3400c_reset(client);
-
- /* update our own array */
- for (i = 0; i < MSP3400_MAX; i++) {
- if (client == msps[i]) {
- msps[i] = NULL;
- break;
- }
- }
-
- i2c_detach_client(client);
-
- kfree(msp);
- kfree(client);
- return 0;
-}
-
-static int msp_probe(struct i2c_adapter *adap)
-{
- if (adap->class & I2C_CLASS_TV_ANALOG)
- return i2c_probe(adap, &addr_data, msp_attach);
- return 0;
-}
-
-static void msp_wake_thread(struct i2c_client *client)
-{
- struct msp3400c *msp = i2c_get_clientdata(client);
-
- if (NULL == msp->kthread)
- return;
- msp3400c_setvolume(client,msp->muted,0,0);
- msp->watch_stereo = 0;
- msp->restart = 1;
- wake_up_interruptible(&msp->wq);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int mode_v4l2_to_v4l1(int rxsubchans)
-{
- int mode = 0;
-
- if (rxsubchans & V4L2_TUNER_SUB_STEREO)
- mode |= VIDEO_SOUND_STEREO;
- if (rxsubchans & V4L2_TUNER_SUB_LANG2)
- mode |= VIDEO_SOUND_LANG2;
- if (rxsubchans & V4L2_TUNER_SUB_LANG1)
- mode |= VIDEO_SOUND_LANG1;
- if (0 == mode)
- mode |= VIDEO_SOUND_MONO;
- return mode;
-}
-
-static int mode_v4l1_to_v4l2(int mode)
-{
- if (mode & VIDEO_SOUND_STEREO)
- return V4L2_TUNER_MODE_STEREO;
- if (mode & VIDEO_SOUND_LANG2)
- return V4L2_TUNER_MODE_LANG2;
- if (mode & VIDEO_SOUND_LANG1)
- return V4L2_TUNER_MODE_LANG1;
- return V4L2_TUNER_MODE_MONO;
-}
-
-static void msp_any_detect_stereo(struct i2c_client *client)
-{
- struct msp3400c *msp = i2c_get_clientdata(client);
-
- switch (msp->opmode) {
- case OPMODE_MANUAL:
- case OPMODE_SIMPLE:
- autodetect_stereo(client);
- break;
- case OPMODE_SIMPLER:
- msp34xxg_detect_stereo(client);
- break;
- }
-}
-
-static void msp_any_set_audmode(struct i2c_client *client, int audmode)
-{
- struct msp3400c *msp = i2c_get_clientdata(client);
-
- switch (msp->opmode) {
- case OPMODE_MANUAL:
- case OPMODE_SIMPLE:
- msp->watch_stereo = 0;
- msp3400c_setstereo(client, audmode);
- break;
- case OPMODE_SIMPLER:
- msp34xxg_set_audmode(client, audmode);
- break;
- }
-}
-
-
-static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
- struct msp3400c *msp = i2c_get_clientdata(client);
- __u16 *sarg = arg;
- int scart = 0;
-
- switch (cmd) {
-
- case AUDC_SET_INPUT:
- msp3400_dbg("AUDC_SET_INPUT(%d)\n",*sarg);
-
- if (*sarg == msp->input)
- break;
- msp->input = *sarg;
- switch (*sarg) {
- case AUDIO_RADIO:
- /* Hauppauge uses IN2 for the radio */
- msp->mode = MSP_MODE_FM_RADIO;
- scart = SCART_IN2;
- break;
- case AUDIO_EXTERN_1:
- /* IN1 is often used for external input ... */
- msp->mode = MSP_MODE_EXTERN;
- scart = SCART_IN1;
- break;
- case AUDIO_EXTERN_2:
- /* ... sometimes it is IN2 through ;) */
- msp->mode = MSP_MODE_EXTERN;
- scart = SCART_IN2;
- break;
- case AUDIO_TUNER:
- msp->mode = -1;
- break;
- default:
- if (*sarg & AUDIO_MUTE)
- msp3400c_set_scart(client,SCART_MUTE,0);
- break;
- }
- if (scart) {
- msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
- msp->audmode = V4L2_TUNER_MODE_STEREO;
- msp3400c_set_scart(client,scart,0);
- msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
- if (msp->opmode != OPMODE_SIMPLER)
- msp3400c_setstereo(client, msp->audmode);
- }
- msp_wake_thread(client);
- break;
-
- case AUDC_SET_RADIO:
- msp3400_dbg("AUDC_SET_RADIO\n");
- msp->norm = VIDEO_MODE_RADIO;
- msp3400_dbg("switching to radio mode\n");
- msp->watch_stereo = 0;
- switch (msp->opmode) {
- case OPMODE_MANUAL:
- /* set msp3400 to FM radio mode */
- msp3400c_setmode(client,MSP_MODE_FM_RADIO);
- msp3400c_setcarrier(client, MSP_CARRIER(10.7),
- MSP_CARRIER(10.7));
- msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
- break;
- case OPMODE_SIMPLE:
- case OPMODE_SIMPLER:
- /* the thread will do for us */
- msp_wake_thread(client);
- break;
- }
- break;
- /* work-in-progress: hook to control the DFP registers */
- case MSP_SET_DFPREG:
- {
- struct msp_dfpreg *r = arg;
- int i;
-
- if (r->reg < 0 || r->reg >= DFP_COUNT)
- return -EINVAL;
- for (i = 0; i < sizeof(bl_dfp) / sizeof(int); i++)
- if (r->reg == bl_dfp[i])
- return -EINVAL;
- msp->dfp_regs[r->reg] = r->value;
- msp3400c_write(client, I2C_MSP3400C_DFP, r->reg, r->value);
- return 0;
- }
- case MSP_GET_DFPREG:
- {
- struct msp_dfpreg *r = arg;
-
- if (r->reg < 0 || r->reg >= DFP_COUNT)
- return -EINVAL;
- r->value = msp3400c_read(client, I2C_MSP3400C_DFP, r->reg);
- return 0;
- }
-
- /* --- v4l ioctls --- */
- /* take care: bttv does userspace copying, we'll get a
- kernel pointer here... */
- case VIDIOCGAUDIO:
- {
- struct video_audio *va = arg;
-
- msp3400_dbg("VIDIOCGAUDIO\n");
- va->flags |= VIDEO_AUDIO_VOLUME |
- VIDEO_AUDIO_BASS |
- VIDEO_AUDIO_TREBLE |
- VIDEO_AUDIO_MUTABLE;
- if (msp->muted)
- va->flags |= VIDEO_AUDIO_MUTE;
-
- if (msp->muted)
- va->flags |= VIDEO_AUDIO_MUTE;
- va->volume = MAX(msp->left, msp->right);
- va->balance = (32768 * MIN(msp->left, msp->right)) /
- (va->volume ? va->volume : 1);
- va->balance = (msp->left < msp->right) ?
- (65535 - va->balance) : va->balance;
- if (0 == va->volume)
- va->balance = 32768;
- va->bass = msp->bass;
- va->treble = msp->treble;
-
- msp_any_detect_stereo(client);
- va->mode = mode_v4l2_to_v4l1(msp->rxsubchans);
- break;
- }
- case VIDIOCSAUDIO:
- {
- struct video_audio *va = arg;
-
- msp3400_dbg("VIDIOCSAUDIO\n");
- msp->muted = (va->flags & VIDEO_AUDIO_MUTE);
- msp->left = (MIN(65536 - va->balance, 32768) *
- va->volume) / 32768;
- msp->right = (MIN(va->balance, 32768) * va->volume) / 32768;
- msp->bass = va->bass;
- msp->treble = va->treble;
- msp3400_dbg("VIDIOCSAUDIO setting va->volume to %d\n",
- va->volume);
- msp3400_dbg("VIDIOCSAUDIO setting va->balance to %d\n",
- va->balance);
- msp3400_dbg("VIDIOCSAUDIO setting va->flags to %d\n",
- va->flags);
- msp3400_dbg("VIDIOCSAUDIO setting msp->left to %d\n",
- msp->left);
- msp3400_dbg("VIDIOCSAUDIO setting msp->right to %d\n",
- msp->right);
- msp3400_dbg("VIDIOCSAUDIO setting msp->bass to %d\n",
- msp->bass);
- msp3400_dbg("VIDIOCSAUDIO setting msp->treble to %d\n",
- msp->treble);
- msp3400_dbg("VIDIOCSAUDIO setting msp->mode to %d\n",
- msp->mode);
- msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
- msp3400c_setbass(client, msp->bass);
- msp3400c_settreble(client, msp->treble);
-
- if (va->mode != 0 && msp->norm != VIDEO_MODE_RADIO)
- msp_any_set_audmode(client,mode_v4l1_to_v4l2(va->mode));
- break;
- }
-
- case VIDIOCSCHAN:
- {
- struct video_channel *vc = arg;
-
- msp3400_dbg("VIDIOCSCHAN (norm=%d)\n",vc->norm);
- msp->norm = vc->norm;
- msp_wake_thread(client);
- break;
- }
-
- case VIDIOCSFREQ:
- case VIDIOC_S_FREQUENCY:
- {
- /* new channel -- kick audio carrier scan */
- msp3400_dbg("VIDIOCSFREQ\n");
- msp_wake_thread(client);
- break;
- }
-
- /* msp34xx specific */
- case MSP_SET_MATRIX:
- {
- struct msp_matrix *mspm = arg;
-
- msp3400_dbg("MSP_SET_MATRIX\n");
- msp3400c_set_scart(client, mspm->input, mspm->output);
- break;
- }
-
- /* --- v4l2 ioctls --- */
- case VIDIOC_S_STD:
- {
- v4l2_std_id *id = arg;
-
- /*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/
- if (*id & V4L2_STD_PAL) {
- msp->norm=VIDEO_MODE_PAL;
- } else if (*id & V4L2_STD_SECAM) {
- msp->norm=VIDEO_MODE_SECAM;
- } else {
- msp->norm=VIDEO_MODE_NTSC;
- }
-
- msp_wake_thread(client);
- return 0;
- }
-
- case VIDIOC_ENUMINPUT:
- {
- struct v4l2_input *i = arg;
-
- if (i->index != 0)
- return -EINVAL;
-
- i->type = V4L2_INPUT_TYPE_TUNER;
- switch (i->index) {
- case AUDIO_RADIO:
- strcpy(i->name,"Radio");
- break;
- case AUDIO_EXTERN_1:
- strcpy(i->name,"Extern 1");
- break;
- case AUDIO_EXTERN_2:
- strcpy(i->name,"Extern 2");
- break;
- case AUDIO_TUNER:
- strcpy(i->name,"Television");
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
-
- case VIDIOC_G_AUDIO:
- {
- struct v4l2_audio *a = arg;
-
- memset(a,0,sizeof(*a));
-
- switch (a->index) {
- case AUDIO_RADIO:
- strcpy(a->name,"Radio");
- break;
- case AUDIO_EXTERN_1:
- strcpy(a->name,"Extern 1");
- break;
- case AUDIO_EXTERN_2:
- strcpy(a->name,"Extern 2");
- break;
- case AUDIO_TUNER:
- strcpy(a->name,"Television");
- break;
- default:
- return -EINVAL;
- }
-
- msp_any_detect_stereo(client);
- if (msp->audmode == V4L2_TUNER_MODE_STEREO) {
- a->capability=V4L2_AUDCAP_STEREO;
- }
-
- break;
- }
- case VIDIOC_S_AUDIO:
- {
- struct v4l2_audio *sarg = arg;
-
- switch (sarg->index) {
- case AUDIO_RADIO:
- /* Hauppauge uses IN2 for the radio */
- msp->mode = MSP_MODE_FM_RADIO;
- scart = SCART_IN2;
- break;
- case AUDIO_EXTERN_1:
- /* IN1 is often used for external input ... */
- msp->mode = MSP_MODE_EXTERN;
- scart = SCART_IN1;
- break;
- case AUDIO_EXTERN_2:
- /* ... sometimes it is IN2 through ;) */
- msp->mode = MSP_MODE_EXTERN;
- scart = SCART_IN2;
- break;
- case AUDIO_TUNER:
- msp->mode = -1;
- break;
- }
- if (scart) {
- msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
- msp->audmode = V4L2_TUNER_MODE_STEREO;
- msp3400c_set_scart(client,scart,0);
- msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
- }
- if (sarg->capability==V4L2_AUDCAP_STEREO) {
- msp->audmode = V4L2_TUNER_MODE_STEREO;
- } else {
- msp->audmode &= ~V4L2_TUNER_MODE_STEREO;
- }
- msp_any_set_audmode(client, msp->audmode);
- msp_wake_thread(client);
- break;
- }
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *vt = arg;
-
- msp_any_detect_stereo(client);
- vt->audmode = msp->audmode;
- vt->rxsubchans = msp->rxsubchans;
- vt->capability = V4L2_TUNER_CAP_STEREO |
- V4L2_TUNER_CAP_LANG1|
- V4L2_TUNER_CAP_LANG2;
- break;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
-
- /* only set audmode */
- if (vt->audmode != -1 && vt->audmode != 0)
- msp_any_set_audmode(client, vt->audmode);
- break;
- }
-
- case VIDIOC_G_AUDOUT:
- {
- struct v4l2_audioout *a=(struct v4l2_audioout *)arg;
- int idx=a->index;
-
- memset(a,0,sizeof(*a));
-
- switch (idx) {
- case 0:
- strcpy(a->name,"Scart1 Out");
- break;
- case 1:
- strcpy(a->name,"Scart2 Out");
- break;
- case 2:
- strcpy(a->name,"I2S Out");
- break;
- default:
- return -EINVAL;
- }
- break;
-
- }
- case VIDIOC_S_AUDOUT:
- {
- struct v4l2_audioout *a=(struct v4l2_audioout *)arg;
-
- if (a->index<0||a->index>2)
- return -EINVAL;
-
- if (a->index==2) {
- if (a->mode == V4L2_AUDMODE_32BITS)
- msp->i2s_mode=1;
- else
- msp->i2s_mode=0;
- }
- msp3400_dbg("Setting audio out on msp34xx to input %i, mode %i\n",
- a->index,msp->i2s_mode);
- msp3400c_set_scart(client,msp->in_scart,a->index+1);
-
- break;
- }
-
- default:
- /* nothing */
- break;
- }
- return 0;
-}
-
-static int msp_suspend(struct device * dev, pm_message_t state)
-{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
-
- msp3400_dbg("msp34xx: suspend\n");
- msp3400c_reset(client);
- return 0;
-}
-
-static int msp_resume(struct device * dev)
-{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
-
- msp3400_dbg("msp34xx: resume\n");
- msp_wake_thread(client);
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int __init msp3400_init_module(void)
-{
- return i2c_add_driver(&driver);
-}
-
-static void __exit msp3400_cleanup_module(void)
-{
- i2c_del_driver(&driver);
-}
-
-module_init(msp3400_init_module);
-module_exit(msp3400_cleanup_module);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h
index 2d9ff40f0b09..8a05cf500a8c 100644
--- a/drivers/media/video/msp3400.h
+++ b/drivers/media/video/msp3400.h
@@ -6,22 +6,28 @@
/* ---------------------------------------------------------------------- */
-struct msp_dfpreg {
- int reg;
- int value;
-};
-
struct msp_matrix {
int input;
int output;
};
-#define MSP_SET_DFPREG _IOW('m',15,struct msp_dfpreg)
-#define MSP_GET_DFPREG _IOW('m',16,struct msp_dfpreg)
-
/* ioctl for MSP_SET_MATRIX will have to be registered */
#define MSP_SET_MATRIX _IOW('m',17,struct msp_matrix)
+/* This macro is allowed for *constants* only, gcc must calculate it
+ at compile time. Remember -- no floats in kernel mode */
+#define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24)))
+
+#define MSP_MODE_AM_DETECT 0
+#define MSP_MODE_FM_RADIO 2
+#define MSP_MODE_FM_TERRA 3
+#define MSP_MODE_FM_SAT 4
+#define MSP_MODE_FM_NICAM1 5
+#define MSP_MODE_FM_NICAM2 6
+#define MSP_MODE_AM_NICAM 7
+#define MSP_MODE_BTSC 8
+#define MSP_MODE_EXTERN 9
+
#define SCART_MASK 0
#define SCART_IN1 1
#define SCART_IN2 2
@@ -36,4 +42,84 @@ struct msp_matrix {
#define SCART1_OUT 1
#define SCART2_OUT 2
+#define OPMODE_AUTO -1
+#define OPMODE_MANUAL 0
+#define OPMODE_AUTODETECT 1 /* use autodetect (>= msp3410 only) */
+#define OPMODE_AUTOSELECT 2 /* use autodetect & autoselect (>= msp34xxG) */
+
+/* module parameters */
+extern int debug;
+extern int once;
+extern int amsound;
+extern int standard;
+extern int dolby;
+extern int stereo_threshold;
+
+struct msp_state {
+ int rev1, rev2;
+ u8 has_nicam;
+ u8 has_radio;
+ u8 has_headphones;
+ u8 has_ntsc_jp_d_k3;
+ u8 has_scart4;
+ u8 has_scart23_in_scart2_out;
+ u8 has_scart2_out_volume;
+ u8 has_i2s_conf;
+ u8 has_subwoofer;
+ u8 has_sound_processing;
+ u8 has_virtual_dolby_surround;
+ u8 has_dolby_pro_logic;
+
+ int radio;
+ int opmode;
+ int std;
+ int mode;
+ v4l2_std_id v4l2_std;
+ int nicam_on;
+ int acb;
+ int in_scart;
+ int i2s_mode;
+ int main, second; /* sound carrier */
+ int input;
+ int source; /* see msp34xxg_set_source */
+
+ /* v4l2 */
+ int audmode;
+ int rxsubchans;
+
+ int volume, muted;
+ int balance, loudness;
+ int bass, treble;
+
+ /* thread */
+ struct task_struct *kthread;
+ wait_queue_head_t wq;
+ int restart:1;
+ int watch_stereo:1;
+};
+
+/* msp3400-driver.c */
+int msp_write_dem(struct i2c_client *client, int addr, int val);
+int msp_write_dsp(struct i2c_client *client, int addr, int val);
+int msp_read_dem(struct i2c_client *client, int addr);
+int msp_read_dsp(struct i2c_client *client, int addr);
+int msp_reset(struct i2c_client *client);
+void msp_set_scart(struct i2c_client *client, int in, int out);
+void msp_set_mute(struct i2c_client *client);
+void msp_set_audio(struct i2c_client *client);
+int msp_modus(struct i2c_client *client);
+int msp_sleep(struct msp_state *state, int timeout);
+
+/* msp3400-kthreads.c */
+const char *msp_standard_std_name(int std);
+void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2);
+void msp3400c_setmode(struct i2c_client *client, int type);
+void msp3400c_setstereo(struct i2c_client *client, int mode);
+int autodetect_stereo(struct i2c_client *client);
+int msp3400c_thread(void *data);
+int msp3410d_thread(void *data);
+int msp34xxg_thread(void *data);
+void msp34xxg_detect_stereo(struct i2c_client *client);
+void msp34xxg_set_audmode(struct i2c_client *client, int audmode);
+
#endif /* MSP3400_H */
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
index 2180018f06de..2c19c9588c02 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/video/mt20xx.c
@@ -20,6 +20,9 @@ module_param(tv_antenna, int, 0644);
static unsigned int radio_antenna = 0;
module_param(radio_antenna, int, 0644);
+/* from tuner-core.c */
+extern int debug;
+
/* ---------------------------------------------------------------------- */
#define MT2032 0x04
@@ -401,7 +404,7 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned
div2a=(lo2/8)-1;
div2b=lo2-(div2a+1)*8;
- if (tuner_debug > 1) {
+ if (debug > 1) {
tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2);
tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n",
num1,num2,div1a,div1b,div2a,div2b);
@@ -417,7 +420,7 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned
buf[5]=div2a;
if(num2!=0) buf[5]=buf[5]|0x40;
- if (tuner_debug > 1) {
+ if (debug > 1) {
int i;
tuner_dbg("bufs is: ");
for(i=0;i<6;i++)
@@ -494,11 +497,18 @@ int microtune_init(struct i2c_client *c)
t->tv_freq = NULL;
t->radio_freq = NULL;
t->standby = NULL;
+ if (t->std & V4L2_STD_525_60) {
+ tuner_dbg("pinnacle ntsc\n");
+ t->radio_if2 = 41300 * 1000;
+ } else {
+ tuner_dbg("pinnacle pal\n");
+ t->radio_if2 = 33300 * 1000;
+ }
name = "unknown";
i2c_master_send(c,buf,1);
i2c_master_recv(c,buf,21);
- if (tuner_debug) {
+ if (debug) {
int i;
tuner_dbg("MT20xx hexdump:");
for(i=0;i<21;i++) {
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index d04793fb80fc..91681aa6c657 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -26,6 +26,7 @@
#include <media/saa7146_vv.h>
#include <media/tuner.h>
#include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
#include "mxb.h"
#include "tea6415c.h"
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 2504207b2e3d..9e6448639480 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -883,6 +883,7 @@ static struct file_operations pms_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = pms_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.read = pms_read,
.llseek = no_llseek,
};
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index a51c7bd96618..73b4f0e2abf0 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -702,6 +702,7 @@ static struct file_operations saa_fops = {
.open = saa5249_open,
.release = saa5249_release,
.ioctl = saa5249_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
index d60a783e0473..e70b17ef36e9 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -427,18 +427,8 @@ static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind)
static int saa6588_probe(struct i2c_adapter *adap)
{
-#ifdef I2C_CLASS_TV_ANALOG
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, saa6588_attach);
-#else
- switch (adap->id) {
- case I2C_HW_B_BT848:
- case I2C_HW_B_RIVA:
- case I2C_HW_SAA7134:
- return i2c_probe(adap, &addr_data, saa6588_attach);
- break;
- }
-#endif
return 0;
}
@@ -496,7 +486,7 @@ static int saa6588_command(struct i2c_client *client, unsigned int cmd,
static struct i2c_driver driver = {
.driver = {
- .name = "i2c saa6588 driver",
+ .name = "saa6588",
},
.id = -1, /* FIXME */
.attach_adapter = saa6588_probe,
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index 29e28c742cd4..4a4bc69fb0e9 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -39,31 +39,18 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
+#include <media/audiochip.h>
+#include <asm/div64.h>
MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver");
MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil");
MODULE_LICENSE("GPL");
static int debug = 0;
-module_param(debug, int, 0644);
+module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
-#define saa7115_dbg(fmt,arg...) \
- do { \
- if (debug) \
- printk(KERN_INFO "%s debug %d-%04x: " fmt, \
- client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); \
- } while (0)
-
-#define saa7115_err(fmt, arg...) do { \
- printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define saa7115_info(fmt, arg...) do { \
- printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };
@@ -73,12 +60,13 @@ struct saa7115_state {
v4l2_std_id std;
int input;
int enable;
+ int radio;
int bright;
int contrast;
int hue;
int sat;
enum v4l2_chip_ident ident;
- enum v4l2_audio_clock_freq audclk_freq;
+ u32 audclk_freq;
};
/* ----------------------------------------------------------------------- */
@@ -469,80 +457,6 @@ static const unsigned char saa7115_init_misc[] = {
0x00, 0x00
};
-/* ============== SAA7715 AUDIO settings ============= */
-
-/* 48.0 kHz */
-static const unsigned char saa7115_cfg_48_audio[] = {
- 0x34, 0xce,
- 0x35, 0xfb,
- 0x36, 0x30,
- 0x00, 0x00
-};
-
-/* 44.1 kHz */
-static const unsigned char saa7115_cfg_441_audio[] = {
- 0x34, 0xf2,
- 0x35, 0x00,
- 0x36, 0x2d,
- 0x00, 0x00
-};
-
-/* 32.0 kHz */
-static const unsigned char saa7115_cfg_32_audio[] = {
- 0x34, 0xdf,
- 0x35, 0xa7,
- 0x36, 0x20,
- 0x00, 0x00
-};
-
-/* 48.0 kHz 60hz */
-static const unsigned char saa7115_cfg_60hz_48_audio[] = {
- 0x30, 0xcd,
- 0x31, 0x20,
- 0x32, 0x03,
- 0x00, 0x00
-};
-
-/* 48.0 kHz 50hz */
-static const unsigned char saa7115_cfg_50hz_48_audio[] = {
- 0x30, 0x00,
- 0x31, 0xc0,
- 0x32, 0x03,
- 0x00, 0x00
-};
-
-/* 44.1 kHz 60hz */
-static const unsigned char saa7115_cfg_60hz_441_audio[] = {
- 0x30, 0xbc,
- 0x31, 0xdf,
- 0x32, 0x02,
- 0x00, 0x00
-};
-
-/* 44.1 kHz 50hz */
-static const unsigned char saa7115_cfg_50hz_441_audio[] = {
- 0x30, 0x00,
- 0x31, 0x72,
- 0x32, 0x03,
- 0x00, 0x00
-};
-
-/* 32.0 kHz 60hz */
-static const unsigned char saa7115_cfg_60hz_32_audio[] = {
- 0x30, 0xde,
- 0x31, 0x15,
- 0x32, 0x02,
- 0x00, 0x00
-};
-
-/* 32.0 kHz 50hz */
-static const unsigned char saa7115_cfg_50hz_32_audio[] = {
- 0x30, 0x00,
- 0x31, 0x80,
- 0x32, 0x02,
- 0x00, 0x00
-};
-
static int saa7115_odd_parity(u8 c)
{
c ^= (c >> 4);
@@ -627,40 +541,38 @@ static int saa7115_decode_wss(u8 * p)
}
-static int saa7115_set_audio_clock_freq(struct i2c_client *client, enum v4l2_audio_clock_freq freq)
+static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
{
struct saa7115_state *state = i2c_get_clientdata(client);
+ u32 acpf;
+ u32 acni;
+ u32 hz;
+ u64 f;
- saa7115_dbg("set audio clock freq: %d\n", freq);
- switch (freq) {
- case V4L2_AUDCLK_32_KHZ:
- saa7115_writeregs(client, saa7115_cfg_32_audio);
- if (state->std & V4L2_STD_525_60) {
- saa7115_writeregs(client, saa7115_cfg_60hz_32_audio);
- } else {
- saa7115_writeregs(client, saa7115_cfg_50hz_32_audio);
- }
- break;
- case V4L2_AUDCLK_441_KHZ:
- saa7115_writeregs(client, saa7115_cfg_441_audio);
- if (state->std & V4L2_STD_525_60) {
- saa7115_writeregs(client, saa7115_cfg_60hz_441_audio);
- } else {
- saa7115_writeregs(client, saa7115_cfg_50hz_441_audio);
- }
- break;
- case V4L2_AUDCLK_48_KHZ:
- saa7115_writeregs(client, saa7115_cfg_48_audio);
- if (state->std & V4L2_STD_525_60) {
- saa7115_writeregs(client, saa7115_cfg_60hz_48_audio);
- } else {
- saa7115_writeregs(client, saa7115_cfg_50hz_48_audio);
- }
- break;
- default:
- saa7115_dbg("invalid audio setting %d\n", freq);
- return -EINVAL;
- }
+ v4l_dbg(1, client, "set audio clock freq: %d\n", freq);
+
+ /* sanity check */
+ if (freq < 32000 || freq > 48000)
+ return -EINVAL;
+
+ /* hz is the refresh rate times 100 */
+ hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
+ /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
+ acpf = (25600 * freq) / hz;
+ /* acni = (256 * freq * 2^23) / crystal_frequency =
+ (freq * 2^(8+23)) / crystal_frequency =
+ (freq << 31) / 32.11 MHz */
+ f = freq;
+ f = f << 31;
+ do_div(f, 32110000);
+ acni = f;
+
+ saa7115_write(client, 0x30, acpf & 0xff);
+ saa7115_write(client, 0x31, (acpf >> 8) & 0xff);
+ saa7115_write(client, 0x32, (acpf >> 16) & 0x03);
+ saa7115_write(client, 0x34, acni & 0xff);
+ saa7115_write(client, 0x35, (acni >> 8) & 0xff);
+ saa7115_write(client, 0x36, (acni >> 16) & 0x3f);
state->audclk_freq = freq;
return 0;
}
@@ -672,7 +584,7 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
if (ctrl->value < 0 || ctrl->value > 255) {
- saa7115_err("invalid brightness setting %d\n", ctrl->value);
+ v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
return -ERANGE;
}
@@ -682,7 +594,7 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
case V4L2_CID_CONTRAST:
if (ctrl->value < 0 || ctrl->value > 127) {
- saa7115_err("invalid contrast setting %d\n", ctrl->value);
+ v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
return -ERANGE;
}
@@ -692,7 +604,7 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
case V4L2_CID_SATURATION:
if (ctrl->value < 0 || ctrl->value > 127) {
- saa7115_err("invalid saturation setting %d\n", ctrl->value);
+ v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
return -ERANGE;
}
@@ -702,13 +614,16 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
case V4L2_CID_HUE:
if (ctrl->value < -127 || ctrl->value > 127) {
- saa7115_err("invalid hue setting %d\n", ctrl->value);
+ v4l_err(client, "invalid hue setting %d\n", ctrl->value);
return -ERANGE;
}
state->hue = ctrl->value;
saa7115_write(client, 0x0d, state->hue);
break;
+
+ default:
+ return -EINVAL;
}
return 0;
@@ -743,12 +658,22 @@ static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
struct saa7115_state *state = i2c_get_clientdata(client);
int taskb = saa7115_read(client, 0x80) & 0x10;
+ /* Prevent unnecessary standard changes. During a standard
+ change the I-Port is temporarily disabled. Any devices
+ reading from that port can get confused.
+ Note that VIDIOC_S_STD is also used to switch from
+ radio to TV mode, so if a VIDIOC_S_STD is broadcast to
+ all I2C devices then you do not want to have an unwanted
+ side-effect here. */
+ if (std == state->std)
+ return;
+
// This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
if (std & V4L2_STD_525_60) {
- saa7115_dbg("decoder set standard 60 Hz\n");
+ v4l_dbg(1, client, "decoder set standard 60 Hz\n");
saa7115_writeregs(client, saa7115_cfg_60hz_video);
} else {
- saa7115_dbg("decoder set standard 50 Hz\n");
+ v4l_dbg(1, client, "decoder set standard 50 Hz\n");
saa7115_writeregs(client, saa7115_cfg_50hz_video);
}
@@ -773,24 +698,17 @@ static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client)
static void saa7115_log_status(struct i2c_client *client)
{
struct saa7115_state *state = i2c_get_clientdata(client);
- char *audfreq = "undefined";
int reg1e, reg1f;
int signalOk;
int vcr;
- switch (state->audclk_freq) {
- case V4L2_AUDCLK_32_KHZ: audfreq = "32 kHz"; break;
- case V4L2_AUDCLK_441_KHZ: audfreq = "44.1 kHz"; break;
- case V4L2_AUDCLK_48_KHZ: audfreq = "48 kHz"; break;
- }
-
- saa7115_info("Audio frequency: %s\n", audfreq);
+ v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
if (client->name[6] == '4') {
/* status for the saa7114 */
reg1f = saa7115_read(client, 0x1f);
signalOk = (reg1f & 0xc1) == 0x81;
- saa7115_info("Video signal: %s\n", signalOk ? "ok" : "bad");
- saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz");
+ v4l_info(client, "Video signal: %s\n", signalOk ? "ok" : "bad");
+ v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
return;
}
@@ -801,21 +719,26 @@ static void saa7115_log_status(struct i2c_client *client)
signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
vcr = !(reg1f & 0x10);
- saa7115_info("Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
- saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz");
+ if (state->input >= 6) {
+ v4l_info(client, "Input: S-Video %d\n", state->input - 6);
+ } else {
+ v4l_info(client, "Input: Composite %d\n", state->input);
+ }
+ v4l_info(client, "Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
+ v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
switch (reg1e & 0x03) {
case 1:
- saa7115_info("Detected format: NTSC\n");
+ v4l_info(client, "Detected format: NTSC\n");
break;
case 2:
- saa7115_info("Detected format: PAL\n");
+ v4l_info(client, "Detected format: PAL\n");
break;
case 3:
- saa7115_info("Detected format: SECAM\n");
+ v4l_info(client, "Detected format: SECAM\n");
break;
default:
- saa7115_info("Detected format: BW/No color\n");
+ v4l_info(client, "Detected format: BW/No color\n");
break;
}
}
@@ -940,7 +863,7 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
pix = &(fmt->fmt.pix);
- saa7115_dbg("decoder set size\n");
+ v4l_dbg(1, client, "decoder set size\n");
/* FIXME need better bounds checking here */
if ((pix->width < 1) || (pix->width > 1440))
@@ -966,7 +889,7 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
HPSC = HPSC ? HPSC : 1;
HFSC = (int)((1024 * 720) / (HPSC * pix->width));
- saa7115_dbg("Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
+ v4l_dbg(1, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
/* FIXME hardcodes to "Task B"
* write H prescaler integer */
saa7115_write(client, 0xd0, (u8) (HPSC & 0x3f));
@@ -980,10 +903,10 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
saa7115_write(client, 0xDD, (u8) ((HFSC >> 9) & 0xff));
} else {
if (is_50hz) {
- saa7115_dbg("Setting full 50hz width\n");
+ v4l_dbg(1, client, "Setting full 50hz width\n");
saa7115_writeregs(client, saa7115_cfg_50hz_fullres_x);
} else {
- saa7115_dbg("Setting full 60hz width\n");
+ v4l_dbg(1, client, "Setting full 60hz width\n");
saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
}
}
@@ -992,7 +915,7 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
if (pix->height != Vsrc) {
VSCY = (int)((1024 * Vsrc) / pix->height);
- saa7115_dbg("Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
+ v4l_dbg(1, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
/* Correct Contrast and Luminance */
saa7115_write(client, 0xd5, (u8) (64 * 1024 / VSCY));
@@ -1006,10 +929,10 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
saa7115_write(client, 0xe3, (u8) ((VSCY >> 8) & 0xff));
} else {
if (is_50hz) {
- saa7115_dbg("Setting full 50Hz height\n");
+ v4l_dbg(1, client, "Setting full 50Hz height\n");
saa7115_writeregs(client, saa7115_cfg_50hz_fullres_y);
} else {
- saa7115_dbg("Setting full 60hz height\n");
+ v4l_dbg(1, client, "Setting full 60hz height\n");
saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
}
}
@@ -1089,6 +1012,48 @@ static void saa7115_decode_vbi_line(struct i2c_client *client,
/* ============ SAA7115 AUDIO settings (end) ============= */
+static struct v4l2_queryctrl saa7115_qctrl[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 128,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 64,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 64,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ },
+};
+
+/* ----------------------------------------------------------------------- */
+
static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct saa7115_state *state = i2c_get_clientdata(client);
@@ -1103,16 +1068,18 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg);
case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- return saa7115_set_audio_clock_freq(client, *(enum v4l2_audio_clock_freq *)arg);
+ return saa7115_set_audio_clock_freq(client, *(u32 *)arg);
case VIDIOC_G_TUNER:
{
struct v4l2_tuner *vt = arg;
int status;
+ if (state->radio)
+ break;
status = saa7115_read(client, 0x1f);
- saa7115_dbg("status: 0x%02x\n", status);
+ v4l_dbg(1, client, "status: 0x%02x\n", status);
vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
break;
}
@@ -1127,20 +1094,38 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
case VIDIOC_S_CTRL:
return saa7115_set_v4lctrl(client, (struct v4l2_control *)arg);
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(saa7115_qctrl); i++)
+ if (qc->id && qc->id == saa7115_qctrl[i].id) {
+ memcpy(qc, &saa7115_qctrl[i], sizeof(*qc));
+ return 0;
+ }
+ return -EINVAL;
+ }
+
case VIDIOC_G_STD:
*(v4l2_std_id *)arg = saa7115_get_v4lstd(client);
break;
case VIDIOC_S_STD:
+ state->radio = 0;
saa7115_set_v4lstd(client, *(v4l2_std_id *)arg);
break;
+ case AUDC_SET_RADIO:
+ state->radio = 1;
+ break;
+
case VIDIOC_G_INPUT:
*(int *)arg = state->input;
break;
case VIDIOC_S_INPUT:
- saa7115_dbg("decoder set input %d\n", *iarg);
+ v4l_dbg(1, client, "decoder set input %d\n", *iarg);
/* inputs from 0-9 are available */
if (*iarg < 0 || *iarg > 9) {
return -EINVAL;
@@ -1148,7 +1133,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
if (state->input == *iarg)
break;
- saa7115_dbg("now setting %s input\n",
+ v4l_dbg(1, client, "now setting %s input\n",
*iarg >= 6 ? "S-Video" : "Composite");
state->input = *iarg;
@@ -1165,7 +1150,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
case VIDIOC_STREAMON:
case VIDIOC_STREAMOFF:
- saa7115_dbg("%s output\n",
+ v4l_dbg(1, client, "%s output\n",
(cmd == VIDIOC_STREAMON) ? "enable" : "disable");
if (state->enable != (cmd == VIDIOC_STREAMON)) {
@@ -1179,7 +1164,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
break;
case VIDIOC_INT_RESET:
- saa7115_dbg("decoder RESET\n");
+ v4l_dbg(1, client, "decoder RESET\n");
saa7115_writeregs(client, saa7115_cfg_reset_scaler);
break;
@@ -1273,19 +1258,19 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
client->driver = &i2c_driver_saa7115;
snprintf(client->name, sizeof(client->name) - 1, "saa7115");
- saa7115_dbg("detecting saa7115 client on address 0x%x\n", address << 1);
+ v4l_dbg(1, client, "detecting saa7115 client on address 0x%x\n", address << 1);
saa7115_write(client, 0, 5);
chip_id = saa7115_read(client, 0) & 0x0f;
if (chip_id != 4 && chip_id != 5) {
- saa7115_dbg("saa7115 not found\n");
+ v4l_dbg(1, client, "saa7115 not found\n");
kfree(client);
return 0;
}
if (chip_id == 4) {
snprintf(client->name, sizeof(client->name) - 1, "saa7114");
}
- saa7115_info("saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name);
+ v4l_info(client, "saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name);
state = kmalloc(sizeof(struct saa7115_state), GFP_KERNEL);
i2c_set_clientdata(client, state);
@@ -1297,14 +1282,15 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
state->std = V4L2_STD_NTSC;
state->input = -1;
state->enable = 1;
+ state->radio = 0;
state->bright = 128;
state->contrast = 64;
state->hue = 0;
state->sat = 64;
state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115;
- state->audclk_freq = V4L2_AUDCLK_48_KHZ;
+ state->audclk_freq = 48000;
- saa7115_dbg("writing init values\n");
+ v4l_dbg(1, client, "writing init values\n");
/* init to 60hz/48khz */
saa7115_writeregs(client, saa7115_init_auto_input);
@@ -1312,13 +1298,12 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
saa7115_writeregs(client, saa7115_cfg_60hz_video);
- saa7115_writeregs(client, saa7115_cfg_48_audio);
- saa7115_writeregs(client, saa7115_cfg_60hz_48_audio);
+ saa7115_set_audio_clock_freq(client, state->audclk_freq);
saa7115_writeregs(client, saa7115_cfg_reset_scaler);
i2c_attach_client(client);
- saa7115_dbg("status: (1E) 0x%02x, (1F) 0x%02x\n",
+ v4l_dbg(1, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
saa7115_read(client, 0x1e), saa7115_read(client, 0x1f));
return 0;
@@ -1326,11 +1311,7 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
static int saa7115_probe(struct i2c_adapter *adapter)
{
-#ifdef I2C_CLASS_TV_ANALOG
if (adapter->class & I2C_CLASS_TV_ANALOG)
-#else
- if (adapter->id == I2C_HW_B_BT848)
-#endif
return i2c_probe(adapter, &addr_data, &saa7115_attach);
return 0;
}
diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c
index 8008537391b5..f39a7be08588 100644
--- a/drivers/media/video/saa711x.c
+++ b/drivers/media/video/saa711x.c
@@ -567,9 +567,7 @@ static struct i2c_driver i2c_driver_saa711x = {
.driver = {
.name = "saa711x",
},
-
.id = I2C_DRIVERID_SAA711X,
-
.attach_adapter = saa711x_attach_adapter,
.detach_client = saa711x_detach_client,
.command = saa711x_command,
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index bca6ed0e2752..2009c1bc4720 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -66,30 +66,6 @@ module_param(test_image, int, 0644);
MODULE_PARM_DESC(debug, "debug level (0-2)");
MODULE_PARM_DESC(test_image, "test_image (0-1)");
-#define saa7127_dbg(fmt, arg...) \
- do { \
- if (debug >= 1) \
- printk(KERN_INFO "%s debug %d-%04x: " fmt, \
- client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); \
- } while (0)
-
-/* High volume debug. Use with care. */
-#define saa7127_dbg_highvol(fmt, arg...) \
- do { \
- if (debug == 2) \
- printk(KERN_INFO "%s debug %d-%04x: " fmt, \
- client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); \
- } while (0)
-
-#define saa7127_err(fmt, arg...) do { \
- printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define saa7127_info(fmt, arg...) do { \
- printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
@@ -336,7 +312,7 @@ static int saa7127_write(struct i2c_client *client, u8 reg, u8 val)
if (i2c_smbus_write_byte_data(client, reg, val) == 0)
return 0;
}
- saa7127_err("I2C Write Problem\n");
+ v4l_err(client, "I2C Write Problem\n");
return -1;
}
@@ -362,7 +338,7 @@ static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_dat
if (enable && (data->field != 0 || data->line != 16))
return -EINVAL;
if (state->vps_enable != enable) {
- saa7127_dbg("Turn VPS Signal %s\n", enable ? "on" : "off");
+ v4l_dbg(1, client, "Turn VPS Signal %s\n", enable ? "on" : "off");
saa7127_write(client, 0x54, enable << 7);
state->vps_enable = enable;
}
@@ -374,7 +350,7 @@ static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_dat
state->vps_data[2] = data->data[11];
state->vps_data[3] = data->data[12];
state->vps_data[4] = data->data[13];
- saa7127_dbg("Set VPS data %02x %02x %02x %02x %02x\n",
+ v4l_dbg(1, client, "Set VPS data %02x %02x %02x %02x %02x\n",
state->vps_data[0], state->vps_data[1],
state->vps_data[2], state->vps_data[3],
state->vps_data[4]);
@@ -397,7 +373,7 @@ static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data
if (enable && (data->field != 0 || data->line != 21))
return -EINVAL;
if (state->cc_enable != enable) {
- saa7127_dbg("Turn CC %s\n", enable ? "on" : "off");
+ v4l_dbg(1, client, "Turn CC %s\n", enable ? "on" : "off");
saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
(state->xds_enable << 7) | (enable << 6) | 0x11);
state->cc_enable = enable;
@@ -405,7 +381,7 @@ static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data
if (!enable)
return 0;
- saa7127_dbg_highvol("CC data: %04x\n", cc);
+ v4l_dbg(2, client, "CC data: %04x\n", cc);
saa7127_write(client, SAA7127_REG_LINE_21_ODD_0, cc & 0xff);
saa7127_write(client, SAA7127_REG_LINE_21_ODD_1, cc >> 8);
state->cc_data = cc;
@@ -423,7 +399,7 @@ static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_dat
if (enable && (data->field != 1 || data->line != 21))
return -EINVAL;
if (state->xds_enable != enable) {
- saa7127_dbg("Turn XDS %s\n", enable ? "on" : "off");
+ v4l_dbg(1, client, "Turn XDS %s\n", enable ? "on" : "off");
saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
(enable << 7) | (state->cc_enable << 6) | 0x11);
state->xds_enable = enable;
@@ -431,7 +407,7 @@ static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_dat
if (!enable)
return 0;
- saa7127_dbg_highvol("XDS data: %04x\n", xds);
+ v4l_dbg(2, client, "XDS data: %04x\n", xds);
saa7127_write(client, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff);
saa7127_write(client, SAA7127_REG_LINE_21_EVEN_1, xds >> 8);
state->xds_data = xds;
@@ -448,7 +424,7 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat
if (enable && (data->field != 0 || data->line != 23))
return -EINVAL;
if (state->wss_enable != enable) {
- saa7127_dbg("Turn WSS %s\n", enable ? "on" : "off");
+ v4l_dbg(1, client, "Turn WSS %s\n", enable ? "on" : "off");
saa7127_write(client, 0x27, enable << 7);
state->wss_enable = enable;
}
@@ -457,7 +433,7 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat
saa7127_write(client, 0x26, data->data[0]);
saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f));
- saa7127_dbg("WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
+ v4l_dbg(1, client, "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
return 0;
}
@@ -469,11 +445,11 @@ static int saa7127_set_video_enable(struct i2c_client *client, int enable)
struct saa7127_state *state = i2c_get_clientdata(client);
if (enable) {
- saa7127_dbg("Enable Video Output\n");
+ v4l_dbg(1, client, "Enable Video Output\n");
saa7127_write(client, 0x2d, state->reg_2d);
saa7127_write(client, 0x61, state->reg_61);
} else {
- saa7127_dbg("Disable Video Output\n");
+ v4l_dbg(1, client, "Disable Video Output\n");
saa7127_write(client, 0x2d, (state->reg_2d & 0xf0));
saa7127_write(client, 0x61, (state->reg_61 | 0xc0));
}
@@ -489,11 +465,11 @@ static int saa7127_set_std(struct i2c_client *client, v4l2_std_id std)
const struct i2c_reg_value *inittab;
if (std & V4L2_STD_525_60) {
- saa7127_dbg("Selecting 60 Hz video Standard\n");
+ v4l_dbg(1, client, "Selecting 60 Hz video Standard\n");
inittab = saa7127_init_config_60hz;
state->reg_61 = SAA7127_60HZ_DAC_CONTROL;
} else {
- saa7127_dbg("Selecting 50 Hz video Standard\n");
+ v4l_dbg(1, client, "Selecting 50 Hz video Standard\n");
inittab = saa7127_init_config_50hz;
state->reg_61 = SAA7127_50HZ_DAC_CONTROL;
}
@@ -544,7 +520,7 @@ static int saa7127_set_output_type(struct i2c_client *client, int output)
default:
return -EINVAL;
}
- saa7127_dbg("Selecting %s output type\n", output_strs[output]);
+ v4l_dbg(1, client, "Selecting %s output type\n", output_strs[output]);
/* Configure Encoder */
saa7127_write(client, 0x2d, state->reg_2d);
@@ -561,12 +537,12 @@ static int saa7127_set_input_type(struct i2c_client *client, int input)
switch (input) {
case SAA7127_INPUT_TYPE_NORMAL: /* avia */
- saa7127_dbg("Selecting Normal Encoder Input\n");
+ v4l_dbg(1, client, "Selecting Normal Encoder Input\n");
state->reg_3a_cb = 0;
break;
case SAA7127_INPUT_TYPE_TEST_IMAGE: /* color bar */
- saa7127_dbg("Selecting Color Bar generator\n");
+ v4l_dbg(1, client, "Selecting Color Bar generator\n");
state->reg_3a_cb = 0x80;
break;
@@ -633,14 +609,14 @@ static int saa7127_command(struct i2c_client *client,
break;
case VIDIOC_LOG_STATUS:
- saa7127_info("Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
- saa7127_info("Input: %s\n", state->input_type ? "color bars" : "normal");
- saa7127_info("Output: %s\n", state->video_enable ?
+ v4l_info(client, "Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
+ v4l_info(client, "Input: %s\n", state->input_type ? "color bars" : "normal");
+ v4l_info(client, "Output: %s\n", state->video_enable ?
output_strs[state->output_type] : "disabled");
- saa7127_info("WSS: %s\n", state->wss_enable ?
+ v4l_info(client, "WSS: %s\n", state->wss_enable ?
wss_strs[state->wss_mode] : "disabled");
- saa7127_info("VPS: %s\n", state->vps_enable ? "enabled" : "disabled");
- saa7127_info("CC: %s\n", state->cc_enable ? "enabled" : "disabled");
+ v4l_info(client, "VPS: %s\n", state->vps_enable ? "enabled" : "disabled");
+ v4l_info(client, "CC: %s\n", state->cc_enable ? "enabled" : "disabled");
break;
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -723,7 +699,7 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
client->driver = &i2c_driver_saa7127;
snprintf(client->name, sizeof(client->name) - 1, "saa7127");
- saa7127_dbg("detecting saa7127 client on address 0x%x\n", address << 1);
+ v4l_dbg(1, client, "detecting saa7127 client on address 0x%x\n", address << 1);
/* First test register 0: Bits 5-7 are a version ID (should be 0),
and bit 2 should also be 0.
@@ -732,7 +708,7 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
0x1d after a reset and not expected to ever change. */
if ((saa7127_read(client, 0) & 0xe4) != 0 ||
(saa7127_read(client, 0x29) & 0x3f) != 0x1d) {
- saa7127_dbg("saa7127 not found\n");
+ v4l_dbg(1, client, "saa7127 not found\n");
kfree(client);
return 0;
}
@@ -748,7 +724,7 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
/* Configure Encoder */
- saa7127_dbg("Configuring encoder\n");
+ v4l_dbg(1, client, "Configuring encoder\n");
saa7127_write_inittab(client, saa7127_init_config_common);
saa7127_set_std(client, V4L2_STD_NTSC);
saa7127_set_output_type(client, SAA7127_OUTPUT_TYPE_BOTH);
@@ -769,12 +745,12 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2);
saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa);
if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
- saa7127_info("saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name);
+ v4l_info(client, "saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name);
saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result);
saa7127_write_inittab(client, saa7129_init_config_extra);
state->ident = V4L2_IDENT_SAA7129;
} else {
- saa7127_info("saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name);
+ v4l_info(client, "saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name);
state->ident = V4L2_IDENT_SAA7127;
}
@@ -787,11 +763,7 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
static int saa7127_probe(struct i2c_adapter *adapter)
{
-#ifdef I2C_CLASS_TV_ANALOG
if (adapter->class & I2C_CLASS_TV_ANALOG)
-#else
- if (adapter->id == I2C_HW_B_BT848)
-#endif
return i2c_probe(adapter, &addr_data, saa7127_attach);
return 0;
}
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index 4615a982ac64..ad73c4a60f2b 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -9,7 +9,8 @@
#include <linux/poll.h>
#include <linux/i2c.h>
#include <linux/types.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
#include <linux/init.h>
#include <linux/crc32.h>
@@ -509,7 +510,6 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct saa6752hs_state *h;
- printk("saa6752hs: chip found @ 0x%x\n", addr<<1);
if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL)))
return -ENOMEM;
@@ -525,6 +525,8 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
i2c_set_clientdata(&h->client, h);
i2c_attach_client(&h->client);
+ v4l_info(&h->client,"saa6752hs: chip found @ 0x%x\n", addr<<1);
+
return 0;
}
@@ -598,7 +600,7 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
static struct i2c_driver driver = {
.driver = {
- .name = "i2c saa6752hs MPEG encoder",
+ .name = "saa6752hs",
},
.id = I2C_DRIVERID_SAA6752HS,
.attach_adapter = saa6752hs_probe,
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index ade05f75fdb0..a7a6ab9298a9 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -20,13 +20,13 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/moduleparam.h>
#include <linux/module.h>
+#include <sound/driver.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 672fb205959f..77e5be98e4c6 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -25,6 +25,7 @@
#include "saa7134-reg.h"
#include "saa7134.h"
+#include <media/v4l2-common.h>
/* commly used strings */
static char name_mute[] = "mute";
@@ -2555,6 +2556,69 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE1,
},
},
+ [SAA7134_BOARD_CINERGY250PCI] = {
+ /* remote-control does not work. The signal about a
+ key press comes in via gpio, but the key code
+ doesn't. Neither does it have an i2c remote control
+ interface. */
+ .name = "Terratec Cinergy 250 PCI TV",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x80200000,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_svideo, /* NOT tested */
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE1,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_FLYDVB_TRIO] = {
+ /* LifeView LR319 FlyDVB Trio */
+ /* Peter Missel <peter.missel@onlinehome.de> */
+ .name = "LifeView FlyDVB Trio",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00200000,
+ .inputs = {{
+ .name = name_tv, /* Analog broadcast/cable TV */
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x200000, /* GPIO21=High for TV input */
+ .tv = 1,
+ },{
+ .name = name_svideo, /* S-Video signal on S-Video input */
+ .vmux = 8,
+ .amux = LINE2,
+ },{
+ .name = name_comp1, /* Composite signal on S-Video input */
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .name = name_comp2, /* Composite input */
+ .vmux = 3,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x000000, /* GPIO21=Low for FM radio antenna */
+ },
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -2895,6 +2959,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x1421,
+ .subdevice = 0x0351, /* PCI version, new revision */
+ .driver_data = SAA7134_BOARD_ADS_INSTANT_TV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1421,
.subdevice = 0x0370, /* cardbus version */
.driver_data = SAA7134_BOARD_ADS_INSTANT_TV,
},{
@@ -3002,6 +3072,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x6231,
.driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
},{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x153b,
+ .subdevice = 0x1160,
+ .driver_data = SAA7134_BOARD_CINERGY250PCI,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA 7131E */
+ .subvendor = 0x5168,
+ .subdevice = 0x0319,
+ .driver_data = SAA7134_BOARD_FLYDVB_TRIO,
+ },{
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -3090,6 +3172,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
/* case SAA7134_BOARD_SABRENT_SBTTVFM: */ /* not finished yet */
case SAA7134_BOARD_VIDEOMATE_TV_PVR:
+ case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 23d8747338ed..accbc32725cf 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -95,77 +95,6 @@ int (*dmasound_exit)(struct saa7134_dev *dev);
#define dprintk(fmt, arg...) if (core_debug) \
printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg)
-/* ------------------------------------------------------------------ */
-/* debug help functions */
-
-static const char *v4l1_ioctls[] = {
- "0", "GCAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
- "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
- "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
- "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
- "SMICROCODE", "GVBIFMT", "SVBIFMT" };
-#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
-
-static const char *v4l2_ioctls[] = {
- "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
- "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
- "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
- "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
- "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
- "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
- "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
- "44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
- "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
- "S_MODULATOR"
-};
-#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
-
-static const char *osspcm_ioctls[] = {
- "RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT",
- "CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS",
- "GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER",
- "GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO",
- "SETDUPLEX", "GETODELAY"
-};
-#define OSSPCM_IOCTLS ARRAY_SIZE(v4l2_ioctls)
-
-void saa7134_print_ioctl(char *name, unsigned int cmd)
-{
- char *dir;
-
- switch (_IOC_DIR(cmd)) {
- case _IOC_NONE: dir = "--"; break;
- case _IOC_READ: dir = "r-"; break;
- case _IOC_WRITE: dir = "-w"; break;
- case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
- default: dir = "??"; break;
- }
- switch (_IOC_TYPE(cmd)) {
- case 'v':
- printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n",
- name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
- v4l1_ioctls[_IOC_NR(cmd)] : "???");
- break;
- case 'V':
- printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n",
- name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ?
- v4l2_ioctls[_IOC_NR(cmd)] : "???");
- break;
- case 'P':
- printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n",
- name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ?
- osspcm_ioctls[_IOC_NR(cmd)] : "???");
- break;
- case 'M':
- printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n",
- name, cmd, dir, _IOC_NR(cmd));
- break;
- default:
- printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
- name, cmd, dir, _IOC_NR(cmd));
- }
-}
-
void saa7134_track_gpio(struct saa7134_dev *dev, char *msg)
{
unsigned long mode,status;
@@ -211,7 +140,7 @@ static int pending_call(struct notifier_block *self, unsigned long state,
return NOTIFY_DONE;
}
-static int pending_registered;
+static int pending_registered=0;
static struct notifier_block pending_notifier = {
.notifier_call = pending_call,
};
@@ -610,11 +539,38 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
card_has_mpeg(dev))
saa7134_irq_ts_done(dev,status);
- if ((report & (SAA7134_IRQ_REPORT_GPIO16 |
- SAA7134_IRQ_REPORT_GPIO18)) &&
- dev->remote)
- saa7134_input_irq(dev);
+ if (report & SAA7134_IRQ_REPORT_GPIO16) {
+ switch (dev->has_remote) {
+ case SAA7134_REMOTE_GPIO:
+ if (dev->remote->mask_keydown & 0x10000) {
+ saa7134_input_irq(dev);
+ }
+ break;
+
+ case SAA7134_REMOTE_I2C:
+ break; /* FIXME: invoke I2C get_key() */
+ default: /* GPIO16 not used by IR remote */
+ break;
+ }
+ }
+
+ if (report & SAA7134_IRQ_REPORT_GPIO18) {
+ switch (dev->has_remote) {
+ case SAA7134_REMOTE_GPIO:
+ if ((dev->remote->mask_keydown & 0x40000) ||
+ (dev->remote->mask_keyup & 0x40000)) {
+ saa7134_input_irq(dev);
+ }
+ break;
+
+ case SAA7134_REMOTE_I2C:
+ break; /* FIXME: invoke I2C get_key() */
+
+ default: /* GPIO18 not used by IR remote */
+ break;
+ }
+ }
}
if (10 == loop) {
@@ -624,13 +580,16 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
printk(KERN_WARNING "%s/irq: looping -- "
"clearing PE (parity error!) enable bit\n",dev->name);
saa_clearl(SAA7134_IRQ2,SAA7134_IRQ2_INTE_PE);
- } else if (report & (SAA7134_IRQ_REPORT_GPIO16 |
- SAA7134_IRQ_REPORT_GPIO18)) {
- /* disable gpio IRQs */
+ } else if (report & SAA7134_IRQ_REPORT_GPIO16) {
+ /* disable gpio16 IRQ */
printk(KERN_WARNING "%s/irq: looping -- "
- "clearing GPIO enable bits\n",dev->name);
- saa_clearl(SAA7134_IRQ2, (SAA7134_IRQ2_INTE_GPIO16 |
- SAA7134_IRQ2_INTE_GPIO18));
+ "clearing GPIO16 enable bit\n",dev->name);
+ saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16);
+ } else if (report & SAA7134_IRQ_REPORT_GPIO18) {
+ /* disable gpio18 IRQs */
+ printk(KERN_WARNING "%s/irq: looping -- "
+ "clearing GPIO18 enable bit\n",dev->name);
+ saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18);
} else {
/* disable all irqs */
printk(KERN_WARNING "%s/irq: looping -- "
@@ -711,10 +670,14 @@ static int saa7134_hwinit2(struct saa7134_dev *dev)
SAA7134_IRQ2_INTE_PE |
SAA7134_IRQ2_INTE_AR;
- if (dev->has_remote == SAA7134_REMOTE_GPIO)
- irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18 |
- SAA7134_IRQ2_INTE_GPIO18A |
- SAA7134_IRQ2_INTE_GPIO16 );
+ if (dev->has_remote == SAA7134_REMOTE_GPIO) {
+ if (dev->remote->mask_keydown & 0x10000)
+ irq2_mask |= SAA7134_IRQ2_INTE_GPIO16;
+ else if (dev->remote->mask_keydown & 0x40000)
+ irq2_mask |= SAA7134_IRQ2_INTE_GPIO18;
+ else if (dev->remote->mask_keyup & 0x40000)
+ irq2_mask |= SAA7134_IRQ2_INTE_GPIO18A;
+ }
saa_writel(SAA7134_IRQ1, 0);
saa_writel(SAA7134_IRQ2, irq2_mask);
@@ -1156,7 +1119,7 @@ static int saa7134_init(void)
printk(KERN_INFO "saa7130/34: snapshot date %04d-%02d-%02d\n",
SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
#endif
- return pci_module_init(&saa7134_pci_driver);
+ return pci_register_driver(&saa7134_pci_driver);
}
static void saa7134_fini(void)
@@ -1173,7 +1136,6 @@ module_exit(saa7134_fini);
/* ----------------------------------------------------------- */
-EXPORT_SYMBOL(saa7134_print_ioctl);
EXPORT_SYMBOL(saa7134_i2c_call_clients);
EXPORT_SYMBOL(saa7134_devlist);
EXPORT_SYMBOL(saa7134_boards);
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index e016480c3468..399f9952596c 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -31,6 +31,7 @@
#include "saa7134-reg.h"
#include "saa7134.h"
+#include <media/v4l2-common.h>
#ifdef HAVE_MT352
# include "mt352.h"
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index 575f3e835f91..bd4c389d4c37 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -29,6 +29,7 @@
#include "saa7134.h"
#include <media/saa6752hs.h>
+#include <media/v4l2-common.h>
/* ------------------------------------------------------------------ */
@@ -163,7 +164,7 @@ static int ts_do_ioctl(struct inode *inode, struct file *file,
struct saa7134_dev *dev = file->private_data;
if (debug > 1)
- saa7134_print_ioctl(dev->name,cmd);
+ v4l_print_ioctl(dev->name,cmd);
switch (cmd) {
case VIDIOC_QUERYCAP:
{
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 1792d03d621d..6162550c4136 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -30,6 +30,7 @@
#include "saa7134-reg.h"
#include "saa7134.h"
+#include <media/v4l2-common.h>
/* ----------------------------------------------------------- */
@@ -390,9 +391,7 @@ static struct i2c_algorithm saa7134_algo = {
static struct i2c_adapter saa7134_adap_template = {
.owner = THIS_MODULE,
-#ifdef I2C_CLASS_TV_ANALOG
.class = I2C_CLASS_TV_ANALOG,
-#endif
.name = "saa7134",
.id = I2C_HW_SAA7134,
.algo = &saa7134_algo,
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index ab75ca5ac356..82d28cbf289f 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -56,23 +56,23 @@ static IR_KEYTAB_TYPE flyvideo_codes[IR_KEYTAB_SIZE] = {
[ 12 ] = KEY_KP8,
[ 13 ] = KEY_KP9,
- [ 14 ] = KEY_TUNER, // Air/Cable
+ [ 14 ] = KEY_MODE, // Air/Cable
[ 17 ] = KEY_VIDEO, // Video
[ 21 ] = KEY_AUDIO, // Audio
- [ 0 ] = KEY_POWER, // Pover
+ [ 0 ] = KEY_POWER, // Power
+ [ 24 ] = KEY_TUNER, // AV Source
[ 2 ] = KEY_ZOOM, // Fullscreen
+ [ 26 ] = KEY_LANGUAGE, // Stereo
[ 27 ] = KEY_MUTE, // Mute
- [ 20 ] = KEY_VOLUMEUP,
- [ 23 ] = KEY_VOLUMEDOWN,
+ [ 20 ] = KEY_VOLUMEUP, // Volume +
+ [ 23 ] = KEY_VOLUMEDOWN, // Volume -
[ 18 ] = KEY_CHANNELUP, // Channel +
[ 19 ] = KEY_CHANNELDOWN, // Channel -
- [ 6 ] = KEY_AGAIN, // Recal
- [ 16 ] = KEY_KPENTER, // Enter
-
- [ 26 ] = KEY_F22, // Stereo
- [ 24 ] = KEY_EDIT, // AV Source
+ [ 6 ] = KEY_AGAIN, // Recall
+ [ 16 ] = KEY_ENTER, // Enter
};
+
static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = {
[ 0 ] = KEY_KP0,
[ 1 ] = KEY_KP1,
@@ -543,12 +543,22 @@ static int build_key(struct saa7134_dev *dev)
dprintk("build_key gpio=0x%x mask=0x%x data=%d\n",
gpio, ir->mask_keycode, data);
- if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
- (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
- ir_input_keydown(ir->dev, &ir->ir, data, data);
- } else {
- ir_input_nokey(ir->dev, &ir->ir);
+ if (ir->polling) {
+ if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
+ (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
+ ir_input_keydown(ir->dev, &ir->ir, data, data);
+ } else {
+ ir_input_nokey(ir->dev, &ir->ir);
+ }
+ }
+ else { /* IRQ driven mode - handle key press and release in one go */
+ if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
+ (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
+ ir_input_keydown(ir->dev, &ir->ir, data, data);
+ ir_input_nokey(ir->dev, &ir->ir);
+ }
}
+
return 0;
}
@@ -686,6 +696,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
polling = 50; // ms
break;
case SAA7134_BOARD_VIDEOMATE_TV_PVR:
+ case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
ir_codes = videomate_tv_pvr_codes;
mask_keycode = 0x00003F;
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
index 8badd2a9cb2f..7448e386a804 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -373,6 +373,42 @@ static ssize_t dsp_write(struct file *file, const char __user *buffer,
return -EINVAL;
}
+static const char *osspcm_ioctls[] = {
+ "RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT",
+ "CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS",
+ "GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER",
+ "GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO",
+ "SETDUPLEX", "GETODELAY"
+};
+#define OSSPCM_IOCTLS ARRAY_SIZE(osspcm_ioctls)
+
+static void saa7134_oss_print_ioctl(char *name, unsigned int cmd)
+{
+ char *dir;
+
+ switch (_IOC_DIR(cmd)) {
+ case _IOC_NONE: dir = "--"; break;
+ case _IOC_READ: dir = "r-"; break;
+ case _IOC_WRITE: dir = "-w"; break;
+ case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
+ default: dir = "??"; break;
+ }
+ switch (_IOC_TYPE(cmd)) {
+ case 'P':
+ printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n",
+ name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ?
+ osspcm_ioctls[_IOC_NR(cmd)] : "???");
+ break;
+ case 'M':
+ printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n",
+ name, cmd, dir, _IOC_NR(cmd));
+ break;
+ default:
+ printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
+ name, cmd, dir, _IOC_NR(cmd));
+ }
+}
+
static int dsp_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -382,7 +418,7 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
int val = 0;
if (debug > 1)
- saa7134_print_ioctl(dev->name,cmd);
+ saa7134_oss_print_ioctl(dev->name,cmd);
switch (cmd) {
case OSS_GETVERSION:
return put_user(SOUND_VERSION, p);
@@ -678,7 +714,7 @@ static int mixer_ioctl(struct inode *inode, struct file *file,
int __user *p = argp;
if (debug > 1)
- saa7134_print_ioctl(dev->name,cmd);
+ saa7134_oss_print_ioctl(dev->name,cmd);
switch (cmd) {
case OSS_GETVERSION:
return put_user(SOUND_VERSION, p);
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 45c852df13ed..adfa8fe49a11 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -29,6 +29,7 @@
#include "saa7134-reg.h"
#include "saa7134.h"
+#include <media/v4l2-common.h>
/* Include V4L1 specific functions. Should be removed soon */
#include <linux/videodev.h>
@@ -1689,7 +1690,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
int err;
if (video_debug > 1)
- saa7134_print_ioctl(dev->name,cmd);
+ v4l_print_ioctl(dev->name,cmd);
switch (cmd) {
case VIDIOC_S_CTRL:
@@ -2142,7 +2143,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
struct saa7134_dev *dev = fh->dev;
if (video_debug > 1)
- saa7134_print_ioctl(dev->name,cmd);
+ v4l_print_ioctl(dev->name,cmd);
switch (cmd) {
case VIDIOC_QUERYCAP:
{
@@ -2262,6 +2263,7 @@ static struct file_operations video_fops =
.poll = video_poll,
.mmap = video_mmap,
.ioctl = video_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
@@ -2271,6 +2273,7 @@ static struct file_operations radio_fops =
.open = video_open,
.release = video_release,
.ioctl = radio_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index add49db1ad41..e70eae8d29bb 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -37,6 +37,9 @@
#include <media/ir-common.h>
#include <media/ir-kbd-i2c.h>
#include <media/video-buf.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
#include <media/video-buf-dvb.h>
#ifndef TRUE
@@ -47,10 +50,6 @@
#endif
#define UNSET (-1U)
-#include <sound/driver.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-
/* ----------------------------------------------------------- */
/* enums */
@@ -209,6 +208,8 @@ struct saa7134_format {
#define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80
#define SAA7134_BOARD_PHILIPS_TIGER 81
#define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS 82
+#define SAA7134_BOARD_CINERGY250PCI 83
+#define SAA7134_BOARD_FLYDVB_TRIO 84
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
@@ -546,7 +547,6 @@ struct saa7134_dev {
extern struct list_head saa7134_devlist;
-void saa7134_print_ioctl(char *name, unsigned int cmd);
void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
#define SAA7134_PGTABLE_SIZE 4096
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
index d4497dbae05c..6ee54a45411f 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -1974,6 +1974,7 @@ static struct file_operations saa_fops =
.open = saa_open,
.release = saa_release,
.ioctl = saa_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.read = saa_read,
.llseek = no_llseek,
.write = saa_write,
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
index 549c9929f107..99261f15e66e 100644
--- a/drivers/media/video/tda7432.c
+++ b/drivers/media/video/tda7432.c
@@ -50,6 +50,7 @@
#include "bttv.h"
#include <media/audiochip.h>
+#include <media/v4l2-common.h>
#ifndef VIDEO_AUDIO_BALANCE
# define VIDEO_AUDIO_BALANCE 32
@@ -90,9 +91,6 @@ struct tda7432 {
static struct i2c_driver driver;
static struct i2c_client client_template;
-#define dprintk if (debug) printk
-#define d2printk if (debug > 1) printk
-
/* The TDA7432 is made by STS-Thompson
* http://www.st.com
* http://us.st.com/stonline/books/pdf/docs/4056.pdf
@@ -229,12 +227,12 @@ static struct i2c_client client_template;
static int tda7432_write(struct i2c_client *client, int subaddr, int val)
{
unsigned char buffer[2];
- d2printk("tda7432: In tda7432_write\n");
- dprintk("tda7432: Writing %d 0x%x\n", subaddr, val);
+ v4l_dbg(2,client,"In tda7432_write\n");
+ v4l_dbg(1,client,"Writing %d 0x%x\n", subaddr, val);
buffer[0] = subaddr;
buffer[1] = val;
if (2 != i2c_master_send(client,buffer,2)) {
- printk(KERN_WARNING "tda7432: I/O error, trying (write %d 0x%x)\n",
+ v4l_err(client,"I/O error, trying (write %d 0x%x)\n",
subaddr, val);
return -1;
}
@@ -247,9 +245,9 @@ static int tda7432_set(struct i2c_client *client)
{
struct tda7432 *t = i2c_get_clientdata(client);
unsigned char buf[16];
- d2printk("tda7432: In tda7432_set\n");
+ v4l_dbg(2,client,"In tda7432_set\n");
- dprintk(KERN_INFO
+ v4l_dbg(1,client,
"tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
t->input,t->volume,t->bass,t->treble,t->lf,t->lr,t->rf,t->rr,t->loud);
buf[0] = TDA7432_IN;
@@ -263,7 +261,7 @@ static int tda7432_set(struct i2c_client *client)
buf[8] = t->rr;
buf[9] = t->loud;
if (10 != i2c_master_send(client,buf,10)) {
- printk(KERN_WARNING "tda7432: I/O error, trying tda7432_set\n");
+ v4l_err(client,"I/O error, trying tda7432_set\n");
return -1;
}
@@ -273,7 +271,7 @@ static int tda7432_set(struct i2c_client *client)
static void do_tda7432_init(struct i2c_client *client)
{
struct tda7432 *t = i2c_get_clientdata(client);
- d2printk("tda7432: In tda7432_init\n");
+ v4l_dbg(2,client,"In tda7432_init\n");
t->input = TDA7432_STEREO_IN | /* Main (stereo) input */
TDA7432_BASS_SYM | /* Symmetric bass cut */
@@ -301,7 +299,6 @@ static int tda7432_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct tda7432 *t;
struct i2c_client *client;
- d2printk("tda7432: In tda7432_attach\n");
t = kmalloc(sizeof *t,GFP_KERNEL);
if (!t)
@@ -315,21 +312,16 @@ static int tda7432_attach(struct i2c_adapter *adap, int addr, int kind)
i2c_set_clientdata(client, t);
do_tda7432_init(client);
- printk(KERN_INFO "tda7432: init\n");
-
i2c_attach_client(client);
+
+ v4l_info(client, "chip found @ 0x%x (%s)\n", addr << 1, adap->name);
return 0;
}
static int tda7432_probe(struct i2c_adapter *adap)
{
-#ifdef I2C_CLASS_TV_ANALOG
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, tda7432_attach);
-#else
- if (adap->id == I2C_HW_B_BT848)
- return i2c_probe(adap, &addr_data, tda7432_attach);
-#endif
return 0;
}
@@ -348,7 +340,9 @@ static int tda7432_command(struct i2c_client *client,
unsigned int cmd, void *arg)
{
struct tda7432 *t = i2c_get_clientdata(client);
- d2printk("tda7432: In tda7432_command\n");
+ v4l_dbg(2,client,"In tda7432_command\n");
+ if (debug>1)
+ v4l_i2c_print_ioctl(client,cmd);
switch (cmd) {
/* --- v4l ioctls --- */
@@ -359,7 +353,6 @@ static int tda7432_command(struct i2c_client *client,
case VIDIOCGAUDIO:
{
struct video_audio *va = arg;
- dprintk("tda7432: VIDIOCGAUDIO\n");
va->flags |= VIDEO_AUDIO_VOLUME |
VIDEO_AUDIO_BASS |
@@ -414,7 +407,6 @@ static int tda7432_command(struct i2c_client *client,
case VIDIOCSAUDIO:
{
struct video_audio *va = arg;
- dprintk("tda7432: VIDEOCSAUDIO\n");
if(va->flags & VIDEO_AUDIO_VOLUME){
if(!maxvol){ /* max +20db */
@@ -490,11 +482,6 @@ static int tda7432_command(struct i2c_client *client,
} /* end of VIDEOCSAUDIO case */
- default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */
-
- /* nothing */
- d2printk("tda7432: Default\n");
-
} /* end of (cmd) switch */
return 0;
@@ -502,7 +489,7 @@ static int tda7432_command(struct i2c_client *client,
static struct i2c_driver driver = {
.driver = {
- .name = "i2c tda7432 driver",
+ .name = "tda7432",
},
.id = I2C_DRIVERID_TDA7432,
.attach_adapter = tda7432_probe,
@@ -519,7 +506,7 @@ static struct i2c_client client_template =
static int __init tda7432_init(void)
{
if ( (loudness < 0) || (loudness > 15) ) {
- printk(KERN_ERR "tda7432: loudness parameter must be between 0 and 15\n");
+ printk(KERN_ERR "loudness parameter must be between 0 and 15\n");
return -EINVAL;
}
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index 61d94ddaff41..2498b76df429 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -398,14 +398,8 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
return 0;
}
-
/*---------------------------------------------------------------------*/
-#define V4L2_STD_MN (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC)
-#define V4L2_STD_B (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B)
-#define V4L2_STD_GH (V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H)
-#define V4L2_STD_DK (V4L2_STD_PAL_DK|V4L2_STD_SECAM_DK)
-
static void set_audio(struct tuner *t)
{
char* mode;
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
index 9c3ecf7a0fed..299393bf900a 100644
--- a/drivers/media/video/tda9875.c
+++ b/drivers/media/video/tda9875.c
@@ -257,13 +257,8 @@ static int tda9875_attach(struct i2c_adapter *adap, int addr, int kind)
static int tda9875_probe(struct i2c_adapter *adap)
{
-#ifdef I2C_CLASS_TV_ANALOG
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, tda9875_attach);
-#else
- if (adap->id == I2C_HW_B_BT848)
- return i2c_probe(adap, &addr_data, tda9875_attach);
-#endif
return 0;
}
@@ -373,7 +368,7 @@ static int tda9875_command(struct i2c_client *client,
static struct i2c_driver driver = {
.driver = {
- .name = "i2c tda9875 driver",
+ .name = "tda9875",
},
.id = I2C_DRIVERID_TDA9875,
.attach_adapter = tda9875_probe,
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index 7165a1b9625a..9cf47dc65579 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -9,7 +9,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
-#include <media/audiochip.h>
+#include <media/v4l2-common.h>
#include <media/tuner.h>
@@ -57,7 +57,6 @@ struct tda9887 {
v4l2_std_id std;
enum tuner_mode mode;
unsigned int config;
- unsigned int pinnacle_id;
unsigned int using_v4l2;
unsigned int radio_mode;
unsigned char data[4];
@@ -115,6 +114,9 @@ static struct i2c_client client_template;
#define cAudioGain0 0x00 // bit c7
#define cAudioGain6 0x80 // bit c7
+#define cTopMask 0x1f // bit c0:4
+#define cTopPalSecamDefault 0x14 // bit c0:4
+#define cTopNtscRadioDefault 0x10 // bit c0:4
//// third reg (e)
#define cAudioIF_4_5 0x00 // bit e0:1
@@ -146,13 +148,15 @@ static struct i2c_client client_template;
static struct tvnorm tvnorms[] = {
{
- .std = V4L2_STD_PAL_BG,
- .name = "PAL-BG",
+ .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
+ .name = "PAL-BGHN",
.b = ( cNegativeFmTV |
cQSS ),
.c = ( cDeemphasisON |
- cDeemphasis50 ),
- .e = ( cAudioIF_5_5 |
+ cDeemphasis50 |
+ cTopPalSecamDefault),
+ .e = ( cGating_36 |
+ cAudioIF_5_5 |
cVideoIF_38_90 ),
},{
.std = V4L2_STD_PAL_I,
@@ -160,8 +164,10 @@ static struct tvnorm tvnorms[] = {
.b = ( cNegativeFmTV |
cQSS ),
.c = ( cDeemphasisON |
- cDeemphasis50 ),
- .e = ( cAudioIF_6_0 |
+ cDeemphasis50 |
+ cTopPalSecamDefault),
+ .e = ( cGating_36 |
+ cAudioIF_6_0 |
cVideoIF_38_90 ),
},{
.std = V4L2_STD_PAL_DK,
@@ -169,52 +175,80 @@ static struct tvnorm tvnorms[] = {
.b = ( cNegativeFmTV |
cQSS ),
.c = ( cDeemphasisON |
- cDeemphasis50 ),
- .e = ( cAudioIF_6_5 |
- cVideoIF_38_00 ),
+ cDeemphasis50 |
+ cTopPalSecamDefault),
+ .e = ( cGating_36 |
+ cAudioIF_6_5 |
+ cVideoIF_38_90 ),
},{
- .std = V4L2_STD_PAL_M | V4L2_STD_PAL_N,
- .name = "PAL-M/N",
+ .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
+ .name = "PAL-M/Nc",
.b = ( cNegativeFmTV |
cQSS ),
.c = ( cDeemphasisON |
- cDeemphasis75 ),
- .e = ( cAudioIF_4_5 |
+ cDeemphasis75 |
+ cTopNtscRadioDefault),
+ .e = ( cGating_36 |
+ cAudioIF_4_5 |
cVideoIF_45_75 ),
},{
+ .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
+ .name = "SECAM-BGH",
+ .b = ( cPositiveAmTV |
+ cQSS ),
+ .c = ( cTopPalSecamDefault),
+ .e = ( cGating_36 |
+ cAudioIF_5_5 |
+ cVideoIF_38_90 ),
+ },{
.std = V4L2_STD_SECAM_L,
.name = "SECAM-L",
.b = ( cPositiveAmTV |
cQSS ),
+ .c = ( cTopPalSecamDefault),
.e = ( cGating_36 |
cAudioIF_6_5 |
cVideoIF_38_90 ),
},{
+ .std = V4L2_STD_SECAM_LC,
+ .name = "SECAM-L'",
+ .b = ( cOutputPort2Inactive |
+ cPositiveAmTV |
+ cQSS ),
+ .c = ( cTopPalSecamDefault),
+ .e = ( cGating_36 |
+ cAudioIF_6_5 |
+ cVideoIF_33_90 ),
+ },{
.std = V4L2_STD_SECAM_DK,
.name = "SECAM-DK",
.b = ( cNegativeFmTV |
cQSS ),
.c = ( cDeemphasisON |
- cDeemphasis50 ),
- .e = ( cAudioIF_6_5 |
- cVideoIF_38_00 ),
+ cDeemphasis50 |
+ cTopPalSecamDefault),
+ .e = ( cGating_36 |
+ cAudioIF_6_5 |
+ cVideoIF_38_90 ),
},{
.std = V4L2_STD_NTSC_M,
.name = "NTSC-M",
.b = ( cNegativeFmTV |
cQSS ),
.c = ( cDeemphasisON |
- cDeemphasis75 ),
+ cDeemphasis75 |
+ cTopNtscRadioDefault),
.e = ( cGating_36 |
cAudioIF_4_5 |
cVideoIF_45_75 ),
},{
.std = V4L2_STD_NTSC_M_JP,
- .name = "NTSC-JP",
+ .name = "NTSC-M-JP",
.b = ( cNegativeFmTV |
cQSS ),
.c = ( cDeemphasisON |
- cDeemphasis50 ),
+ cDeemphasis50 |
+ cTopNtscRadioDefault),
.e = ( cGating_36 |
cAudioIF_4_5 |
cVideoIF_58_75 ),
@@ -226,8 +260,10 @@ static struct tvnorm radio_stereo = {
.b = ( cFmRadio |
cQSS ),
.c = ( cDeemphasisOFF |
- cAudioGain6 ),
- .e = ( cAudioIF_5_5 |
+ cAudioGain6 |
+ cTopNtscRadioDefault),
+ .e = ( cTunerGainLow |
+ cAudioIF_5_5 |
cRadioIF_38_90 ),
};
@@ -236,8 +272,10 @@ static struct tvnorm radio_mono = {
.b = ( cFmRadio |
cQSS ),
.c = ( cDeemphasisON |
- cDeemphasis50),
- .e = ( cAudioIF_5_5 |
+ cDeemphasis75 |
+ cTopNtscRadioDefault),
+ .e = ( cTunerGainLow |
+ cAudioIF_5_5 |
cRadioIF_38_90 ),
};
@@ -400,7 +438,8 @@ static int tda9887_set_tvnorm(struct tda9887 *t, char *buf)
static unsigned int port1 = UNSET;
static unsigned int port2 = UNSET;
static unsigned int qss = UNSET;
-static unsigned int adjust = 0x10;
+static unsigned int adjust = UNSET;
+
module_param(port1, int, 0644);
module_param(port2, int, 0644);
module_param(qss, int, 0644);
@@ -428,8 +467,10 @@ static int tda9887_set_insmod(struct tda9887 *t, char *buf)
buf[1] &= ~cQSS;
}
- if (adjust >= 0x00 && adjust < 0x20)
+ if (adjust >= 0x00 && adjust < 0x20) {
+ buf[2] &= ~cTopMask;
buf[2] |= adjust;
+ }
return 0;
}
@@ -465,6 +506,10 @@ static int tda9887_set_config(struct tda9887 *t, char *buf)
break;
}
}
+ if (t->config & TDA9887_TOP_SET) {
+ buf[2] &= ~cTopMask;
+ buf[2] |= (t->config >> 8) & cTopMask;
+ }
if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
buf[1] &= ~cQSS;
return 0;
@@ -472,38 +517,13 @@ static int tda9887_set_config(struct tda9887 *t, char *buf)
/* ---------------------------------------------------------------------- */
-static int tda9887_set_pinnacle(struct tda9887 *t, char *buf)
-{
- unsigned int bCarrierMode = UNSET;
-
- if (t->std & V4L2_STD_625_50) {
- if ((1 == t->pinnacle_id) || (7 == t->pinnacle_id)) {
- bCarrierMode = cIntercarrier;
- } else {
- bCarrierMode = cQSS;
- }
- }
- if (t->std & V4L2_STD_525_60) {
- if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) {
- bCarrierMode = cIntercarrier;
- } else {
- bCarrierMode = cQSS;
- }
- }
-
- if (bCarrierMode != UNSET) {
- buf[1] &= ~0x04;
- buf[1] |= bCarrierMode;
- }
- return 0;
-}
-
-/* ---------------------------------------------------------------------- */
+static char pal[] = "--";
+static char secam[] = "--";
+static char ntsc[] = "-";
-static char pal[] = "-";
module_param_string(pal, pal, sizeof(pal), 0644);
-static char secam[] = "-";
module_param_string(secam, secam, sizeof(secam), 0644);
+module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
static int tda9887_fixup_std(struct tda9887 *t)
{
@@ -514,8 +534,17 @@ static int tda9887_fixup_std(struct tda9887 *t)
case 'B':
case 'g':
case 'G':
- tda9887_dbg("insmod fixup: PAL => PAL-BG\n");
- t->std = V4L2_STD_PAL_BG;
+ case 'h':
+ case 'H':
+ case 'n':
+ case 'N':
+ if (pal[1] == 'c' || pal[1] == 'C') {
+ tda9887_dbg("insmod fixup: PAL => PAL-Nc\n");
+ t->std = V4L2_STD_PAL_Nc;
+ } else {
+ tda9887_dbg("insmod fixup: PAL => PAL-BGHN\n");
+ t->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N;
+ }
break;
case 'i':
case 'I':
@@ -529,6 +558,11 @@ static int tda9887_fixup_std(struct tda9887 *t)
tda9887_dbg("insmod fixup: PAL => PAL-DK\n");
t->std = V4L2_STD_PAL_DK;
break;
+ case 'm':
+ case 'M':
+ tda9887_dbg("insmod fixup: PAL => PAL-M\n");
+ t->std = V4L2_STD_PAL_M;
+ break;
case '-':
/* default parameter, do nothing */
break;
@@ -539,6 +573,15 @@ static int tda9887_fixup_std(struct tda9887 *t)
}
if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
switch (secam[0]) {
+ case 'b':
+ case 'B':
+ case 'g':
+ case 'G':
+ case 'h':
+ case 'H':
+ tda9887_dbg("insmod fixup: SECAM => SECAM-BGH\n");
+ t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
+ break;
case 'd':
case 'D':
case 'k':
@@ -548,8 +591,13 @@ static int tda9887_fixup_std(struct tda9887 *t)
break;
case 'l':
case 'L':
- tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
- t->std = V4L2_STD_SECAM_L;
+ if (secam[1] == 'c' || secam[1] == 'C') {
+ tda9887_dbg("insmod fixup: SECAM => SECAM-L'\n");
+ t->std = V4L2_STD_SECAM_LC;
+ } else {
+ tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
+ t->std = V4L2_STD_SECAM_L;
+ }
break;
case '-':
/* default parameter, do nothing */
@@ -559,6 +607,26 @@ static int tda9887_fixup_std(struct tda9887 *t)
break;
}
}
+ if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
+ switch (ntsc[0]) {
+ case 'm':
+ case 'M':
+ tda9887_dbg("insmod fixup: NTSC => NTSC-M\n");
+ t->std = V4L2_STD_NTSC_M;
+ break;
+ case 'j':
+ case 'J':
+ tda9887_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
+ t->std = V4L2_STD_NTSC_M_JP;
+ break;
+ case '-':
+ /* default parameter, do nothing */
+ break;
+ default:
+ tda9887_info("ntsc= argument not recognised\n");
+ break;
+ }
+ }
return 0;
}
@@ -581,12 +649,22 @@ static int tda9887_configure(struct tda9887 *t)
memset(t->data,0,sizeof(t->data));
tda9887_set_tvnorm(t,t->data);
+ /* A note on the port settings:
+ These settings tend to depend on the specifics of the board.
+ By default they are set to inactive (bit value 1) by this driver,
+ overwriting any changes made by the tvnorm. This means that it
+ is the responsibility of the module using the tda9887 to set
+ these values in case of changes in the tvnorm.
+ In many cases port 2 should be made active (0) when selecting
+ SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.
+
+ For the other standards the tda9887 application note says that
+ the ports should be set to active (0), but, again, that may
+ differ depending on the precise hardware configuration.
+ */
t->data[1] |= cOutputPort1Inactive;
t->data[1] |= cOutputPort2Inactive;
- if (UNSET != t->pinnacle_id) {
- tda9887_set_pinnacle(t,t->data);
- }
tda9887_set_config(t,t->data);
tda9887_set_insmod(t,t->data);
@@ -594,7 +672,6 @@ static int tda9887_configure(struct tda9887 *t)
t->data[1] |= cForcedMuteAudioON;
}
-
tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
t->data[1],t->data[2],t->data[3]);
if (debug > 1)
@@ -625,7 +702,6 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
t->client = client_template;
t->std = 0;
- t->pinnacle_id = UNSET;
t->radio_mode = V4L2_TUNER_MODE_STEREO;
tda9887_info("chip found @ 0x%x (%s)\n", addr<<1, adap->name);
@@ -638,18 +714,8 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
static int tda9887_probe(struct i2c_adapter *adap)
{
-#ifdef I2C_CLASS_TV_ANALOG
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, tda9887_attach);
-#else
- switch (adap->id) {
- case I2C_HW_B_BT848:
- case I2C_HW_B_RIVA:
- case I2C_HW_SAA7134:
- return i2c_probe(adap, &addr_data, tda9887_attach);
- break;
- }
-#endif
return 0;
}
@@ -689,14 +755,6 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
tda9887_configure(t);
break;
}
- case AUDC_CONFIG_PINNACLE:
- {
- int *i = arg;
-
- t->pinnacle_id = *i;
- tda9887_configure(t);
- break;
- }
case TDA9887_SET_CONFIG:
{
int *i = arg;
@@ -787,7 +845,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
}
case VIDIOC_LOG_STATUS:
{
- tda9887_info("Data bytes: b=%02x c=%02x e=%02x\n", t->data[1], t->data[2], t->data[3]);
+ tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->data[1], t->data[2], t->data[3]);
break;
}
default:
@@ -824,7 +882,7 @@ static struct i2c_driver driver = {
.detach_client = tda9887_detach,
.command = tda9887_command,
.driver = {
- .name = "i2c tda9887 driver",
+ .name = "tda9887",
.suspend = tda9887_suspend,
.resume = tda9887_resume,
},
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index a9375ef05de1..261b7a3c0417 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/video/tea5767.c
@@ -17,6 +17,9 @@
#define PREFIX "TEA5767 "
+/* from tuner-core.c */
+extern int debug;
+
/*****************************************************************************/
/******************************
@@ -246,7 +249,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq)
if (5 != (rc = i2c_master_send(c, buffer, 5)))
tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
- if (tuner_debug) {
+ if (debug) {
if (5 != (rc = i2c_master_recv(c, buffer, 5)))
tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
else
@@ -264,7 +267,7 @@ static int tea5767_signal(struct i2c_client *c)
if (5 != (rc = i2c_master_recv(c, buffer, 5)))
tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
- return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << (13 - 4));
+ return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8);
}
static int tea5767_stereo(struct i2c_client *c)
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index c13c7b95ef35..57bc585a6955 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -20,10 +20,9 @@
#include <linux/init.h>
#include <media/tuner.h>
+#include <media/v4l2-common.h>
#include <media/audiochip.h>
-#include "msp3400.h"
-
#define UNSET (-1U)
/* standard i2c insmod options */
@@ -38,21 +37,30 @@ I2C_CLIENT_INSMOD;
/* insmod options used at init time => read/only */
static unsigned int addr = 0;
-module_param(addr, int, 0444);
-
static unsigned int no_autodetect = 0;
-module_param(no_autodetect, int, 0444);
-
static unsigned int show_i2c = 0;
-module_param(show_i2c, int, 0444);
/* insmod options used at runtime => read/write */
-unsigned int tuner_debug = 0;
-module_param(tuner_debug, int, 0644);
+static unsigned int tuner_debug = 0;
+int debug = 0;
static unsigned int tv_range[2] = { 44, 958 };
static unsigned int radio_range[2] = { 65, 108 };
+static char pal[] = "--";
+static char secam[] = "--";
+static char ntsc[] = "-";
+
+module_param(addr, int, 0444);
+module_param(no_autodetect, int, 0444);
+module_param(show_i2c, int, 0444);
+/* Note: tuner_debug is deprecated and will be removed in 2.6.17 */
+module_param(tuner_debug, int, 0444);
+module_param(debug, int, 0644);
+
+module_param_string(pal, pal, sizeof(pal), 0644);
+module_param_string(secam, secam, sizeof(secam), 0644);
+module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
module_param_array(tv_range, int, NULL, 0644);
module_param_array(radio_range, int, NULL, 0644);
@@ -249,11 +257,6 @@ static inline int check_mode(struct tuner *t, char *cmd)
return 0;
}
-static char pal[] = "-";
-module_param_string(pal, pal, sizeof(pal), 0644);
-static char secam[] = "--";
-module_param_string(secam, secam, sizeof(secam), 0644);
-
/* get more precise norm info from insmod option */
static int tuner_fixup_std(struct tuner *t)
{
@@ -285,8 +288,13 @@ static int tuner_fixup_std(struct tuner *t)
break;
case 'N':
case 'n':
- tuner_dbg ("insmod fixup: PAL => PAL-N\n");
- t->std = V4L2_STD_PAL_N;
+ if (pal[1] == 'c' || pal[1] == 'C') {
+ tuner_dbg("insmod fixup: PAL => PAL-Nc\n");
+ t->std = V4L2_STD_PAL_Nc;
+ } else {
+ tuner_dbg ("insmod fixup: PAL => PAL-N\n");
+ t->std = V4L2_STD_PAL_N;
+ }
break;
case '-':
/* default parameter, do nothing */
@@ -298,6 +306,15 @@ static int tuner_fixup_std(struct tuner *t)
}
if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
switch (secam[0]) {
+ case 'b':
+ case 'B':
+ case 'g':
+ case 'G':
+ case 'h':
+ case 'H':
+ tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n");
+ t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
+ break;
case 'd':
case 'D':
case 'k':
@@ -324,9 +341,60 @@ static int tuner_fixup_std(struct tuner *t)
}
}
+ if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
+ switch (ntsc[0]) {
+ case 'm':
+ case 'M':
+ tuner_dbg("insmod fixup: NTSC => NTSC-M\n");
+ t->std = V4L2_STD_NTSC_M;
+ break;
+ case 'j':
+ case 'J':
+ tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
+ t->std = V4L2_STD_NTSC_M_JP;
+ break;
+ case '-':
+ /* default parameter, do nothing */
+ break;
+ default:
+ tuner_info("ntsc= argument not recognised\n");
+ break;
+ }
+ }
return 0;
}
+static void tuner_status(struct i2c_client *client)
+{
+ struct tuner *t = i2c_get_clientdata(client);
+ unsigned long freq, freq_fraction;
+ const char *p;
+
+ switch (t->mode) {
+ case V4L2_TUNER_RADIO: p = "radio"; break;
+ case V4L2_TUNER_ANALOG_TV: p = "analog TV"; break;
+ case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break;
+ default: p = "undefined"; break;
+ }
+ if (t->mode == V4L2_TUNER_RADIO) {
+ freq = t->freq / 16000;
+ freq_fraction = (t->freq % 16000) * 100 / 16000;
+ } else {
+ freq = t->freq / 16;
+ freq_fraction = (t->freq % 16) * 100 / 16;
+ }
+ tuner_info("Tuner mode: %s\n", p);
+ tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction);
+ tuner_info("Standard: 0x%08llx\n", t->std);
+ if (t->mode == V4L2_TUNER_RADIO) {
+ if (t->has_signal) {
+ tuner_info("Signal strength: %d\n", t->has_signal(client));
+ }
+ if (t->is_stereo) {
+ tuner_info("Stereo: %s\n", t->is_stereo(client) ? "yes" : "no");
+ }
+ }
+}
/* ---------------------------------------------------------------------- */
/* static var Used only in tuner_attach and tuner_probe */
@@ -352,6 +420,11 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
t->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
t->audmode = V4L2_TUNER_MODE_STEREO;
t->mode_mask = T_UNINITIALIZED;
+ if (tuner_debug) {
+ debug = tuner_debug;
+ printk(KERN_ERR "tuner: tuner_debug is deprecated and will be removed in 2.6.17.\n");
+ printk(KERN_ERR "tuner: use the debug option instead.\n");
+ }
if (show_i2c) {
unsigned char buffer[16];
@@ -478,7 +551,9 @@ static inline int check_v4l2(struct tuner *t)
static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct tuner *t = i2c_get_clientdata(client);
- unsigned int *iarg = (int *)arg;
+
+ if (debug>1)
+ v4l_i2c_print_ioctl(&(t->i2c),cmd);
switch (cmd) {
/* --- configuration --- */
@@ -501,18 +576,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
t->standby (client);
break;
}
- case AUDC_CONFIG_PINNACLE:
- switch (*iarg) {
- case 2:
- tuner_dbg("pinnacle pal\n");
- t->radio_if2 = 33300 * 1000;
- break;
- case 3:
- tuner_dbg("pinnacle ntsc\n");
- t->radio_if2 = 41300 * 1000;
- break;
- }
- break;
case VIDIOCSAUDIO:
if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
return 0;
@@ -523,9 +586,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
tuner_dbg("VIDIOCSAUDIO not implemented.\n");
break;
- case MSP_SET_MATRIX:
- case TDA9887_SET_CONFIG:
- break;
/* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a
kernel pointer here... */
@@ -708,10 +768,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
}
break;
}
- default:
- tuner_dbg("Unimplemented IOCTL 0x%08x(dir=%d,tp='%c',nr=%d,sz=%d)\n",
- cmd, _IOC_DIR(cmd), _IOC_TYPE(cmd),
- _IOC_NR(cmd), _IOC_SIZE(cmd));
+ case VIDIOC_LOG_STATUS:
+ tuner_status(client);
break;
}
@@ -747,10 +805,10 @@ static struct i2c_driver driver = {
.detach_client = tuner_detach,
.command = tuner_command,
.driver = {
- .name = "tuner",
- .suspend = tuner_suspend,
- .resume = tuner_resume,
- },
+ .name = "tuner",
+ .suspend = tuner_suspend,
+ .resume = tuner_resume,
+ },
};
static struct i2c_client client_template = {
.name = "(tuner unset)",
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index e0c9fdb9914a..e5fb74365836 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -8,6 +8,10 @@
#include <linux/videodev.h>
#include <media/tuner.h>
+static int offset = 0;
+module_param(offset, int, 0666);
+MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
+
/* ---------------------------------------------------------------------- */
/* tv standard selection for Temic 4046 FM5
@@ -75,24 +79,20 @@
#define TUNER_PLL_LOCKED 0x40
#define TUNER_STEREO_MK3 0x04
+#define TUNER_MAX_RANGES 3
+
/* ---------------------------------------------------------------------- */
struct tunertype
{
char *name;
- unsigned char Vendor;
- unsigned char Type;
-
- unsigned short thresh1; /* band switch VHF_LO <=> VHF_HI */
- unsigned short thresh2; /* band switch VHF_HI <=> UHF */
- unsigned char VHF_L;
- unsigned char VHF_H;
- unsigned char UHF;
+
+ int count;
+ struct {
+ unsigned short thresh;
+ unsigned char cb;
+ } ranges[TUNER_MAX_RANGES];
unsigned char config;
- unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL,
- 732 =16*45.75 NTSCi,
- 940 =16*58.75 NTSC-Japan
- 704 =16*44 ATSC */
};
/*
@@ -102,158 +102,696 @@ struct tunertype
*/
static struct tunertype tuners[] = {
/* 0-9 */
- { "Temic PAL (4002 FH5)", TEMIC, PAL,
- 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623},
- { "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I,
- 16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
- { "Philips NTSC (FI1236,FM1236 and compatibles)", Philips, NTSC,
- 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732},
- { "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", Philips, SECAM,
- 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623},
- { "NoTuner", NoTuner, NOTUNER,
- 0,0,0x00,0x00,0x00,0x00,0x00},
- { "Philips PAL_BG (FI1216 and compatibles)", Philips, PAL,
- 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623},
- { "Temic NTSC (4032 FY5)", TEMIC, NTSC,
- 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732},
- { "Temic PAL_I (4062 FY5)", TEMIC, PAL_I,
- 16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623},
- { "Temic NTSC (4036 FY5)", TEMIC, NTSC,
- 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732},
- { "Alps HSBH1", TEMIC, NTSC,
- 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
+ [TUNER_TEMIC_PAL] = { /* TEMIC PAL */
+ .name = "Temic PAL (4002 FH5)",
+ .count = 3,
+ .ranges = {
+ { 16 * 140.25 /*MHz*/, 0x02, },
+ { 16 * 463.25 /*MHz*/, 0x04, },
+ { 16 * 999.99 , 0x01, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */
+ .name = "Philips PAL_I (FI1246 and compatibles)",
+ .count = 3,
+ .ranges = {
+ { 16 * 140.25 /*MHz*/, 0xa0, },
+ { 16 * 463.25 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_PHILIPS_NTSC] = { /* Philips NTSC */
+ .name = "Philips NTSC (FI1236,FM1236 and compatibles)",
+ .count = 3,
+ .ranges = {
+ { 16 * 157.25 /*MHz*/, 0xa0, },
+ { 16 * 451.25 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_PHILIPS_SECAM] = { /* Philips SECAM */
+ .name = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)",
+ .count = 3,
+ .ranges = {
+ { 16 * 168.25 /*MHz*/, 0xa7, },
+ { 16 * 447.25 /*MHz*/, 0x97, },
+ { 16 * 999.99 , 0x37, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_ABSENT] = { /* Tuner Absent */
+ .name = "NoTuner",
+ .count = 1,
+ .ranges = {
+ { 0, 0x00, },
+ },
+ .config = 0x00,
+ },
+ [TUNER_PHILIPS_PAL] = { /* Philips PAL */
+ .name = "Philips PAL_BG (FI1216 and compatibles)",
+ .count = 3,
+ .ranges = {
+ { 16 * 168.25 /*MHz*/, 0xa0, },
+ { 16 * 447.25 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */
+ .name = "Temic NTSC (4032 FY5)",
+ .count = 3,
+ .ranges = {
+ { 16 * 157.25 /*MHz*/, 0x02, },
+ { 16 * 463.25 /*MHz*/, 0x04, },
+ { 16 * 999.99 , 0x01, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */
+ .name = "Temic PAL_I (4062 FY5)",
+ .count = 3,
+ .ranges = {
+ { 16 * 170.00 /*MHz*/, 0x02, },
+ { 16 * 450.00 /*MHz*/, 0x04, },
+ { 16 * 999.99 , 0x01, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */
+ .name = "Temic NTSC (4036 FY5)",
+ .count = 3,
+ .ranges = {
+ { 16 * 157.25 /*MHz*/, 0xa0, },
+ { 16 * 463.25 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */
+ .name = "Alps HSBH1",
+ .count = 3,
+ .ranges = {
+ { 16 * 137.25 /*MHz*/, 0x01, },
+ { 16 * 385.25 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x08, },
+ },
+ .config = 0x8e,
+ },
/* 10-19 */
- { "Alps TSBE1", TEMIC, PAL,
- 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
- { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */
- 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632},
- { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
- 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622},
- { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
- 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608},
- { "Temic PAL_BG (4006FH5)", TEMIC, PAL,
- 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
- { "Alps TSCH6", Alps, NTSC,
- 16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
- { "Temic PAL_DK (4016 FY5)", TEMIC, PAL,
- 16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623},
- { "Philips NTSC_M (MK2)", Philips, NTSC,
- 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
- { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I,
- 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
- { "Temic PAL* auto (4006 FN5)", TEMIC, PAL,
- 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+ [TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */
+ .name = "Alps TSBE1",
+ .count = 3,
+ .ranges = {
+ { 16 * 137.25 /*MHz*/, 0x01, },
+ { 16 * 385.25 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x08, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */
+ .name = "Alps TSBB5",
+ .count = 3,
+ .ranges = {
+ { 16 * 133.25 /*MHz*/, 0x01, },
+ { 16 * 351.25 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x08, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */
+ .name = "Alps TSBE5",
+ .count = 3,
+ .ranges = {
+ { 16 * 133.25 /*MHz*/, 0x01, },
+ { 16 * 351.25 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x08, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */
+ .name = "Alps TSBC5",
+ .count = 3,
+ .ranges = {
+ { 16 * 133.25 /*MHz*/, 0x01, },
+ { 16 * 351.25 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x08, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */
+ .name = "Temic PAL_BG (4006FH5)",
+ .count = 3,
+ .ranges = {
+ { 16 * 170.00 /*MHz*/, 0xa0, },
+ { 16 * 450.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */
+ .name = "Alps TSCH6",
+ .count = 3,
+ .ranges = {
+ { 16 * 137.25 /*MHz*/, 0x14, },
+ { 16 * 385.25 /*MHz*/, 0x12, },
+ { 16 * 999.99 , 0x11, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */
+ .name = "Temic PAL_DK (4016 FY5)",
+ .count = 3,
+ .ranges = {
+ { 16 * 168.25 /*MHz*/, 0xa0, },
+ { 16 * 456.25 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */
+ .name = "Philips NTSC_M (MK2)",
+ .count = 3,
+ .ranges = {
+ { 16 * 160.00 /*MHz*/, 0xa0, },
+ { 16 * 454.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */
+ .name = "Temic PAL_I (4066 FY5)",
+ .count = 3,
+ .ranges = {
+ { 16 * 169.00 /*MHz*/, 0xa0, },
+ { 16 * 454.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */
+ .name = "Temic PAL* auto (4006 FN5)",
+ .count = 3,
+ .ranges = {
+ { 16 * 169.00 /*MHz*/, 0xa0, },
+ { 16 * 454.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
/* 20-29 */
- { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL,
- 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
- { "Temic NTSC (4039 FR5)", TEMIC, NTSC,
- 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
- { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL,
- 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
- { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL,
- 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
- { "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL,
- 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
- { "LG PAL_I+FM (TAPC-I001D)", LGINNOTEK, PAL_I,
- 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
- { "LG PAL_I (TAPC-I701D)", LGINNOTEK, PAL_I,
- 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
- { "LG NTSC+FM (TPI8NSR01F)", LGINNOTEK, NTSC,
- 16*210.00,16*497.00,0xa0,0x90,0x30,0x8e,732},
- { "LG PAL_BG+FM (TPI8PSB01D)", LGINNOTEK, PAL,
- 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
- { "LG PAL_BG (TPI8PSB11D)", LGINNOTEK, PAL,
- 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+ [TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */
+ .name = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)",
+ .count = 3,
+ .ranges = {
+ { 16 * 141.00 /*MHz*/, 0xa0, },
+ { 16 * 464.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */
+ .name = "Temic NTSC (4039 FR5)",
+ .count = 3,
+ .ranges = {
+ { 16 * 158.00 /*MHz*/, 0xa0, },
+ { 16 * 453.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */
+ .name = "Temic PAL/SECAM multi (4046 FM5)",
+ .count = 3,
+ .ranges = {
+ { 16 * 169.00 /*MHz*/, 0xa0, },
+ { 16 * 454.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */
+ .name = "Philips PAL_DK (FI1256 and compatibles)",
+ .count = 3,
+ .ranges = {
+ { 16 * 170.00 /*MHz*/, 0xa0, },
+ { 16 * 450.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */
+ .name = "Philips PAL/SECAM multi (FQ1216ME)",
+ .count = 3,
+ .ranges = {
+ { 16 * 170.00 /*MHz*/, 0xa0, },
+ { 16 * 450.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */
+ .name = "LG PAL_I+FM (TAPC-I001D)",
+ .count = 3,
+ .ranges = {
+ { 16 * 170.00 /*MHz*/, 0xa0, },
+ { 16 * 450.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */
+ .name = "LG PAL_I (TAPC-I701D)",
+ .count = 3,
+ .ranges = {
+ { 16 * 170.00 /*MHz*/, 0xa0, },
+ { 16 * 450.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */
+ .name = "LG NTSC+FM (TPI8NSR01F)",
+ .count = 3,
+ .ranges = {
+ { 16 * 210.00 /*MHz*/, 0xa0, },
+ { 16 * 497.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */
+ .name = "LG PAL_BG+FM (TPI8PSB01D)",
+ .count = 3,
+ .ranges = {
+ { 16 * 170.00 /*MHz*/, 0xa0, },
+ { 16 * 450.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_LG_PAL] = { /* LGINNOTEK PAL */
+ .name = "LG PAL_BG (TPI8PSB11D)",
+ .count = 3,
+ .ranges = {
+ { 16 * 170.00 /*MHz*/, 0xa0, },
+ { 16 * 450.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
/* 30-39 */
- { "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL,
- 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
- { "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */
- 16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940 },
- { "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */
- 16*169,16*464,0xA0,0x90,0x30,0x8e,623},
- { "MT20xx universal", Microtune, PAL|NTSC,
+ [TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */
+ .name = "Temic PAL* auto + FM (4009 FN5)",
+ .count = 3,
+ .ranges = {
+ { 16 * 141.00 /*MHz*/, 0xa0, },
+ { 16 * 464.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */
+ .name = "SHARP NTSC_JP (2U5JF5540)",
+ .count = 3,
+ .ranges = {
+ { 16 * 137.25 /*MHz*/, 0x01, },
+ { 16 * 317.25 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x08, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */
+ .name = "Samsung PAL TCPM9091PD27",
+ .count = 3,
+ .ranges = {
+ { 16 * 169 /*MHz*/, 0xa0, },
+ { 16 * 464 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_MT2032] = { /* Microtune PAL|NTSC */
+ .name = "MT20xx universal",
/* see mt20xx.c for details */ },
- { "Temic PAL_BG (4106 FH5)", TEMIC, PAL,
- 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
- { "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL,
- 16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623},
- { "Temic NTSC (4136 FY5)", TEMIC, NTSC,
- 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
- { "LG PAL (newer TAPC series)", LGINNOTEK, PAL,
- 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623},
- { "Philips PAL/SECAM multi (FM1216ME MK3)", Philips, PAL,
- 16*158.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
- { "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC,
- 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732},
+ [TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */
+ .name = "Temic PAL_BG (4106 FH5)",
+ .count = 3,
+ .ranges = {
+ { 16 * 141.00 /*MHz*/, 0xa0, },
+ { 16 * 464.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */
+ .name = "Temic PAL_DK/SECAM_L (4012 FY5)",
+ .count = 3,
+ .ranges = {
+ { 16 * 140.25 /*MHz*/, 0x02, },
+ { 16 * 463.25 /*MHz*/, 0x04, },
+ { 16 * 999.99 , 0x01, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */
+ .name = "Temic NTSC (4136 FY5)",
+ .count = 3,
+ .ranges = {
+ { 16 * 158.00 /*MHz*/, 0xa0, },
+ { 16 * 453.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */
+ .name = "LG PAL (newer TAPC series)",
+ .count = 3,
+ .ranges = {
+ { 16 * 170.00 /*MHz*/, 0x01, },
+ { 16 * 450.00 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x08, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */
+ .name = "Philips PAL/SECAM multi (FM1216ME MK3)",
+ .count = 3,
+ .ranges = {
+ { 16 * 158.00 /*MHz*/, 0x01, },
+ { 16 * 442.00 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x04, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */
+ .name = "LG NTSC (newer TAPC series)",
+ .count = 3,
+ .ranges = {
+ { 16 * 170.00 /*MHz*/, 0x01, },
+ { 16 * 450.00 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x08, },
+ },
+ .config = 0x8e,
+ },
/* 40-49 */
- { "HITACHI V7-J180AT", HITACHI, NTSC,
- 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,940 },
- { "Philips PAL_MK (FI1216 MK)", Philips, PAL,
- 16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623},
- { "Philips 1236D ATSC/NTSC daul in", Philips, ATSC,
- 16*157.25,16*454.00,0xa0,0x90,0x30,0x8e,732},
- { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC,
- 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
- { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC,
- 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
- { "Microtune 4049 FM5", Microtune, PAL,
- 16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623},
- { "Panasonic VP27s/ENGE4324D", Panasonic, NTSC,
- 16*160.00,16*454.00,0x01,0x02,0x08,0xce,940},
- { "LG NTSC (TAPE series)", LGINNOTEK, NTSC,
- 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
- { "Tenna TNF 8831 BGFF)", Philips, PAL,
- 16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
- { "Microtune 4042 FI5 ATSC/NTSC dual in", Microtune, NTSC,
- 16*162.00,16*457.00,0xa2,0x94,0x31,0x8e,732},
+ [TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */
+ .name = "HITACHI V7-J180AT",
+ .count = 3,
+ .ranges = {
+ { 16 * 170.00 /*MHz*/, 0x01, },
+ { 16 * 450.00 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x08, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */
+ .name = "Philips PAL_MK (FI1216 MK)",
+ .count = 3,
+ .ranges = {
+ { 16 * 140.25 /*MHz*/, 0x01, },
+ { 16 * 463.25 /*MHz*/, 0xc2, },
+ { 16 * 999.99 , 0xcf, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_PHILIPS_ATSC] = { /* Philips ATSC */
+ .name = "Philips 1236D ATSC/NTSC dual in",
+ .count = 3,
+ .ranges = {
+ { 16 * 157.25 /*MHz*/, 0xa0, },
+ { 16 * 454.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */
+ .name = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)",
+ .count = 3,
+ .ranges = {
+ { 16 * 160.00 /*MHz*/, 0x01, },
+ { 16 * 442.00 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x04, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_PHILIPS_4IN1] = { /* Philips NTSC */
+ .name = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)",
+ .count = 3,
+ .ranges = {
+ { 16 * 160.00 /*MHz*/, 0x01, },
+ { 16 * 442.00 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x04, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */
+ .name = "Microtune 4049 FM5",
+ .count = 3,
+ .ranges = {
+ { 16 * 141.00 /*MHz*/, 0xa0, },
+ { 16 * 464.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */
+ .name = "Panasonic VP27s/ENGE4324D",
+ .count = 3,
+ .ranges = {
+ { 16 * 160.00 /*MHz*/, 0x01, },
+ { 16 * 454.00 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x08, },
+ },
+ .config = 0xce,
+ },
+ [TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */
+ .name = "LG NTSC (TAPE series)",
+ .count = 3,
+ .ranges = {
+ { 16 * 160.00 /*MHz*/, 0x01, },
+ { 16 * 442.00 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x04, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_TNF_8831BGFF] = { /* Philips PAL */
+ .name = "Tenna TNF 8831 BGFF)",
+ .count = 3,
+ .ranges = {
+ { 16 * 161.25 /*MHz*/, 0xa0, },
+ { 16 * 463.25 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */
+ .name = "Microtune 4042 FI5 ATSC/NTSC dual in",
+ .count = 3,
+ .ranges = {
+ { 16 * 162.00 /*MHz*/, 0xa2, },
+ { 16 * 457.00 /*MHz*/, 0x94, },
+ { 16 * 999.99 , 0x31, },
+ },
+ .config = 0x8e,
+ },
/* 50-59 */
- { "TCL 2002N", TCL, NTSC,
- 16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732},
- { "Philips PAL/SECAM_D (FM 1256 I-H3)", Philips, PAL,
- 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
- { "Thomson DDT 7610 (ATSC/NTSC)", THOMSON, ATSC,
- 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732},
- { "Philips FQ1286", Philips, NTSC,
- 16*160.00,16*454.00,0x41,0x42,0x04,0x8e,940}, /* UHF band untested */
- { "tda8290+75", Philips, PAL|NTSC,
+ [TUNER_TCL_2002N] = { /* TCL NTSC */
+ .name = "TCL 2002N",
+ .count = 3,
+ .ranges = {
+ { 16 * 172.00 /*MHz*/, 0x01, },
+ { 16 * 448.00 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x08, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */
+ .name = "Philips PAL/SECAM_D (FM 1256 I-H3)",
+ .count = 3,
+ .ranges = {
+ { 16 * 160.00 /*MHz*/, 0x01, },
+ { 16 * 442.00 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x04, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */
+ .name = "Thomson DTT 7610 (ATSC/NTSC)",
+ .count = 3,
+ .ranges = {
+ { 16 * 157.25 /*MHz*/, 0x39, },
+ { 16 * 454.00 /*MHz*/, 0x3a, },
+ { 16 * 999.99 , 0x3c, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */
+ .name = "Philips FQ1286",
+ .count = 3,
+ .ranges = {
+ { 16 * 160.00 /*MHz*/, 0x41, },
+ { 16 * 454.00 /*MHz*/, 0x42, },
+ { 16 * 999.99 , 0x04, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */
+ .name = "tda8290+75",
/* see tda8290.c for details */ },
- { "TCL 2002MB", TCL, PAL,
- 16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623},
- { "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL,
- 16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 },
- { "Philips FQ1236A MK4", Philips, NTSC,
- 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
- { "Ymec TVision TVF-8531MF/8831MF/8731MF", Philips, NTSC,
- 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
- { "Ymec TVision TVF-5533MF", Philips, NTSC,
- 16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732},
+ [TUNER_TCL_2002MB] = { /* TCL PAL */
+ .name = "TCL 2002MB",
+ .count = 3,
+ .ranges = {
+ { 16 * 170.00 /*MHz*/, 0x01, },
+ { 16 * 450.00 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x08, },
+ },
+ .config = 0xce,
+ },
+ [TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */
+ .name = "Philips PAL/SECAM multi (FQ1216AME MK4)",
+ .count = 3,
+ .ranges = {
+ { 16 * 160.00 /*MHz*/, 0x01, },
+ { 16 * 442.00 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x04, },
+ },
+ .config = 0xce,
+ },
+ [TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */
+ .name = "Philips FQ1236A MK4",
+ .count = 3,
+ .ranges = {
+ { 16 * 160.00 /*MHz*/, 0x01, },
+ { 16 * 442.00 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x04, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */
+ .name = "Ymec TVision TVF-8531MF/8831MF/8731MF",
+ .count = 3,
+ .ranges = {
+ { 16 * 160.00 /*MHz*/, 0xa0, },
+ { 16 * 454.00 /*MHz*/, 0x90, },
+ { 16 * 999.99 , 0x30, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */
+ .name = "Ymec TVision TVF-5533MF",
+ .count = 3,
+ .ranges = {
+ { 16 * 160.00 /*MHz*/, 0x01, },
+ { 16 * 454.00 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x04, },
+ },
+ .config = 0x8e,
+ },
/* 60-69 */
- { "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC,
- 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732},
- { "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL,
- 16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623},
- { "Philips TEA5767HN FM Radio", Philips, RADIO,
+ [TUNER_THOMSON_DTT761X] = { /* THOMSON ATSC */
+ /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
+ .name = "Thomson DTT 761X (ATSC/NTSC)",
+ .count = 3,
+ .ranges = {
+ { 16 * 145.25 /*MHz*/, 0x39, },
+ { 16 * 415.25 /*MHz*/, 0x3a, },
+ { 16 * 999.99 , 0x3c, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_TENA_9533_DI] = { /* Philips PAL */
+ .name = "Tena TNF9533-D/IF/TNF9533-B/DF",
+ .count = 3,
+ .ranges = {
+ { 16 * 160.25 /*MHz*/, 0x01, },
+ { 16 * 464.25 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x04, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_TEA5767] = { /* Philips RADIO */
+ .name = "Philips TEA5767HN FM Radio",
/* see tea5767.c for details */},
- { "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL,
- 16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 },
- { "LG TDVS-H062F/TUA6034", LGINNOTEK, ATSC,
- 16*160.00,16*455.00,0x01,0x02,0x04,0x8e,732},
- { "Ymec TVF66T5-B/DFF", Philips, PAL,
- 16*160.25,16*464.25,0x01,0x02,0x08,0x8e,623},
- { "LG NTSC (TALN mini series)", LGINNOTEK, NTSC,
- 16*137.25,16*373.25,0x01,0x02,0x08,0x8e,732 },
- { "Philips TD1316 Hybrid Tuner", Philips, PAL,
- 16*160.00,16*442.00,0xa1,0xa2,0xa4,0xc8,623 },
- { "Philips TUV1236D ATSC/NTSC dual in", Philips, ATSC,
- 16*157.25,16*454.00,0x01,0x02,0x04,0xce,732 },
- { "Tena TNF 5335 MF", Philips, NTSC,
- 16*157.25,16*454.00,0x01,0x02,0x04,0x8e,732 },
+ [TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */
+ .name = "Philips FMD1216ME MK3 Hybrid Tuner",
+ .count = 3,
+ .ranges = {
+ { 16 * 160.00 /*MHz*/, 0x51, },
+ { 16 * 442.00 /*MHz*/, 0x52, },
+ { 16 * 999.99 , 0x54, },
+ },
+ .config = 0x86,
+ },
+ [TUNER_LG_TDVS_H062F] = { /* LGINNOTEK ATSC */
+ .name = "LG TDVS-H062F/TUA6034",
+ .count = 3,
+ .ranges = {
+ { 16 * 160.00 /*MHz*/, 0x01 },
+ { 16 * 455.00 /*MHz*/, 0x02 },
+ { 16 * 999.99 , 0x04 },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */
+ .name = "Ymec TVF66T5-B/DFF",
+ .count = 3,
+ .ranges = {
+ { 16 * 160.25 /*MHz*/, 0x01, },
+ { 16 * 464.25 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x08, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_LG_NTSC_TALN_MINI] = { /* LGINNOTEK NTSC */
+ .name = "LG NTSC (TALN mini series)",
+ .count = 3,
+ .ranges = {
+ { 16 * 137.25 /*MHz*/, 0x01, },
+ { 16 * 373.25 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x08, },
+ },
+ .config = 0x8e,
+ },
+ [TUNER_PHILIPS_TD1316] = { /* Philips PAL */
+ .name = "Philips TD1316 Hybrid Tuner",
+ .count = 3,
+ .ranges = {
+ { 16 * 160.00 /*MHz*/, 0xa1, },
+ { 16 * 442.00 /*MHz*/, 0xa2, },
+ { 16 * 999.99 , 0xa4, },
+ },
+ .config = 0xc8,
+ },
+ [TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */
+ .name = "Philips TUV1236D ATSC/NTSC dual in",
+ .count = 3,
+ .ranges = {
+ { 16 * 157.25 /*MHz*/, 0x01, },
+ { 16 * 454.00 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x04, },
+ },
+ .config = 0xce,
+ },
+ [TUNER_TNF_5335MF] = { /* Philips NTSC */
+ .name = "Tena TNF 5335 MF",
+ .count = 3,
+ .ranges = {
+ { 16 * 157.25 /*MHz*/, 0x01, },
+ { 16 * 454.00 /*MHz*/, 0x02, },
+ { 16 * 999.99 , 0x04, },
+ },
+ .config = 0x8e,
+ },
};
unsigned const int tuner_count = ARRAY_SIZE(tuners);
@@ -305,20 +843,19 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
u16 div;
struct tunertype *tun;
unsigned char buffer[4];
- int rc;
+ int rc, IFPCoff, i;
tun = &tuners[t->type];
- if (freq < tun->thresh1) {
- config = tun->VHF_L;
- tuner_dbg("tv: VHF lowrange\n");
- } else if (freq < tun->thresh2) {
- config = tun->VHF_H;
- tuner_dbg("tv: VHF high range\n");
- } else {
- config = tun->UHF;
- tuner_dbg("tv: UHF range\n");
+ for (i = 0; i < tun->count; i++) {
+ if (freq > tun->ranges[i].thresh)
+ continue;
+ break;
}
-
+ config = tun->ranges[i].cb;
+ /* i == 0 -> VHF_LO */
+ /* i == 1 -> VHF_HI */
+ /* i == 2 -> UHF */
+ tuner_dbg("tv: range %d\n",i);
/* tv norm specific stuff for multi-norm tuners */
switch (t->type) {
@@ -420,7 +957,37 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
* frequency in case (wanted frequency < current frequency).
*/
- div=freq + tun->IFPCoff;
+ /* IFPCoff = Video Intermediate Frequency - Vif:
+ 940 =16*58.75 NTSC/J (Japan)
+ 732 =16*45.75 M/N STD
+ 704 =16*44 ATSC (at DVB code)
+ 632 =16*39.50 I U.K.
+ 622.4=16*38.90 B/G D/K I, L STD
+ 592 =16*37.00 D China
+ 590 =16.36.875 B Australia
+ 543.2=16*33.95 L' STD
+ 171.2=16*10.70 FM Radio (at set_radio_freq)
+ */
+
+ if (t->std == V4L2_STD_NTSC_M_JP) {
+ IFPCoff = 940;
+ } else if ((t->std & V4L2_STD_MN) &&
+ !(t->std & ~V4L2_STD_MN)) {
+ IFPCoff = 732;
+ } else if (t->std == V4L2_STD_SECAM_LC) {
+ IFPCoff = 543;
+ } else {
+ IFPCoff = 623;
+ }
+
+ div=freq + IFPCoff + offset;
+
+ tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n",
+ freq / 16, freq % 16 * 100 / 16,
+ IFPCoff / 16, IFPCoff % 16 * 100 / 16,
+ offset / 16, offset % 16 * 100 / 16,
+ div);
+
if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) {
buffer[0] = tun->config;
buffer[1] = config;
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 0292c5abf14a..b582943a0d3e 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -31,6 +31,7 @@
#include <linux/smp_lock.h>
#include <media/audiochip.h>
+#include <media/v4l2-common.h>
#include "tvaudio.h"
@@ -46,17 +47,6 @@ MODULE_LICENSE("GPL");
#define UNSET (-1U)
-#define tvaudio_info(fmt, arg...) do {\
- printk(KERN_INFO "tvaudio %d-%04x: " fmt, \
- chip->c.adapter->nr, chip->c.addr , ##arg); } while (0)
-#define tvaudio_warn(fmt, arg...) do {\
- printk(KERN_WARNING "tvaudio %d-%04x: " fmt, \
- chip->c.adapter->nr, chip->c.addr , ##arg); } while (0)
-#define tvaudio_dbg(fmt, arg...) do {\
- if (debug) \
- printk(KERN_INFO "tvaudio %d-%04x: " fmt, \
- chip->c.adapter->nr, chip->c.addr , ##arg); } while (0)
-
/* ---------------------------------------------------------------------- */
/* our structs */
@@ -131,7 +121,7 @@ struct CHIPSTATE {
/* current settings */
__u16 left,right,treble,bass,mode;
int prevmode;
- int norm;
+ int radio;
/* thread */
pid_t tpid;
@@ -142,8 +132,6 @@ struct CHIPSTATE {
int watch_stereo;
};
-#define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */
-
/* ---------------------------------------------------------------------- */
/* i2c addresses */
@@ -171,23 +159,23 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
unsigned char buffer[2];
if (-1 == subaddr) {
- tvaudio_dbg("%s: chip_write: 0x%x\n",
+ v4l_dbg(1, &chip->c, "%s: chip_write: 0x%x\n",
chip->c.name, val);
chip->shadow.bytes[1] = val;
buffer[0] = val;
if (1 != i2c_master_send(&chip->c,buffer,1)) {
- tvaudio_warn("%s: I/O error (write 0x%x)\n",
+ v4l_warn(&chip->c, "%s: I/O error (write 0x%x)\n",
chip->c.name, val);
return -1;
}
} else {
- tvaudio_dbg("%s: chip_write: reg%d=0x%x\n",
+ v4l_dbg(1, &chip->c, "%s: chip_write: reg%d=0x%x\n",
chip->c.name, subaddr, val);
chip->shadow.bytes[subaddr+1] = val;
buffer[0] = subaddr;
buffer[1] = val;
if (2 != i2c_master_send(&chip->c,buffer,2)) {
- tvaudio_warn("%s: I/O error (write reg%d=0x%x)\n",
+ v4l_warn(&chip->c, "%s: I/O error (write reg%d=0x%x)\n",
chip->c.name, subaddr, val);
return -1;
}
@@ -212,11 +200,11 @@ static int chip_read(struct CHIPSTATE *chip)
unsigned char buffer;
if (1 != i2c_master_recv(&chip->c,&buffer,1)) {
- tvaudio_warn("%s: I/O error (read)\n",
+ v4l_warn(&chip->c, "%s: I/O error (read)\n",
chip->c.name);
return -1;
}
- tvaudio_dbg("%s: chip_read: 0x%x\n",chip->c.name, buffer);
+ v4l_dbg(1, &chip->c, "%s: chip_read: 0x%x\n",chip->c.name, buffer);
return buffer;
}
@@ -231,10 +219,10 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr)
write[0] = subaddr;
if (2 != i2c_transfer(chip->c.adapter,msgs,2)) {
- tvaudio_warn("%s: I/O error (read2)\n", chip->c.name);
+ v4l_warn(&chip->c, "%s: I/O error (read2)\n", chip->c.name);
return -1;
}
- tvaudio_dbg("%s: chip_read2: reg%d=0x%x\n",
+ v4l_dbg(1, &chip->c, "%s: chip_read2: reg%d=0x%x\n",
chip->c.name, subaddr,read[0]);
return read[0];
}
@@ -247,7 +235,7 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
return 0;
/* update our shadow register set; print bytes if (debug > 0) */
- tvaudio_dbg("%s: chip_cmd(%s): reg=%d, data:",
+ v4l_dbg(1, &chip->c, "%s: chip_cmd(%s): reg=%d, data:",
chip->c.name, name,cmd->bytes[0]);
for (i = 1; i < cmd->count; i++) {
if (debug)
@@ -259,7 +247,7 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
/* send data to the chip */
if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) {
- tvaudio_warn("%s: I/O error (%s)\n", chip->c.name, name);
+ v4l_warn(&chip->c, "%s: I/O error (%s)\n", chip->c.name, name);
return -1;
}
return 0;
@@ -286,7 +274,7 @@ static int chip_thread(void *data)
daemonize("%s", chip->c.name);
allow_signal(SIGTERM);
- tvaudio_dbg("%s: thread started\n", chip->c.name);
+ v4l_dbg(1, &chip->c, "%s: thread started\n", chip->c.name);
for (;;) {
add_wait_queue(&chip->wq, &wait);
@@ -298,10 +286,10 @@ static int chip_thread(void *data)
try_to_freeze();
if (chip->done || signal_pending(current))
break;
- tvaudio_dbg("%s: thread wakeup\n", chip->c.name);
+ v4l_dbg(1, &chip->c, "%s: thread wakeup\n", chip->c.name);
/* don't do anything for radio or if mode != auto */
- if (chip->norm == VIDEO_MODE_RADIO || chip->mode != 0)
+ if (chip->radio || chip->mode != 0)
continue;
/* have a look what's going on */
@@ -311,7 +299,7 @@ static int chip_thread(void *data)
mod_timer(&chip->wt, jiffies+2*HZ);
}
- tvaudio_dbg("%s: thread exiting\n", chip->c.name);
+ v4l_dbg(1, &chip->c, "%s: thread exiting\n", chip->c.name);
complete_and_exit(&chip->texit, 0);
return 0;
}
@@ -324,7 +312,7 @@ static void generic_checkmode(struct CHIPSTATE *chip)
if (mode == chip->prevmode)
return;
- tvaudio_dbg("%s: thread checkmode\n", chip->c.name);
+ v4l_dbg(1, &chip->c, "%s: thread checkmode\n", chip->c.name);
chip->prevmode = mode;
if (mode & VIDEO_SOUND_STEREO)
@@ -371,7 +359,7 @@ static int tda9840_getmode(struct CHIPSTATE *chip)
if (val & TDA9840_ST_STEREO)
mode |= VIDEO_SOUND_STEREO;
- tvaudio_dbg ("tda9840_getmode(): raw chip read: %d, return: %d\n",
+ v4l_dbg(1, &chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n",
val, mode);
return mode;
}
@@ -667,7 +655,7 @@ static int tda9873_getmode(struct CHIPSTATE *chip)
mode |= VIDEO_SOUND_STEREO;
if (val & TDA9873_DUAL)
mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
- tvaudio_dbg ("tda9873_getmode(): raw chip read: %d, return: %d\n",
+ v4l_dbg(1, &chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n",
val, mode);
return mode;
}
@@ -678,12 +666,12 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
/* int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) {
- tvaudio_dbg("tda9873_setmode(): external input\n");
+ v4l_dbg(1, &chip->c, "tda9873_setmode(): external input\n");
return;
}
- tvaudio_dbg("tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
- tvaudio_dbg("tda9873_setmode(): sw_data = %d\n", sw_data);
+ v4l_dbg(1, &chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
+ v4l_dbg(1, &chip->c, "tda9873_setmode(): sw_data = %d\n", sw_data);
switch (mode) {
case VIDEO_SOUND_MONO:
@@ -704,7 +692,7 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
}
chip_write(chip, TDA9873_SW, sw_data);
- tvaudio_dbg("tda9873_setmode(): req. mode %d; chip_write: %d\n",
+ v4l_dbg(1, &chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n",
mode, sw_data);
}
@@ -843,7 +831,7 @@ static int tda9874a_setup(struct CHIPSTATE *chip)
chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80);
chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */
}
- tvaudio_dbg("tda9874a_setup(): %s [0x%02X].\n",
+ v4l_dbg(1, &chip->c, "tda9874a_setup(): %s [0x%02X].\n",
tda9874a_modelist[tda9874a_STD].name,tda9874a_STD);
return 1;
}
@@ -886,7 +874,7 @@ static int tda9874a_getmode(struct CHIPSTATE *chip)
mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
}
- tvaudio_dbg("tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
+ v4l_dbg(1, &chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
dsr, nsr, necr, mode);
return mode;
}
@@ -932,7 +920,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
chip_write(chip, TDA9874A_AOSR, aosr);
chip_write(chip, TDA9874A_MDACOSR, mdacosr);
- tvaudio_dbg("tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
+ v4l_dbg(1, &chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
mode, aosr, mdacosr);
} else { /* dic == 0x07 */
@@ -967,7 +955,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
chip_write(chip, TDA9874A_FMMR, fmmr);
chip_write(chip, TDA9874A_AOSR, aosr);
- tvaudio_dbg("tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
+ v4l_dbg(1, &chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
mode, fmmr, aosr);
}
}
@@ -981,10 +969,10 @@ static int tda9874a_checkit(struct CHIPSTATE *chip)
if(-1 == (sic = chip_read2(chip,TDA9874A_SIC)))
return 0;
- tvaudio_dbg("tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
+ v4l_dbg(1, &chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
if((dic == 0x11)||(dic == 0x07)) {
- tvaudio_info("found tda9874%s.\n", (dic == 0x11) ? "a":"h");
+ v4l_info(&chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h");
tda9874a_dic = dic; /* remember device id. */
return 1;
}
@@ -1196,7 +1184,7 @@ static int ta8874z_getmode(struct CHIPSTATE *chip)
}else if (!(val & TA8874Z_B0)){
mode |= VIDEO_SOUND_STEREO;
}
- /* tvaudio_dbg ("ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */
+ /* v4l_dbg(1, &chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */
return mode;
}
@@ -1209,7 +1197,7 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode)
{
int update = 1;
audiocmd *t = NULL;
- tvaudio_dbg("ta8874z_setmode(): mode: 0x%02x\n", mode);
+ v4l_dbg(1, &chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode);
switch(mode){
case VIDEO_SOUND_MONO:
@@ -1490,7 +1478,7 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
i2c_set_clientdata(&chip->c, chip);
/* find description for the chip */
- tvaudio_dbg("chip found @ 0x%x\n", addr<<1);
+ v4l_dbg(1, &chip->c, "chip found @ 0x%x\n", addr<<1);
for (desc = chiplist; desc->name != NULL; desc++) {
if (0 == *(desc->insmodopt))
continue;
@@ -1502,12 +1490,12 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
break;
}
if (desc->name == NULL) {
- tvaudio_dbg("no matching chip description found\n");
+ v4l_dbg(1, &chip->c, "no matching chip description found\n");
return -EIO;
}
- tvaudio_info("%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name);
+ v4l_info(&chip->c, "%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name);
if (desc->flags) {
- tvaudio_dbg("matches:%s%s%s.\n",
+ v4l_dbg(1, &chip->c, "matches:%s%s%s.\n",
(desc->flags & CHIP_HAS_VOLUME) ? " volume" : "",
(desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",
(desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : "");
@@ -1550,7 +1538,7 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
init_completion(&chip->texit);
chip->tpid = kernel_thread(chip_thread,(void *)chip,0);
if (chip->tpid < 0)
- tvaudio_warn("%s: kernel_thread() failed\n",
+ v4l_warn(&chip->c, "%s: kernel_thread() failed\n",
chip->c.name);
wake_up_interruptible(&chip->wq);
}
@@ -1563,17 +1551,8 @@ static int chip_probe(struct i2c_adapter *adap)
because dedicated drivers are used */
if ((adap->id == I2C_HW_SAA7146))
return 0;
-#ifdef I2C_CLASS_TV_ANALOG
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, chip_attach);
-#else
- switch (adap->id) {
- case I2C_HW_B_BT848:
- case I2C_HW_B_RIVA:
- case I2C_HW_SAA7134:
- return i2c_probe(adap, &addr_data, chip_attach);
- }
-#endif
return 0;
}
@@ -1604,7 +1583,7 @@ static int chip_command(struct i2c_client *client,
struct CHIPSTATE *chip = i2c_get_clientdata(client);
struct CHIPDESC *desc = chiplist + chip->type;
- tvaudio_dbg("%s: chip_command 0x%x\n", chip->c.name, cmd);
+ v4l_dbg(1, &chip->c, "%s: chip_command 0x%x\n", chip->c.name, cmd);
switch (cmd) {
case AUDC_SET_INPUT:
@@ -1617,7 +1596,7 @@ static int chip_command(struct i2c_client *client,
break;
case AUDC_SET_RADIO:
- chip->norm = VIDEO_MODE_RADIO;
+ chip->radio = 1;
chip->watch_stereo = 0;
/* del_timer(&chip->wt); */
break;
@@ -1643,7 +1622,7 @@ static int chip_command(struct i2c_client *client,
va->bass = chip->bass;
va->treble = chip->treble;
}
- if (chip->norm != VIDEO_MODE_RADIO) {
+ if (!chip->radio) {
if (desc->getmode)
va->mode = desc->getmode(chip);
else
@@ -1678,15 +1657,80 @@ static int chip_command(struct i2c_client *client,
}
break;
}
- case VIDIOCSCHAN:
+
+ case VIDIOC_S_TUNER:
{
- struct video_channel *vc = arg;
+ struct v4l2_tuner *vt = arg;
+ int mode = 0;
- chip->norm = vc->norm;
+ switch (vt->audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ mode = VIDEO_SOUND_MONO;
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ mode = VIDEO_SOUND_STEREO;
+ break;
+ case V4L2_TUNER_MODE_LANG1:
+ mode = VIDEO_SOUND_LANG1;
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ mode = VIDEO_SOUND_LANG2;
+ break;
+ default:
+ break;
+ }
+
+ if (desc->setmode && mode) {
+ chip->watch_stereo = 0;
+ /* del_timer(&chip->wt); */
+ chip->mode = mode;
+ desc->setmode(chip, mode);
+ }
break;
}
- case VIDIOCSFREQ:
+
+ case VIDIOC_G_TUNER:
{
+ struct v4l2_tuner *vt = arg;
+ int mode = VIDEO_SOUND_MONO;
+
+ if (chip->radio)
+ break;
+ vt->audmode = 0;
+ vt->rxsubchans = 0;
+ vt->capability = V4L2_TUNER_CAP_STEREO |
+ V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+
+ if (desc->getmode)
+ mode = desc->getmode(chip);
+
+ if (mode & VIDEO_SOUND_MONO)
+ vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
+ if (mode & VIDEO_SOUND_STEREO)
+ vt->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+ if (mode & VIDEO_SOUND_LANG1)
+ vt->rxsubchans |= V4L2_TUNER_SUB_LANG1 |
+ V4L2_TUNER_SUB_LANG2;
+
+ mode = chip->mode;
+ if (mode & VIDEO_SOUND_MONO)
+ vt->audmode = V4L2_TUNER_MODE_MONO;
+ if (mode & VIDEO_SOUND_STEREO)
+ vt->audmode = V4L2_TUNER_MODE_STEREO;
+ if (mode & VIDEO_SOUND_LANG1)
+ vt->audmode = V4L2_TUNER_MODE_LANG1;
+ if (mode & VIDEO_SOUND_LANG2)
+ vt->audmode = V4L2_TUNER_MODE_LANG2;
+ break;
+ }
+
+ case VIDIOCSCHAN:
+ case VIDIOC_S_STD:
+ chip->radio = 0;
+ break;
+
+ case VIDIOCSFREQ:
+ case VIDIOC_S_FREQUENCY:
chip->mode = 0; /* automatic */
if (desc->checkmode) {
desc->setmode(chip,VIDEO_SOUND_MONO);
@@ -1695,15 +1739,14 @@ static int chip_command(struct i2c_client *client,
mod_timer(&chip->wt, jiffies+2*HZ);
/* the thread will call checkmode() later */
}
- }
+ break;
}
return 0;
}
-
static struct i2c_driver driver = {
.driver = {
- .name = "generic i2c audio driver",
+ .name = "tvaudio",
},
.id = I2C_DRIVERID_TVAUDIO,
.attach_adapter = chip_probe,
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 8ac4cb82a459..fd0acc5da667 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -40,6 +40,7 @@
#include <media/tuner.h>
#include <media/tveeprom.h>
+#include <media/v4l2-common.h>
#include <media/audiochip.h>
MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver");
@@ -52,21 +53,19 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
#define STRM(array,i) (i < sizeof(array)/sizeof(char*) ? array[i] : "unknown")
-#define tveeprom_info(fmt, arg...) do {\
- printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
- c->adapter->nr, c->addr , ##arg); } while (0)
-#define tveeprom_warn(fmt, arg...) do {\
- printk(KERN_WARNING "tveeprom %d-%04x: " fmt, \
- c->adapter->nr, c->addr , ##arg); } while (0)
-#define tveeprom_dbg(fmt, arg...) do {\
+#define tveeprom_info(fmt, arg...) \
+ v4l_printk(KERN_INFO, "tveeprom", c->adapter, c->addr, fmt , ## arg)
+#define tveeprom_warn(fmt, arg...) \
+ v4l_printk(KERN_WARNING, "tveeprom", c->adapter, c->addr, fmt , ## arg)
+#define tveeprom_dbg(fmt, arg...) do { \
if (debug) \
- printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
- c->adapter->nr, c->addr , ##arg); } while (0)
-
-
-/* ----------------------------------------------------------------------- */
-/* some hauppauge specific stuff */
+ v4l_printk(KERN_DEBUG, "tveeprom", c->adapter, c->addr, fmt , ## arg); \
+ } while (0)
+/*
+ * The Hauppauge eeprom uses an 8bit field to determine which
+ * tuner formats the tuner supports.
+ */
static struct HAUPPAUGE_TUNER_FMT
{
int id;
@@ -74,14 +73,14 @@ static struct HAUPPAUGE_TUNER_FMT
}
hauppauge_tuner_fmt[] =
{
- { 0x00000000, " unknown1" },
- { 0x00000000, " unknown2" },
- { 0x00000007, " PAL(B/G)" },
- { 0x00001000, " NTSC(M)" },
- { 0x00000010, " PAL(I)" },
- { 0x00400000, " SECAM(L/L')" },
- { 0x00000e00, " PAL(D/K)" },
- { 0x03000000, " ATSC/DVB Digital" },
+ { V4L2_STD_UNKNOWN," UNKNOWN" },
+ { V4L2_STD_UNKNOWN," FM" },
+ { V4L2_STD_PAL_BG, " PAL(B/G)" },
+ { V4L2_STD_NTSC_M, " NTSC(M)" },
+ { V4L2_STD_PAL_I, " PAL(I)" },
+ { V4L2_STD_SECAM_L," SECAM(L/L')" },
+ { V4L2_STD_PAL_DK, " PAL(D/D1/K)" },
+ { V4L2_STD_ATSC, " ATSC/DVB Digital" },
};
/* This is the full list of possible tuners. Many thanks to Hauppauge for
@@ -387,7 +386,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
if ((eeprom_data[0] == 0x1a) && (eeprom_data[1] == 0xeb) &&
(eeprom_data[2] == 0x67) && (eeprom_data[3] == 0x95))
start=0xa0; /* Generic em28xx offset */
- else if (((eeprom_data[0] & 0xf0) == 0x10) &&
+ else if (((eeprom_data[0] & 0xe1) == 0x01) &&
(eeprom_data[1] == 0x00) &&
(eeprom_data[2] == 0x00) &&
(eeprom_data[8] == 0x84))
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
index e837f9f7fed6..9e86caeb96a7 100644
--- a/drivers/media/video/tvmixer.c
+++ b/drivers/media/video/tvmixer.c
@@ -227,13 +227,9 @@ static int tvmixer_release(struct inode *inode, struct file *file)
}
static struct i2c_driver driver = {
-#ifdef I2C_PEC
.driver = {
- .name = "tv card mixer driver",
+ .name = "tvmixer",
},
-#else
- .name = "tv card mixer driver",
-#endif
.id = I2C_DRIVERID_TVMIXER,
.detach_adapter = tvmixer_adapters,
.attach_adapter = tvmixer_adapters,
@@ -267,22 +263,8 @@ static int tvmixer_clients(struct i2c_client *client)
struct video_audio va;
int i,minor;
-#ifdef I2C_CLASS_TV_ANALOG
if (!(client->adapter->class & I2C_CLASS_TV_ANALOG))
return -1;
-#else
- /* TV card ??? */
- switch (client->adapter->id) {
- case I2C_HW_SMBUS_VOODOO3:
- case I2C_HW_B_BT848:
- case I2C_HW_B_RIVA:
- /* ok, have a look ... */
- break;
- default:
- /* ignore that one */
- return -1;
- }
-#endif
/* unregister ?? */
for (i = 0; i < DEV_MAX; i++) {
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index a60442ea4f94..c35b8042eee5 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -9,6 +9,7 @@
#include <linux/videodev.h>
#include <linux/delay.h>
#include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
#include "tvp5150_reg.h"
@@ -28,33 +29,38 @@ static int debug = 0;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
-#define dprintk(num, format, args...) \
+#define tvp5150_info(fmt, arg...) do { \
+ printk(KERN_INFO "%s %d-%04x: " fmt, c->driver->driver.name, \
+ i2c_adapter_id(c->adapter), c->addr , ## arg); } while (0)
+#define tvp5150_dbg(num, fmt, arg...) \
do { \
if (debug >= num) \
- printk(format, ##args); \
- } while (0)
+ printk(KERN_DEBUG "%s debug %d-%04x: " fmt,\
+ c->driver->driver.name, \
+ i2c_adapter_id(c->adapter), \
+ c->addr , ## arg); } while (0)
/* supported controls */
static struct v4l2_queryctrl tvp5150_qctrl[] = {
{
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- }, {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 255,
- .step = 0x1,
- .default_value = 0x10,
- .flags = 0,
- }, {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = 0x10,
+ .flags = 0,
+ }, {
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Saturation",
@@ -63,16 +69,16 @@ static struct v4l2_queryctrl tvp5150_qctrl[] = {
.step = 0x1,
.default_value = 0x10,
.flags = 0,
- }, {
- .id = V4L2_CID_HUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hue",
- .minimum = -128,
- .maximum = 127,
- .step = 0x1,
- .default_value = 0x10,
- .flags = 0,
- }
+ }, {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 0x1,
+ .default_value = 0x10,
+ .flags = 0,
+ }
};
struct tvp5150 {
@@ -94,12 +100,14 @@ static inline int tvp5150_read(struct i2c_client *c, unsigned char addr)
buffer[0] = addr;
if (1 != (rc = i2c_master_send(c, buffer, 1)))
- dprintk(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+ tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
msleep(10);
if (1 != (rc = i2c_master_recv(c, buffer, 1)))
- dprintk(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+ tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+
+ tvp5150_dbg(2, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]);
return (buffer[0]);
}
@@ -109,13 +117,12 @@ static inline void tvp5150_write(struct i2c_client *c, unsigned char addr,
{
unsigned char buffer[2];
int rc;
-/* struct tvp5150 *core = i2c_get_clientdata(c); */
buffer[0] = addr;
buffer[1] = value;
- dprintk(1, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
+ tvp5150_dbg(2, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
if (2 != (rc = i2c_master_send(c, buffer, 2)))
- dprintk(0, "i2c i/o error: rc == %d (should be 2)\n", rc);
+ tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 2)\n", rc);
}
static void dump_reg(struct i2c_client *c)
@@ -437,48 +444,346 @@ enum tvp5150_input {
static inline void tvp5150_selmux(struct i2c_client *c,
enum tvp5150_input input)
{
+ int opmode=0;
+
struct tvp5150 *decoder = i2c_get_clientdata(c);
if (!decoder->enable)
input |= TVP5150_BLACK_SCREEN;
+ switch (input) {
+ case TVP5150_ANALOG_CH0:
+ case TVP5150_ANALOG_CH1:
+ opmode=0x30; /* TV Mode */
+ break;
+ default:
+ opmode=0; /* Auto Mode */
+ break;
+ }
+
+ tvp5150_write(c, TVP5150_OP_MODE_CTL, opmode);
tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, input);
};
-static inline void tvp5150_reset(struct i2c_client *c)
+struct i2c_reg_value {
+ unsigned char reg;
+ unsigned char value;
+};
+
+/* Default values as sugested at TVP5150AM1 datasheet */
+static const struct i2c_reg_value tvp5150_init_default[] = {
+ { /* 0x00 */
+ TVP5150_VD_IN_SRC_SEL_1,0x00
+ },
+ { /* 0x01 */
+ TVP5150_ANAL_CHL_CTL,0x15
+ },
+ { /* 0x02 */
+ TVP5150_OP_MODE_CTL,0x00
+ },
+ { /* 0x03 */
+ TVP5150_MISC_CTL,0x01
+ },
+ { /* 0x06 */
+ TVP5150_COLOR_KIL_THSH_CTL,0x10
+ },
+ { /* 0x07 */
+ TVP5150_LUMA_PROC_CTL_1,0x60
+ },
+ { /* 0x08 */
+ TVP5150_LUMA_PROC_CTL_2,0x00
+ },
+ { /* 0x09 */
+ TVP5150_BRIGHT_CTL,0x80
+ },
+ { /* 0x0a */
+ TVP5150_SATURATION_CTL,0x80
+ },
+ { /* 0x0b */
+ TVP5150_HUE_CTL,0x00
+ },
+ { /* 0x0c */
+ TVP5150_CONTRAST_CTL,0x80
+ },
+ { /* 0x0d */
+ TVP5150_DATA_RATE_SEL,0x47
+ },
+ { /* 0x0e */
+ TVP5150_LUMA_PROC_CTL_3,0x00
+ },
+ { /* 0x0f */
+ TVP5150_CONF_SHARED_PIN,0x08
+ },
+ { /* 0x11 */
+ TVP5150_ACT_VD_CROP_ST_MSB,0x00
+ },
+ { /* 0x12 */
+ TVP5150_ACT_VD_CROP_ST_LSB,0x00
+ },
+ { /* 0x13 */
+ TVP5150_ACT_VD_CROP_STP_MSB,0x00
+ },
+ { /* 0x14 */
+ TVP5150_ACT_VD_CROP_STP_LSB,0x00
+ },
+ { /* 0x15 */
+ TVP5150_GENLOCK,0x01
+ },
+ { /* 0x16 */
+ TVP5150_HORIZ_SYNC_START,0x80
+ },
+ { /* 0x18 */
+ TVP5150_VERT_BLANKING_START,0x00
+ },
+ { /* 0x19 */
+ TVP5150_VERT_BLANKING_STOP,0x00
+ },
+ { /* 0x1a */
+ TVP5150_CHROMA_PROC_CTL_1,0x0c
+ },
+ { /* 0x1b */
+ TVP5150_CHROMA_PROC_CTL_2,0x14
+ },
+ { /* 0x1c */
+ TVP5150_INT_RESET_REG_B,0x00
+ },
+ { /* 0x1d */
+ TVP5150_INT_ENABLE_REG_B,0x00
+ },
+ { /* 0x1e */
+ TVP5150_INTT_CONFIG_REG_B,0x00
+ },
+ { /* 0x28 */
+ TVP5150_VIDEO_STD,0x00
+ },
+ { /* 0x2e */
+ TVP5150_MACROVISION_ON_CTR,0x0f
+ },
+ { /* 0x2f */
+ TVP5150_MACROVISION_OFF_CTR,0x01
+ },
+ { /* 0xbb */
+ TVP5150_TELETEXT_FIL_ENA,0x00
+ },
+ { /* 0xc0 */
+ TVP5150_INT_STATUS_REG_A,0x00
+ },
+ { /* 0xc1 */
+ TVP5150_INT_ENABLE_REG_A,0x00
+ },
+ { /* 0xc2 */
+ TVP5150_INT_CONF,0x04
+ },
+ { /* 0xc8 */
+ TVP5150_FIFO_INT_THRESHOLD,0x80
+ },
+ { /* 0xc9 */
+ TVP5150_FIFO_RESET,0x00
+ },
+ { /* 0xca */
+ TVP5150_LINE_NUMBER_INT,0x00
+ },
+ { /* 0xcb */
+ TVP5150_PIX_ALIGN_REG_LOW,0x4e
+ },
+ { /* 0xcc */
+ TVP5150_PIX_ALIGN_REG_HIGH,0x00
+ },
+ { /* 0xcd */
+ TVP5150_FIFO_OUT_CTRL,0x01
+ },
+ { /* 0xcf */
+ TVP5150_FULL_FIELD_ENA_1,0x00
+ },
+ { /* 0xd0 */
+ TVP5150_FULL_FIELD_ENA_2,0x00
+ },
+ { /* 0xfc */
+ TVP5150_FULL_FIELD_MODE_REG,0x7f
+ },
+ { /* end of data */
+ 0xff,0xff
+ }
+};
+
+/* Default values as sugested at TVP5150AM1 datasheet */
+static const struct i2c_reg_value tvp5150_init_enable[] = {
+ {
+ TVP5150_CONF_SHARED_PIN, 2
+ },{ /* Automatic offset and AGC enabled */
+ TVP5150_ANAL_CHL_CTL, 0x15
+ },{ /* Activate YCrCb output 0x9 or 0xd ? */
+ TVP5150_MISC_CTL, 0x6f
+ },{ /* Activates video std autodetection for all standards */
+ TVP5150_AUTOSW_MSK, 0x0
+ },{ /* Default format: 0x47. For 4:2:2: 0x40 */
+ TVP5150_DATA_RATE_SEL, 0x47
+ },{
+ TVP5150_CHROMA_PROC_CTL_1, 0x0c
+ },{
+ TVP5150_CHROMA_PROC_CTL_2, 0x54
+ },{ /* Non documented, but initialized on WinTV USB2 */
+ 0x27, 0x20
+ },{
+ 0xff,0xff
+ }
+};
+
+struct i2c_vbi_ram_value {
+ u16 reg;
+ unsigned char values[26];
+};
+
+struct i2c_vbi_ram_value vbi_ram_default[] =
{
- struct tvp5150 *decoder = i2c_get_clientdata(c);
+ {0x010, /* WST SECAM 6 */
+ { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x26, 0xe6, 0xb4, 0x0e, 0x0, 0x0, 0x0, 0x10, 0x0 }
+ },
+ {0x030, /* WST PAL B 6 */
+ { 0xaa, 0xaa, 0xff, 0xff , 0x27, 0x2e, 0x20, 0x2b, 0xa6, 0x72, 0x10, 0x0, 0x0, 0x0, 0x10, 0x0 }
+ },
+ {0x050, /* WST PAL C 6 */
+ { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x22, 0xa6, 0x98, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+ },
+ {0x070, /* WST NTSC 6 */
+ { 0xaa, 0xaa, 0xff, 0xff , 0x27, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+ },
+ {0x090, /* NABTS, NTSC 6 */
+ { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x22, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x15, 0x0 }
+ },
+ {0x0b0, /* NABTS, NTSC-J 6 */
+ { 0xaa, 0xaa, 0xff, 0xff , 0xa7, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+ },
+ {0x0d0, /* CC, PAL/SECAM 6 */
+ { 0xaa, 0x2a, 0xff, 0x3f , 0x04, 0x51, 0x6e, 0x02, 0xa6, 0x7b, 0x09, 0x0, 0x0, 0x0, 0x27, 0x0 }
+ },
+ {0x0f0, /* CC, NTSC 6 */
+ { 0xaa, 0x2a, 0xff, 0x3f , 0x04, 0x51, 0x6e, 0x02, 0x69, 0x8c, 0x09, 0x0, 0x0, 0x0, 0x27, 0x0 }
+ },
+ {0x110, /* WSS, PAL/SECAM 6 */
+ { 0x5b, 0x55, 0xc5, 0xff , 0x0, 0x71, 0x6e, 0x42, 0xa6, 0xcd, 0x0f, 0x0, 0x0, 0x0, 0x3a, 0x0 }
+ },
+ {0x130, /* WSS, NTSC C */
+ { 0x38, 0x00, 0x3f, 0x00 , 0x0, 0x71, 0x6e, 0x43, 0x69, 0x7c, 0x08, 0x0, 0x0, 0x0, 0x39, 0x0 }
+ },
+ {0x150, /* VITC, PAL/SECAM 6 */
+ { 0x0, 0x0, 0x0, 0x0 , 0x0, 0x8f, 0x6d, 0x49, 0xa6, 0x85, 0x08, 0x0, 0x0, 0x0, 0x4c, 0x0 }
+ },
+ {0x170, /* VITC, NTSC 6 */
+ { 0x0, 0x0, 0x0, 0x0 , 0x0, 0x8f, 0x6d, 0x49, 0x69, 0x94, 0x08, 0x0, 0x0, 0x0, 0x4c, 0x0 }
+ },
+ { (u16)-1 }
+};
- tvp5150_write(c, TVP5150_CONF_SHARED_PIN, 2);
+static int tvp5150_write_inittab(struct i2c_client *c,
+ const struct i2c_reg_value *regs)
+{
+ while (regs->reg != 0xff) {
+ tvp5150_write(c, regs->reg, regs->value);
+ regs++;
+ }
+ return 0;
+}
- /* Automatic offset and AGC enabled */
- tvp5150_write(c, TVP5150_ANAL_CHL_CTL, 0x15);
+static int tvp5150_vdp_init(struct i2c_client *c,
+ const struct i2c_vbi_ram_value *regs)
+{
+ unsigned int i;
- /* Normal Operation */
-// tvp5150_write(c, TVP5150_OP_MODE_CTL, 0x00);
+ /* Disable Full Field */
+ tvp5150_write(c, TVP5150_FULL_FIELD_ENA_1, 0);
- /* Activate YCrCb output 0x9 or 0xd ? */
- tvp5150_write(c, TVP5150_MISC_CTL, 0x6f);
+ /* Before programming, Line mode should be at 0xff */
+ for (i=TVP5150_FULL_FIELD_ENA_2; i<=TVP5150_LINE_MODE_REG_44; i++)
+ tvp5150_write(c, i, 0xff);
- /* Activates video std autodetection for all standards */
- tvp5150_write(c, TVP5150_AUTOSW_MSK, 0x0);
+ /* Load Ram Table */
+ while (regs->reg != (u16)-1 ) {
+ tvp5150_write(c, TVP5150_CONF_RAM_ADDR_HIGH,regs->reg>>8);
+ tvp5150_write(c, TVP5150_CONF_RAM_ADDR_LOW,regs->reg);
- /* Default format: 0x47, 4:2:2: 0x40 */
- tvp5150_write(c, TVP5150_DATA_RATE_SEL, 0x47);
+ for (i=0;i<16;i++)
+ tvp5150_write(c, TVP5150_VDP_CONF_RAM_DATA,regs->values[i]);
- tvp5150_selmux(c, decoder->input);
+ regs++;
+ }
+ return 0;
+}
+
+static int tvp5150_set_std(struct i2c_client *c, v4l2_std_id std)
+{
+ struct tvp5150 *decoder = i2c_get_clientdata(c);
+ int fmt=0;
+
+ decoder->norm=std;
+
+ /* First tests should be against specific std */
+
+ if (std == V4L2_STD_ALL) {
+ fmt=0; /* Autodetect mode */
+ } else if (std & V4L2_STD_NTSC_443) {
+ fmt=0xa;
+ } else if (std & V4L2_STD_PAL_M) {
+ fmt=0x6;
+ } else if (std & (V4L2_STD_PAL_N| V4L2_STD_PAL_Nc)) {
+ fmt=0x8;
+ } else {
+ /* Then, test against generic ones */
+ if (std & V4L2_STD_NTSC) {
+ fmt=0x2;
+ } else if (std & V4L2_STD_PAL) {
+ fmt=0x4;
+ } else if (std & V4L2_STD_SECAM) {
+ fmt=0xc;
+ }
+ }
+
+ tvp5150_dbg(1,"Set video std register to %d.\n",fmt);
+ tvp5150_write(c, TVP5150_VIDEO_STD, fmt);
- tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_1, 0x0c);
- tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_2, 0x54);
+ return 0;
+}
- tvp5150_write(c, 0x27, 0x20); /* ?????????? */
+static inline void tvp5150_reset(struct i2c_client *c)
+{
+ u8 type, ver_656, msb_id, lsb_id, msb_rom, lsb_rom;
+ struct tvp5150 *decoder = i2c_get_clientdata(c);
- tvp5150_write(c, TVP5150_VIDEO_STD, 0x0); /* Auto switch */
+ type=tvp5150_read(c,TVP5150_AUTOSW_MSK);
+ msb_id=tvp5150_read(c,TVP5150_MSB_DEV_ID);
+ lsb_id=tvp5150_read(c,TVP5150_LSB_DEV_ID);
+ msb_rom=tvp5150_read(c,TVP5150_ROM_MAJOR_VER);
+ lsb_rom=tvp5150_read(c,TVP5150_ROM_MINOR_VER);
+
+ if (type==0xdc) {
+ ver_656=tvp5150_read(c,TVP5150_REV_SELECT);
+ tvp5150_info("tvp%02x%02xam1 detected 656 version is %d.\n",msb_id, lsb_id,ver_656);
+ } else if (type==0xfc) {
+ tvp5150_info("tvp%02x%02xa detected.\n",msb_id, lsb_id);
+ } else {
+ tvp5150_info("unknown tvp%02x%02x chip detected(%d).\n",msb_id,lsb_id,type);
+ }
+ tvp5150_info("Rom ver is %d.%d\n",msb_rom,lsb_rom);
+ /* Initializes TVP5150 to its default values */
+ tvp5150_write_inittab(c, tvp5150_init_default);
+
+ /* Initializes VDP registers */
+ tvp5150_vdp_init(c, vbi_ram_default);
+
+ /* Selects decoder input */
+ tvp5150_selmux(c, decoder->input);
+
+ /* Initializes TVP5150 to stream enabled values */
+ tvp5150_write_inittab(c, tvp5150_init_enable);
+
+ /* Initialize image preferences */
tvp5150_write(c, TVP5150_BRIGHT_CTL, decoder->bright >> 8);
tvp5150_write(c, TVP5150_CONTRAST_CTL, decoder->contrast >> 8);
tvp5150_write(c, TVP5150_SATURATION_CTL, decoder->contrast >> 8);
tvp5150_write(c, TVP5150_HUE_CTL, (decoder->hue - 32768) >> 8);
+
+ tvp5150_set_std(c, decoder->norm);
};
static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
@@ -498,9 +803,8 @@ static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
case V4L2_CID_HUE:
ctrl->value = tvp5150_read(c, TVP5150_HUE_CTL);
return 0;
- default:
- return -EINVAL;
}
+ return -EINVAL;
}
static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
@@ -520,28 +824,59 @@ static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
case V4L2_CID_HUE:
tvp5150_write(c, TVP5150_HUE_CTL, ctrl->value);
return 0;
- default:
- return -EINVAL;
}
+ return -EINVAL;
}
/****************************************************************************
I2C Command
****************************************************************************/
-static int tvp5150_command(struct i2c_client *client,
+static int tvp5150_command(struct i2c_client *c,
unsigned int cmd, void *arg)
{
- struct tvp5150 *decoder = i2c_get_clientdata(client);
+ struct tvp5150 *decoder = i2c_get_clientdata(c);
switch (cmd) {
case 0:
+ case VIDIOC_INT_RESET:
case DECODER_INIT:
- tvp5150_reset(client);
+ tvp5150_reset(c);
+ break;
+ case VIDIOC_S_STD:
+ if (decoder->norm == *(v4l2_std_id *)arg)
+ break;
+ return tvp5150_set_std(c, *(v4l2_std_id *)arg);
+ case VIDIOC_G_STD:
+ *(v4l2_std_id *)arg = decoder->norm;
+ break;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ case VIDIOC_INT_G_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+
+ if (reg->i2c_id != I2C_DRIVERID_TVP5150)
+ return -EINVAL;
+ reg->val = tvp5150_read(c, reg->reg & 0xff);
+ break;
+ }
+
+ case VIDIOC_INT_S_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+
+ if (reg->i2c_id != I2C_DRIVERID_TVP5150)
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ tvp5150_write(c, reg->reg & 0xff, reg->val & 0xff);
break;
+ }
+#endif
case DECODER_DUMP:
- dump_reg(client);
+ dump_reg(c);
break;
case DECODER_GET_CAPABILITIES:
@@ -600,7 +935,7 @@ static int tvp5150_command(struct i2c_client *client,
}
decoder->input = *iarg;
- tvp5150_selmux(client, decoder->input);
+ tvp5150_selmux(c, decoder->input);
break;
}
@@ -620,19 +955,18 @@ static int tvp5150_command(struct i2c_client *client,
decoder->enable = (*iarg != 0);
- tvp5150_selmux(client, decoder->input);
+ tvp5150_selmux(c, decoder->input);
break;
}
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *qc = arg;
- u8 i, n;
+ int i;
- dprintk(1, KERN_DEBUG "VIDIOC_QUERYCTRL");
+ tvp5150_dbg(1, "VIDIOC_QUERYCTRL called\n");
- n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
- for (i = 0; i < n; i++)
+ for (i = 0; i < ARRAY_SIZE(tvp5150_qctrl); i++)
if (qc->id && qc->id == tvp5150_qctrl[i].id) {
memcpy(qc, &(tvp5150_qctrl[i]),
sizeof(*qc));
@@ -644,16 +978,14 @@ static int tvp5150_command(struct i2c_client *client,
case VIDIOC_G_CTRL:
{
struct v4l2_control *ctrl = arg;
- dprintk(1, KERN_DEBUG "VIDIOC_G_CTRL");
+ tvp5150_dbg(1, "VIDIOC_G_CTRL called\n");
- return tvp5150_get_ctrl(client, ctrl);
+ return tvp5150_get_ctrl(c, ctrl);
}
- case VIDIOC_S_CTRL_OLD: /* ??? */
case VIDIOC_S_CTRL:
{
struct v4l2_control *ctrl = arg;
u8 i, n;
- dprintk(1, KERN_DEBUG "VIDIOC_S_CTRL");
n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
for (i = 0; i < n; i++)
if (ctrl->id == tvp5150_qctrl[i].id) {
@@ -662,11 +994,10 @@ static int tvp5150_command(struct i2c_client *client,
|| ctrl->value >
tvp5150_qctrl[i].maximum)
return -ERANGE;
- dprintk(1,
- KERN_DEBUG
- "VIDIOC_S_CTRL: id=%d, value=%d",
+ tvp5150_dbg(1,
+ "VIDIOC_S_CTRL: id=%d, value=%d\n",
ctrl->id, ctrl->value);
- return tvp5150_set_ctrl(client, ctrl);
+ return tvp5150_set_ctrl(c, ctrl);
}
return -EINVAL;
}
@@ -677,25 +1008,25 @@ static int tvp5150_command(struct i2c_client *client,
if (decoder->bright != pic->brightness) {
/* We want 0 to 255 we get 0-65535 */
decoder->bright = pic->brightness;
- tvp5150_write(client, TVP5150_BRIGHT_CTL,
+ tvp5150_write(c, TVP5150_BRIGHT_CTL,
decoder->bright >> 8);
}
if (decoder->contrast != pic->contrast) {
/* We want 0 to 255 we get 0-65535 */
decoder->contrast = pic->contrast;
- tvp5150_write(client, TVP5150_CONTRAST_CTL,
+ tvp5150_write(c, TVP5150_CONTRAST_CTL,
decoder->contrast >> 8);
}
if (decoder->sat != pic->colour) {
/* We want 0 to 255 we get 0-65535 */
decoder->sat = pic->colour;
- tvp5150_write(client, TVP5150_SATURATION_CTL,
+ tvp5150_write(c, TVP5150_SATURATION_CTL,
decoder->contrast >> 8);
}
if (decoder->hue != pic->hue) {
/* We want -128 to 127 we get 0-65535 */
decoder->hue = pic->hue;
- tvp5150_write(client, TVP5150_HUE_CTL,
+ tvp5150_write(c, TVP5150_HUE_CTL,
(decoder->hue - 32768) >> 8);
}
break;
@@ -720,12 +1051,12 @@ static struct i2c_client client_template = {
static int tvp5150_detect_client(struct i2c_adapter *adapter,
int address, int kind)
{
- struct i2c_client *client;
+ struct i2c_client *c;
struct tvp5150 *core;
int rv;
- dprintk(1,
- KERN_INFO
+ if (debug)
+ printk( KERN_INFO
"tvp5150.c: detecting tvp5150 client on address 0x%x\n",
address << 1);
@@ -738,22 +1069,22 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
return 0;
- client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ c = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (c == 0)
return -ENOMEM;
- memcpy(client, &client_template, sizeof(struct i2c_client));
+ memcpy(c, &client_template, sizeof(struct i2c_client));
core = kmalloc(sizeof(struct tvp5150), GFP_KERNEL);
if (core == 0) {
- kfree(client);
+ kfree(c);
return -ENOMEM;
}
memset(core, 0, sizeof(struct tvp5150));
- i2c_set_clientdata(client, core);
+ i2c_set_clientdata(c, core);
- rv = i2c_attach_client(client);
+ rv = i2c_attach_client(c);
- core->norm = VIDEO_MODE_AUTO;
+ core->norm = V4L2_STD_ALL;
core->input = 2;
core->enable = 1;
core->bright = 32768;
@@ -762,37 +1093,41 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
core->sat = 32768;
if (rv) {
- kfree(client);
+ kfree(c);
kfree(core);
return rv;
}
if (debug > 1)
- dump_reg(client);
+ dump_reg(c);
return 0;
}
static int tvp5150_attach_adapter(struct i2c_adapter *adapter)
{
- dprintk(1,
- KERN_INFO
+ if (debug)
+ printk( KERN_INFO
"tvp5150.c: starting probe for adapter %s (0x%x)\n",
adapter->name, adapter->id);
return i2c_probe(adapter, &addr_data, &tvp5150_detect_client);
}
-static int tvp5150_detach_client(struct i2c_client *client)
+static int tvp5150_detach_client(struct i2c_client *c)
{
- struct tvp5150 *decoder = i2c_get_clientdata(client);
+ struct tvp5150 *decoder = i2c_get_clientdata(c);
int err;
- err = i2c_detach_client(client);
+ tvp5150_dbg(1,
+ "tvp5150.c: removing tvp5150 adapter on address 0x%x\n",
+ c->addr << 1);
+
+ err = i2c_detach_client(c);
if (err) {
return err;
}
kfree(decoder);
- kfree(client);
+ kfree(c);
return 0;
}
@@ -803,9 +1138,7 @@ static struct i2c_driver driver = {
.driver = {
.name = "tvp5150",
},
-
- /* FIXME */
- .id = I2C_DRIVERID_SAA7110,
+ .id = I2C_DRIVERID_TVP5150,
.attach_adapter = tvp5150_attach_adapter,
.detach_client = tvp5150_detach_client,
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index 4134549d11a8..2ab5b4093800 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -951,6 +951,10 @@ v4l_compat_translate_ioctl(struct inode *inode,
dprintk("VIDIOCGVBIFMT / VIDIOC_G_FMT: %d\n", err);
break;
}
+ if (fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY) {
+ err = -EINVAL;
+ break;
+ }
memset(fmt, 0, sizeof(*fmt));
fmt->samples_per_line = fmt2->fmt.vbi.samples_per_line;
fmt->sampling_rate = fmt2->fmt.vbi.sampling_rate;
@@ -966,6 +970,11 @@ v4l_compat_translate_ioctl(struct inode *inode,
{
struct vbi_format *fmt = arg;
+ if (VIDEO_PALETTE_RAW != fmt->sample_format) {
+ err = -EINVAL;
+ break;
+ }
+
fmt2 = kmalloc(sizeof(*fmt2),GFP_KERNEL);
memset(fmt2, 0, sizeof(*fmt2));
@@ -986,7 +995,7 @@ v4l_compat_translate_ioctl(struct inode *inode,
if (fmt2->fmt.vbi.samples_per_line != fmt->samples_per_line ||
fmt2->fmt.vbi.sampling_rate != fmt->sampling_rate ||
- VIDEO_PALETTE_RAW != fmt->sample_format ||
+ fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY ||
fmt2->fmt.vbi.start[0] != fmt->start[0] ||
fmt2->fmt.vbi.count[0] != fmt->count[0] ||
fmt2->fmt.vbi.start[1] != fmt->start[1] ||
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 62a7d636ef11..5dbd7c1b362a 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -58,6 +58,8 @@
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/div64.h>
+#include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
@@ -190,55 +192,174 @@ char *v4l2_type_names[] = {
[V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
};
-char *v4l2_ioctl_names[256] = {
- [0 ... 255] = "UNKNOWN",
- [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP",
- [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED",
- [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT",
- [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT",
- [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT",
- [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS",
- [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF",
- [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF",
- [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF",
- [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY",
- [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF",
- [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF",
- [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON",
- [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF",
- [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM",
- [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM",
- [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD",
- [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD",
- [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD",
- [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT",
- [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL",
- [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL",
- [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER",
- [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER",
- [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO",
- [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO",
- [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL",
- [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU",
- [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT",
- [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT",
- [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT",
- [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT",
- [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT",
- [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT",
- [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT",
- [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR",
- [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR",
- [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY",
- [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY",
- [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP",
- [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP",
- [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP",
- [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP",
- [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP",
- [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD",
- [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT",
+/* ------------------------------------------------------------------ */
+/* debug help functions */
+
+#ifdef HAVE_V4L1
+static const char *v4l1_ioctls[] = {
+ [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP",
+ [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN",
+ [_IOC_NR(VIDIOCSCHAN)] = "VIDIOCSCHAN",
+ [_IOC_NR(VIDIOCGTUNER)] = "VIDIOCGTUNER",
+ [_IOC_NR(VIDIOCSTUNER)] = "VIDIOCSTUNER",
+ [_IOC_NR(VIDIOCGPICT)] = "VIDIOCGPICT",
+ [_IOC_NR(VIDIOCSPICT)] = "VIDIOCSPICT",
+ [_IOC_NR(VIDIOCCAPTURE)] = "VIDIOCCAPTURE",
+ [_IOC_NR(VIDIOCGWIN)] = "VIDIOCGWIN",
+ [_IOC_NR(VIDIOCSWIN)] = "VIDIOCSWIN",
+ [_IOC_NR(VIDIOCGFBUF)] = "VIDIOCGFBUF",
+ [_IOC_NR(VIDIOCSFBUF)] = "VIDIOCSFBUF",
+ [_IOC_NR(VIDIOCKEY)] = "VIDIOCKEY",
+ [_IOC_NR(VIDIOCGFREQ)] = "VIDIOCGFREQ",
+ [_IOC_NR(VIDIOCSFREQ)] = "VIDIOCSFREQ",
+ [_IOC_NR(VIDIOCGAUDIO)] = "VIDIOCGAUDIO",
+ [_IOC_NR(VIDIOCSAUDIO)] = "VIDIOCSAUDIO",
+ [_IOC_NR(VIDIOCSYNC)] = "VIDIOCSYNC",
+ [_IOC_NR(VIDIOCMCAPTURE)] = "VIDIOCMCAPTURE",
+ [_IOC_NR(VIDIOCGMBUF)] = "VIDIOCGMBUF",
+ [_IOC_NR(VIDIOCGUNIT)] = "VIDIOCGUNIT",
+ [_IOC_NR(VIDIOCGCAPTURE)] = "VIDIOCGCAPTURE",
+ [_IOC_NR(VIDIOCSCAPTURE)] = "VIDIOCSCAPTURE",
+ [_IOC_NR(VIDIOCSPLAYMODE)] = "VIDIOCSPLAYMODE",
+ [_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE",
+ [_IOC_NR(VIDIOCGPLAYINFO)] = "VIDIOCGPLAYINFO",
+ [_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE",
+ [_IOC_NR(VIDIOCGVBIFMT)] = "VIDIOCGVBIFMT",
+ [_IOC_NR(VIDIOCSVBIFMT)] = "VIDIOCSVBIFMT"
};
+#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
+#endif
+
+static const char *v4l2_ioctls[] = {
+ [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP",
+ [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED",
+ [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT",
+ [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT",
+ [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT",
+ [_IOC_NR(VIDIOC_G_MPEGCOMP)] = "VIDIOC_G_MPEGCOMP",
+ [_IOC_NR(VIDIOC_S_MPEGCOMP)] = "VIDIOC_S_MPEGCOMP",
+ [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS",
+ [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF",
+ [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF",
+ [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF",
+ [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY",
+ [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF",
+ [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF",
+ [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON",
+ [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF",
+ [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM",
+ [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM",
+ [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD",
+ [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD",
+ [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD",
+ [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT",
+ [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL",
+ [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL",
+ [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER",
+ [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER",
+ [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO",
+ [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO",
+ [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL",
+ [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU",
+ [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT",
+ [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT",
+ [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT",
+ [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT",
+ [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT",
+ [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT",
+ [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT",
+ [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR",
+ [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR",
+ [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY",
+ [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY",
+ [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP",
+ [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP",
+ [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP",
+ [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP",
+ [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP",
+ [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD",
+ [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT",
+ [_IOC_NR(VIDIOC_ENUMAUDIO)] = "VIDIOC_ENUMAUDIO",
+ [_IOC_NR(VIDIOC_ENUMAUDOUT)] = "VIDIOC_ENUMAUDOUT",
+ [_IOC_NR(VIDIOC_G_PRIORITY)] = "VIDIOC_G_PRIORITY",
+ [_IOC_NR(VIDIOC_S_PRIORITY)] = "VIDIOC_S_PRIORITY",
+#if 1
+ [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP",
+#endif
+ [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS"
+};
+#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
+
+static const char *v4l2_int_ioctls[] = {
+#ifdef HAVE_VIDEO_DECODER
+ [_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES",
+ [_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS",
+ [_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM",
+ [_IOC_NR(DECODER_SET_INPUT)] = "DECODER_SET_INPUT",
+ [_IOC_NR(DECODER_SET_OUTPUT)] = "DECODER_SET_OUTPUT",
+ [_IOC_NR(DECODER_ENABLE_OUTPUT)] = "DECODER_ENABLE_OUTPUT",
+ [_IOC_NR(DECODER_SET_PICTURE)] = "DECODER_SET_PICTURE",
+ [_IOC_NR(DECODER_SET_GPIO)] = "DECODER_SET_GPIO",
+ [_IOC_NR(DECODER_INIT)] = "DECODER_INIT",
+ [_IOC_NR(DECODER_SET_VBI_BYPASS)] = "DECODER_SET_VBI_BYPASS",
+ [_IOC_NR(DECODER_DUMP)] = "DECODER_DUMP",
+#endif
+ [_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO",
+ [_IOC_NR(AUDC_SET_INPUT)] = "AUDC_SET_INPUT",
+
+ [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR",
+ [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY",
+ [_IOC_NR(TDA9887_SET_CONFIG)] = "TDA9887_SET_CONFIG",
+
+ [_IOC_NR(VIDIOC_INT_S_REGISTER)] = "VIDIOC_INT_S_REGISTER",
+ [_IOC_NR(VIDIOC_INT_G_REGISTER)] = "VIDIOC_INT_G_REGISTER",
+ [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET",
+ [_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ",
+ [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE",
+ [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA",
+ [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA",
+ [_IOC_NR(VIDIOC_INT_G_CHIP_IDENT)] = "VIDIOC_INT_G_CHIP_IDENT",
+ [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ"
+};
+#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
+
+/* Common ioctl debug function. This function can be used by
+ external ioctl messages as well as internal V4L ioctl */
+void v4l_printk_ioctl(unsigned int cmd)
+{
+ char *dir;
+
+ switch (_IOC_DIR(cmd)) {
+ case _IOC_NONE: dir = "--"; break;
+ case _IOC_READ: dir = "r-"; break;
+ case _IOC_WRITE: dir = "-w"; break;
+ case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
+ default: dir = "*ERR*"; break;
+ }
+ switch (_IOC_TYPE(cmd)) {
+ case 'd':
+ printk("v4l2_int ioctl %s, dir=%s (0x%08x)\n",
+ (_IOC_NR(cmd) < V4L2_INT_IOCTLS) ?
+ v4l2_int_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
+ break;
+#ifdef HAVE_V4L1
+ case 'v':
+ printk("v4l1 ioctl %s, dir=%s (0x%08x)\n",
+ (_IOC_NR(cmd) < V4L1_IOCTLS) ?
+ v4l1_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
+ break;
+#endif
+ case 'V':
+ printk("v4l2 ioctl %s, dir=%s (0x%08x)\n",
+ (_IOC_NR(cmd) < V4L2_IOCTLS) ?
+ v4l2_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
+ break;
+
+ default:
+ printk("unknown ioctl '%c', dir=%s, #%d (0x%08x)\n",
+ _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd);
+ }
+}
/* ----------------------------------------------------------------- */
@@ -253,7 +374,7 @@ EXPORT_SYMBOL(v4l2_prio_check);
EXPORT_SYMBOL(v4l2_field_names);
EXPORT_SYMBOL(v4l2_type_names);
-EXPORT_SYMBOL(v4l2_ioctl_names);
+EXPORT_SYMBOL(v4l_printk_ioctl);
/*
* Local variables:
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 6de5b0094b82..9a9902c56ae7 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -68,7 +68,8 @@ static void video_release(struct class_device *cd)
{
struct video_device *vfd = container_of(cd, struct video_device, class_dev);
-#if 1 /* needed until all drivers are fixed */
+#if 1
+ /* needed until all drivers are fixed */
if (!vfd->release)
return;
#endif
@@ -338,13 +339,14 @@ int video_register_device(struct video_device *vfd, int type, int nr)
if (vfd->dev)
vfd->class_dev.dev = vfd->dev;
vfd->class_dev.class = &video_class;
- vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
+ vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
strlcpy(vfd->class_dev.class_id, vfd->devfs_name + 4, BUS_ID_SIZE);
class_device_register(&vfd->class_dev);
class_device_create_file(&vfd->class_dev,
- &class_device_attr_name);
+ &class_device_attr_name);
-#if 1 /* needed until all drivers are fixed */
+#if 1
+ /* needed until all drivers are fixed */
if (!vfd->release)
printk(KERN_WARNING "videodev: \"%s\" has no release callback. "
"Please fix your driver for proper sysfs support, see "
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index c318ba32fbaf..b7b0afffd214 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -187,6 +187,7 @@ static struct file_operations w9966_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = w9966_v4l_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.read = w9966_v4l_read,
.llseek = no_llseek,
};
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index bbfd55cd9948..c2e6d2e9f5f1 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -25,7 +25,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
#include <linux/module.h>
#include <linux/types.h>
#include <linux/ioctl.h>
@@ -33,20 +32,12 @@
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/videodev.h>
-#include <media/audiochip.h>
+#include <media/v4l2-common.h>
MODULE_DESCRIPTION("wm8775 driver");
MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
MODULE_LICENSE("GPL");
-#define wm8775_err(fmt, arg...) do { \
- printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define wm8775_info(fmt, arg...) do { \
- printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
- i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
-
static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END };
@@ -70,7 +61,7 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val)
int i;
if (reg < 0 || reg >= TOT_REGS) {
- wm8775_err("Invalid register R%d\n", reg);
+ v4l_err(client, "Invalid register R%d\n", reg);
return -1;
}
@@ -80,7 +71,7 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val)
return 0;
}
}
- wm8775_err("I2C: cannot write %03x to register R%d\n", val, reg);
+ v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
return -1;
}
@@ -88,38 +79,53 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd,
void *arg)
{
struct wm8775_state *state = i2c_get_clientdata(client);
- int *input = arg;
+ struct v4l2_audio *input = arg;
+ struct v4l2_control *ctrl = arg;
switch (cmd) {
- case AUDC_SET_INPUT:
+ case VIDIOC_S_AUDIO:
+ /* There are 4 inputs and one output. Zero or more inputs
+ are multiplexed together to the output. Hence there are
+ 16 combinations.
+ If only one input is active (the normal case) then the
+ input values 1, 2, 4 or 8 should be used. */
+ if (input->index > 15) {
+ v4l_err(client, "Invalid input %d.\n", input->index);
+ return -EINVAL;
+ }
+ state->input = input->index;
+ if (state->muted)
+ break;
wm8775_write(client, R21, 0x0c0);
wm8775_write(client, R14, 0x1d4);
wm8775_write(client, R15, 0x1d4);
+ wm8775_write(client, R21, 0x100 + state->input);
+ break;
- if (*input == AUDIO_RADIO) {
- wm8775_write(client, R21, 0x108);
- state->input = 8;
- state->muted = 0;
- break;
- }
- if (*input == AUDIO_MUTE) {
- state->muted = 1;
- break;
- }
- if (*input == AUDIO_UNMUTE) {
+ case VIDIOC_G_AUDIO:
+ memset(input, 0, sizeof(*input));
+ input->index = state->input;
+ break;
+
+ case VIDIOC_G_CTRL:
+ if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ ctrl->value = state->muted;
+ break;
+
+ case VIDIOC_S_CTRL:
+ if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ state->muted = ctrl->value;
+ wm8775_write(client, R21, 0x0c0);
+ wm8775_write(client, R14, 0x1d4);
+ wm8775_write(client, R15, 0x1d4);
+ if (!state->muted)
wm8775_write(client, R21, 0x100 + state->input);
- state->muted = 0;
- break;
- }
- /* All other inputs... */
- wm8775_write(client, R21, 0x102);
- state->input = 2;
- state->muted = 0;
break;
case VIDIOC_LOG_STATUS:
- wm8775_info("Input: %s%s\n",
- state->input == 8 ? "radio" : "default",
+ v4l_info(client, "Input: %d%s\n", state->input,
state->muted ? " (muted)" : "");
break;
@@ -170,7 +176,7 @@ static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind)
client->driver = &i2c_driver;
snprintf(client->name, sizeof(client->name) - 1, "wm8775");
- wm8775_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+ v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL);
if (state == NULL) {
@@ -206,11 +212,7 @@ static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind)
static int wm8775_probe(struct i2c_adapter *adapter)
{
-#ifdef I2C_CLASS_TV_ANALOG
if (adapter->class & I2C_CLASS_TV_ANALOG)
-#else
- if (adapter->id == I2C_HW_B_BT848)
-#endif
return i2c_probe(adapter, &addr_data, wm8775_attach);
return 0;
}
@@ -235,12 +237,10 @@ static struct i2c_driver i2c_driver = {
.driver = {
.name = "wm8775",
},
-
- .id = I2C_DRIVERID_WM8775,
-
+ .id = I2C_DRIVERID_WM8775,
.attach_adapter = wm8775_probe,
- .detach_client = wm8775_detach,
- .command = wm8775_command,
+ .detach_client = wm8775_detach,
+ .command = wm8775_command,
};
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index 4034f1b45366..15283f44e79f 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -4678,6 +4678,7 @@ static struct file_operations zoran_fops = {
.open = zoran_open,
.release = zoran_close,
.ioctl = zoran_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
.read = zoran_read,
.write = zoran_write,
diff --git a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c
index 07286816d7df..d4c633b8a7f5 100644
--- a/drivers/media/video/zr36120.c
+++ b/drivers/media/video/zr36120.c
@@ -1490,6 +1490,7 @@ static struct video_device zr36120_template=
.write = zoran_write,
.poll = zoran_poll,
.ioctl = zoran_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.mmap = zoran_mmap,
.minor = -1,
};
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 6696f71363b9..bfca5c176e88 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -495,6 +495,7 @@ static void mmc_decode_cid(struct mmc_card *card)
case 2: /* MMC v2.0 - v2.2 */
case 3: /* MMC v3.1 - v3.3 */
+ case 4: /* MMC v4 */
card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index d5f28981596b..f2c42b13945d 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -187,7 +187,13 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.data.flags |= MMC_DATA_WRITE;
brq.data.blocks = 1;
}
- brq.mrq.stop = brq.data.blocks > 1 ? &brq.stop : NULL;
+
+ if (brq.data.blocks > 1) {
+ brq.data.flags |= MMC_DATA_MULTI;
+ brq.mrq.stop = &brq.stop;
+ } else {
+ brq.mrq.stop = NULL;
+ }
brq.data.sg = mq->sg;
brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg);
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index 4f13bd2ccf9a..f25757625361 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -90,7 +90,7 @@ static int dma = 2;
* Basic functions
*/
-static inline void wbsd_unlock_config(struct wbsd_host* host)
+static inline void wbsd_unlock_config(struct wbsd_host *host)
{
BUG_ON(host->config == 0);
@@ -98,14 +98,14 @@ static inline void wbsd_unlock_config(struct wbsd_host* host)
outb(host->unlock_code, host->config);
}
-static inline void wbsd_lock_config(struct wbsd_host* host)
+static inline void wbsd_lock_config(struct wbsd_host *host)
{
BUG_ON(host->config == 0);
outb(LOCK_CODE, host->config);
}
-static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value)
+static inline void wbsd_write_config(struct wbsd_host *host, u8 reg, u8 value)
{
BUG_ON(host->config == 0);
@@ -113,7 +113,7 @@ static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value)
outb(value, host->config + 1);
}
-static inline u8 wbsd_read_config(struct wbsd_host* host, u8 reg)
+static inline u8 wbsd_read_config(struct wbsd_host *host, u8 reg)
{
BUG_ON(host->config == 0);
@@ -121,13 +121,13 @@ static inline u8 wbsd_read_config(struct wbsd_host* host, u8 reg)
return inb(host->config + 1);
}
-static inline void wbsd_write_index(struct wbsd_host* host, u8 index, u8 value)
+static inline void wbsd_write_index(struct wbsd_host *host, u8 index, u8 value)
{
outb(index, host->base + WBSD_IDXR);
outb(value, host->base + WBSD_DATAR);
}
-static inline u8 wbsd_read_index(struct wbsd_host* host, u8 index)
+static inline u8 wbsd_read_index(struct wbsd_host *host, u8 index)
{
outb(index, host->base + WBSD_IDXR);
return inb(host->base + WBSD_DATAR);
@@ -137,7 +137,7 @@ static inline u8 wbsd_read_index(struct wbsd_host* host, u8 index)
* Common routines
*/
-static void wbsd_init_device(struct wbsd_host* host)
+static void wbsd_init_device(struct wbsd_host *host)
{
u8 setup, ier;
@@ -197,7 +197,7 @@ static void wbsd_init_device(struct wbsd_host* host)
inb(host->base + WBSD_ISR);
}
-static void wbsd_reset(struct wbsd_host* host)
+static void wbsd_reset(struct wbsd_host *host)
{
u8 setup;
@@ -211,14 +211,13 @@ static void wbsd_reset(struct wbsd_host* host)
wbsd_write_index(host, WBSD_IDX_SETUP, setup);
}
-static void wbsd_request_end(struct wbsd_host* host, struct mmc_request* mrq)
+static void wbsd_request_end(struct wbsd_host *host, struct mmc_request *mrq)
{
unsigned long dmaflags;
DBGF("Ending request, cmd (%x)\n", mrq->cmd->opcode);
- if (host->dma >= 0)
- {
+ if (host->dma >= 0) {
/*
* Release ISA DMA controller.
*/
@@ -247,7 +246,7 @@ static void wbsd_request_end(struct wbsd_host* host, struct mmc_request* mrq)
* Scatter/gather functions
*/
-static inline void wbsd_init_sg(struct wbsd_host* host, struct mmc_data* data)
+static inline void wbsd_init_sg(struct wbsd_host *host, struct mmc_data *data)
{
/*
* Get info. about SG list from data structure.
@@ -259,7 +258,7 @@ static inline void wbsd_init_sg(struct wbsd_host* host, struct mmc_data* data)
host->remain = host->cur_sg->length;
}
-static inline int wbsd_next_sg(struct wbsd_host* host)
+static inline int wbsd_next_sg(struct wbsd_host *host)
{
/*
* Skip to next SG entry.
@@ -270,33 +269,32 @@ static inline int wbsd_next_sg(struct wbsd_host* host)
/*
* Any entries left?
*/
- if (host->num_sg > 0)
- {
- host->offset = 0;
- host->remain = host->cur_sg->length;
- }
+ if (host->num_sg > 0) {
+ host->offset = 0;
+ host->remain = host->cur_sg->length;
+ }
return host->num_sg;
}
-static inline char* wbsd_kmap_sg(struct wbsd_host* host)
+static inline char *wbsd_kmap_sg(struct wbsd_host *host)
{
host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ) +
host->cur_sg->offset;
return host->mapped_sg;
}
-static inline void wbsd_kunmap_sg(struct wbsd_host* host)
+static inline void wbsd_kunmap_sg(struct wbsd_host *host)
{
kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
}
-static inline void wbsd_sg_to_dma(struct wbsd_host* host, struct mmc_data* data)
+static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
{
unsigned int len, i, size;
- struct scatterlist* sg;
- char* dmabuf = host->dma_buffer;
- char* sgbuf;
+ struct scatterlist *sg;
+ char *dmabuf = host->dma_buffer;
+ char *sgbuf;
size = host->size;
@@ -308,8 +306,7 @@ static inline void wbsd_sg_to_dma(struct wbsd_host* host, struct mmc_data* data)
* be the entire list though so make sure that
* we do not transfer too much.
*/
- for (i = 0;i < len;i++)
- {
+ for (i = 0; i < len; i++) {
sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
if (size < sg[i].length)
memcpy(dmabuf, sgbuf, size);
@@ -337,12 +334,12 @@ static inline void wbsd_sg_to_dma(struct wbsd_host* host, struct mmc_data* data)
host->size -= size;
}
-static inline void wbsd_dma_to_sg(struct wbsd_host* host, struct mmc_data* data)
+static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
{
unsigned int len, i, size;
- struct scatterlist* sg;
- char* dmabuf = host->dma_buffer;
- char* sgbuf;
+ struct scatterlist *sg;
+ char *dmabuf = host->dma_buffer;
+ char *sgbuf;
size = host->size;
@@ -354,8 +351,7 @@ static inline void wbsd_dma_to_sg(struct wbsd_host* host, struct mmc_data* data)
* be the entire list though so make sure that
* we do not transfer too much.
*/
- for (i = 0;i < len;i++)
- {
+ for (i = 0; i < len; i++) {
sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
if (size < sg[i].length)
memcpy(sgbuf, dmabuf, size);
@@ -387,46 +383,38 @@ static inline void wbsd_dma_to_sg(struct wbsd_host* host, struct mmc_data* data)
* Command handling
*/
-static inline void wbsd_get_short_reply(struct wbsd_host* host,
- struct mmc_command* cmd)
+static inline void wbsd_get_short_reply(struct wbsd_host *host,
+ struct mmc_command *cmd)
{
/*
* Correct response type?
*/
- if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT)
- {
+ if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT) {
cmd->error = MMC_ERR_INVALID;
return;
}
- cmd->resp[0] =
- wbsd_read_index(host, WBSD_IDX_RESP12) << 24;
- cmd->resp[0] |=
- wbsd_read_index(host, WBSD_IDX_RESP13) << 16;
- cmd->resp[0] |=
- wbsd_read_index(host, WBSD_IDX_RESP14) << 8;
- cmd->resp[0] |=
- wbsd_read_index(host, WBSD_IDX_RESP15) << 0;
- cmd->resp[1] =
- wbsd_read_index(host, WBSD_IDX_RESP16) << 24;
+ cmd->resp[0] = wbsd_read_index(host, WBSD_IDX_RESP12) << 24;
+ cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP13) << 16;
+ cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP14) << 8;
+ cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP15) << 0;
+ cmd->resp[1] = wbsd_read_index(host, WBSD_IDX_RESP16) << 24;
}
-static inline void wbsd_get_long_reply(struct wbsd_host* host,
- struct mmc_command* cmd)
+static inline void wbsd_get_long_reply(struct wbsd_host *host,
+ struct mmc_command *cmd)
{
int i;
/*
* Correct response type?
*/
- if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG)
- {
+ if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG) {
cmd->error = MMC_ERR_INVALID;
return;
}
- for (i = 0;i < 4;i++)
- {
+ for (i = 0; i < 4; i++) {
cmd->resp[i] =
wbsd_read_index(host, WBSD_IDX_RESP1 + i * 4) << 24;
cmd->resp[i] |=
@@ -438,7 +426,7 @@ static inline void wbsd_get_long_reply(struct wbsd_host* host,
}
}
-static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd)
+static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
{
int i;
u8 status, isr;
@@ -456,7 +444,7 @@ static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd)
* Send the command (CRC calculated by host).
*/
outb(cmd->opcode, host->base + WBSD_CMDR);
- for (i = 3;i >= 0;i--)
+ for (i = 3; i >= 0; i--)
outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR);
cmd->error = MMC_ERR_NONE;
@@ -471,8 +459,7 @@ static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd)
/*
* Do we expect a reply?
*/
- if ((cmd->flags & MMC_RSP_MASK) != MMC_RSP_NONE)
- {
+ if ((cmd->flags & MMC_RSP_MASK) != MMC_RSP_NONE) {
/*
* Read back status.
*/
@@ -488,8 +475,7 @@ static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd)
else if ((cmd->flags & MMC_RSP_CRC) && (isr & WBSD_INT_CRC))
cmd->error = MMC_ERR_BADCRC;
/* All ok */
- else
- {
+ else {
if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_SHORT)
wbsd_get_short_reply(host, cmd);
else
@@ -504,10 +490,10 @@ static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd)
* Data functions
*/
-static void wbsd_empty_fifo(struct wbsd_host* host)
+static void wbsd_empty_fifo(struct wbsd_host *host)
{
- struct mmc_data* data = host->mrq->cmd->data;
- char* buffer;
+ struct mmc_data *data = host->mrq->cmd->data;
+ char *buffer;
int i, fsr, fifo;
/*
@@ -522,8 +508,7 @@ static void wbsd_empty_fifo(struct wbsd_host* host)
* Drain the fifo. This has a tendency to loop longer
* than the FIFO length (usually one block).
*/
- while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_EMPTY))
- {
+ while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_EMPTY)) {
/*
* The size field in the FSR is broken so we have to
* do some guessing.
@@ -535,8 +520,7 @@ static void wbsd_empty_fifo(struct wbsd_host* host)
else
fifo = 1;
- for (i = 0;i < fifo;i++)
- {
+ for (i = 0; i < fifo; i++) {
*buffer = inb(host->base + WBSD_DFR);
buffer++;
host->offset++;
@@ -547,8 +531,7 @@ static void wbsd_empty_fifo(struct wbsd_host* host)
/*
* Transfer done?
*/
- if (data->bytes_xfered == host->size)
- {
+ if (data->bytes_xfered == host->size) {
wbsd_kunmap_sg(host);
return;
}
@@ -556,15 +539,13 @@ static void wbsd_empty_fifo(struct wbsd_host* host)
/*
* End of scatter list entry?
*/
- if (host->remain == 0)
- {
+ if (host->remain == 0) {
wbsd_kunmap_sg(host);
/*
* Get next entry. Check if last.
*/
- if (!wbsd_next_sg(host))
- {
+ if (!wbsd_next_sg(host)) {
/*
* We should never reach this point.
* It means that we're trying to
@@ -594,10 +575,10 @@ static void wbsd_empty_fifo(struct wbsd_host* host)
tasklet_schedule(&host->fifo_tasklet);
}
-static void wbsd_fill_fifo(struct wbsd_host* host)
+static void wbsd_fill_fifo(struct wbsd_host *host)
{
- struct mmc_data* data = host->mrq->cmd->data;
- char* buffer;
+ struct mmc_data *data = host->mrq->cmd->data;
+ char *buffer;
int i, fsr, fifo;
/*
@@ -613,8 +594,7 @@ static void wbsd_fill_fifo(struct wbsd_host* host)
* Fill the fifo. This has a tendency to loop longer
* than the FIFO length (usually one block).
*/
- while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_FULL))
- {
+ while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_FULL)) {
/*
* The size field in the FSR is broken so we have to
* do some guessing.
@@ -626,8 +606,7 @@ static void wbsd_fill_fifo(struct wbsd_host* host)
else
fifo = 15;
- for (i = 16;i > fifo;i--)
- {
+ for (i = 16; i > fifo; i--) {
outb(*buffer, host->base + WBSD_DFR);
buffer++;
host->offset++;
@@ -638,8 +617,7 @@ static void wbsd_fill_fifo(struct wbsd_host* host)
/*
* Transfer done?
*/
- if (data->bytes_xfered == host->size)
- {
+ if (data->bytes_xfered == host->size) {
wbsd_kunmap_sg(host);
return;
}
@@ -647,15 +625,13 @@ static void wbsd_fill_fifo(struct wbsd_host* host)
/*
* End of scatter list entry?
*/
- if (host->remain == 0)
- {
+ if (host->remain == 0) {
wbsd_kunmap_sg(host);
/*
* Get next entry. Check if last.
*/
- if (!wbsd_next_sg(host))
- {
+ if (!wbsd_next_sg(host)) {
/*
* We should never reach this point.
* It means that we're trying to
@@ -684,7 +660,7 @@ static void wbsd_fill_fifo(struct wbsd_host* host)
tasklet_schedule(&host->fifo_tasklet);
}
-static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
+static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
{
u16 blksize;
u8 setup;
@@ -706,8 +682,10 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
*/
if (data->timeout_ns > 127000000)
wbsd_write_index(host, WBSD_IDX_TAAC, 127);
- else
- wbsd_write_index(host, WBSD_IDX_TAAC, data->timeout_ns/1000000);
+ else {
+ wbsd_write_index(host, WBSD_IDX_TAAC,
+ data->timeout_ns / 1000000);
+ }
if (data->timeout_clks > 255)
wbsd_write_index(host, WBSD_IDX_NSAC, 255);
@@ -722,23 +700,18 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
* Space for CRC must be included in the size.
* Two bytes are needed for each data line.
*/
- if (host->bus_width == MMC_BUS_WIDTH_1)
- {
+ if (host->bus_width == MMC_BUS_WIDTH_1) {
blksize = (1 << data->blksz_bits) + 2;
wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
- }
- else if (host->bus_width == MMC_BUS_WIDTH_4)
- {
+ } else if (host->bus_width == MMC_BUS_WIDTH_4) {
blksize = (1 << data->blksz_bits) + 2 * 4;
- wbsd_write_index(host, WBSD_IDX_PBSMSB, ((blksize >> 4) & 0xF0)
- | WBSD_DATA_WIDTH);
+ wbsd_write_index(host, WBSD_IDX_PBSMSB,
+ ((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH);
wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
- }
- else
- {
+ } else {
data->error = MMC_ERR_INVALID;
return;
}
@@ -755,14 +728,12 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
/*
* DMA transfer?
*/
- if (host->dma >= 0)
- {
+ if (host->dma >= 0) {
/*
* The buffer for DMA is only 64 kB.
*/
BUG_ON(host->size > 0x10000);
- if (host->size > 0x10000)
- {
+ if (host->size > 0x10000) {
data->error = MMC_ERR_INVALID;
return;
}
@@ -794,9 +765,7 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
* Enable DMA on the host.
*/
wbsd_write_index(host, WBSD_IDX_DMA, WBSD_DMA_ENABLE);
- }
- else
- {
+ } else {
/*
* This flag is used to keep printk
* output to a minimum.
@@ -817,13 +786,10 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
* Set up FIFO threshold levels (and fill
* buffer if doing a write).
*/
- if (data->flags & MMC_DATA_READ)
- {
+ if (data->flags & MMC_DATA_READ) {
wbsd_write_index(host, WBSD_IDX_FIFOEN,
WBSD_FIFOEN_FULL | 8);
- }
- else
- {
+ } else {
wbsd_write_index(host, WBSD_IDX_FIFOEN,
WBSD_FIFOEN_EMPTY | 8);
wbsd_fill_fifo(host);
@@ -833,7 +799,7 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
data->error = MMC_ERR_NONE;
}
-static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data)
+static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
{
unsigned long dmaflags;
int count;
@@ -851,16 +817,14 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data)
* Wait for the controller to leave data
* transfer state.
*/
- do
- {
+ do {
status = wbsd_read_index(host, WBSD_IDX_STATUS);
} while (status & (WBSD_BLOCK_READ | WBSD_BLOCK_WRITE));
/*
* DMA transfer?
*/
- if (host->dma >= 0)
- {
+ if (host->dma >= 0) {
/*
* Disable DMA on the host.
*/
@@ -878,16 +842,13 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data)
/*
* Any leftover data?
*/
- if (count)
- {
+ if (count) {
printk(KERN_ERR "%s: Incomplete DMA transfer. "
"%d bytes left.\n",
mmc_hostname(host->mmc), count);
data->error = MMC_ERR_FAILED;
- }
- else
- {
+ } else {
/*
* Transfer data from DMA buffer to
* SG list.
@@ -910,10 +871,10 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data)
* *
\*****************************************************************************/
-static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq)
+static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
- struct wbsd_host* host = mmc_priv(mmc);
- struct mmc_command* cmd;
+ struct wbsd_host *host = mmc_priv(mmc);
+ struct mmc_command *cmd;
/*
* Disable tasklets to avoid a deadlock.
@@ -930,8 +891,7 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq)
* If there is no card in the slot then
* timeout immediatly.
*/
- if (!(host->flags & WBSD_FCARD_PRESENT))
- {
+ if (!(host->flags & WBSD_FCARD_PRESENT)) {
cmd->error = MMC_ERR_TIMEOUT;
goto done;
}
@@ -939,8 +899,7 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq)
/*
* Does the request include data?
*/
- if (cmd->data)
- {
+ if (cmd->data) {
wbsd_prepare_data(host, cmd->data);
if (cmd->data->error != MMC_ERR_NONE)
@@ -954,8 +913,7 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq)
* will be finished after the data has
* transfered.
*/
- if (cmd->data && (cmd->error == MMC_ERR_NONE))
- {
+ if (cmd->data && (cmd->error == MMC_ERR_NONE)) {
/*
* Dirty fix for hardware bug.
*/
@@ -973,14 +931,14 @@ done:
spin_unlock_bh(&host->lock);
}
-static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
+static void wbsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
- struct wbsd_host* host = mmc_priv(mmc);
+ struct wbsd_host *host = mmc_priv(mmc);
u8 clk, setup, pwr;
DBGF("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n",
- ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select,
- ios->vdd, ios->bus_width);
+ ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select,
+ ios->vdd, ios->bus_width);
spin_lock_bh(&host->lock);
@@ -1004,8 +962,7 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
* Only write to the clock register when
* there is an actual change.
*/
- if (clk != host->clk)
- {
+ if (clk != host->clk) {
wbsd_write_index(host, WBSD_IDX_CLK, clk);
host->clk = clk;
}
@@ -1013,8 +970,7 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
/*
* Power up card.
*/
- if (ios->power_mode != MMC_POWER_OFF)
- {
+ if (ios->power_mode != MMC_POWER_OFF) {
pwr = inb(host->base + WBSD_CSR);
pwr &= ~WBSD_POWER_N;
outb(pwr, host->base + WBSD_CSR);
@@ -1026,23 +982,19 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
* that needs to be disabled.
*/
setup = wbsd_read_index(host, WBSD_IDX_SETUP);
- if (ios->chip_select == MMC_CS_HIGH)
- {
+ if (ios->chip_select == MMC_CS_HIGH) {
BUG_ON(ios->bus_width != MMC_BUS_WIDTH_1);
setup |= WBSD_DAT3_H;
host->flags |= WBSD_FIGNORE_DETECT;
- }
- else
- {
- if (setup & WBSD_DAT3_H)
- {
+ } else {
+ if (setup & WBSD_DAT3_H) {
setup &= ~WBSD_DAT3_H;
/*
* We cannot resume card detection immediatly
* because of capacitance and delays in the chip.
*/
- mod_timer(&host->ignore_timer, jiffies + HZ/100);
+ mod_timer(&host->ignore_timer, jiffies + HZ / 100);
}
}
wbsd_write_index(host, WBSD_IDX_SETUP, setup);
@@ -1056,9 +1008,9 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
spin_unlock_bh(&host->lock);
}
-static int wbsd_get_ro(struct mmc_host* mmc)
+static int wbsd_get_ro(struct mmc_host *mmc)
{
- struct wbsd_host* host = mmc_priv(mmc);
+ struct wbsd_host *host = mmc_priv(mmc);
u8 csr;
spin_lock_bh(&host->lock);
@@ -1096,7 +1048,7 @@ static struct mmc_host_ops wbsd_ops = {
static void wbsd_reset_ignore(unsigned long data)
{
- struct wbsd_host *host = (struct wbsd_host*)data;
+ struct wbsd_host *host = (struct wbsd_host *)data;
BUG_ON(host == NULL);
@@ -1119,7 +1071,7 @@ static void wbsd_reset_ignore(unsigned long data)
* Tasklets
*/
-static inline struct mmc_data* wbsd_get_data(struct wbsd_host* host)
+static inline struct mmc_data *wbsd_get_data(struct wbsd_host *host)
{
WARN_ON(!host->mrq);
if (!host->mrq)
@@ -1138,14 +1090,13 @@ static inline struct mmc_data* wbsd_get_data(struct wbsd_host* host)
static void wbsd_tasklet_card(unsigned long param)
{
- struct wbsd_host* host = (struct wbsd_host*)param;
+ struct wbsd_host *host = (struct wbsd_host *)param;
u8 csr;
int delay = -1;
spin_lock(&host->lock);
- if (host->flags & WBSD_FIGNORE_DETECT)
- {
+ if (host->flags & WBSD_FIGNORE_DETECT) {
spin_unlock(&host->lock);
return;
}
@@ -1153,23 +1104,18 @@ static void wbsd_tasklet_card(unsigned long param)
csr = inb(host->base + WBSD_CSR);
WARN_ON(csr == 0xff);
- if (csr & WBSD_CARDPRESENT)
- {
- if (!(host->flags & WBSD_FCARD_PRESENT))
- {
+ if (csr & WBSD_CARDPRESENT) {
+ if (!(host->flags & WBSD_FCARD_PRESENT)) {
DBG("Card inserted\n");
host->flags |= WBSD_FCARD_PRESENT;
delay = 500;
}
- }
- else if (host->flags & WBSD_FCARD_PRESENT)
- {
+ } else if (host->flags & WBSD_FCARD_PRESENT) {
DBG("Card removed\n");
host->flags &= ~WBSD_FCARD_PRESENT;
- if (host->mrq)
- {
+ if (host->mrq) {
printk(KERN_ERR "%s: Card removed during transfer!\n",
mmc_hostname(host->mmc));
wbsd_reset(host);
@@ -1193,8 +1139,8 @@ static void wbsd_tasklet_card(unsigned long param)
static void wbsd_tasklet_fifo(unsigned long param)
{
- struct wbsd_host* host = (struct wbsd_host*)param;
- struct mmc_data* data;
+ struct wbsd_host *host = (struct wbsd_host *)param;
+ struct mmc_data *data;
spin_lock(&host->lock);
@@ -1213,8 +1159,7 @@ static void wbsd_tasklet_fifo(unsigned long param)
/*
* Done?
*/
- if (host->size == data->bytes_xfered)
- {
+ if (host->size == data->bytes_xfered) {
wbsd_write_index(host, WBSD_IDX_FIFOEN, 0);
tasklet_schedule(&host->finish_tasklet);
}
@@ -1225,8 +1170,8 @@ end:
static void wbsd_tasklet_crc(unsigned long param)
{
- struct wbsd_host* host = (struct wbsd_host*)param;
- struct mmc_data* data;
+ struct wbsd_host *host = (struct wbsd_host *)param;
+ struct mmc_data *data;
spin_lock(&host->lock);
@@ -1249,8 +1194,8 @@ end:
static void wbsd_tasklet_timeout(unsigned long param)
{
- struct wbsd_host* host = (struct wbsd_host*)param;
- struct mmc_data* data;
+ struct wbsd_host *host = (struct wbsd_host *)param;
+ struct mmc_data *data;
spin_lock(&host->lock);
@@ -1273,8 +1218,8 @@ end:
static void wbsd_tasklet_finish(unsigned long param)
{
- struct wbsd_host* host = (struct wbsd_host*)param;
- struct mmc_data* data;
+ struct wbsd_host *host = (struct wbsd_host *)param;
+ struct mmc_data *data;
spin_lock(&host->lock);
@@ -1294,14 +1239,13 @@ end:
static void wbsd_tasklet_block(unsigned long param)
{
- struct wbsd_host* host = (struct wbsd_host*)param;
- struct mmc_data* data;
+ struct wbsd_host *host = (struct wbsd_host *)param;
+ struct mmc_data *data;
spin_lock(&host->lock);
if ((wbsd_read_index(host, WBSD_IDX_CRCSTATUS) & WBSD_CRC_MASK) !=
- WBSD_CRC_OK)
- {
+ WBSD_CRC_OK) {
data = wbsd_get_data(host);
if (!data)
goto end;
@@ -1323,7 +1267,7 @@ end:
static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs)
{
- struct wbsd_host* host = dev_id;
+ struct wbsd_host *host = dev_id;
int isr;
isr = inb(host->base + WBSD_ISR);
@@ -1365,10 +1309,10 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs)
* Allocate/free MMC structure.
*/
-static int __devinit wbsd_alloc_mmc(struct device* dev)
+static int __devinit wbsd_alloc_mmc(struct device *dev)
{
- struct mmc_host* mmc;
- struct wbsd_host* host;
+ struct mmc_host *mmc;
+ struct wbsd_host *host;
/*
* Allocate MMC structure.
@@ -1388,7 +1332,7 @@ static int __devinit wbsd_alloc_mmc(struct device* dev)
mmc->ops = &wbsd_ops;
mmc->f_min = 375000;
mmc->f_max = 24000000;
- mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->caps = MMC_CAP_4_BIT_DATA;
spin_lock_init(&host->lock);
@@ -1424,10 +1368,10 @@ static int __devinit wbsd_alloc_mmc(struct device* dev)
return 0;
}
-static void __devexit wbsd_free_mmc(struct device* dev)
+static void __devexit wbsd_free_mmc(struct device *dev)
{
- struct mmc_host* mmc;
- struct wbsd_host* host;
+ struct mmc_host *mmc;
+ struct wbsd_host *host;
mmc = dev_get_drvdata(dev);
if (!mmc)
@@ -1447,7 +1391,7 @@ static void __devexit wbsd_free_mmc(struct device* dev)
* Scan for known chip id:s
*/
-static int __devinit wbsd_scan(struct wbsd_host* host)
+static int __devinit wbsd_scan(struct wbsd_host *host)
{
int i, j, k;
int id;
@@ -1477,16 +1421,14 @@ static int __devinit wbsd_scan(struct wbsd_host* host)
wbsd_lock_config(host);
for (k = 0; k < ARRAY_SIZE(valid_ids); k++) {
- if (id == valid_ids[k])
- {
+ if (id == valid_ids[k]) {
host->chip_id = id;
return 0;
}
}
- if (id != 0xFFFF)
- {
+ if (id != 0xFFFF) {
DBG("Unknown hardware (id %x) found at %x\n",
id, config_ports[i]);
}
@@ -1505,7 +1447,7 @@ static int __devinit wbsd_scan(struct wbsd_host* host)
* Allocate/free io port ranges
*/
-static int __devinit wbsd_request_region(struct wbsd_host* host, int base)
+static int __devinit wbsd_request_region(struct wbsd_host *host, int base)
{
if (io & 0x7)
return -EINVAL;
@@ -1518,7 +1460,7 @@ static int __devinit wbsd_request_region(struct wbsd_host* host, int base)
return 0;
}
-static void __devexit wbsd_release_regions(struct wbsd_host* host)
+static void __devexit wbsd_release_regions(struct wbsd_host *host)
{
if (host->base)
release_region(host->base, 8);
@@ -1535,7 +1477,7 @@ static void __devexit wbsd_release_regions(struct wbsd_host* host)
* Allocate/free DMA port and buffer
*/
-static void __devinit wbsd_request_dma(struct wbsd_host* host, int dma)
+static void __devinit wbsd_request_dma(struct wbsd_host *host, int dma)
{
if (dma < 0)
return;
@@ -1579,8 +1521,8 @@ kfree:
*/
BUG_ON(1);
- dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE,
- DMA_BIDIRECTIONAL);
+ dma_unmap_single(host->mmc->dev, host->dma_addr,
+ WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
host->dma_addr = (dma_addr_t)NULL;
kfree(host->dma_buffer);
@@ -1594,11 +1536,12 @@ err:
"Falling back on FIFO.\n", dma);
}
-static void __devexit wbsd_release_dma(struct wbsd_host* host)
+static void __devexit wbsd_release_dma(struct wbsd_host *host)
{
- if (host->dma_addr)
- dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE,
- DMA_BIDIRECTIONAL);
+ if (host->dma_addr) {
+ dma_unmap_single(host->mmc->dev, host->dma_addr,
+ WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
+ }
kfree(host->dma_buffer);
if (host->dma >= 0)
free_dma(host->dma);
@@ -1612,7 +1555,7 @@ static void __devexit wbsd_release_dma(struct wbsd_host* host)
* Allocate/free IRQ.
*/
-static int __devinit wbsd_request_irq(struct wbsd_host* host, int irq)
+static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq)
{
int ret;
@@ -1629,17 +1572,23 @@ static int __devinit wbsd_request_irq(struct wbsd_host* host, int irq)
/*
* Set up tasklets.
*/
- tasklet_init(&host->card_tasklet, wbsd_tasklet_card, (unsigned long)host);
- tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, (unsigned long)host);
- tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, (unsigned long)host);
- tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host);
- tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host);
- tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host);
+ tasklet_init(&host->card_tasklet, wbsd_tasklet_card,
+ (unsigned long)host);
+ tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo,
+ (unsigned long)host);
+ tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc,
+ (unsigned long)host);
+ tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout,
+ (unsigned long)host);
+ tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish,
+ (unsigned long)host);
+ tasklet_init(&host->block_tasklet, wbsd_tasklet_block,
+ (unsigned long)host);
return 0;
}
-static void __devexit wbsd_release_irq(struct wbsd_host* host)
+static void __devexit wbsd_release_irq(struct wbsd_host *host)
{
if (!host->irq)
return;
@@ -1660,7 +1609,7 @@ static void __devexit wbsd_release_irq(struct wbsd_host* host)
* Allocate all resources for the host.
*/
-static int __devinit wbsd_request_resources(struct wbsd_host* host,
+static int __devinit wbsd_request_resources(struct wbsd_host *host,
int base, int irq, int dma)
{
int ret;
@@ -1691,7 +1640,7 @@ static int __devinit wbsd_request_resources(struct wbsd_host* host,
* Release all resources for the host.
*/
-static void __devexit wbsd_release_resources(struct wbsd_host* host)
+static void __devexit wbsd_release_resources(struct wbsd_host *host)
{
wbsd_release_dma(host);
wbsd_release_irq(host);
@@ -1702,7 +1651,7 @@ static void __devexit wbsd_release_resources(struct wbsd_host* host)
* Configure the resources the chip should use.
*/
-static void wbsd_chip_config(struct wbsd_host* host)
+static void wbsd_chip_config(struct wbsd_host *host)
{
wbsd_unlock_config(host);
@@ -1746,7 +1695,7 @@ static void wbsd_chip_config(struct wbsd_host* host)
* Check that configured resources are correct.
*/
-static int wbsd_chip_validate(struct wbsd_host* host)
+static int wbsd_chip_validate(struct wbsd_host *host)
{
int base, irq, dma;
@@ -1786,7 +1735,7 @@ static int wbsd_chip_validate(struct wbsd_host* host)
* Powers down the SD function
*/
-static void wbsd_chip_poweroff(struct wbsd_host* host)
+static void wbsd_chip_poweroff(struct wbsd_host *host)
{
wbsd_unlock_config(host);
@@ -1802,11 +1751,11 @@ static void wbsd_chip_poweroff(struct wbsd_host* host)
* *
\*****************************************************************************/
-static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma,
+static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma,
int pnp)
{
- struct wbsd_host* host = NULL;
- struct mmc_host* mmc = NULL;
+ struct wbsd_host *host = NULL;
+ struct mmc_host *mmc = NULL;
int ret;
ret = wbsd_alloc_mmc(dev);
@@ -1820,16 +1769,12 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma,
* Scan for hardware.
*/
ret = wbsd_scan(host);
- if (ret)
- {
- if (pnp && (ret == -ENODEV))
- {
+ if (ret) {
+ if (pnp && (ret == -ENODEV)) {
printk(KERN_WARNING DRIVER_NAME
": Unable to confirm device presence. You may "
"experience lock-ups.\n");
- }
- else
- {
+ } else {
wbsd_free_mmc(dev);
return ret;
}
@@ -1839,8 +1784,7 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma,
* Request resources.
*/
ret = wbsd_request_resources(host, io, irq, dma);
- if (ret)
- {
+ if (ret) {
wbsd_release_resources(host);
wbsd_free_mmc(dev);
return ret;
@@ -1849,18 +1793,15 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma,
/*
* See if chip needs to be configured.
*/
- if (pnp)
- {
- if ((host->config != 0) && !wbsd_chip_validate(host))
- {
+ if (pnp) {
+ if ((host->config != 0) && !wbsd_chip_validate(host)) {
printk(KERN_WARNING DRIVER_NAME
": PnP active but chip not configured! "
"You probably have a buggy BIOS. "
"Configuring chip manually.\n");
wbsd_chip_config(host);
}
- }
- else
+ } else
wbsd_chip_config(host);
/*
@@ -1868,8 +1809,7 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma,
* Not tested.
*/
#ifdef CONFIG_PM
- if (host->config)
- {
+ if (host->config) {
wbsd_unlock_config(host);
wbsd_write_config(host, WBSD_CONF_PME, 0xA0);
wbsd_lock_config(host);
@@ -1902,10 +1842,10 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma,
return 0;
}
-static void __devexit wbsd_shutdown(struct device* dev, int pnp)
+static void __devexit wbsd_shutdown(struct device *dev, int pnp)
{
- struct mmc_host* mmc = dev_get_drvdata(dev);
- struct wbsd_host* host;
+ struct mmc_host *mmc = dev_get_drvdata(dev);
+ struct wbsd_host *host;
if (!mmc)
return;
@@ -1929,12 +1869,12 @@ static void __devexit wbsd_shutdown(struct device* dev, int pnp)
* Non-PnP
*/
-static int __devinit wbsd_probe(struct platform_device* dev)
+static int __devinit wbsd_probe(struct platform_device *dev)
{
return wbsd_init(&dev->dev, io, irq, dma, 0);
}
-static int __devexit wbsd_remove(struct platform_device* dev)
+static int __devexit wbsd_remove(struct platform_device *dev)
{
wbsd_shutdown(&dev->dev, 0);
@@ -1948,7 +1888,7 @@ static int __devexit wbsd_remove(struct platform_device* dev)
#ifdef CONFIG_PNP
static int __devinit
-wbsd_pnp_probe(struct pnp_dev * pnpdev, const struct pnp_device_id *dev_id)
+wbsd_pnp_probe(struct pnp_dev *pnpdev, const struct pnp_device_id *dev_id)
{
int io, irq, dma;
@@ -1967,7 +1907,7 @@ wbsd_pnp_probe(struct pnp_dev * pnpdev, const struct pnp_device_id *dev_id)
return wbsd_init(&pnpdev->dev, io, irq, dma, 1);
}
-static void __devexit wbsd_pnp_remove(struct pnp_dev * dev)
+static void __devexit wbsd_pnp_remove(struct pnp_dev *dev)
{
wbsd_shutdown(&dev->dev, 1);
}
@@ -1980,37 +1920,54 @@ static void __devexit wbsd_pnp_remove(struct pnp_dev * dev)
#ifdef CONFIG_PM
-static int wbsd_suspend(struct platform_device *dev, pm_message_t state)
+static int wbsd_suspend(struct wbsd_host *host, pm_message_t state)
+{
+ BUG_ON(host == NULL);
+
+ return mmc_suspend_host(host->mmc, state);
+}
+
+static int wbsd_resume(struct wbsd_host *host)
+{
+ BUG_ON(host == NULL);
+
+ wbsd_init_device(host);
+
+ return mmc_resume_host(host->mmc);
+}
+
+static int wbsd_platform_suspend(struct platform_device *dev,
+ pm_message_t state)
{
struct mmc_host *mmc = platform_get_drvdata(dev);
struct wbsd_host *host;
int ret;
- if (!mmc)
+ if (mmc == NULL)
return 0;
- DBG("Suspending...\n");
-
- ret = mmc_suspend_host(mmc, state);
- if (!ret)
- return ret;
+ DBGF("Suspending...\n");
host = mmc_priv(mmc);
+ ret = wbsd_suspend(host, state);
+ if (ret)
+ return ret;
+
wbsd_chip_poweroff(host);
return 0;
}
-static int wbsd_resume(struct platform_device *dev)
+static int wbsd_platform_resume(struct platform_device *dev)
{
struct mmc_host *mmc = platform_get_drvdata(dev);
struct wbsd_host *host;
- if (!mmc)
+ if (mmc == NULL)
return 0;
- DBG("Resuming...\n");
+ DBGF("Resuming...\n");
host = mmc_priv(mmc);
@@ -2021,15 +1978,68 @@ static int wbsd_resume(struct platform_device *dev)
*/
mdelay(5);
- wbsd_init_device(host);
+ return wbsd_resume(host);
+}
+
+#ifdef CONFIG_PNP
+
+static int wbsd_pnp_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
+{
+ struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev);
+ struct wbsd_host *host;
+
+ if (mmc == NULL)
+ return 0;
+
+ DBGF("Suspending...\n");
+
+ host = mmc_priv(mmc);
+
+ return wbsd_suspend(host, state);
+}
+
+static int wbsd_pnp_resume(struct pnp_dev *pnp_dev)
+{
+ struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev);
+ struct wbsd_host *host;
+
+ if (mmc == NULL)
+ return 0;
+
+ DBGF("Resuming...\n");
- return mmc_resume_host(mmc);
+ host = mmc_priv(mmc);
+
+ /*
+ * See if chip needs to be configured.
+ */
+ if (host->config != 0) {
+ if (!wbsd_chip_validate(host)) {
+ printk(KERN_WARNING DRIVER_NAME
+ ": PnP active but chip not configured! "
+ "You probably have a buggy BIOS. "
+ "Configuring chip manually.\n");
+ wbsd_chip_config(host);
+ }
+ }
+
+ /*
+ * Allow device to initialise itself properly.
+ */
+ mdelay(5);
+
+ return wbsd_resume(host);
}
+#endif /* CONFIG_PNP */
+
#else /* CONFIG_PM */
-#define wbsd_suspend NULL
-#define wbsd_resume NULL
+#define wbsd_platform_suspend NULL
+#define wbsd_platform_resume NULL
+
+#define wbsd_pnp_suspend NULL
+#define wbsd_pnp_resume NULL
#endif /* CONFIG_PM */
@@ -2039,8 +2049,8 @@ static struct platform_driver wbsd_driver = {
.probe = wbsd_probe,
.remove = __devexit_p(wbsd_remove),
- .suspend = wbsd_suspend,
- .resume = wbsd_resume,
+ .suspend = wbsd_platform_suspend,
+ .resume = wbsd_platform_resume,
.driver = {
.name = DRIVER_NAME,
},
@@ -2053,6 +2063,9 @@ static struct pnp_driver wbsd_pnp_driver = {
.id_table = pnp_dev_table,
.probe = wbsd_pnp_probe,
.remove = __devexit_p(wbsd_pnp_remove),
+
+ .suspend = wbsd_pnp_suspend,
+ .resume = wbsd_pnp_resume,
};
#endif /* CONFIG_PNP */
@@ -2072,31 +2085,26 @@ static int __init wbsd_drv_init(void)
#ifdef CONFIG_PNP
- if (!nopnp)
- {
+ if (!nopnp) {
result = pnp_register_driver(&wbsd_pnp_driver);
if (result < 0)
return result;
}
-
#endif /* CONFIG_PNP */
- if (nopnp)
- {
+ if (nopnp) {
result = platform_driver_register(&wbsd_driver);
if (result < 0)
return result;
wbsd_device = platform_device_alloc(DRIVER_NAME, -1);
- if (!wbsd_device)
- {
+ if (!wbsd_device) {
platform_driver_unregister(&wbsd_driver);
return -ENOMEM;
}
result = platform_device_add(wbsd_device);
- if (result)
- {
+ if (result) {
platform_device_put(wbsd_device);
platform_driver_unregister(&wbsd_driver);
return result;
@@ -2115,8 +2123,7 @@ static void __exit wbsd_drv_exit(void)
#endif /* CONFIG_PNP */
- if (nopnp)
- {
+ if (nopnp) {
platform_device_unregister(wbsd_device);
platform_driver_unregister(&wbsd_driver);
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index 5c5eebdb6914..dcc98afa65d7 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -148,14 +148,6 @@ el2_pio_probe(struct net_device *dev)
return -ENODEV;
}
-static void cleanup_card(struct net_device *dev)
-{
- /* NB: el2_close() handles free_irq */
- release_region(dev->base_addr, EL2_IO_EXTENT);
- if (ei_status.mem)
- iounmap(ei_status.mem);
-}
-
#ifndef MODULE
struct net_device * __init el2_probe(int unit)
{
@@ -726,6 +718,14 @@ init_module(void)
return -ENXIO;
}
+static void cleanup_card(struct net_device *dev)
+{
+ /* NB: el2_close() handles free_irq */
+ release_region(dev->base_addr, EL2_IO_EXTENT);
+ if (ei_status.mem)
+ iounmap(ei_status.mem);
+}
+
void
cleanup_module(void)
{
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 1960961bf28e..733bc25b2bf9 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -129,7 +129,7 @@ config NET_SB1000
If you don't have this card, of course say N.
- source "drivers/net/arcnet/Kconfig"
+source "drivers/net/arcnet/Kconfig"
source "drivers/net/phy/Kconfig"
@@ -844,7 +844,7 @@ config SMC9194
config DM9000
tristate "DM9000 support"
- depends on ARM && NET_ETHERNET
+ depends on (ARM || MIPS) && NET_ETHERNET
select CRC32
select MII
---help---
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index 8a0af5453e21..7952dc6d77e3 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -123,14 +123,6 @@ static int __init do_ac3200_probe(struct net_device *dev)
return -ENODEV;
}
-static void cleanup_card(struct net_device *dev)
-{
- /* Someday free_irq may be in ac_close_card() */
- free_irq(dev->irq, dev);
- release_region(dev->base_addr, AC_IO_EXTENT);
- iounmap(ei_status.mem);
-}
-
#ifndef MODULE
struct net_device * __init ac3200_probe(int unit)
{
@@ -406,6 +398,14 @@ init_module(void)
return -ENXIO;
}
+static void cleanup_card(struct net_device *dev)
+{
+ /* Someday free_irq may be in ac_close_card() */
+ free_irq(dev->irq, dev);
+ release_region(dev->base_addr, AC_IO_EXTENT);
+ iounmap(ei_status.mem);
+}
+
void
cleanup_module(void)
{
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 015c7f1d1bc0..f20bb85c1ea5 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -205,7 +205,7 @@ struct bonding {
*
* Caller must hold bond lock for read
*/
-extern inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev)
+static inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev)
{
struct slave *slave = NULL;
int i;
@@ -219,7 +219,7 @@ extern inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct n
return slave;
}
-extern inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
+static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
{
if (!slave || !slave->dev->master) {
return NULL;
@@ -228,13 +228,13 @@ extern inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
return (struct bonding *)slave->dev->master->priv;
}
-extern inline void bond_set_slave_inactive_flags(struct slave *slave)
+static inline void bond_set_slave_inactive_flags(struct slave *slave)
{
slave->state = BOND_STATE_BACKUP;
slave->dev->flags |= IFF_NOARP;
}
-extern inline void bond_set_slave_active_flags(struct slave *slave)
+static inline void bond_set_slave_active_flags(struct slave *slave)
{
slave->state = BOND_STATE_ACTIVE;
slave->dev->flags &= ~IFF_NOARP;
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index 38695d5b4637..ccbbe5ad8e0f 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -545,7 +545,7 @@ e1000_check_fiber_options(struct e1000_adapter *adapter)
static void __devinit
e1000_check_copper_options(struct e1000_adapter *adapter)
{
- int speed, dplx;
+ int speed, dplx, an;
int bd = adapter->bd_number;
{ /* Speed */
@@ -641,8 +641,12 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
.p = an_list }}
};
- int an = AutoNeg[bd];
- e1000_validate_option(&an, &opt, adapter);
+ if (num_AutoNeg > bd) {
+ an = AutoNeg[bd];
+ e1000_validate_option(&an, &opt, adapter);
+ } else {
+ an = opt.def;
+ }
adapter->hw.autoneg_advertised = an;
}
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index f5a4dd7d8564..e5c5cd2a2712 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -140,13 +140,6 @@ static int __init do_e2100_probe(struct net_device *dev)
return -ENODEV;
}
-static void cleanup_card(struct net_device *dev)
-{
- /* NB: e21_close() handles free_irq */
- iounmap(ei_status.mem);
- release_region(dev->base_addr, E21_IO_EXTENT);
-}
-
#ifndef MODULE
struct net_device * __init e2100_probe(int unit)
{
@@ -463,6 +456,13 @@ init_module(void)
return -ENXIO;
}
+static void cleanup_card(struct net_device *dev)
+{
+ /* NB: e21_close() handles free_irq */
+ iounmap(ei_status.mem);
+ release_region(dev->base_addr, E21_IO_EXTENT);
+}
+
void
cleanup_module(void)
{
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
index 50f8e23bb9e5..6b0ab1eac3fb 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -155,13 +155,6 @@ static int __init do_es_probe(struct net_device *dev)
return -ENODEV;
}
-static void cleanup_card(struct net_device *dev)
-{
- free_irq(dev->irq, dev);
- release_region(dev->base_addr, ES_IO_EXTENT);
- iounmap(ei_status.mem);
-}
-
#ifndef MODULE
struct net_device * __init es_probe(int unit)
{
@@ -456,6 +449,13 @@ init_module(void)
return -ENXIO;
}
+static void cleanup_card(struct net_device *dev)
+{
+ free_irq(dev->irq, dev);
+ release_region(dev->base_addr, ES_IO_EXTENT);
+ iounmap(ei_status.mem);
+}
+
void
cleanup_module(void)
{
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index c39344adecce..3682ec61e8a8 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -101,6 +101,7 @@
* 0.46: 20 Oct 2005: Add irq optimization modes.
* 0.47: 26 Oct 2005: Add phyaddr 0 in phy scan.
* 0.48: 24 Dec 2005: Disable TSO, bugfix for pci_map_single
+ * 0.49: 10 Dec 2005: Fix tso for large buffers.
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
@@ -112,7 +113,7 @@
* DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
* superfluous timer interrupts from the nic.
*/
-#define FORCEDETH_VERSION "0.48"
+#define FORCEDETH_VERSION "0.49"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
@@ -349,6 +350,8 @@ typedef union _ring_type {
#define NV_TX2_VALID (1<<31)
#define NV_TX2_TSO (1<<28)
#define NV_TX2_TSO_SHIFT 14
+#define NV_TX2_TSO_MAX_SHIFT 14
+#define NV_TX2_TSO_MAX_SIZE (1<<NV_TX2_TSO_MAX_SHIFT)
#define NV_TX2_CHECKSUM_L3 (1<<27)
#define NV_TX2_CHECKSUM_L4 (1<<26)
@@ -408,15 +411,15 @@ typedef union _ring_type {
#define NV_WATCHDOG_TIMEO (5*HZ)
#define RX_RING 128
-#define TX_RING 64
+#define TX_RING 256
/*
* If your nic mysteriously hangs then try to reduce the limits
* to 1/0: It might be required to set NV_TX_LASTPACKET in the
* last valid ring entry. But this would be impossible to
* implement - probably a disassembly error.
*/
-#define TX_LIMIT_STOP 63
-#define TX_LIMIT_START 62
+#define TX_LIMIT_STOP 255
+#define TX_LIMIT_START 254
/* rx/tx mac addr + type + vlan + align + slack*/
#define NV_RX_HEADERS (64)
@@ -535,6 +538,7 @@ struct fe_priv {
unsigned int next_tx, nic_tx;
struct sk_buff *tx_skbuff[TX_RING];
dma_addr_t tx_dma[TX_RING];
+ unsigned int tx_dma_len[TX_RING];
u32 tx_flags;
};
@@ -935,6 +939,7 @@ static void nv_init_tx(struct net_device *dev)
else
np->tx_ring.ex[i].FlagLen = 0;
np->tx_skbuff[i] = NULL;
+ np->tx_dma[i] = 0;
}
}
@@ -945,30 +950,27 @@ static int nv_init_ring(struct net_device *dev)
return nv_alloc_rx(dev);
}
-static void nv_release_txskb(struct net_device *dev, unsigned int skbnr)
+static int nv_release_txskb(struct net_device *dev, unsigned int skbnr)
{
struct fe_priv *np = netdev_priv(dev);
- struct sk_buff *skb = np->tx_skbuff[skbnr];
- unsigned int j, entry, fragments;
-
- dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d, skb %p\n",
- dev->name, skbnr, np->tx_skbuff[skbnr]);
-
- entry = skbnr;
- if ((fragments = skb_shinfo(skb)->nr_frags) != 0) {
- for (j = fragments; j >= 1; j--) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[j-1];
- pci_unmap_page(np->pci_dev, np->tx_dma[entry],
- frag->size,
- PCI_DMA_TODEVICE);
- entry = (entry - 1) % TX_RING;
- }
+
+ dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d\n",
+ dev->name, skbnr);
+
+ if (np->tx_dma[skbnr]) {
+ pci_unmap_page(np->pci_dev, np->tx_dma[skbnr],
+ np->tx_dma_len[skbnr],
+ PCI_DMA_TODEVICE);
+ np->tx_dma[skbnr] = 0;
+ }
+
+ if (np->tx_skbuff[skbnr]) {
+ dev_kfree_skb_irq(np->tx_skbuff[skbnr]);
+ np->tx_skbuff[skbnr] = NULL;
+ return 1;
+ } else {
+ return 0;
}
- pci_unmap_single(np->pci_dev, np->tx_dma[entry],
- skb->len - skb->data_len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(skb);
- np->tx_skbuff[skbnr] = NULL;
}
static void nv_drain_tx(struct net_device *dev)
@@ -981,10 +983,8 @@ static void nv_drain_tx(struct net_device *dev)
np->tx_ring.orig[i].FlagLen = 0;
else
np->tx_ring.ex[i].FlagLen = 0;
- if (np->tx_skbuff[i]) {
- nv_release_txskb(dev, i);
+ if (nv_release_txskb(dev, i))
np->stats.tx_dropped++;
- }
}
}
@@ -1021,68 +1021,105 @@ static void drain_ring(struct net_device *dev)
static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
+ u32 tx_flags = 0;
u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
unsigned int fragments = skb_shinfo(skb)->nr_frags;
- unsigned int nr = (np->next_tx + fragments) % TX_RING;
+ unsigned int nr = (np->next_tx - 1) % TX_RING;
+ unsigned int start_nr = np->next_tx % TX_RING;
unsigned int i;
+ u32 offset = 0;
+ u32 bcnt;
+ u32 size = skb->len-skb->data_len;
+ u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+
+ /* add fragments to entries count */
+ for (i = 0; i < fragments; i++) {
+ entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) +
+ ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+ }
spin_lock_irq(&np->lock);
- if ((np->next_tx - np->nic_tx + fragments) > TX_LIMIT_STOP) {
+ if ((np->next_tx - np->nic_tx + entries - 1) > TX_LIMIT_STOP) {
spin_unlock_irq(&np->lock);
netif_stop_queue(dev);
return NETDEV_TX_BUSY;
}
- np->tx_skbuff[nr] = skb;
-
- if (fragments) {
- dprintk(KERN_DEBUG "%s: nv_start_xmit: buffer contains %d fragments\n", dev->name, fragments);
- /* setup descriptors in reverse order */
- for (i = fragments; i >= 1; i--) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1];
- np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset, frag->size,
- PCI_DMA_TODEVICE);
+ /* setup the header buffer */
+ do {
+ bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+ nr = (nr + 1) % TX_RING;
+
+ np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
+ PCI_DMA_TODEVICE);
+ np->tx_dma_len[nr] = bcnt;
+
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
+ np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+ } else {
+ np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+ np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+ np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+ }
+ tx_flags = np->tx_flags;
+ offset += bcnt;
+ size -= bcnt;
+ } while(size);
+
+ /* setup the fragments */
+ for (i = 0; i < fragments; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ u32 size = frag->size;
+ offset = 0;
+
+ do {
+ bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+ nr = (nr + 1) % TX_RING;
+
+ np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
+ PCI_DMA_TODEVICE);
+ np->tx_dma_len[nr] = bcnt;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
- np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra);
+ np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
} else {
np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
- np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra);
+ np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
}
-
- nr = (nr - 1) % TX_RING;
+ offset += bcnt;
+ size -= bcnt;
+ } while (size);
+ }
- if (np->desc_ver == DESC_VER_1)
- tx_flags_extra &= ~NV_TX_LASTPACKET;
- else
- tx_flags_extra &= ~NV_TX2_LASTPACKET;
- }
+ /* set last fragment flag */
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ np->tx_ring.orig[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
+ } else {
+ np->tx_ring.ex[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
}
+ np->tx_skbuff[nr] = skb;
+
#ifdef NETIF_F_TSO
if (skb_shinfo(skb)->tso_size)
- tx_flags_extra |= NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT);
+ tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT);
else
#endif
- tx_flags_extra |= (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
+ tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
- np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len-skb->data_len,
- PCI_DMA_TODEVICE);
-
+ /* set tx flags */
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
- np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra);
+ np->tx_ring.orig[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
} else {
- np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
- np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
- np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra);
+ np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
}
- dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission. tx_flags_extra: %x\n",
- dev->name, np->next_tx, tx_flags_extra);
+ dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n",
+ dev->name, np->next_tx, entries, tx_flags_extra);
{
int j;
for (j=0; j<64; j++) {
@@ -1093,7 +1130,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
dprintk("\n");
}
- np->next_tx += 1 + fragments;
+ np->next_tx += entries;
dev->trans_start = jiffies;
spin_unlock_irq(&np->lock);
@@ -1140,7 +1177,6 @@ static void nv_tx_done(struct net_device *dev)
np->stats.tx_packets++;
np->stats.tx_bytes += skb->len;
}
- nv_release_txskb(dev, i);
}
} else {
if (Flags & NV_TX2_LASTPACKET) {
@@ -1156,9 +1192,9 @@ static void nv_tx_done(struct net_device *dev)
np->stats.tx_packets++;
np->stats.tx_bytes += skb->len;
}
- nv_release_txskb(dev, i);
}
}
+ nv_release_txskb(dev, i);
np->nic_tx++;
}
if (np->next_tx - np->nic_tx < TX_LIMIT_START)
@@ -2456,7 +2492,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
#ifdef NETIF_F_TSO
- /* disabled dev->features |= NETIF_F_TSO; */
+ dev->features |= NETIF_F_TSO;
#endif
}
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 94a91da84fbb..cb9d66ac3ab9 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -718,14 +718,14 @@ struct gfar_private {
uint32_t msg_enable;
};
-extern inline u32 gfar_read(volatile unsigned *addr)
+static inline u32 gfar_read(volatile unsigned *addr)
{
u32 val;
val = in_be32(addr);
return val;
}
-extern inline void gfar_write(volatile unsigned *addr, u32 val)
+static inline void gfar_write(volatile unsigned *addr, u32 val)
{
out_be32(addr, val);
}
diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
index 0abf5dd08b4c..74e167e7dea7 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/hp-plus.c
@@ -138,12 +138,6 @@ static int __init do_hpp_probe(struct net_device *dev)
return -ENODEV;
}
-static void cleanup_card(struct net_device *dev)
-{
- /* NB: hpp_close() handles free_irq */
- release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
-}
-
#ifndef MODULE
struct net_device * __init hp_plus_probe(int unit)
{
@@ -473,6 +467,12 @@ init_module(void)
return -ENXIO;
}
+static void cleanup_card(struct net_device *dev)
+{
+ /* NB: hpp_close() handles free_irq */
+ release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
+}
+
void
cleanup_module(void)
{
diff --git a/drivers/net/hp.c b/drivers/net/hp.c
index 59cf841b14ab..cf9fb3698a6b 100644
--- a/drivers/net/hp.c
+++ b/drivers/net/hp.c
@@ -102,12 +102,6 @@ static int __init do_hp_probe(struct net_device *dev)
return -ENODEV;
}
-static void cleanup_card(struct net_device *dev)
-{
- free_irq(dev->irq, dev);
- release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
-}
-
#ifndef MODULE
struct net_device * __init hp_probe(int unit)
{
@@ -444,6 +438,12 @@ init_module(void)
return -ENXIO;
}
+static void cleanup_card(struct net_device *dev)
+{
+ free_irq(dev->irq, dev);
+ release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
+}
+
void
cleanup_module(void)
{
diff --git a/drivers/net/ibm_emac/ibm_emac.h b/drivers/net/ibm_emac/ibm_emac.h
index 644edbff4f94..c2dae6092c4c 100644
--- a/drivers/net/ibm_emac/ibm_emac.h
+++ b/drivers/net/ibm_emac/ibm_emac.h
@@ -110,6 +110,7 @@ struct emac_regs {
#define EMAC_MR1_TFS_2K 0x00080000
#define EMAC_MR1_TR0_MULT 0x00008000
#define EMAC_MR1_JPSM 0x00000000
+#define EMAC_MR1_MWSW_001 0x00000000
#define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR0_MULT)
#else
#define EMAC_MR1_RFS_4K 0x00180000
@@ -130,7 +131,7 @@ struct emac_regs {
(freq) <= 83 ? EMAC_MR1_OBCI_83 : \
(freq) <= 100 ? EMAC_MR1_OBCI_100 : EMAC_MR1_OBCI_100P)
#define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR | \
- EMAC_MR1_MWSW_001 | EMAC_MR1_OBCI(opb))
+ EMAC_MR1_OBCI(opb))
#endif
/* EMACx_TMR0 */
diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c
index 1da8a66f91e1..591c5864ffb1 100644
--- a/drivers/net/ibm_emac/ibm_emac_core.c
+++ b/drivers/net/ibm_emac/ibm_emac_core.c
@@ -408,7 +408,7 @@ static int emac_configure(struct ocp_enet_private *dev)
/* Mode register */
r = EMAC_MR1_BASE(emac_opb_mhz()) | EMAC_MR1_VLE | EMAC_MR1_IST;
if (dev->phy.duplex == DUPLEX_FULL)
- r |= EMAC_MR1_FDE;
+ r |= EMAC_MR1_FDE | EMAC_MR1_MWSW_001;
dev->stop_timeout = STOP_TIMEOUT_10;
switch (dev->phy.speed) {
case SPEED_1000:
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 1d75ca0bb939..d1d714faa6ce 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -309,17 +309,6 @@ static void lance_tx_timeout (struct net_device *dev);
-static void cleanup_card(struct net_device *dev)
-{
- struct lance_private *lp = dev->priv;
- if (dev->dma != 4)
- free_dma(dev->dma);
- release_region(dev->base_addr, LANCE_TOTAL_SIZE);
- kfree(lp->tx_bounce_buffs);
- kfree((void*)lp->rx_buffs);
- kfree(lp);
-}
-
#ifdef MODULE
#define MAX_CARDS 8 /* Max number of interfaces (cards) per module */
@@ -367,6 +356,17 @@ int init_module(void)
return -ENXIO;
}
+static void cleanup_card(struct net_device *dev)
+{
+ struct lance_private *lp = dev->priv;
+ if (dev->dma != 4)
+ free_dma(dev->dma);
+ release_region(dev->base_addr, LANCE_TOTAL_SIZE);
+ kfree(lp->tx_bounce_buffs);
+ kfree((void*)lp->rx_buffs);
+ kfree(lp);
+}
+
void cleanup_module(void)
{
int this_dev;
diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c
index 309d254842cf..646e89fc3562 100644
--- a/drivers/net/lne390.c
+++ b/drivers/net/lne390.c
@@ -145,13 +145,6 @@ static int __init do_lne390_probe(struct net_device *dev)
return -ENODEV;
}
-static void cleanup_card(struct net_device *dev)
-{
- free_irq(dev->irq, dev);
- release_region(dev->base_addr, LNE390_IO_EXTENT);
- iounmap(ei_status.mem);
-}
-
#ifndef MODULE
struct net_device * __init lne390_probe(int unit)
{
@@ -440,6 +433,13 @@ int init_module(void)
return -ENXIO;
}
+static void cleanup_card(struct net_device *dev)
+{
+ free_irq(dev->irq, dev);
+ release_region(dev->base_addr, LNE390_IO_EXTENT);
+ iounmap(ei_status.mem);
+}
+
void cleanup_module(void)
{
int this_dev;
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 3cb9b3fe0cf1..22c3a37bba5a 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -6,7 +6,7 @@
* Copyright (C) 2002 rabeeh@galileo.co.il
*
* Copyright (C) 2003 PMC-Sierra, Inc.,
- * written by Manish Lachwani (lachwani@pmc-sierra.com)
+ * written by Manish Lachwani
*
* Copyright (C) 2003 Ralf Baechle <ralf@linux-mips.org>
*
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index 0de8fdd2aa86..94f782d51f0f 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -212,15 +212,6 @@ static int __init do_ne_probe(struct net_device *dev)
return -ENODEV;
}
-static void cleanup_card(struct net_device *dev)
-{
- struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
- if (idev)
- pnp_device_detach(idev);
- free_irq(dev->irq, dev);
- release_region(dev->base_addr, NE_IO_EXTENT);
-}
-
#ifndef MODULE
struct net_device * __init ne_probe(int unit)
{
@@ -859,6 +850,15 @@ int init_module(void)
return -ENODEV;
}
+static void cleanup_card(struct net_device *dev)
+{
+ struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
+ if (idev)
+ pnp_device_detach(idev);
+ free_irq(dev->irq, dev);
+ release_region(dev->base_addr, NE_IO_EXTENT);
+}
+
void cleanup_module(void)
{
int this_dev;
diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c
index 6d62ada85de6..e6df375a1d4b 100644
--- a/drivers/net/ne2.c
+++ b/drivers/net/ne2.c
@@ -278,14 +278,6 @@ static int __init do_ne2_probe(struct net_device *dev)
return -ENODEV;
}
-static void cleanup_card(struct net_device *dev)
-{
- mca_mark_as_unused(ei_status.priv);
- mca_set_adapter_procfn( ei_status.priv, NULL, NULL);
- free_irq(dev->irq, dev);
- release_region(dev->base_addr, NE_IO_EXTENT);
-}
-
#ifndef MODULE
struct net_device * __init ne2_probe(int unit)
{
@@ -812,6 +804,14 @@ int init_module(void)
return -ENXIO;
}
+static void cleanup_card(struct net_device *dev)
+{
+ mca_mark_as_unused(ei_status.priv);
+ mca_set_adapter_procfn( ei_status.priv, NULL, NULL);
+ free_irq(dev->irq, dev);
+ release_region(dev->base_addr, NE_IO_EXTENT);
+}
+
void cleanup_module(void)
{
int this_dev;
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index 9a76ac180b11..197edd74fbb5 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -282,26 +282,22 @@ SK_U32 Val) /* pointer to store the read value */
* Description:
* This function initialize the PCI resources and IO
*
- * Returns: N/A
- *
+ * Returns:
+ * 0 - indicate everything worked ok.
+ * != 0 - error indication
*/
-int SkGeInitPCI(SK_AC *pAC)
+static __devinit int SkGeInitPCI(SK_AC *pAC)
{
struct SK_NET_DEVICE *dev = pAC->dev[0];
struct pci_dev *pdev = pAC->PciDev;
int retval;
- if (pci_enable_device(pdev) != 0) {
- return 1;
- }
-
dev->mem_start = pci_resource_start (pdev, 0);
pci_set_master(pdev);
- if (pci_request_regions(pdev, "sk98lin") != 0) {
- retval = 2;
- goto out_disable;
- }
+ retval = pci_request_regions(pdev, "sk98lin");
+ if (retval)
+ goto out;
#ifdef SK_BIG_ENDIAN
/*
@@ -320,9 +316,8 @@ int SkGeInitPCI(SK_AC *pAC)
* Remap the regs into kernel space.
*/
pAC->IoBase = ioremap_nocache(dev->mem_start, 0x4000);
-
- if (!pAC->IoBase){
- retval = 3;
+ if (!pAC->IoBase) {
+ retval = -EIO;
goto out_release;
}
@@ -330,8 +325,7 @@ int SkGeInitPCI(SK_AC *pAC)
out_release:
pci_release_regions(pdev);
- out_disable:
- pci_disable_device(pdev);
+ out:
return retval;
}
@@ -492,7 +486,7 @@ module_param_array(AutoSizing, charp, NULL, 0);
* 0, if everything is ok
* !=0, on error
*/
-static int __init SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC)
+static int __devinit SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC)
{
short i;
unsigned long Flags;
@@ -529,7 +523,7 @@ SK_BOOL DualNet;
if (SkGeInit(pAC, pAC->IoBase, SK_INIT_DATA) != 0) {
printk("HWInit (0) failed.\n");
spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
- return(-EAGAIN);
+ return -EIO;
}
SkI2cInit( pAC, pAC->IoBase, SK_INIT_DATA);
SkEventInit(pAC, pAC->IoBase, SK_INIT_DATA);
@@ -551,7 +545,7 @@ SK_BOOL DualNet;
if (SkGeInit(pAC, pAC->IoBase, SK_INIT_IO) != 0) {
printk("sk98lin: HWInit (1) failed.\n");
spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
- return(-EAGAIN);
+ return -EIO;
}
SkI2cInit( pAC, pAC->IoBase, SK_INIT_IO);
SkEventInit(pAC, pAC->IoBase, SK_INIT_IO);
@@ -583,20 +577,20 @@ SK_BOOL DualNet;
} else {
printk(KERN_WARNING "sk98lin: Illegal number of ports: %d\n",
pAC->GIni.GIMacsFound);
- return -EAGAIN;
+ return -EIO;
}
if (Ret) {
printk(KERN_WARNING "sk98lin: Requested IRQ %d is busy.\n",
dev->irq);
- return -EAGAIN;
+ return Ret;
}
pAC->AllocFlag |= SK_ALLOC_IRQ;
/* Alloc memory for this board (Mem for RxD/TxD) : */
if(!BoardAllocMem(pAC)) {
printk("No memory for descriptor rings.\n");
- return(-EAGAIN);
+ return -ENOMEM;
}
BoardInitMem(pAC);
@@ -612,7 +606,7 @@ SK_BOOL DualNet;
DualNet)) {
BoardFreeMem(pAC);
printk("sk98lin: SkGeInitAssignRamToQueues failed.\n");
- return(-EAGAIN);
+ return -EIO;
}
return (0);
@@ -633,8 +627,7 @@ SK_BOOL DualNet;
* SK_TRUE, if all memory could be allocated
* SK_FALSE, if not
*/
-static SK_BOOL BoardAllocMem(
-SK_AC *pAC)
+static __devinit SK_BOOL BoardAllocMem(SK_AC *pAC)
{
caddr_t pDescrMem; /* pointer to descriptor memory area */
size_t AllocLength; /* length of complete descriptor area */
@@ -727,8 +720,7 @@ size_t AllocLength; /* length of complete descriptor area */
*
* Returns: N/A
*/
-static void BoardInitMem(
-SK_AC *pAC) /* pointer to adapter context */
+static __devinit void BoardInitMem(SK_AC *pAC)
{
int i; /* loop counter */
int RxDescrSize; /* the size of a rx descriptor rounded up to alignment*/
@@ -4776,32 +4768,47 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
struct net_device *dev = NULL;
static int boards_found = 0;
int error = -ENODEV;
+ int using_dac = 0;
char DeviceStr[80];
if (pci_enable_device(pdev))
goto out;
/* Configure DMA attributes. */
- if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) &&
- pci_set_dma_mask(pdev, DMA_32BIT_MASK))
- goto out_disable_device;
-
+ if (sizeof(dma_addr_t) > sizeof(u32) &&
+ !(error = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) {
+ using_dac = 1;
+ error = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (error < 0) {
+ printk(KERN_ERR "sk98lin %s unable to obtain 64 bit DMA "
+ "for consistent allocations\n", pci_name(pdev));
+ goto out_disable_device;
+ }
+ } else {
+ error = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (error) {
+ printk(KERN_ERR "sk98lin %s no usable DMA configuration\n",
+ pci_name(pdev));
+ goto out_disable_device;
+ }
+ }
- if ((dev = alloc_etherdev(sizeof(DEV_NET))) == NULL) {
- printk(KERN_ERR "Unable to allocate etherdev "
+ error = -ENOMEM;
+ dev = alloc_etherdev(sizeof(DEV_NET));
+ if (!dev) {
+ printk(KERN_ERR "sk98lin: unable to allocate etherdev "
"structure!\n");
goto out_disable_device;
}
pNet = netdev_priv(dev);
- pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL);
+ pNet->pAC = kzalloc(sizeof(SK_AC), GFP_KERNEL);
if (!pNet->pAC) {
- printk(KERN_ERR "Unable to allocate adapter "
+ printk(KERN_ERR "sk98lin: unable to allocate adapter "
"structure!\n");
goto out_free_netdev;
}
- memset(pNet->pAC, 0, sizeof(SK_AC));
pAC = pNet->pAC;
pAC->PciDev = pdev;
@@ -4810,6 +4817,7 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
pAC->CheckQueue = SK_FALSE;
dev->irq = pdev->irq;
+
error = SkGeInitPCI(pAC);
if (error) {
printk(KERN_ERR "sk98lin: PCI setup failed: %i\n", error);
@@ -4844,19 +4852,25 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
#endif
}
+ if (using_dac)
+ dev->features |= NETIF_F_HIGHDMA;
+
pAC->Index = boards_found++;
- if (SkGeBoardInit(dev, pAC))
+ error = SkGeBoardInit(dev, pAC);
+ if (error)
goto out_free_netdev;
/* Read Adapter name from VPD */
if (ProductStr(pAC, DeviceStr, sizeof(DeviceStr)) != 0) {
+ error = -EIO;
printk(KERN_ERR "sk98lin: Could not read VPD data.\n");
goto out_free_resources;
}
/* Register net device */
- if (register_netdev(dev)) {
+ error = register_netdev(dev);
+ if (error) {
printk(KERN_ERR "sk98lin: Could not register device.\n");
goto out_free_resources;
}
@@ -4883,15 +4897,17 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
boards_found++;
+ pci_set_drvdata(pdev, dev);
+
/* More then one port found */
if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
- if ((dev = alloc_etherdev(sizeof(DEV_NET))) == 0) {
- printk(KERN_ERR "Unable to allocate etherdev "
+ dev = alloc_etherdev(sizeof(DEV_NET));
+ if (!dev) {
+ printk(KERN_ERR "sk98lin: unable to allocate etherdev "
"structure!\n");
- goto out;
+ goto single_port;
}
- pAC->dev[1] = dev;
pNet = netdev_priv(dev);
pNet->PortNr = 1;
pNet->NetNr = 1;
@@ -4920,20 +4936,28 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
#endif
}
- if (register_netdev(dev)) {
- printk(KERN_ERR "sk98lin: Could not register device for seconf port.\n");
+ if (using_dac)
+ dev->features |= NETIF_F_HIGHDMA;
+
+ error = register_netdev(dev);
+ if (error) {
+ printk(KERN_ERR "sk98lin: Could not register device"
+ " for second port. (%d)\n", error);
free_netdev(dev);
- pAC->dev[1] = pAC->dev[0];
- } else {
- memcpy(&dev->dev_addr,
- &pAC->Addr.Net[1].CurrentMacAddress, 6);
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-
- printk("%s: %s\n", dev->name, DeviceStr);
- printk(" PrefPort:B RlmtMode:Dual Check Link State\n");
+ goto single_port;
}
+
+ pAC->dev[1] = dev;
+ memcpy(&dev->dev_addr,
+ &pAC->Addr.Net[1].CurrentMacAddress, 6);
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+ printk("%s: %s\n", dev->name, DeviceStr);
+ printk(" PrefPort:B RlmtMode:Dual Check Link State\n");
}
+single_port:
+
/* Save the hardware revision */
pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) +
(pAC->GIni.GIPciHwRev & 0x0F);
@@ -4945,7 +4969,6 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
memset(&pAC->PnmiBackup, 0, sizeof(SK_PNMI_STRUCT_DATA));
memcpy(&pAC->PnmiBackup, &pAC->PnmiStruct, sizeof(SK_PNMI_STRUCT_DATA));
- pci_set_drvdata(pdev, dev);
return 0;
out_free_resources:
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index ba8593ac3f8a..3db30cd0625e 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -168,18 +168,6 @@ static int __init do_ultra_probe(struct net_device *dev)
return -ENODEV;
}
-static void cleanup_card(struct net_device *dev)
-{
- /* NB: ultra_close_card() does free_irq */
-#ifdef __ISAPNP__
- struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
- if (idev)
- pnp_device_detach(idev);
-#endif
- release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT);
- iounmap(ei_status.mem);
-}
-
#ifndef MODULE
struct net_device * __init ultra_probe(int unit)
{
@@ -594,6 +582,18 @@ init_module(void)
return -ENXIO;
}
+static void cleanup_card(struct net_device *dev)
+{
+ /* NB: ultra_close_card() does free_irq */
+#ifdef __ISAPNP__
+ struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
+ if (idev)
+ pnp_device_detach(idev);
+#endif
+ release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT);
+ iounmap(ei_status.mem);
+}
+
void
cleanup_module(void)
{
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 125ed00e95a5..c67c91251d04 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -1564,7 +1564,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
dev->dev_addr, 6);
}
#endif
-#if defined(__i386__) /* Patch up x86 BIOS bug. */
+#if defined(__i386__) || defined(__x86_64__) /* Patch up x86 BIOS bug. */
if (last_irq)
irq = last_irq;
#endif
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index b03feae459fc..7caa8dc88a58 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -127,13 +127,6 @@ static int __init do_wd_probe(struct net_device *dev)
return -ENODEV;
}
-static void cleanup_card(struct net_device *dev)
-{
- free_irq(dev->irq, dev);
- release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT);
- iounmap(ei_status.mem);
-}
-
#ifndef MODULE
struct net_device * __init wd_probe(int unit)
{
@@ -538,6 +531,13 @@ init_module(void)
return -ENXIO;
}
+static void cleanup_card(struct net_device *dev)
+{
+ free_irq(dev->irq, dev);
+ release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT);
+ iounmap(ei_status.mem);
+}
+
void
cleanup_module(void)
{
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index 44cd3fcd1572..cf05661fb1bd 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -7153,7 +7153,7 @@ static int ipw2100_wx_get_range(struct net_device *dev,
/* Set the Wireless Extension versions */
range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 16;
+ range->we_version_source = 18;
// range->retry_capa; /* What retry options are supported */
// range->retry_flags; /* How to decode max/min retry limit */
@@ -7184,6 +7184,9 @@ static int ipw2100_wx_get_range(struct net_device *dev,
IW_EVENT_CAPA_MASK(SIOCGIWAP));
range->event_capa[1] = IW_EVENT_CAPA_K_1;
+ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+ IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+
IPW_DEBUG_WX("GET Range\n");
return 0;
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index 932dcf0366eb..311a4122bd70 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -432,11 +432,12 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat
struct Scsi_Host *host;
void *dma_cmd_space;
unsigned char *clkprop;
- int proplen;
+ int proplen, rc = -ENODEV;
if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) {
- printk(KERN_ERR "mac53c94: expected 2 addrs and intrs (got %d/%d)\n",
- node->n_addrs, node->n_intrs);
+ printk(KERN_ERR "mac53c94: expected 2 addrs and intrs"
+ " (got %d/%d)\n",
+ macio_resource_count(mdev), macio_irq_count(mdev));
return -ENODEV;
}
@@ -448,6 +449,7 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat
host = scsi_host_alloc(&mac53c94_template, sizeof(struct fsc_state));
if (host == NULL) {
printk(KERN_ERR "mac53c94: couldn't register host");
+ rc = -ENOMEM;
goto out_release;
}
@@ -486,6 +488,7 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat
if (dma_cmd_space == 0) {
printk(KERN_ERR "mac53c94: couldn't allocate dma "
"command space for %s\n", node->full_name);
+ rc = -ENOMEM;
goto out_free;
}
state->dma_cmds = (struct dbdma_cmd *)DBDMA_ALIGN(dma_cmd_space);
@@ -495,18 +498,21 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat
mac53c94_init(state);
- if (request_irq(state->intr, do_mac53c94_interrupt, 0, "53C94", state)) {
+ if (request_irq(state->intr, do_mac53c94_interrupt, 0, "53C94",state)) {
printk(KERN_ERR "mac53C94: can't get irq %d for %s\n",
state->intr, node->full_name);
goto out_free_dma;
}
- /* XXX FIXME: handle failure */
- scsi_add_host(host, &mdev->ofdev.dev);
- scsi_scan_host(host);
+ rc = scsi_add_host(host, &mdev->ofdev.dev);
+ if (rc != 0)
+ goto out_release_irq;
+ scsi_scan_host(host);
return 0;
+ out_release_irq:
+ free_irq(state->intr, state);
out_free_dma:
kfree(state->dma_cmd_space);
out_free:
@@ -518,7 +524,7 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat
out_release:
macio_release_resources(mdev);
- return -ENODEV;
+ return rc;
}
static int mac53c94_remove(struct macio_dev *mdev)
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index bdccf73cf9fe..d6d2125f9044 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -1869,7 +1869,8 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match)
if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) {
printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs"
- " (got %d,%d)\n", mesh->n_addrs, mesh->n_intrs);
+ " (got %d,%d)\n", macio_resource_count(mdev),
+ macio_irq_count(mdev));
return -ENODEV;
}
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index c0cf52cb975a..bbbb55eeb73a 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -29,6 +29,12 @@
* NV-specific details such as register offsets, SATA phy location,
* hotplug info, etc.
*
+ * 0.10
+ * - Fixed spurious interrupts issue seen with the Maxtor 6H500F0 500GB
+ * drive. Also made the check_hotplug() callbacks return whether there
+ * was a hotplug interrupt or not. This was not the source of the
+ * spurious interrupts, but is the right thing to do anyway.
+ *
* 0.09
* - Fixed bug introduced by 0.08's MCP51 and MCP55 support.
*
@@ -124,10 +130,10 @@ static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static void nv_host_stop (struct ata_host_set *host_set);
static void nv_enable_hotplug(struct ata_probe_ent *probe_ent);
static void nv_disable_hotplug(struct ata_host_set *host_set);
-static void nv_check_hotplug(struct ata_host_set *host_set);
+static int nv_check_hotplug(struct ata_host_set *host_set);
static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent);
static void nv_disable_hotplug_ck804(struct ata_host_set *host_set);
-static void nv_check_hotplug_ck804(struct ata_host_set *host_set);
+static int nv_check_hotplug_ck804(struct ata_host_set *host_set);
enum nv_host_type
{
@@ -176,7 +182,7 @@ struct nv_host_desc
enum nv_host_type host_type;
void (*enable_hotplug)(struct ata_probe_ent *probe_ent);
void (*disable_hotplug)(struct ata_host_set *host_set);
- void (*check_hotplug)(struct ata_host_set *host_set);
+ int (*check_hotplug)(struct ata_host_set *host_set);
};
static struct nv_host_desc nv_device_tbl[] = {
@@ -309,12 +315,16 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance,
qc = ata_qc_from_tag(ap, ap->active_tag);
if (qc && (!(qc->tf.ctl & ATA_NIEN)))
handled += ata_host_intr(ap, qc);
+ else
+ // No request pending? Clear interrupt status
+ // anyway, in case there's one pending.
+ ap->ops->check_status(ap);
}
}
if (host->host_desc->check_hotplug)
- host->host_desc->check_hotplug(host_set);
+ handled += host->host_desc->check_hotplug(host_set);
spin_unlock_irqrestore(&host_set->lock, flags);
@@ -497,7 +507,7 @@ static void nv_disable_hotplug(struct ata_host_set *host_set)
outb(intr_mask, host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE);
}
-static void nv_check_hotplug(struct ata_host_set *host_set)
+static int nv_check_hotplug(struct ata_host_set *host_set)
{
u8 intr_status;
@@ -522,7 +532,11 @@ static void nv_check_hotplug(struct ata_host_set *host_set)
if (intr_status & NV_INT_STATUS_SDEV_REMOVED)
printk(KERN_WARNING "nv_sata: "
"Secondary device removed\n");
+
+ return 1;
}
+
+ return 0;
}
static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent)
@@ -560,7 +574,7 @@ static void nv_disable_hotplug_ck804(struct ata_host_set *host_set)
pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
}
-static void nv_check_hotplug_ck804(struct ata_host_set *host_set)
+static int nv_check_hotplug_ck804(struct ata_host_set *host_set)
{
u8 intr_status;
@@ -585,7 +599,11 @@ static void nv_check_hotplug_ck804(struct ata_host_set *host_set)
if (intr_status & NV_INT_STATUS_SDEV_REMOVED)
printk(KERN_WARNING "nv_sata: "
"Secondary device removed\n");
+
+ return 1;
}
+
+ return 0;
}
static int __init nv_init(void)
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 180676d7115a..ee5f4dfdab14 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -69,7 +69,6 @@
#include "scsi_logging.h"
static void scsi_done(struct scsi_cmnd *cmd);
-static int scsi_retry_command(struct scsi_cmnd *cmd);
/*
* Definitions and constants.
@@ -752,7 +751,7 @@ static void scsi_done(struct scsi_cmnd *cmd)
* isn't running --- used by scsi_times_out */
void __scsi_done(struct scsi_cmnd *cmd)
{
- unsigned long flags;
+ struct request *rq = cmd->request;
/*
* Set the serial numbers back to zero
@@ -763,71 +762,14 @@ void __scsi_done(struct scsi_cmnd *cmd)
if (cmd->result)
atomic_inc(&cmd->device->ioerr_cnt);
+ BUG_ON(!rq);
+
/*
- * Next, enqueue the command into the done queue.
- * It is a per-CPU queue, so we just disable local interrupts
- * and need no spinlock.
+ * The uptodate/nbytes values don't matter, as we allow partial
+ * completes and thus will check this in the softirq callback
*/
- local_irq_save(flags);
- list_add_tail(&cmd->eh_entry, &__get_cpu_var(scsi_done_q));
- raise_softirq_irqoff(SCSI_SOFTIRQ);
- local_irq_restore(flags);
-}
-
-/**
- * scsi_softirq - Perform post-interrupt processing of finished SCSI commands.
- *
- * This is the consumer of the done queue.
- *
- * This is called with all interrupts enabled. This should reduce
- * interrupt latency, stack depth, and reentrancy of the low-level
- * drivers.
- */
-static void scsi_softirq(struct softirq_action *h)
-{
- int disposition;
- LIST_HEAD(local_q);
-
- local_irq_disable();
- list_splice_init(&__get_cpu_var(scsi_done_q), &local_q);
- local_irq_enable();
-
- while (!list_empty(&local_q)) {
- struct scsi_cmnd *cmd = list_entry(local_q.next,
- struct scsi_cmnd, eh_entry);
- /* The longest time any command should be outstanding is the
- * per command timeout multiplied by the number of retries.
- *
- * For a typical command, this is 2.5 minutes */
- unsigned long wait_for
- = cmd->allowed * cmd->timeout_per_command;
- list_del_init(&cmd->eh_entry);
-
- disposition = scsi_decide_disposition(cmd);
- if (disposition != SUCCESS &&
- time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
- sdev_printk(KERN_ERR, cmd->device,
- "timing out command, waited %lus\n",
- wait_for/HZ);
- disposition = SUCCESS;
- }
-
- scsi_log_completion(cmd, disposition);
- switch (disposition) {
- case SUCCESS:
- scsi_finish_command(cmd);
- break;
- case NEEDS_RETRY:
- scsi_retry_command(cmd);
- break;
- case ADD_TO_MLQUEUE:
- scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
- break;
- default:
- if (!scsi_eh_scmd_add(cmd, 0))
- scsi_finish_command(cmd);
- }
- }
+ rq->completion_data = cmd;
+ blk_complete_request(rq);
}
/*
@@ -840,7 +782,7 @@ static void scsi_softirq(struct softirq_action *h)
* level drivers should not become re-entrant as a result of
* this.
*/
-static int scsi_retry_command(struct scsi_cmnd *cmd)
+int scsi_retry_command(struct scsi_cmnd *cmd)
{
/*
* Restore the SCSI command state.
@@ -1273,38 +1215,6 @@ int scsi_device_cancel(struct scsi_device *sdev, int recovery)
}
EXPORT_SYMBOL(scsi_device_cancel);
-#ifdef CONFIG_HOTPLUG_CPU
-static int scsi_cpu_notify(struct notifier_block *self,
- unsigned long action, void *hcpu)
-{
- int cpu = (unsigned long)hcpu;
-
- switch(action) {
- case CPU_DEAD:
- /* Drain scsi_done_q. */
- local_irq_disable();
- list_splice_init(&per_cpu(scsi_done_q, cpu),
- &__get_cpu_var(scsi_done_q));
- raise_softirq_irqoff(SCSI_SOFTIRQ);
- local_irq_enable();
- break;
- default:
- break;
- }
- return NOTIFY_OK;
-}
-
-static struct notifier_block __devinitdata scsi_cpu_nb = {
- .notifier_call = scsi_cpu_notify,
-};
-
-#define register_scsi_cpu() register_cpu_notifier(&scsi_cpu_nb)
-#define unregister_scsi_cpu() unregister_cpu_notifier(&scsi_cpu_nb)
-#else
-#define register_scsi_cpu()
-#define unregister_scsi_cpu()
-#endif /* CONFIG_HOTPLUG_CPU */
-
MODULE_DESCRIPTION("SCSI core");
MODULE_LICENSE("GPL");
@@ -1338,8 +1248,6 @@ static int __init init_scsi(void)
INIT_LIST_HEAD(&per_cpu(scsi_done_q, i));
devfs_mk_dir("scsi");
- open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL);
- register_scsi_cpu();
printk(KERN_NOTICE "SCSI subsystem initialized\n");
return 0;
@@ -1367,7 +1275,6 @@ static void __exit exit_scsi(void)
devfs_remove("scsi");
scsi_exit_procfs();
scsi_exit_queue();
- unregister_scsi_cpu();
}
subsys_initcall(init_scsi);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index ba93d6e66d48..00c9bf383e23 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1493,6 +1493,41 @@ static void scsi_kill_request(struct request *req, request_queue_t *q)
__scsi_done(cmd);
}
+static void scsi_softirq_done(struct request *rq)
+{
+ struct scsi_cmnd *cmd = rq->completion_data;
+ unsigned long wait_for = cmd->allowed * cmd->timeout_per_command;
+ int disposition;
+
+ INIT_LIST_HEAD(&cmd->eh_entry);
+
+ disposition = scsi_decide_disposition(cmd);
+ if (disposition != SUCCESS &&
+ time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
+ sdev_printk(KERN_ERR, cmd->device,
+ "timing out command, waited %lus\n",
+ wait_for/HZ);
+ disposition = SUCCESS;
+ }
+
+ scsi_log_completion(cmd, disposition);
+
+ switch (disposition) {
+ case SUCCESS:
+ scsi_finish_command(cmd);
+ break;
+ case NEEDS_RETRY:
+ scsi_retry_command(cmd);
+ break;
+ case ADD_TO_MLQUEUE:
+ scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
+ break;
+ default:
+ if (!scsi_eh_scmd_add(cmd, 0))
+ scsi_finish_command(cmd);
+ }
+}
+
/*
* Function: scsi_request_fn()
*
@@ -1667,6 +1702,7 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
blk_queue_segment_boundary(q, shost->dma_boundary);
blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
+ blk_queue_softirq_done(q, scsi_softirq_done);
if (!shost->use_clustering)
clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index f04e7e11f57a..14a6198cb8d2 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -44,6 +44,7 @@ extern void scsi_init_cmd_from_req(struct scsi_cmnd *cmd,
struct scsi_request *sreq);
extern void __scsi_release_request(struct scsi_request *sreq);
extern void __scsi_done(struct scsi_cmnd *cmd);
+extern int scsi_retry_command(struct scsi_cmnd *cmd);
#ifdef CONFIG_SCSI_LOGGING
void scsi_log_send(struct scsi_cmnd *cmd);
void scsi_log_completion(struct scsi_cmnd *cmd, int disposition);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 221e96e2620a..78aad9582bcf 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -2493,7 +2493,7 @@ sg_page_malloc(int rqSz, int lowDma, int *retSzp)
}
if (resp) {
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
- memset(resp, 0, resSz);
+ memset(page_address(resp), 0, resSz);
if (retSzp)
*retSzp = resSz;
}
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 1891cf5bdeef..e8454611cb65 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -54,6 +54,8 @@
*/
static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
+static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
+
/*
* Debugging.
*/
@@ -2118,7 +2120,7 @@ static void __init serial8250_isa_init_ports(void)
return;
first = 0;
- for (i = 0; i < UART_NR; i++) {
+ for (i = 0; i < nr_uarts; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
up->port.line = i;
@@ -2137,7 +2139,7 @@ static void __init serial8250_isa_init_ports(void)
}
for (i = 0, up = serial8250_ports;
- i < ARRAY_SIZE(old_serial_port) && i < UART_NR;
+ i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
i++, up++) {
up->port.iobase = old_serial_port[i].port;
up->port.irq = irq_canonicalize(old_serial_port[i].irq);
@@ -2159,7 +2161,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
serial8250_isa_init_ports();
- for (i = 0; i < UART_NR; i++) {
+ for (i = 0; i < nr_uarts; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
up->port.dev = dev;
@@ -2262,7 +2264,7 @@ static int serial8250_console_setup(struct console *co, char *options)
* if so, search for the first available port that does have
* console support.
*/
- if (co->index >= UART_NR)
+ if (co->index >= nr_uarts)
co->index = 0;
port = &serial8250_ports[co->index].port;
if (!port->iobase && !port->membase)
@@ -2298,7 +2300,7 @@ static int __init find_port(struct uart_port *p)
int line;
struct uart_port *port;
- for (line = 0; line < UART_NR; line++) {
+ for (line = 0; line < nr_uarts; line++) {
port = &serial8250_ports[line].port;
if (uart_match_port(p, port))
return line;
@@ -2420,7 +2422,7 @@ static int __devexit serial8250_remove(struct platform_device *dev)
{
int i;
- for (i = 0; i < UART_NR; i++) {
+ for (i = 0; i < nr_uarts; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
if (up->port.dev == &dev->dev)
@@ -2487,7 +2489,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
/*
* First, find a port entry which matches.
*/
- for (i = 0; i < UART_NR; i++)
+ for (i = 0; i < nr_uarts; i++)
if (uart_match_port(&serial8250_ports[i].port, port))
return &serial8250_ports[i];
@@ -2496,7 +2498,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
* free entry. We look for one which hasn't been previously
* used (indicated by zero iobase).
*/
- for (i = 0; i < UART_NR; i++)
+ for (i = 0; i < nr_uarts; i++)
if (serial8250_ports[i].port.type == PORT_UNKNOWN &&
serial8250_ports[i].port.iobase == 0)
return &serial8250_ports[i];
@@ -2505,7 +2507,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
* That also failed. Last resort is to find any entry which
* doesn't have a real port associated with it.
*/
- for (i = 0; i < UART_NR; i++)
+ for (i = 0; i < nr_uarts; i++)
if (serial8250_ports[i].port.type == PORT_UNKNOWN)
return &serial8250_ports[i];
@@ -2590,8 +2592,11 @@ static int __init serial8250_init(void)
{
int ret, i;
+ if (nr_uarts > UART_NR)
+ nr_uarts = UART_NR;
+
printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.90 $ "
- "%d ports, IRQ sharing %sabled\n", (int) UART_NR,
+ "%d ports, IRQ sharing %sabled\n", nr_uarts,
share_irqs ? "en" : "dis");
for (i = 0; i < NR_IRQS; i++)
@@ -2651,6 +2656,9 @@ module_param(share_irqs, uint, 0644);
MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
" (unsafe)");
+module_param(nr_uarts, uint, 0644);
+MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
+
#ifdef CONFIG_SERIAL_8250_RSA
module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444);
MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 47ea8338c03c..1bae26a8a503 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -95,6 +95,16 @@ config SERIAL_8250_NR_UARTS
PCI enumeration and any ports that may be added at run-time
via hot-plug, or any ISA multi-port serial cards.
+config SERIAL_8250_RUNTIME_UARTS
+ int "Number of 8250/16550 serial ports to register at runtime"
+ depends on SERIAL_8250
+ default "4"
+ help
+ Set this to the maximum number of serial ports you want
+ the kernel to register at boot time. This can be overriden
+ with the module parameter "nr_uarts", or boot-time parameter
+ 8250.nr_uarts
+
config SERIAL_8250_EXTENDED
bool "Extended 8250/16550 serial driver options"
depends on SERIAL_8250
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index 987d22b53c22..16af5626c243 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -608,7 +608,7 @@ static int cpm_uart_tx_pump(struct uart_port *port)
p = cpm2cpu_addr(bdp->cbd_bufaddr);
- *p++ = xmit->buf[xmit->tail];
+ *p++ = port->x_char;
bdp->cbd_datlen = 1;
bdp->cbd_sc |= BD_SC_READY;
/* Get next BD. */
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 5ddd8ab1f108..ea24129eb6b9 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -1431,11 +1431,14 @@ static int __init pmz_init_port(struct uart_pmac_port *uap)
char name[1];
} *slots;
int len;
+ struct resource r_ports, r_rxdma, r_txdma;
/*
* Request & map chip registers
*/
- uap->port.mapbase = np->addrs[0].address;
+ if (of_address_to_resource(np, 0, &r_ports))
+ return -ENODEV;
+ uap->port.mapbase = r_ports.start;
uap->port.membase = ioremap(uap->port.mapbase, 0x1000);
uap->control_reg = uap->port.membase;
@@ -1445,16 +1448,20 @@ static int __init pmz_init_port(struct uart_pmac_port *uap)
* Request & map DBDMA registers
*/
#ifdef HAS_DBDMA
- if (np->n_addrs >= 3 && np->n_intrs >= 3)
+ if (of_address_to_resource(np, 1, &r_txdma) == 0 &&
+ of_address_to_resource(np, 2, &r_rxdma) == 0)
uap->flags |= PMACZILOG_FLAG_HAS_DMA;
+#else
+ memset(&r_txdma, 0, sizeof(struct resource));
+ memset(&r_rxdma, 0, sizeof(struct resource));
#endif
if (ZS_HAS_DMA(uap)) {
- uap->tx_dma_regs = ioremap(np->addrs[np->n_addrs - 2].address, 0x1000);
+ uap->tx_dma_regs = ioremap(r_txdma.start, 0x100);
if (uap->tx_dma_regs == NULL) {
uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
goto no_dma;
}
- uap->rx_dma_regs = ioremap(np->addrs[np->n_addrs - 1].address, 0x1000);
+ uap->rx_dma_regs = ioremap(r_rxdma.start, 0x100);
if (uap->rx_dma_regs == NULL) {
iounmap(uap->tx_dma_regs);
uap->tx_dma_regs = NULL;
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 34c576dfad8d..9589509fc5bd 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1440,6 +1440,7 @@ uart_block_til_ready(struct file *filp, struct uart_state *state)
* modem is ready for us.
*/
spin_lock_irq(&port->lock);
+ port->ops->enable_ms(port);
mctrl = port->ops->get_mctrl(port);
spin_unlock_irq(&port->lock);
if (mctrl & TIOCM_CAR)
diff --git a/drivers/usb/media/dsbr100.c b/drivers/usb/media/dsbr100.c
index 6a5700e9d428..25646804d5be 100644
--- a/drivers/usb/media/dsbr100.c
+++ b/drivers/usb/media/dsbr100.c
@@ -127,6 +127,7 @@ static struct file_operations usb_dsbr100_fops = {
.open = usb_dsbr100_open,
.release = usb_dsbr100_close,
.ioctl = usb_dsbr100_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c
index 3a0e8ce67ebe..8af665bbe330 100644
--- a/drivers/usb/media/ov511.c
+++ b/drivers/usb/media/ov511.c
@@ -4774,6 +4774,7 @@ static struct file_operations ov511_fops = {
.read = ov51x_v4l1_read,
.mmap = ov51x_v4l1_mmap,
.ioctl = ov51x_v4l1_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/usb/media/pwc/pwc-if.c b/drivers/usb/media/pwc/pwc-if.c
index 09ca6128ac20..4f9b0dc6fd7b 100644
--- a/drivers/usb/media/pwc/pwc-if.c
+++ b/drivers/usb/media/pwc/pwc-if.c
@@ -154,6 +154,7 @@ static struct file_operations pwc_fops = {
.poll = pwc_video_poll,
.mmap = pwc_video_mmap,
.ioctl = pwc_video_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
static struct video_device pwc_template = {
diff --git a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c
index b2ae29af5940..2ba562285fda 100644
--- a/drivers/usb/media/se401.c
+++ b/drivers/usb/media/se401.c
@@ -1193,6 +1193,7 @@ static struct file_operations se401_fops = {
.read = se401_read,
.mmap = se401_mmap,
.ioctl = se401_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
static struct video_device se401_template = {
diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c
index 774038b352cd..b497a6a0a206 100644
--- a/drivers/usb/media/stv680.c
+++ b/drivers/usb/media/stv680.c
@@ -1343,6 +1343,7 @@ static struct file_operations stv680_fops = {
.read = stv680_read,
.mmap = stv680_mmap,
.ioctl = stv680_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
static struct video_device stv680_template = {
diff --git a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c
index 4bd113325ef9..63a72e550a1b 100644
--- a/drivers/usb/media/usbvideo.c
+++ b/drivers/usb/media/usbvideo.c
@@ -953,6 +953,7 @@ static struct file_operations usbvideo_fops = {
.read = usbvideo_v4l_read,
.mmap = usbvideo_v4l_mmap,
.ioctl = usbvideo_v4l_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
static const struct video_device usbvideo_template = {
diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c
index 1c73155c8d77..5df144073871 100644
--- a/drivers/usb/media/vicam.c
+++ b/drivers/usb/media/vicam.c
@@ -1236,6 +1236,7 @@ static struct file_operations vicam_fops = {
.read = vicam_read,
.mmap = vicam_mmap,
.ioctl = vicam_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c
index 3605a6f3067b..bff9434c8e55 100644
--- a/drivers/usb/media/w9968cf.c
+++ b/drivers/usb/media/w9968cf.c
@@ -3490,6 +3490,7 @@ static struct file_operations w9968cf_fops = {
.release = w9968cf_release,
.read = w9968cf_read,
.ioctl = w9968cf_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.mmap = w9968cf_mmap,
.llseek = no_llseek,
};
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index cc8e3bf5001b..3f04427c9026 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1151,7 +1151,7 @@ config FB_VOODOO1
config FB_CYBLA
tristate "Cyberblade/i1 support"
- depends on FB && PCI
+ depends on FB && PCI && X86_32 && !64BIT
select FB_CFB_IMAGEBLIT
select VIDEO_SELECT
---help---
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index 403d17377f8d..03798e9c882d 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -133,12 +133,6 @@ static int controlfb_mmap(struct fb_info *info, struct file *file,
static int controlfb_set_par (struct fb_info *info);
static int controlfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info);
-/*
- * inititialization
- */
-int control_init(void);
-void control_setup(char *);
-
/******************** Prototypes for internal functions **********************/
static void set_control_clock(unsigned char *params);
@@ -550,9 +544,46 @@ static void control_set_hardware(struct fb_info_control *p, struct fb_par_contro
/*
- * Called from fbmem.c for probing & initializing
+ * Parse user speficied options (`video=controlfb:')
*/
-int __init control_init(void)
+static void __init control_setup(char *options)
+{
+ char *this_opt;
+
+ if (!options || !*options)
+ return;
+
+ while ((this_opt = strsep(&options, ",")) != NULL) {
+ if (!strncmp(this_opt, "vmode:", 6)) {
+ int vmode = simple_strtoul(this_opt+6, NULL, 0);
+ if (vmode > 0 && vmode <= VMODE_MAX &&
+ control_mac_modes[vmode - 1].m[1] >= 0)
+ default_vmode = vmode;
+ } else if (!strncmp(this_opt, "cmode:", 6)) {
+ int depth = simple_strtoul(this_opt+6, NULL, 0);
+ switch (depth) {
+ case CMODE_8:
+ case CMODE_16:
+ case CMODE_32:
+ default_cmode = depth;
+ break;
+ case 8:
+ default_cmode = CMODE_8;
+ break;
+ case 15:
+ case 16:
+ default_cmode = CMODE_16;
+ break;
+ case 24:
+ case 32:
+ default_cmode = CMODE_32;
+ break;
+ }
+ }
+ }
+}
+
+static int __init control_init(void)
{
struct device_node *dp;
char *option = NULL;
@@ -651,15 +682,16 @@ static void __init find_vram_size(struct fb_info_control *p)
static int __init control_of_init(struct device_node *dp)
{
struct fb_info_control *p;
- unsigned long addr;
- int i;
+ struct resource fb_res, reg_res;
if (control_fb) {
printk(KERN_ERR "controlfb: only one control is supported\n");
return -ENXIO;
}
- if(dp->n_addrs != 2) {
- printk(KERN_ERR "expecting 2 address for control (got %d)", dp->n_addrs);
+
+ if (of_pci_address_to_resource(dp, 2, &fb_res) ||
+ of_pci_address_to_resource(dp, 1, &reg_res)) {
+ printk(KERN_ERR "can't get 2 addresses for control\n");
return -ENXIO;
}
p = kmalloc(sizeof(*p), GFP_KERNEL);
@@ -669,18 +701,12 @@ static int __init control_of_init(struct device_node *dp)
memset(p, 0, sizeof(*p));
/* Map in frame buffer and registers */
- for (i = 0; i < dp->n_addrs; ++i) {
- addr = dp->addrs[i].address;
- if (dp->addrs[i].size >= 0x800000) {
- p->fb_orig_base = addr;
- p->fb_orig_size = dp->addrs[i].size;
- /* use the big-endian aperture (??) */
- p->frame_buffer_phys = addr + 0x800000;
- } else {
- p->control_regs_phys = addr;
- p->control_regs_size = dp->addrs[i].size;
- }
- }
+ p->fb_orig_base = fb_res.start;
+ p->fb_orig_size = fb_res.end - fb_res.start + 1;
+ /* use the big-endian aperture (??) */
+ p->frame_buffer_phys = fb_res.start + 0x800000;
+ p->control_regs_phys = reg_res.start;
+ p->control_regs_size = reg_res.end - reg_res.start + 1;
if (!p->fb_orig_base ||
!request_mem_region(p->fb_orig_base,p->fb_orig_size,"controlfb")) {
@@ -1059,43 +1085,3 @@ static void control_cleanup(void)
}
-/*
- * Parse user speficied options (`video=controlfb:')
- */
-void __init control_setup(char *options)
-{
- char *this_opt;
-
- if (!options || !*options)
- return;
-
- while ((this_opt = strsep(&options, ",")) != NULL) {
- if (!strncmp(this_opt, "vmode:", 6)) {
- int vmode = simple_strtoul(this_opt+6, NULL, 0);
- if (vmode > 0 && vmode <= VMODE_MAX &&
- control_mac_modes[vmode - 1].m[1] >= 0)
- default_vmode = vmode;
- } else if (!strncmp(this_opt, "cmode:", 6)) {
- int depth = simple_strtoul(this_opt+6, NULL, 0);
- switch (depth) {
- case CMODE_8:
- case CMODE_16:
- case CMODE_32:
- default_cmode = depth;
- break;
- case 8:
- default_cmode = CMODE_8;
- break;
- case 15:
- case 16:
- default_cmode = CMODE_16;
- break;
- case 24:
- case 32:
- default_cmode = CMODE_32;
- break;
- }
- }
- }
-}
-
diff --git a/drivers/video/cyblafb.c b/drivers/video/cyblafb.c
index 03fbe83d71a8..e9f5dee67e3c 100644
--- a/drivers/video/cyblafb.c
+++ b/drivers/video/cyblafb.c
@@ -7,11 +7,12 @@
* tridentfb.c by Jani Monoses
* see files above for further credits
*
- * TODO:
- *
*/
#define CYBLAFB_DEBUG 0
+#define CYBLAFB_KD_GRAPHICS_QUIRK 1
+
+#define CYBLAFB_PIXMAPSIZE 8192
#include <linux/config.h>
#include <linux/module.h>
@@ -22,7 +23,7 @@
#include <asm/types.h>
#include <video/cyblafb.h>
-#define VERSION "0.54"
+#define VERSION "0.62"
struct cyblafb_par {
u32 pseudo_pal[16];
@@ -32,7 +33,9 @@ struct cyblafb_par {
static struct fb_fix_screeninfo cyblafb_fix __devinitdata = {
.id = "CyBla",
.type = FB_TYPE_PACKED_PIXELS,
+ .xpanstep = 1,
.ypanstep = 1,
+ .ywrapstep = 1,
.visual = FB_VISUAL_PSEUDOCOLOR,
.accel = FB_ACCEL_NONE,
};
@@ -43,8 +46,9 @@ static int ref __devinitdata = 75;
static int fp __devinitdata;
static int crt __devinitdata;
static int memsize __devinitdata;
-static int vesafb __devinitdata;
+static int basestride;
+static int vesafb;
static int nativex;
static int center;
static int stretch;
@@ -52,26 +56,50 @@ static int pciwb = 1;
static int pcirb = 1;
static int pciwr = 1;
static int pcirr = 1;
+static int disabled;
static int verbosity;
static int displaytype;
-static void __iomem * io_virt; // iospace virtual memory address
-
-module_param(mode,charp,0);
-module_param(bpp,int,0);
-module_param(ref,int,0);
-module_param(fp,int,0);
-module_param(crt,int,0);
-module_param(nativex,int,0);
-module_param(center,int,0);
-module_param(stretch,int,0);
-module_param(pciwb,int,0);
-module_param(pcirb,int,0);
-module_param(pciwr,int,0);
-module_param(pcirr,int,0);
-module_param(memsize,int,0);
-module_param(verbosity,int,0);
-module_param(vesafb,int,0);
+static void __iomem *io_virt; // iospace virtual memory address
+
+module_param(mode, charp, 0);
+module_param(bpp, int, 0);
+module_param(ref, int, 0);
+module_param(fp, int, 0);
+module_param(crt, int, 0);
+module_param(nativex, int, 0);
+module_param(center, int, 0);
+module_param(stretch, int, 0);
+module_param(pciwb, int, 0);
+module_param(pcirb, int, 0);
+module_param(pciwr, int, 0);
+module_param(pcirr, int, 0);
+module_param(memsize, int, 0);
+module_param(verbosity, int, 0);
+
+//=========================================
+//
+// Well, we have to fix the upper layers.
+// Until this has been done, we work around
+// the bugs.
+//
+//=========================================
+
+#if (CYBLAFB_KD_GRAPHICS_QUIRK && CYBLAFB_DEBUG)
+ if (disabled) { \
+ printk("********\n");\
+ dump_stack();\
+ return val;\
+ }
+
+#elif CYBLAFB_KD_GRAPHICS_QUIRK
+#define KD_GRAPHICS_RETURN(val)\
+ if (disabled) {\
+ return val;\
+ }
+#else
+#define KD_GRAPHICS_RETURN(val)
+#endif
//=========================================
//
@@ -79,10 +107,10 @@ module_param(vesafb,int,0);
//
//=========================================
-#define out8(r,v) writeb(v,io_virt+r)
-#define out32(r,v) writel(v,io_virt+r)
-#define in8(r) readb(io_virt+r)
-#define in32(r) readl(io_virt+r)
+#define out8(r, v) writeb(v, io_virt + r)
+#define out32(r, v) writel(v, io_virt + r)
+#define in8(r) readb(io_virt + r)
+#define in32(r) readl(io_virt + r)
//======================================
//
@@ -90,47 +118,47 @@ module_param(vesafb,int,0);
//
//======================================
-static inline unsigned char read3X4(int reg)
+static inline u8 read3X4(u32 reg)
{
- out8(0x3D4,reg);
+ out8(0x3D4, reg);
return in8(0x3D5);
}
-static inline unsigned char read3C4(int reg)
+static inline u8 read3C4(u32 reg)
{
- out8(0x3C4,reg);
+ out8(0x3C4, reg);
return in8(0x3C5);
}
-static inline unsigned char read3CE(int reg)
+static inline u8 read3CE(u32 reg)
{
- out8(0x3CE,reg);
+ out8(0x3CE, reg);
return in8(0x3CF);
}
-static inline void write3X4(int reg,unsigned char val)
+static inline void write3X4(u32 reg, u8 val)
{
- out8(0x3D4,reg);
- out8(0x3D5,val);
+ out8(0x3D4, reg);
+ out8(0x3D5, val);
}
-static inline void write3C4(int reg,unsigned char val)
+static inline void write3C4(u32 reg, u8 val)
{
- out8(0x3C4,reg);
- out8(0x3C5,val);
+ out8(0x3C4, reg);
+ out8(0x3C5, val);
}
-static inline void write3CE(int reg,unsigned char val)
+static inline void write3CE(u32 reg, u8 val)
{
- out8(0x3CE,reg);
- out8(0x3CF,val);
+ out8(0x3CE, reg);
+ out8(0x3CF, val);
}
-static inline void write3C0(int reg,unsigned char val)
+static inline void write3C0(u32 reg, u8 val)
{
- in8(0x3DA); // read to reset index
- out8(0x3C0,reg);
- out8(0x3C0,val);
+ in8(0x3DA); // read to reset index
+ out8(0x3C0, reg);
+ out8(0x3C0, val);
}
//=================================================
@@ -139,58 +167,62 @@ static inline void write3C0(int reg,unsigned char val)
//
//=================================================
-static inline void enable_mmio(void)
+static void enable_mmio(void)
{
- int tmp;
+ u8 tmp;
- outb(0x0B,0x3C4);
+ outb(0x0B, 0x3C4);
inb(0x3C5); // Set NEW mode
- outb(SR0E,0x3C4); // write enable a lot of extended ports
- outb(0x80,0x3C5);
+ outb(SR0E, 0x3C4); // write enable a lot of extended ports
+ outb(0x80, 0x3C5);
- outb(SR11,0x3C4); // write enable those extended ports that
- outb(0x87,0x3C5); // are not affected by SR0E_New
+ outb(SR11, 0x3C4); // write enable those extended ports that
+ outb(0x87, 0x3C5); // are not affected by SR0E_New
- outb(CR1E,0x3d4); // clear write protect bit for port 0x3c2
- tmp=inb(0x3d5) & 0xBF;
- outb(CR1E,0x3d4);
- outb(tmp,0x3d5);
+ outb(CR1E, 0x3d4); // clear write protect bit for port 0x3c2
+ tmp = inb(0x3d5) & 0xBF;
+ outb(CR1E, 0x3d4);
+ outb(tmp, 0x3d5);
- outb(CR39,0x3D4);
- outb(inb(0x3D5)|0x01,0x3D5); // Enable mmio, everything else untouched
+ outb(CR39, 0x3D4);
+ outb(inb(0x3D5) | 0x01, 0x3D5); // Enable mmio
}
//=================================================
//
// Set pixel clock VCLK1
-// - multipliers set elswhere
-// - freq in units of 0.01 MHz
+// - multipliers set elswhere
+// - freq in units of 0.01 MHz
+//
+// Hardware bug: SR18 >= 250 is broken for the
+// cyberblade/i1
//
//=================================================
static void set_vclk(struct cyblafb_par *par, int freq)
{
- u32 m,n,k;
- int f,fi,d,di;
- u8 lo=0,hi=0;
+ u32 m, n, k;
+ int f, fi, d, di;
+ u8 lo = 0, hi = 0;
d = 2000;
k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3;
- for(m = 0;m<64;m++)
- for(n = 0;n<250;n++) { // max 249 is a hardware limit for cybla/i1 !
- fi = (int)(((5864727*(n+8))/((m+2)*(1<<k)))>>12);
- if ((di = abs(fi - freq)) < d) {
- d = di;
- f = fi;
- lo = (u8) n;
- hi = (u8) ((k<<6) | m);
+ for (m = 0; m < 64; m++)
+ for (n = 0; n < 250; n++) {
+ fi = (int)(((5864727 * (n + 8)) /
+ ((m + 2) * (1 << k))) >> 12);
+ if ((di = abs(fi - freq)) < d) {
+ d = di;
+ f = fi;
+ lo = (u8) n;
+ hi = (u8) ((k << 6) | m);
+ }
}
- }
- write3C4(SR19,hi);
- write3C4(SR18,lo);
- if(verbosity > 1)
+ write3C4(SR19, hi);
+ write3C4(SR18, lo);
+ if (verbosity > 0)
output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n",
- freq/100,freq%100,(hi&0xc0)>>6,hi&0x3f,lo);
+ freq / 100, freq % 100, (hi & 0xc0) >> 6, hi & 0x3f, lo);
}
//================================================
@@ -199,83 +231,83 @@ static void set_vclk(struct cyblafb_par *par, int freq)
//
//================================================
-static void cyblafb_setup_GE(int pitch,int bpp)
+static void cyblafb_setup_GE(int pitch, int bpp)
{
- int base = (pitch>>3)<<20;
+ KD_GRAPHICS_RETURN();
switch (bpp) {
- case 8: base |= (0<<29); break;
- case 15: base |= (5<<29); break;
- case 16: base |= (1<<29); break;
- case 24:
- case 32: base |= (2<<29); break;
+ case 8:
+ basestride = ((pitch >> 3) << 20) | (0 << 29);
+ break;
+ case 15:
+ basestride = ((pitch >> 3) << 20) | (5 << 29);
+ break;
+ case 16:
+ basestride = ((pitch >> 3) << 20) | (1 << 29);
+ break;
+ case 24:
+ case 32:
+ basestride = ((pitch >> 3) << 20) | (2 << 29);
+ break;
}
- write3X4(CR36,0x90); // reset GE
- write3X4(CR36,0x80); // enable GE
-
- out32(GE24,1<<7); // reset all GE pointers
- out32(GE24,0);
-
- write3X4(CR2D,0x00); // GE Timinigs, no delays
-
- out32(GEB8,base); // Destination Stride / Buffer Base 0, p 133
- out32(GEBC,base); // Destination Stride / Buffer Base 1, p 133
- out32(GEC0,base); // Destination Stride / Buffer Base 2, p 133
- out32(GEC4,base); // Destination Stride / Buffer Base 3, p 133
- out32(GEC8,base); // Source Stride / Buffer Base 0, p 133
- out32(GECC,base); // Source Stride / Buffer Base 1, p 133
- out32(GED0,base); // Source Stride / Buffer Base 2, p 133
- out32(GED4,base); // Source Stride / Buffer Base 3, p 133
- out32(GE6C,0); // Pattern and Style, p 129, ok
+ write3X4(CR36, 0x90); // reset GE
+ write3X4(CR36, 0x80); // enable GE
+ out32(GE24, 1 << 7); // reset all GE pointers by toggling
+ out32(GE24, 0); // d7 of GE24
+ write3X4(CR2D, 0x00); // GE Timinigs, no delays
+ out32(GE6C, 0); // Pattern and Style, p 129, ok
}
//=====================================================================
//
-// Although this is a .fb_sync function that could be enabled in
-// cyblafb_ops, we do not include it there. We sync immediately before
-// new GE operations to improve performance.
+// Cyberblade specific syncing
+//
+// A timeout might be caused by disabled mmio.
+// Cause:
+// - bit CR39 & 1 == 0 upon return, X trident driver bug
+// - kdm bug (KD_GRAPHICS not set on first switch)
+// - kernel design flaw (it believes in the correctness
+// of kdm/X
+// First we try to sync ignoring that problem, as most of the
+// time that will succeed immediately and the enable_mmio()
+// would only degrade performance.
//
//=====================================================================
static int cyblafb_sync(struct fb_info *info)
{
- int status, i=100000;
- while( ((status=in32(GE20)) & 0xFA800000) && i != 0)
+ u32 status, i = 100000;
+
+ KD_GRAPHICS_RETURN(0);
+
+ while (((status = in32(GE20)) & 0xFe800000) && i != 0)
i--;
if (i == 0) {
- // The timeout might be caused by disabled mmio.
- // Cause:
- // - bit CR39 & 1 == 0 upon return, X trident driver bug
- // - kdm bug (KD_GRAPHICS not set on first switch)
- // - kernel design flaw (it believes in the correctness
- // of kdm/X
- // So we make sure that mmio is enabled first ...
enable_mmio();
-// show_trace(NULL,&status);
- i=1000000;
- while( ((status=in32(GE20)) & 0xFA800000) && i != 0)
+ i = 1000000;
+ while (((status = in32(GE20)) & 0xFA800000) && i != 0)
i--;
if (i == 0) {
- output("GE Timeout, status: %x\n",status);
- if(status & 0x80000000)
+ output("GE Timeout, status: %x\n", status);
+ if (status & 0x80000000)
output("Bresenham Engine : Busy\n");
- if(status & 0x40000000)
+ if (status & 0x40000000)
output("Setup Engine : Busy\n");
- if(status & 0x20000000)
+ if (status & 0x20000000)
output("SP / DPE : Busy\n");
- if(status & 0x10000000)
+ if (status & 0x10000000)
output("Memory Interface : Busy\n");
- if(status & 0x08000000)
+ if (status & 0x08000000)
output("Com Lst Proc : Busy\n");
- if(status & 0x04000000)
+ if (status & 0x04000000)
output("Block Write : Busy\n");
- if(status & 0x02000000)
+ if (status & 0x02000000)
output("Command Buffer : Full\n");
- if(status & 0x01000000)
+ if (status & 0x01000000)
output("RESERVED : Busy\n");
- if(status & 0x00800000)
+ if (status & 0x00800000)
output("PCI Write Buffer : Busy\n");
cyblafb_setup_GE(info->var.xres,
info->var.bits_per_pixel);
@@ -291,142 +323,193 @@ static int cyblafb_sync(struct fb_info *info)
//
//==============================
-static void cyblafb_fillrect(struct fb_info * info,
- const struct fb_fillrect *fr)
+static void cyblafb_fillrect(struct fb_info *info, const struct fb_fillrect *fr)
{
- int bpp = info->var.bits_per_pixel;
- int col;
+ u32 bpp = info->var.bits_per_pixel, col, desty, height;
+
+ KD_GRAPHICS_RETURN();
switch (bpp) {
- default:
- case 8: col = fr->color;
- col |= col <<8;
- col |= col <<16;
- break;
- case 16: col = ((u32 *)(info->pseudo_palette))[fr->color];
- col |= col <<16;
- break;
- case 32: col = ((u32 *)(info->pseudo_palette))[fr->color];
- break;
+ default:
+ case 8:
+ col = fr->color;
+ col |= col << 8;
+ col |= col << 16;
+ break;
+ case 16:
+ col = ((u32 *) (info->pseudo_palette))[fr->color];
+ col |= col << 16;
+ break;
+ case 32:
+ col = ((u32 *) (info->pseudo_palette))[fr->color];
+ break;
}
- cyblafb_sync(info);
-
- out32(GE60,col);
- out32(GE48,fr->rop ? 0x66:ROP_S);
- out32(GE44,0x20000000|1<<19|1<<4|2<<2);
- out32(GE08,point(fr->dx,fr->dy));
- out32(GE0C,point(fr->dx+fr->width-1,fr->dy+fr->height-1));
-
+ desty = fr->dy;
+ height = fr->height;
+ while (height) {
+ out32(GEB8, basestride | ((desty * info->var.xres_virtual *
+ bpp) >> 6));
+ out32(GE60, col);
+ out32(GE48, fr->rop ? 0x66 : ROP_S);
+ out32(GE44, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
+ out32(GE08, point(fr->dx, 0));
+ out32(GE0C, point(fr->dx + fr->width - 1,
+ height > 4096 ? 4095 : height - 1));
+ if (likely(height <= 4096))
+ return;
+ desty += 4096;
+ height -= 4096;
+ }
}
-//==============================
+//================================================
//
// Cyberblade specific copyarea
//
-//==============================
+// This function silently assumes that it never
+// will be called with width or height exceeding
+// 4096.
+//
+//================================================
-static void cyblafb_copyarea(struct fb_info *info,
- const struct fb_copyarea *ca)
+static void cyblafb_copyarea(struct fb_info *info, const struct fb_copyarea *ca)
{
- __u32 s1,s2,d1,d2;
- int direction;
+ u32 s1, s2, d1, d2, direction;
+
+ KD_GRAPHICS_RETURN();
+
+ s1 = point(ca->sx, 0);
+ s2 = point(ca->sx + ca->width - 1, ca->height - 1);
+ d1 = point(ca->dx, 0);
+ d2 = point(ca->dx + ca->width - 1, ca->height - 1);
- s1 = point(ca->sx,ca->sy);
- s2 = point(ca->sx+ca->width-1,ca->sy+ca->height-1);
- d1 = point(ca->dx,ca->dy);
- d2 = point(ca->dx+ca->width-1,ca->dy+ca->height-1);
if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx)))
direction = 0;
else
direction = 2;
- cyblafb_sync(info);
-
- out32(GE44,0xa0000000|1<<19|1<<2|direction);
- out32(GE00,direction?s2:s1);
- out32(GE04,direction?s1:s2);
- out32(GE08,direction?d2:d1);
- out32(GE0C,direction?d1:d2);
-
+ out32(GEB8, basestride | ((ca->dy * info->var.xres_virtual *
+ info->var.bits_per_pixel) >> 6));
+ out32(GEC8, basestride | ((ca->sy * info->var.xres_virtual *
+ info->var.bits_per_pixel) >> 6));
+ out32(GE44, 0xa0000000 | 1 << 19 | 1 << 2 | direction);
+ out32(GE00, direction ? s2 : s1);
+ out32(GE04, direction ? s1 : s2);
+ out32(GE08, direction ? d2 : d1);
+ out32(GE0C, direction ? d1 : d2);
}
//=======================================================================
//
// Cyberblade specific imageblit
//
-// Accelerated for the most usual case, blitting 1-bit deep character
-// character images. Everything else is passed to the generic imageblit.
+// Accelerated for the most usual case, blitting 1 - bit deep
+// character images. Everything else is passed to the generic imageblit
+// unless it is so insane that it is better to printk an alert.
+//
+// Hardware bug: _Never_ blit across pixel column 2048, that will lock
+// the system. We split those blit requests into three blitting
+// operations.
//
//=======================================================================
static void cyblafb_imageblit(struct fb_info *info,
const struct fb_image *image)
{
-
u32 fgcol, bgcol;
+ u32 *pd = (u32 *) image->data;
+ u32 bpp = info->var.bits_per_pixel;
- int i;
- int bpp = info->var.bits_per_pixel;
- int index = 0;
- int index_end=image->height * image->width / 8;
- int width_dds=image->width / 32;
- int width_dbs=image->width % 32;
-
- if (image->depth != 1 || bpp < 8 || bpp > 32 || bpp % 8 != 0 ||
- image->width % 8 != 0 || image->width == 0 || image->height == 0) {
- cfb_imageblit(info,image);
+ KD_GRAPHICS_RETURN();
+
+ // Used only for drawing the penguine (image->depth > 1)
+ if (image->depth != 1) {
+ cfb_imageblit(info, image);
+ return;
+ }
+ // That should never happen, but it would be fatal
+ if (image->width == 0 || image->height == 0) {
+ output("imageblit: width/height 0 detected\n");
return;
}
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
- fgcol = ((u32*)(info->pseudo_palette))[image->fg_color];
- bgcol = ((u32*)(info->pseudo_palette))[image->bg_color];
+ fgcol = ((u32 *) (info->pseudo_palette))[image->fg_color];
+ bgcol = ((u32 *) (info->pseudo_palette))[image->bg_color];
} else {
fgcol = image->fg_color;
bgcol = image->bg_color;
}
switch (bpp) {
- case 8:
- fgcol |= fgcol <<8; fgcol |= fgcol <<16;
- bgcol |= bgcol <<8; bgcol |= bgcol <<16;
- break;
- case 16:
- fgcol |= fgcol <<16;
- bgcol |= bgcol <<16;
- break;
- default:
- break;
+ case 8:
+ fgcol |= fgcol << 8;
+ bgcol |= bgcol << 8;
+ case 16:
+ fgcol |= fgcol << 16;
+ bgcol |= bgcol << 16;
+ default:
+ break;
}
- cyblafb_sync(info);
-
- out32(GE60,fgcol);
- out32(GE64,bgcol);
- out32(GE44,0xa0000000 | 1<<20 | 1<<19);
- out32(GE08,point(image->dx,image->dy));
- out32(GE0C,point(image->dx+image->width-1,image->dy+image->height-1));
+ out32(GEB8, basestride | ((image->dy * info->var.xres_virtual *
+ bpp) >> 6));
+ out32(GE60, fgcol);
+ out32(GE64, bgcol);
+
+ if (!(image->dx < 2048 && (image->dx + image->width - 1) >= 2048)) {
+ u32 dds = ((image->width + 31) >> 5) * image->height;
+ out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
+ out32(GE08, point(image->dx, 0));
+ out32(GE0C, point(image->dx + image->width - 1,
+ image->height - 1));
+ while (dds--)
+ out32(GE9C, *pd++);
+ } else {
+ int i, j;
+ u32 ddstotal = (image->width + 31) >> 5;
+ u32 ddsleft = (2048 - image->dx + 31) >> 5;
+ u32 skipleft = ddstotal - ddsleft;
+
+ out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
+ out32(GE08, point(image->dx, 0));
+ out32(GE0C, point(2048 - 1, image->height - 1));
+ for (i = 0; i < image->height; i++) {
+ for (j = 0; j < ddsleft; j++)
+ out32(GE9C, *pd++);
+ pd += skipleft;
+ }
- while(index < index_end) {
- const char *p = image->data + index;
- for(i=0;i<width_dds;i++) {
- out32(GE9C,*(u32*)p);
- p+=4;
- index+=4;
+ if (image->dx % 32) {
+ out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
+ out32(GE08, point(2048, 0));
+ if (image->width > ddsleft << 5)
+ out32(GE0C, point(image->dx + (ddsleft << 5) -
+ 1, image->height - 1));
+ else
+ out32(GE0C, point(image->dx + image->width - 1,
+ image->height - 1));
+ pd = ((u32 *) image->data) + ddstotal - skipleft - 1;
+ for (i = 0; i < image->height; i++) {
+ out32(GE9C, swab32(swab32(*pd) << ((32 -
+ (image->dx & 31)) & 31)));
+ pd += ddstotal;
+ }
}
- switch(width_dbs) {
- case 0: break;
- case 8: out32(GE9C,*(u8*)p);
- index+=1;
- break;
- case 16: out32(GE9C,*(u16*)p);
- index+=2;
- break;
- case 24: out32(GE9C,*(u16*)p | *(u8*)(p+2)<<16);
- index+=3;
- break;
+
+ if (skipleft) {
+ out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
+ out32(GE08, point(image->dx + (ddsleft << 5), 0));
+ out32(GE0C, point(image->dx + image->width - 1,
+ image->height - 1));
+ pd = (u32 *) image->data;
+ for (i = 0; i < image->height; i++) {
+ pd += ddsleft;
+ for (j = 0; j < skipleft; j++)
+ out32(GE9C, *pd++);
+ }
}
}
}
@@ -443,7 +526,6 @@ static int cyblafb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
int bpp = var->bits_per_pixel;
- int s,t,maxvyres;
//
// we try to support 8, 16, 24 and 32 bpp modes,
@@ -453,9 +535,9 @@ static int cyblafb_check_var(struct fb_var_screeninfo *var,
// (This is what tridentfb does ... will be changed in the future)
//
//
- if ( bpp % 8 != 0 || bpp < 8 || bpp >32)
+ if (bpp % 8 != 0 || bpp < 8 || bpp > 32)
bpp = 8;
- if (bpp == 24 )
+ if (bpp == 24)
bpp = var->bits_per_pixel = 32;
//
@@ -472,65 +554,93 @@ static int cyblafb_check_var(struct fb_var_screeninfo *var,
return -EINVAL;
//
- // xres != xres_virtual is broken, fail if such an
- // unusual mode is requested
+ // we do not allow vclk to exceed 230 MHz. If the requested
+ // vclk is too high, we default to 200 MHz
//
- if (var->xres != var->xres_virtual)
- return -EINVAL;
+ if ((bpp == 32 ? 200000000 : 100000000) / var->pixclock > 23000)
+ var->pixclock = (bpp == 32 ? 200000000 : 100000000) / 20000;
//
- // we do not allow vclk to exceed 230 MHz
+ // enforce (h|v)sync_len limits
//
- if ((bpp==32 ? 200000000 : 100000000) / var->pixclock > 23000)
- return -EINVAL;
+ var->hsync_len &= ~7;
+ if(var->hsync_len > 248)
+ var->hsync_len = 248;
+
+ var->vsync_len &= 15;
//
- // calc max yres_virtual that would fit in memory
- // and max yres_virtual that could be used for scrolling
- // and use minimum of the results as maxvyres
- //
- // adjust vyres_virtual to maxvyres if necessary
- // fail if requested yres is bigger than maxvyres
+ // Enforce horizontal and vertical hardware limits.
+ // 1600x1200 is mentioned as a maximum, but higher resolutions could
+ // work with slow refresh, small margins and short sync.
//
- s = (0x1fffff / (var->xres * bpp/8)) + var->yres;
- t = info->fix.smem_len / (var->xres * bpp/8);
- maxvyres = t < s ? t : s;
- if (maxvyres < var->yres_virtual)
- var->yres_virtual=maxvyres;
- if (maxvyres < var->yres)
+ var->xres &= ~7;
+
+ if (((var->xres + var->left_margin + var->right_margin +
+ var->hsync_len) > (bpp == 32 ? 2040 : 4088)) ||
+ ((var->yres + var->upper_margin + var->lower_margin +
+ var->vsync_len) > 2047))
return -EINVAL;
- switch (bpp) {
- case 8:
- var->red.offset = 0;
- var->green.offset = 0;
- var->blue.offset = 0;
- var->red.length = 6;
- var->green.length = 6;
- var->blue.length = 6;
- break;
- case 16:
- var->red.offset = 11;
- var->green.offset = 5;
- var->blue.offset = 0;
- var->red.length = 5;
- var->green.length = 6;
- var->blue.length = 5;
- break;
- case 32:
- var->red.offset = 16;
- var->green.offset = 8;
- var->blue.offset = 0;
- var->red.length = 8;
- var->green.length = 8;
- var->blue.length = 8;
- break;
- default:
+ if ((var->xres > 1600) || (var->yres > 1200))
+ output("Mode %dx%d exceeds documented limits.\n",
+ var->xres, var->yres);
+ //
+ // try to be smart about (x|y)res_virtual problems.
+ //
+ if (var->xres > var->xres_virtual)
+ var->xres_virtual = var->xres;
+ if (var->yres > var->yres_virtual)
+ var->yres_virtual = var->yres;
+
+ if (bpp == 8 || bpp == 16) {
+ if (var->xres_virtual > 4088)
+ var->xres_virtual = 4088;
+ } else {
+ if (var->xres_virtual > 2040)
+ var->xres_virtual = 2040;
+ }
+ var->xres_virtual &= ~7;
+ while (var->xres_virtual * var->yres_virtual * bpp / 8 >
+ info->fix.smem_len) {
+ if (var->yres_virtual > var->yres)
+ var->yres_virtual--;
+ else if (var->xres_virtual > var->xres)
+ var->xres_virtual -= 8;
+ else
return -EINVAL;
}
- return 0;
+ switch (bpp) {
+ case 8:
+ var->red.offset = 0;
+ var->green.offset = 0;
+ var->blue.offset = 0;
+ var->red.length = 6;
+ var->green.length = 6;
+ var->blue.length = 6;
+ break;
+ case 16:
+ var->red.offset = 11;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ var->red.length = 5;
+ var->green.length = 6;
+ var->blue.length = 5;
+ break;
+ case 32:
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
}
//=====================================================================
@@ -543,23 +653,25 @@ static int cyblafb_check_var(struct fb_var_screeninfo *var,
// it, so it is also safe to be used here. BTW: datasheet CR0E on page
// 90 really is CR1E, the real CRE is documented on page 72.
//
+// BUT:
+//
+// As of internal version 0.60 we do not use vga panning any longer.
+// Vga panning did not allow us the use of all available video memory
+// and thus prevented ywrap scrolling. We do use the "right view"
+// register now.
+//
+//
//=====================================================================
static int cyblafb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
- unsigned int offset;
+ KD_GRAPHICS_RETURN(0);
- offset=(var->xoffset+(var->yoffset*var->xres))*var->bits_per_pixel/32;
info->var.xoffset = var->xoffset;
info->var.yoffset = var->yoffset;
-
- write3X4(CR0D,offset & 0xFF);
- write3X4(CR0C,(offset & 0xFF00) >> 8);
- write3X4(CR1E,(read3X4(CR1E) & 0xDF) | ((offset & 0x10000) >> 11));
- write3X4(CR27,(read3X4(CR27) & 0xF8) | ((offset & 0xE0000) >> 17));
- write3X4(CR2B,(read3X4(CR2B) & 0xDF) | ((offset & 0x100000) >> 15));
-
+ out32(GE10, 0x80000000 | ((var->xoffset + (var->yoffset *
+ var->xres_virtual)) * var->bits_per_pixel / 32));
return 0;
}
@@ -578,56 +690,96 @@ static void regdump(struct cyblafb_par *par)
return;
printk("\n");
- for(i=0; i<=0xff; i++) {
- outb(i,0x3d4);
- printk("CR%02x=%02x ",i,inb(0x3d5));
- if (i%16==15)
+ for (i = 0; i <= 0xff; i++) {
+ outb(i, 0x3d4);
+ printk("CR%02x=%02x ", i, inb(0x3d5));
+ if (i % 16 == 15)
printk("\n");
}
- outb(0x30,0x3ce);
- outb(inb(0x3cf) | 0x40,0x3cf);
- for(i=0; i<=0x1f; i++) {
- if (i==0 || (i>2 && i<8) || i==0x10 || i==0x11 || i==0x16) {
- outb(i,0x3d4);
- printk("CR%02x=%02x ",i,inb(0x3d5));
+ outb(0x30, 0x3ce);
+ outb(inb(0x3cf) | 0x40, 0x3cf);
+ for (i = 0; i <= 0x1f; i++) {
+ if (i == 0 || (i > 2 && i < 8) || i == 0x10 || i == 0x11
+ || i == 0x16) {
+ outb(i, 0x3d4);
+ printk("CR%02x=%02x ", i, inb(0x3d5));
} else
printk("------- ");
- if (i%16==15)
+ if (i % 16 == 15)
printk("\n");
}
- outb(0x30,0x3ce);
- outb(inb(0x3cf) & 0xbf,0x3cf);
+ outb(0x30, 0x3ce);
+ outb(inb(0x3cf) & 0xbf, 0x3cf);
printk("\n");
- for(i=0; i<=0x7f; i++) {
- outb(i,0x3ce);
- printk("GR%02x=%02x ",i,inb(0x3cf));
- if (i%16==15)
+ for (i = 0; i <= 0x7f; i++) {
+ outb(i, 0x3ce);
+ printk("GR%02x=%02x ", i, inb(0x3cf));
+ if (i % 16 == 15)
printk("\n");
}
printk("\n");
- for(i=0; i<=0xff; i++) {
- outb(i,0x3c4);
- printk("SR%02x=%02x ",i,inb(0x3c5));
- if (i%16==15)
+ for (i = 0; i <= 0xff; i++) {
+ outb(i, 0x3c4);
+ printk("SR%02x=%02x ", i, inb(0x3c5));
+ if (i % 16 == 15)
printk("\n");
}
printk("\n");
- for(i=0; i <= 0x1F; i++) {
- inb(0x3da); // next access is index!
- outb(i,0x3c0);
- printk("AR%02x=%02x ",i,inb(0x3c1));
- if (i%16==15)
+ for (i = 0; i <= 0x1F; i++) {
+ inb(0x3da); // next access is index!
+ outb(i, 0x3c0);
+ printk("AR%02x=%02x ", i, inb(0x3c1));
+ if (i % 16 == 15)
printk("\n");
}
printk("\n");
- inb(0x3DA); // reset internal flag to 3c0 index
- outb(0x20,0x3C0); // enable attr
+ inb(0x3DA); // reset internal flag to 3c0 index
+ outb(0x20, 0x3C0); // enable attr
+
+ return;
+}
+
+//=======================================================================
+//
+// Save State
+//
+// This function is called while a switch to KD_TEXT is in progress,
+// before any of the other functions are called.
+//
+//=======================================================================
+static void cyblafb_save_state(struct fb_info *info)
+{
+ struct cyblafb_par *par = info->par;
+ if (verbosity > 0)
+ output("Switching to KD_TEXT\n");
+ disabled = 0;
+ regdump(par);
+ enable_mmio();
+ return;
+}
+
+//=======================================================================
+//
+// Restore State
+//
+// This function is called while a switch to KD_GRAPHICS is in progress,
+// We have to turn on vga style panning registers again because the
+// trident driver of X does not know about GE10.
+//
+//=======================================================================
+
+static void cyblafb_restore_state(struct fb_info *info)
+{
+ if (verbosity > 0)
+ output("Switching to KD_GRAPHICS\n");
+ out32(GE10, 0);
+ disabled = 1;
return;
}
@@ -640,32 +792,34 @@ static void regdump(struct cyblafb_par *par)
static int cyblafb_set_par(struct fb_info *info)
{
struct cyblafb_par *par = info->par;
- u32
- htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,preendfetch,
- vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend;
+ u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart,
+ hblankend, preendfetch, vtotal, vdispend, vsyncstart,
+ vsyncend, vblankstart, vblankend;
struct fb_var_screeninfo *var = &info->var;
int bpp = var->bits_per_pixel;
int i;
+ KD_GRAPHICS_RETURN(0);
+
if (verbosity > 0)
output("Switching to new mode: "
"fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n",
- var->xres,var->yres,var->xres_virtual,
- var->yres_virtual,var->bits_per_pixel,var->pixclock,
- var->left_margin,var->right_margin,var->upper_margin,
- var->lower_margin,var->hsync_len,var->vsync_len);
+ var->xres, var->yres, var->xres_virtual,
+ var->yres_virtual, var->bits_per_pixel, var->pixclock,
+ var->left_margin, var->right_margin, var->upper_margin,
+ var->lower_margin, var->hsync_len, var->vsync_len);
htotal = (var->xres + var->left_margin + var->right_margin +
- var->hsync_len) / 8 - 5;
- hdispend = var->xres/8 - 1;
- hsyncstart = (var->xres + var->right_margin)/8;
- hsyncend = var->hsync_len/8;
+ var->hsync_len) / 8 - 5;
+ hdispend = var->xres / 8 - 1;
+ hsyncstart = (var->xres + var->right_margin) / 8;
+ hsyncend = var->hsync_len / 8;
hblankstart = hdispend + 1;
hblankend = htotal + 3; // should be htotal + 5, bios does it this way
- preendfetch = ((var->xres >> 3) + 1) * ((bpp+1) >> 3);
+ preendfetch = ((var->xres >> 3) + 1) * ((bpp + 1) >> 3);
vtotal = var->yres + var->upper_margin + var->lower_margin +
- var->vsync_len - 2;
+ var->vsync_len - 2;
vdispend = var->yres - 1;
vsyncstart = var->yres + var->lower_margin;
vblankstart = var->yres;
@@ -674,101 +828,99 @@ static int cyblafb_set_par(struct fb_info *info)
enable_mmio(); // necessary! ... check X ...
- write3X4(CR11,read3X4(CR11) & 0x7F); // unlock cr00 .. cr07
+ write3X4(CR11, read3X4(CR11) & 0x7F); // unlock cr00 .. cr07
- write3CE(GR30,8);
+ write3CE(GR30, 8);
if ((displaytype == DISPLAY_FP) && var->xres < nativex) {
// stretch or center ?
- out8(0x3C2,0xEB);
+ out8(0x3C2, 0xEB);
- write3CE(GR30,read3CE(GR30) | 0x81); // shadow mode on
+ write3CE(GR30, read3CE(GR30) | 0x81); // shadow mode on
if (center) {
- write3CE(GR52,(read3CE(GR52) & 0x7C) | 0x80);
- write3CE(GR53,(read3CE(GR53) & 0x7C) | 0x80);
- }
- else if (stretch) {
- write3CE(GR5D,0);
- write3CE(GR52,(read3CE(GR52) & 0x7C) | 1);
- write3CE(GR53,(read3CE(GR53) & 0x7C) | 1);
+ write3CE(GR52, (read3CE(GR52) & 0x7C) | 0x80);
+ write3CE(GR53, (read3CE(GR53) & 0x7C) | 0x80);
+ } else if (stretch) {
+ write3CE(GR5D, 0);
+ write3CE(GR52, (read3CE(GR52) & 0x7C) | 1);
+ write3CE(GR53, (read3CE(GR53) & 0x7C) | 1);
}
} else {
- out8(0x3C2,0x2B);
- write3CE(GR30,8);
+ out8(0x3C2, 0x2B);
+ write3CE(GR30, 8);
}
//
// Setup CRxx regs
//
- write3X4(CR00,htotal & 0xFF);
- write3X4(CR01,hdispend & 0xFF);
- write3X4(CR02,hblankstart & 0xFF);
- write3X4(CR03,hblankend & 0x1F);
- write3X4(CR04,hsyncstart & 0xFF);
- write3X4(CR05,(hsyncend & 0x1F) | ((hblankend & 0x20)<<2));
- write3X4(CR06,vtotal & 0xFF);
- write3X4(CR07,(vtotal & 0x100) >> 8 |
- (vdispend & 0x100) >> 7 |
- (vsyncstart & 0x100) >> 6 |
- (vblankstart & 0x100) >> 5 |
- 0x10 |
- (vtotal & 0x200) >> 4 |
- (vdispend & 0x200) >> 3 |
- (vsyncstart & 0x200) >> 2);
- write3X4(CR08,0);
- write3X4(CR09,(vblankstart & 0x200) >> 4 | 0x40 | // FIX !!!
- ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0));
- write3X4(CR0A,0); // Init to some reasonable default
- write3X4(CR0B,0); // Init to some reasonable default
- write3X4(CR0C,0); // Offset 0
- write3X4(CR0D,0); // Offset 0
- write3X4(CR0E,0); // Init to some reasonable default
- write3X4(CR0F,0); // Init to some reasonable default
- write3X4(CR10,vsyncstart & 0xFF);
- write3X4(CR11,(vsyncend & 0x0F));
- write3X4(CR12,vdispend & 0xFF);
- write3X4(CR13,((info->var.xres * bpp)/(4*16)) & 0xFF);
- write3X4(CR14,0x40); // double word mode
- write3X4(CR15,vblankstart & 0xFF);
- write3X4(CR16,vblankend & 0xFF);
- write3X4(CR17,0xC3);
- write3X4(CR18,0xFF);
+ write3X4(CR00, htotal & 0xFF);
+ write3X4(CR01, hdispend & 0xFF);
+ write3X4(CR02, hblankstart & 0xFF);
+ write3X4(CR03, hblankend & 0x1F);
+ write3X4(CR04, hsyncstart & 0xFF);
+ write3X4(CR05, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
+ write3X4(CR06, vtotal & 0xFF);
+ write3X4(CR07, (vtotal & 0x100) >> 8 |
+ (vdispend & 0x100) >> 7 |
+ (vsyncstart & 0x100) >> 6 |
+ (vblankstart & 0x100) >> 5 |
+ 0x10 |
+ (vtotal & 0x200) >> 4 |
+ (vdispend & 0x200) >> 3 | (vsyncstart & 0x200) >> 2);
+ write3X4(CR08, 0);
+ write3X4(CR09, (vblankstart & 0x200) >> 4 | 0x40 | // FIX !!!
+ ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0));
+ write3X4(CR0A, 0); // Init to some reasonable default
+ write3X4(CR0B, 0); // Init to some reasonable default
+ write3X4(CR0C, 0); // Offset 0
+ write3X4(CR0D, 0); // Offset 0
+ write3X4(CR0E, 0); // Init to some reasonable default
+ write3X4(CR0F, 0); // Init to some reasonable default
+ write3X4(CR10, vsyncstart & 0xFF);
+ write3X4(CR11, (vsyncend & 0x0F));
+ write3X4(CR12, vdispend & 0xFF);
+ write3X4(CR13, ((info->var.xres_virtual * bpp) / (4 * 16)) & 0xFF);
+ write3X4(CR14, 0x40); // double word mode
+ write3X4(CR15, vblankstart & 0xFF);
+ write3X4(CR16, vblankend & 0xFF);
+ write3X4(CR17, 0xE3);
+ write3X4(CR18, 0xFF);
// CR19: needed for interlaced modes ... ignore it for now
- write3X4(CR1A,0x07); // Arbitration Control Counter 1
- write3X4(CR1B,0x07); // Arbitration Control Counter 2
- write3X4(CR1C,0x07); // Arbitration Control Counter 3
- write3X4(CR1D,0x00); // Don't know, doesn't hurt ;-)
- write3X4(CR1E,(info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80);
+ write3X4(CR1A, 0x07); // Arbitration Control Counter 1
+ write3X4(CR1B, 0x07); // Arbitration Control Counter 2
+ write3X4(CR1C, 0x07); // Arbitration Control Counter 3
+ write3X4(CR1D, 0x00); // Don't know, doesn't hurt ; -)
+ write3X4(CR1E, (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80);
// CR1F: do not set, contains BIOS info about memsize
- write3X4(CR20,0x20); // enabe wr buf, disable 16bit planar mode
- write3X4(CR21,0x20); // enable linear memory access
+ write3X4(CR20, 0x20); // enabe wr buf, disable 16bit planar mode
+ write3X4(CR21, 0x20); // enable linear memory access
// CR22: RO cpu latch readback
// CR23: ???
// CR24: RO AR flag state
// CR25: RAMDAC rw timing, pclk buffer tristate control ????
// CR26: ???
- write3X4(CR27,(vdispend & 0x400) >> 6 |
- (vsyncstart & 0x400) >> 5 |
- (vblankstart & 0x400) >> 4 |
- (vtotal & 0x400) >> 3 |
- 0x8);
+ write3X4(CR27, (vdispend & 0x400) >> 6 |
+ (vsyncstart & 0x400) >> 5 |
+ (vblankstart & 0x400) >> 4 |
+ (vtotal & 0x400) >> 3 |
+ 0x8);
// CR28: ???
- write3X4(CR29,(read3X4(CR29) & 0xCF) |
- ((((info->var.xres * bpp) / (4*16)) & 0x300) >>4));
- write3X4(CR2A,read3X4(CR2A) | 0x40);
- write3X4(CR2B,(htotal & 0x100) >> 8 |
- (hdispend & 0x100) >> 7 |
- // (0x00 & 0x100) >> 6 | hinterlace para bit 8 ???
- (hsyncstart & 0x100) >> 5 |
- (hblankstart & 0x100) >> 4);
+ write3X4(CR29, (read3X4(CR29) & 0xCF) | ((((info->var.xres_virtual *
+ bpp) / (4 * 16)) & 0x300) >> 4));
+ write3X4(CR2A, read3X4(CR2A) | 0x40);
+ write3X4(CR2B, (htotal & 0x100) >> 8 |
+ (hdispend & 0x100) >> 7 |
+ // (0x00 & 0x100) >> 6 | hinterlace para bit 8 ???
+ (hsyncstart & 0x100) >> 5 |
+ (hblankstart & 0x100) >> 4);
// CR2C: ???
// CR2D: initialized in cyblafb_setup_GE()
- write3X4(CR2F,0x92); // conservative, better signal quality
+ write3X4(CR2F, 0x92); // conservative, better signal quality
// CR30: reserved
// CR31: reserved
// CR32: reserved
@@ -777,96 +929,116 @@ static int cyblafb_set_par(struct fb_info *info)
// CR35: disabled in CR36
// CR36: initialized in cyblafb_setup_GE
// CR37: i2c, ignore for now
- write3X4(CR38,(bpp == 8) ? 0x00 : //
- (bpp == 16) ? 0x05 : // highcolor
- (bpp == 24) ? 0x29 : // packed 24bit truecolor
- (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus
- write3X4(CR39,0x01 | // MMIO enable
- (pcirb ? 0x02 : 0) | // pci read burst enable
- (pciwb ? 0x04 : 0)); // pci write burst enable
- write3X4(CR55,0x1F | // pci clocks * 2 for STOP# during 1st data phase
- (pcirr ? 0x40 : 0) | // pci read retry enable
- (pciwr ? 0x80 : 0)); // pci write retry enable
- write3X4(CR56,preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01)|2 : 0);
- write3X4(CR57,preendfetch >> 8 < 2 ? preendfetch & 0xff : 0);
- write3X4(CR58,0x82); // Bios does this .... don't know more
+ write3X4(CR38, (bpp == 8) ? 0x00 : //
+ (bpp == 16) ? 0x05 : // highcolor
+ (bpp == 24) ? 0x29 : // packed 24bit truecolor
+ (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus
+ write3X4(CR39, 0x01 | // MMIO enable
+ (pcirb ? 0x02 : 0) | // pci read burst enable
+ (pciwb ? 0x04 : 0)); // pci write burst enable
+ write3X4(CR55, 0x1F | // pci clocks * 2 for STOP# during 1st data phase
+ (pcirr ? 0x40 : 0) | // pci read retry enable
+ (pciwr ? 0x80 : 0)); // pci write retry enable
+ write3X4(CR56, preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01) | 2
+ : 0);
+ write3X4(CR57, preendfetch >> 8 < 2 ? preendfetch & 0xff : 0);
+ write3X4(CR58, 0x82); // Bios does this .... don't know more
//
// Setup SRxx regs
//
- write3C4(SR00,3);
- write3C4(SR01,1); //set char clock 8 dots wide
- write3C4(SR02,0x0F); //enable 4 maps needed in chain4 mode
- write3C4(SR03,0); //no character map select
- write3C4(SR04,0x0E); //memory mode: ext mem, even, chain4
+ write3C4(SR00, 3);
+ write3C4(SR01, 1); //set char clock 8 dots wide
+ write3C4(SR02, 0x0F); //enable 4 maps needed in chain4 mode
+ write3C4(SR03, 0); //no character map select
+ write3C4(SR04, 0x0E); //memory mode: ext mem, even, chain4
- out8(0x3C4,0x0b);
+ out8(0x3C4, 0x0b);
in8(0x3C5); // Set NEW mode
- write3C4(SR0D,0x00); // test ... check
+ write3C4(SR0D, 0x00); // test ... check
- set_vclk(par,(bpp==32 ? 200000000 : 100000000)/
- info->var.pixclock); //SR18,SR19
+ set_vclk(par, (bpp == 32 ? 200000000 : 100000000)
+ / info->var.pixclock); //SR18, SR19
//
// Setup GRxx regs
//
- write3CE(GR00,0x00); // test ... check
- write3CE(GR01,0x00); // test ... check
- write3CE(GR02,0x00); // test ... check
- write3CE(GR03,0x00); // test ... check
- write3CE(GR04,0x00); // test ... check
- write3CE(GR05,0x40); // no CGA compat,allow 256 col
- write3CE(GR06,0x05); // graphics mode
- write3CE(GR07,0x0F); // planes?
- write3CE(GR08,0xFF); // test ... check
- write3CE(GR0F,(bpp==32)?0x1A:0x12); // div vclk by 2 if 32bpp, chain4
- write3CE(GR20,0xC0); // test ... check
- write3CE(GR2F,0xA0); // PCLK = VCLK, no skew,
+ write3CE(GR00, 0x00); // test ... check
+ write3CE(GR01, 0x00); // test ... check
+ write3CE(GR02, 0x00); // test ... check
+ write3CE(GR03, 0x00); // test ... check
+ write3CE(GR04, 0x00); // test ... check
+ write3CE(GR05, 0x40); // no CGA compat, allow 256 col
+ write3CE(GR06, 0x05); // graphics mode
+ write3CE(GR07, 0x0F); // planes?
+ write3CE(GR08, 0xFF); // test ... check
+ write3CE(GR0F, (bpp == 32) ? 0x1A : 0x12); // vclk / 2 if 32bpp, chain4
+ write3CE(GR20, 0xC0); // test ... check
+ write3CE(GR2F, 0xA0); // PCLK = VCLK, no skew,
//
// Setup ARxx regs
//
- for(i = 0;i < 0x10;i++) // set AR00 .. AR0f
- write3C0(i,i);
- write3C0(AR10,0x41); // graphics mode and support 256 color modes
- write3C0(AR12,0x0F); // planes
- write3C0(AR13,0); // horizontal pel panning
+ for (i = 0; i < 0x10; i++) // set AR00 .. AR0f
+ write3C0(i, i);
+ write3C0(AR10, 0x41); // graphics mode and support 256 color modes
+ write3C0(AR12, 0x0F); // planes
+ write3C0(AR13, 0); // horizontal pel panning
in8(0x3DA); // reset internal flag to 3c0 index
- out8(0x3C0,0x20); // enable attr
+ out8(0x3C0, 0x20); // enable attr
//
// Setup hidden RAMDAC command register
//
- in8(0x3C8); // these reads are
- in8(0x3C6); // necessary to
- in8(0x3C6); // unmask the RAMDAC
- in8(0x3C6); // command reg, otherwise
- in8(0x3C6); // we would write the pixelmask reg!
- out8(0x3C6,(bpp == 8) ? 0x00 : // 256 colors
- (bpp == 15) ? 0x10 : //
- (bpp == 16) ? 0x30 : // hicolor
- (bpp == 24) ? 0xD0 : // truecolor
- (bpp == 32) ? 0xD0 : 0); // truecolor
+ in8(0x3C8); // these reads are
+ in8(0x3C6); // necessary to
+ in8(0x3C6); // unmask the RAMDAC
+ in8(0x3C6); // command reg, otherwise
+ in8(0x3C6); // we would write the pixelmask reg!
+ out8(0x3C6, (bpp == 8) ? 0x00 : // 256 colors
+ (bpp == 15) ? 0x10 : //
+ (bpp == 16) ? 0x30 : // hicolor
+ (bpp == 24) ? 0xD0 : // truecolor
+ (bpp == 32) ? 0xD0 : 0); // truecolor
in8(0x3C8);
//
// GR31 is not mentioned in the datasheet
//
if (displaytype == DISPLAY_FP)
- write3CE(GR31,(read3CE(GR31) & 0x8F) |
+ write3CE(GR31, (read3CE(GR31) & 0x8F) |
((info->var.yres > 1024) ? 0x50 :
- (info->var.yres > 768) ? 0x30 :
- (info->var.yres > 600) ? 0x20 :
- (info->var.yres > 480) ? 0x10 : 0));
+ (info->var.yres > 768) ? 0x30 :
+ (info->var.yres > 600) ? 0x20 :
+ (info->var.yres > 480) ? 0x10 : 0));
info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_TRUECOLOR;
- info->fix.line_length = info->var.xres * (bpp >> 3);
- info->cmap.len = (bpp == 8) ? 256: 16;
+ info->fix.line_length = info->var.xres_virtual * (bpp >> 3);
+ info->cmap.len = (bpp == 8) ? 256 : 16;
//
// init acceleration engine
//
- cyblafb_setup_GE(info->var.xres,info->var.bits_per_pixel);
+ cyblafb_setup_GE(info->var.xres_virtual, info->var.bits_per_pixel);
+
+ //
+ // Set/clear flags to allow proper scroll mode selection.
+ //
+ if (var->xres == var->xres_virtual)
+ info->flags &= ~FBINFO_HWACCEL_XPAN;
+ else
+ info->flags |= FBINFO_HWACCEL_XPAN;
+
+ if (var->yres == var->yres_virtual)
+ info->flags &= ~FBINFO_HWACCEL_YPAN;
+ else
+ info->flags |= FBINFO_HWACCEL_YPAN;
+
+ if (info->fix.smem_len !=
+ var->xres_virtual * var->yres_virtual * bpp / 8)
+ info->flags &= ~FBINFO_HWACCEL_YWRAP;
+ else
+ info->flags |= FBINFO_HWACCEL_YWRAP;
regdump(par);
@@ -885,27 +1057,27 @@ static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green,
{
int bpp = info->var.bits_per_pixel;
+ KD_GRAPHICS_RETURN(0);
+
if (regno >= info->cmap.len)
return 1;
if (bpp == 8) {
- out8(0x3C6,0xFF);
- out8(0x3C8,regno);
- out8(0x3C9,red>>10);
- out8(0x3C9,green>>10);
- out8(0x3C9,blue>>10);
-
- } else if (bpp == 16) // RGB 565
- ((u32*)info->pseudo_palette)[regno] =
- (red & 0xF800) |
- ((green & 0xFC00) >> 5) |
- ((blue & 0xF800) >> 11);
- else if (bpp == 32) // ARGB 8888
- ((u32*)info->pseudo_palette)[regno] =
- ((transp & 0xFF00) <<16) |
- ((red & 0xFF00) << 8) |
- ((green & 0xFF00)) |
- ((blue & 0xFF00)>>8);
+ out8(0x3C6, 0xFF);
+ out8(0x3C8, regno);
+ out8(0x3C9, red >> 10);
+ out8(0x3C9, green >> 10);
+ out8(0x3C9, blue >> 10);
+
+ } else if (bpp == 16) // RGB 565
+ ((u32 *) info->pseudo_palette)[regno] =
+ (red & 0xF800) |
+ ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+ else if (bpp == 32) // ARGB 8888
+ ((u32 *) info->pseudo_palette)[regno] =
+ ((transp & 0xFF00) << 16) |
+ ((red & 0xFF00) << 8) |
+ ((green & 0xFF00)) | ((blue & 0xFF00) >> 8);
return 0;
}
@@ -918,40 +1090,41 @@ static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green,
static int cyblafb_blank(int blank_mode, struct fb_info *info)
{
- unsigned char PMCont,DPMSCont;
+ unsigned char PMCont, DPMSCont;
+
+ KD_GRAPHICS_RETURN(0);
if (displaytype == DISPLAY_FP)
return 0;
- out8(0x83C8,0x04); // DPMS Control
+ out8(0x83C8, 0x04); // DPMS Control
PMCont = in8(0x83C6) & 0xFC;
DPMSCont = read3CE(GR23) & 0xFC;
- switch (blank_mode)
- {
- case FB_BLANK_UNBLANK: // Screen: On, HSync: On, VSync: On
- case FB_BLANK_NORMAL: // Screen: Off, HSync: On, VSync: On
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK: // Screen: On, HSync: On, VSync: On
+ case FB_BLANK_NORMAL: // Screen: Off, HSync: On, VSync: On
PMCont |= 0x03;
DPMSCont |= 0x00;
break;
- case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On
+ case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On
PMCont |= 0x02;
DPMSCont |= 0x01;
break;
- case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off
+ case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off
PMCont |= 0x02;
DPMSCont |= 0x02;
break;
- case FB_BLANK_POWERDOWN: // Screen: Off, HSync: Off, VSync: Off
+ case FB_BLANK_POWERDOWN: // Screen: Off, HSync: Off, VSync: Off
PMCont |= 0x00;
DPMSCont |= 0x03;
break;
}
- write3CE(GR23,DPMSCont);
- out8(0x83C8,4);
- out8(0x83C6,PMCont);
+ write3CE(GR23, DPMSCont);
+ out8(0x83C8, 4);
+ out8(0x83C6, PMCont);
//
// let fbcon do a softblank for us
//
@@ -959,15 +1132,18 @@ static int cyblafb_blank(int blank_mode, struct fb_info *info)
}
static struct fb_ops cyblafb_ops __devinitdata = {
- .owner = THIS_MODULE,
+ .owner = THIS_MODULE,
.fb_setcolreg = cyblafb_setcolreg,
.fb_pan_display = cyblafb_pan_display,
.fb_blank = cyblafb_blank,
.fb_check_var = cyblafb_check_var,
.fb_set_par = cyblafb_set_par,
.fb_fillrect = cyblafb_fillrect,
- .fb_copyarea= cyblafb_copyarea,
+ .fb_copyarea = cyblafb_copyarea,
.fb_imageblit = cyblafb_imageblit,
+ .fb_sync = cyblafb_sync,
+ .fb_restore_state = cyblafb_restore_state,
+ .fb_save_state = cyblafb_save_state,
};
//==========================================================================
@@ -986,74 +1162,89 @@ static struct fb_ops cyblafb_ops __devinitdata = {
static int __devinit getstartupmode(struct fb_info *info)
{
- u32 htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,
- vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend,
- cr00,cr01,cr02,cr03,cr04,cr05,cr2b,
- cr06,cr07,cr09,cr10,cr11,cr12,cr15,cr16,cr27,
- cr38,
- sr0d,sr18,sr19,
- gr0f,
- fi,pxclkdiv,vclkdiv,tmp,i;
+ u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend,
+ vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend,
+ cr00, cr01, cr02, cr03, cr04, cr05, cr2b,
+ cr06, cr07, cr09, cr10, cr11, cr12, cr15, cr16, cr27,
+ cr38, sr0d, sr18, sr19, gr0f, fi, pxclkdiv, vclkdiv, tmp, i;
struct modus {
- int xres; int yres; int vyres; int bpp; int pxclk;
- int left_margin; int right_margin; int upper_margin;
- int lower_margin; int hsync_len; int vsync_len;
- } modedb[5] = {
- { 0, 0, 8000, 0, 0, 0, 0, 0, 0, 0, 0},
- { 640, 480, 3756, 0, 0, -40, 24, 17, 0, 216, 3},
- { 800, 600, 3221, 0, 0, 96, 24, 14, 0, 136, 11},
- {1024, 768, 2815, 0, 0, 144, 24, 29, 0, 120, 3},
- {1280, 1024, 2662, 0, 0, 232, 16, 39, 0, 160, 3}
+ int xres; int vxres; int yres; int vyres;
+ int bpp; int pxclk;
+ int left_margin; int right_margin;
+ int upper_margin; int lower_margin;
+ int hsync_len; int vsync_len;
+ } modedb[5] = {
+ {
+ 0, 2048, 0, 4096, 0, 0, 0, 0, 0, 0, 0, 0}, {
+ 640, 2048, 480, 4096, 0, 0, -40, 24, 17, 0, 216, 3}, {
+ 800, 2048, 600, 4096, 0, 0, 96, 24, 14, 0, 136, 11}, {
+ 1024, 2048, 768, 4096, 0, 0, 144, 24, 29, 0, 120, 3}, {
+ 1280, 2048, 1024, 4096, 0, 0, 232, 16, 39, 0, 160, 3}
};
- outb(0x00,0x3d4); cr00=inb(0x3d5); outb(0x01,0x3d4); cr01=inb(0x3d5);
- outb(0x02,0x3d4); cr02=inb(0x3d5); outb(0x03,0x3d4); cr03=inb(0x3d5);
- outb(0x04,0x3d4); cr04=inb(0x3d5); outb(0x05,0x3d4); cr05=inb(0x3d5);
- outb(0x06,0x3d4); cr06=inb(0x3d5); outb(0x07,0x3d4); cr07=inb(0x3d5);
- outb(0x09,0x3d4); cr09=inb(0x3d5); outb(0x10,0x3d4); cr10=inb(0x3d5);
- outb(0x11,0x3d4); cr11=inb(0x3d5); outb(0x12,0x3d4); cr12=inb(0x3d5);
- outb(0x15,0x3d4); cr15=inb(0x3d5); outb(0x16,0x3d4); cr16=inb(0x3d5);
- outb(0x27,0x3d4); cr27=inb(0x3d5); outb(0x2b,0x3d4); cr2b=inb(0x3d5);
- outb(0x38,0x3d4); cr38=inb(0x3d5); outb(0x0b,0x3c4); inb(0x3c5);
- outb(0x0d,0x3c4); sr0d=inb(0x3c5); outb(0x18,0x3c4); sr18=inb(0x3c5);
- outb(0x19,0x3c4); sr19=inb(0x3c5); outb(0x0f,0x3ce); gr0f=inb(0x3cf);
-
- htotal = cr00 | (cr2b & 0x01) << 8;
- hdispend = cr01 | (cr2b & 0x02) << 7;
+ outb(0x00, 0x3d4); cr00 = inb(0x3d5);
+ outb(0x01, 0x3d4); cr01 = inb(0x3d5);
+ outb(0x02, 0x3d4); cr02 = inb(0x3d5);
+ outb(0x03, 0x3d4); cr03 = inb(0x3d5);
+ outb(0x04, 0x3d4); cr04 = inb(0x3d5);
+ outb(0x05, 0x3d4); cr05 = inb(0x3d5);
+ outb(0x06, 0x3d4); cr06 = inb(0x3d5);
+ outb(0x07, 0x3d4); cr07 = inb(0x3d5);
+ outb(0x09, 0x3d4); cr09 = inb(0x3d5);
+ outb(0x10, 0x3d4); cr10 = inb(0x3d5);
+ outb(0x11, 0x3d4); cr11 = inb(0x3d5);
+ outb(0x12, 0x3d4); cr12 = inb(0x3d5);
+ outb(0x15, 0x3d4); cr15 = inb(0x3d5);
+ outb(0x16, 0x3d4); cr16 = inb(0x3d5);
+ outb(0x27, 0x3d4); cr27 = inb(0x3d5);
+ outb(0x2b, 0x3d4); cr2b = inb(0x3d5);
+ outb(0x38, 0x3d4); cr38 = inb(0x3d5);
+
+ outb(0x0b, 0x3c4);
+ inb(0x3c5);
+
+ outb(0x0d, 0x3c4); sr0d = inb(0x3c5);
+ outb(0x18, 0x3c4); sr18 = inb(0x3c5);
+ outb(0x19, 0x3c4); sr19 = inb(0x3c5);
+ outb(0x0f, 0x3ce); gr0f = inb(0x3cf);
+
+ htotal = cr00 | (cr2b & 0x01) << 8;
+ hdispend = cr01 | (cr2b & 0x02) << 7;
hblankstart = cr02 | (cr2b & 0x10) << 4;
- hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2;
- hsyncstart = cr04 | (cr2b & 0x08) << 5;
- hsyncend = cr05 & 0x1f;
+ hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2;
+ hsyncstart = cr04 | (cr2b & 0x08) << 5;
+ hsyncend = cr05 & 0x1f;
modedb[0].xres = hblankstart * 8;
modedb[0].hsync_len = hsyncend * 8;
modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres;
modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres -
- modedb[0].right_margin - modedb[0].hsync_len;
-
- vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4
- | (cr27 & 0x80) << 3;
- vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3
- | (cr27 & 0x10) << 6;
- vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2
- | (cr27 & 0x20) << 5;
- vsyncend = cr11 & 0x0f;
+ modedb[0].right_margin - modedb[0].hsync_len;
+
+ vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4
+ | (cr27 & 0x80) << 3;
+ vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3
+ | (cr27 & 0x10) << 6;
+ vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2
+ | (cr27 & 0x20) << 5;
+ vsyncend = cr11 & 0x0f;
vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4
- | (cr27 & 0x40) << 4;
- vblankend = cr16;
+ | (cr27 & 0x40) << 4;
+ vblankend = cr16;
- modedb[0].yres = vdispend + 1;
- modedb[0].vsync_len = vsyncend;
+ modedb[0].yres = vdispend + 1;
+ modedb[0].vsync_len = vsyncend;
modedb[0].lower_margin = vsyncstart - modedb[0].yres;
modedb[0].upper_margin = vtotal - modedb[0].yres -
- modedb[0].lower_margin - modedb[0].vsync_len + 2;
+ modedb[0].lower_margin - modedb[0].vsync_len + 2;
tmp = cr38 & 0x3c;
modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 :
- tmp == 8 ? 32 : 8;
+ tmp == 8 ? 32 : 8;
- fi = ((5864727*(sr18+8))/(((sr19&0x3f)+2)*(1<<((sr19&0xc0)>>6))))>>12;
+ fi = ((5864727 * (sr18 + 8)) /
+ (((sr19 & 0x3f) + 2) * (1 << ((sr19 & 0xc0) >> 6)))) >> 12;
pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1;
tmp = sr0d & 0x06;
vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 !
@@ -1062,10 +1253,10 @@ static int __devinit getstartupmode(struct fb_info *info)
if (verbosity > 0)
output("detected startup mode: "
"fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n",
- modedb[0].xres,modedb[0].yres,modedb[0].xres,
- modedb[0].bpp,modedb[0].pxclk,modedb[0].left_margin,
- modedb[0].right_margin,modedb[0].upper_margin,
- modedb[0].lower_margin,modedb[0].hsync_len,
+ modedb[0].xres, modedb[0].yres, modedb[0].xres,
+ modedb[0].bpp, modedb[0].pxclk, modedb[0].left_margin,
+ modedb[0].right_margin, modedb[0].upper_margin,
+ modedb[0].lower_margin, modedb[0].hsync_len,
modedb[0].vsync_len);
//
@@ -1073,36 +1264,39 @@ static int __devinit getstartupmode(struct fb_info *info)
// do not want to do it in another way!
//
- tryagain:
+ tryagain:
i = (mode == NULL) ? 0 :
- !strncmp(mode,"640x480",7) ? 1 :
- !strncmp(mode,"800x600",7) ? 2 :
- !strncmp(mode,"1024x768",8) ? 3 :
- !strncmp(mode,"1280x1024",9) ? 4 : 0;
+ !strncmp(mode, "640x480", 7) ? 1 :
+ !strncmp(mode, "800x600", 7) ? 2 :
+ !strncmp(mode, "1024x768", 8) ? 3 :
+ !strncmp(mode, "1280x1024", 9) ? 4 : 0;
ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref;
- if(i==0) {
+ if (i == 0) {
info->var.pixclock = modedb[i].pxclk;
info->var.bits_per_pixel = modedb[i].bpp;
} else {
info->var.pixclock = (100000000 /
- ((modedb[i].left_margin + modedb[i].xres +
- modedb[i].right_margin + modedb[i].hsync_len
- ) * (
- modedb[i].upper_margin + modedb[i].yres +
- modedb[i].lower_margin + modedb[i].vsync_len
- ) *
- ref / 10000
- ));
+ ((modedb[i].left_margin +
+ modedb[i].xres +
+ modedb[i].right_margin +
+ modedb[i].hsync_len) *
+ (modedb[i].upper_margin +
+ modedb[i].yres +
+ modedb[i].lower_margin +
+ modedb[i].vsync_len) * ref / 10000));
info->var.bits_per_pixel = bpp;
}
info->var.left_margin = modedb[i].left_margin;
info->var.right_margin = modedb[i].right_margin;
info->var.xres = modedb[i].xres;
- info->var.xres_virtual = modedb[i].xres;
+ if (!(modedb[i].yres == 1280 && modedb[i].bpp == 32))
+ info->var.xres_virtual = modedb[i].vxres;
+ else
+ info->var.xres_virtual = modedb[i].xres;
info->var.xoffset = 0;
info->var.hsync_len = modedb[i].hsync_len;
info->var.upper_margin = modedb[i].upper_margin;
@@ -1114,33 +1308,32 @@ static int __devinit getstartupmode(struct fb_info *info)
info->var.sync = 0;
info->var.vmode = FB_VMODE_NONINTERLACED;
- if(cyblafb_check_var(&info->var,info)) {
- // 640x480-8@75 should really never fail. One case would
+ if (cyblafb_check_var(&info->var, info)) {
+ // 640x480 - 8@75 should really never fail. One case would
// be fp == 1 and nativex < 640 ... give up then
- if(i==1 && bpp == 8 && ref == 75){
+ if (i == 1 && bpp == 8 && ref == 75) {
output("Can't find a valid mode :-(\n");
return -EINVAL;
}
// Our detected mode is unlikely to fail. If it does,
- // try 640x480-8@75 ...
- if(i==0) {
- mode="640x480";
- bpp=8;
- ref=75;
+ // try 640x480 - 8@75 ...
+ if (i == 0) {
+ mode = "640x480";
+ bpp = 8;
+ ref = 75;
output("Detected mode failed check_var! "
- "Trying 640x480-8@75\n");
+ "Trying 640x480 - 8@75\n");
goto tryagain;
}
// A specified video mode failed for some reason.
// Try the startup mode first
output("Specified mode '%s' failed check! "
- "Falling back to startup mode.\n",mode);
- mode=NULL;
+ "Falling back to startup mode.\n", mode);
+ mode = NULL;
goto tryagain;
}
return 0;
-
}
//========================================================
@@ -1160,21 +1353,28 @@ static unsigned int __devinit get_memsize(void)
else {
tmp = read3X4(CR1F) & 0x0F;
switch (tmp) {
- case 0x03: k = 1 * Mb; break;
- case 0x07: k = 2 * Mb; break;
- case 0x0F: k = 4 * Mb; break;
- case 0x04: k = 8 * Mb; break;
- default:
- k = 1 * Mb;
- output("Unknown memory size code %x in CR1F."
- " We default to 1 Mb for now, please"
- " do provide a memsize parameter!\n",
- tmp);
+ case 0x03:
+ k = 1 * 1024 * 1024;
+ break;
+ case 0x07:
+ k = 2 * 1024 * 1024;
+ break;
+ case 0x0F:
+ k = 4 * 1024 * 1024;
+ break;
+ case 0x04:
+ k = 8 * 1024 * 1024;
+ break;
+ default:
+ k = 1 * 1024 * 1024;
+ output("Unknown memory size code %x in CR1F."
+ " We default to 1 Mb for now, please"
+ " do provide a memsize parameter!\n", tmp);
}
}
if (verbosity > 0)
- output("framebuffer size = %d Kb\n",k/Kb);
+ output("framebuffer size = %d Kb\n", k / Kb);
return k;
}
@@ -1192,7 +1392,7 @@ static unsigned int __devinit get_displaytype(void)
return DISPLAY_FP;
if (crt)
return DISPLAY_CRT;
- return (read3CE(GR33) & 0x10)?DISPLAY_FP:DISPLAY_CRT;
+ return (read3CE(GR33) & 0x10) ? DISPLAY_FP : DISPLAY_CRT;
}
//=====================================
@@ -1203,7 +1403,7 @@ static unsigned int __devinit get_displaytype(void)
static int __devinit get_nativex(void)
{
- int x,y,tmp;
+ int x, y, tmp;
if (nativex)
return nativex;
@@ -1211,29 +1411,45 @@ static int __devinit get_nativex(void)
tmp = (read3CE(GR52) >> 4) & 3;
switch (tmp) {
- case 0: x = 1280; y = 1024; break;
- case 2: x = 1024; y = 768; break;
- case 3: x = 800; y = 600; break;
- case 4: x = 1400; y = 1050; break;
- case 1:
- default: x = 640; y = 480; break;
+ case 0: x = 1280; y = 1024;
+ break;
+ case 2: x = 1024; y = 768;
+ break;
+ case 3: x = 800; y = 600;
+ break;
+ case 4: x = 1400; y = 1050;
+ break;
+ case 1:
+ default:
+ x = 640; y = 480;
+ break;
}
if (verbosity > 0)
- output("%dx%d flat panel found\n",x,y);
+ output("%dx%d flat panel found\n", x, y);
return x;
}
-static int __devinit cybla_pci_probe(struct pci_dev * dev,
- const struct pci_device_id * id)
+static int __devinit cybla_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
{
struct fb_info *info;
struct cyblafb_par *par;
- info = framebuffer_alloc(sizeof(struct cyblafb_par),&dev->dev);
-
+ info = framebuffer_alloc(sizeof(struct cyblafb_par), &dev->dev);
if (!info)
- goto errout_alloc;
+ goto errout_alloc_info;
+
+ info->pixmap.addr = kzalloc(CYBLAFB_PIXMAPSIZE, GFP_KERNEL);
+ if (!info->pixmap.addr) {
+ output("allocation of pixmap buffer failed!\n");
+ goto errout_alloc_pixmap;
+ }
+ info->pixmap.size = CYBLAFB_PIXMAPSIZE - 4;
+ info->pixmap.buf_align = 4;
+ info->pixmap.access_align = 32;
+ info->pixmap.flags = FB_PIXMAP_SYSTEM;
+ info->pixmap.scan_align = 4;
par = info->par;
par->ops = cyblafb_ops;
@@ -1246,26 +1462,31 @@ static int __devinit cybla_pci_probe(struct pci_dev * dev,
output("could not enable device!\n");
goto errout_enable;
}
-
// might already be requested by vga console or vesafb,
// so we do care about success
- request_region(0x3c0,32,"cyblafb");
+ if (!request_region(0x3c0, 0x20, "cyblafb")) {
+ output("region 0x3c0/0x20 already reserved\n");
+ vesafb |= 1;
+ }
//
// Graphics Engine Registers
//
- request_region(GEBase,0x100,"cyblafb");
+ if (!request_region(GEBase, 0x100, "cyblafb")) {
+ output("region %#x/0x100 already reserved\n", GEBase);
+ vesafb |= 2;
+ }
regdump(par);
enable_mmio();
// setup MMIO region
- info->fix.mmio_start = pci_resource_start(dev,1);
+ info->fix.mmio_start = pci_resource_start(dev, 1);
info->fix.mmio_len = 0x20000;
if (!request_mem_region(info->fix.mmio_start,
- info->fix.mmio_len,"cyblafb")) {
+ info->fix.mmio_len, "cyblafb")) {
output("request_mem_region failed for mmio region!\n");
goto errout_mmio_reqmem;
}
@@ -1276,18 +1497,17 @@ static int __devinit cybla_pci_probe(struct pci_dev * dev,
output("ioremap failed for mmio region\n");
goto errout_mmio_remap;
}
-
// setup framebuffer memory ... might already be requested
// by vesafb. Not to fail in case of an unsuccessful request
- // is useful for the development cycle
- info->fix.smem_start = pci_resource_start(dev,0);
+ // is useful if both are loaded.
+ info->fix.smem_start = pci_resource_start(dev, 0);
info->fix.smem_len = get_memsize();
if (!request_mem_region(info->fix.smem_start,
- info->fix.smem_len,"cyblafb")) {
- output("request_mem_region failed for smem region!\n");
- if (!vesafb)
- goto errout_smem_req;
+ info->fix.smem_len, "cyblafb")) {
+ output("region %#lx/%#x already reserved\n",
+ info->fix.smem_start, info->fix.smem_len);
+ vesafb |= 4;
}
info->screen_base = ioremap_nocache(info->fix.smem_start,
@@ -1300,31 +1520,30 @@ static int __devinit cybla_pci_probe(struct pci_dev * dev,
displaytype = get_displaytype();
- if(displaytype == DISPLAY_FP)
+ if (displaytype == DISPLAY_FP)
nativex = get_nativex();
- //
- // FBINFO_HWACCEL_YWRAP .... does not work (could be made to work?)
- // FBINFO_PARTIAL_PAN_OK .... is not ok
- // FBINFO_READS_FAST .... is necessary for optimal scrolling
- //
- info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN
- | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT
- | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_READS_FAST;
+ info->flags = FBINFO_DEFAULT
+ | FBINFO_HWACCEL_COPYAREA
+ | FBINFO_HWACCEL_FILLRECT
+ | FBINFO_HWACCEL_IMAGEBLIT
+ | FBINFO_READS_FAST
+// | FBINFO_PARTIAL_PAN_OK
+ | FBINFO_MISC_ALWAYS_SETPAR;
info->pseudo_palette = par->pseudo_pal;
- if(getstartupmode(info))
+ if (getstartupmode(info))
goto errout_findmode;
- fb_alloc_cmap(&info->cmap,256,0);
+ fb_alloc_cmap(&info->cmap, 256, 0);
if (register_framebuffer(info)) {
output("Could not register CyBla framebuffer\n");
goto errout_register;
}
- pci_set_drvdata(dev,info);
+ pci_set_drvdata(dev, info);
//
// normal exit and error paths
@@ -1332,23 +1551,24 @@ static int __devinit cybla_pci_probe(struct pci_dev * dev,
return 0;
- errout_register:
- errout_findmode:
+ errout_register:
+ errout_findmode:
iounmap(info->screen_base);
- errout_smem_remap:
- release_mem_region(info->fix.smem_start,
- info->fix.smem_len);
- errout_smem_req:
+ errout_smem_remap:
+ if (!(vesafb & 4))
+ release_mem_region(info->fix.smem_start, info->fix.smem_len);
iounmap(io_virt);
- errout_mmio_remap:
- release_mem_region(info->fix.mmio_start,
- info->fix.mmio_len);
- errout_mmio_reqmem:
-// release_region(0x3c0,32);
- errout_enable:
+ errout_mmio_remap:
+ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+ errout_mmio_reqmem:
+ if (!(vesafb & 1))
+ release_region(0x3c0, 32);
+ errout_enable:
+ kfree(info->pixmap.addr);
+ errout_alloc_pixmap:
framebuffer_release(info);
- errout_alloc:
- output("CyblaFB version %s aborting init.\n",VERSION);
+ errout_alloc_info:
+ output("CyblaFB version %s aborting init.\n", VERSION);
return -ENODEV;
}
@@ -1359,35 +1579,41 @@ static void __devexit cybla_pci_remove(struct pci_dev *dev)
unregister_framebuffer(info);
iounmap(io_virt);
iounmap(info->screen_base);
- release_mem_region(info->fix.smem_start,info->fix.smem_len);
- release_mem_region(info->fix.mmio_start,info->fix.mmio_len);
+ if (!(vesafb & 4))
+ release_mem_region(info->fix.smem_start, info->fix.smem_len);
+ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
fb_dealloc_cmap(&info->cmap);
+ if (!(vesafb & 2))
+ release_region(GEBase, 0x100);
+ if (!(vesafb & 1))
+ release_region(0x3c0, 32);
+ kfree(info->pixmap.addr);
framebuffer_release(info);
- output("CyblaFB version %s normal exit.\n",VERSION);
+ output("CyblaFB version %s normal exit.\n", VERSION);
}
//
// List of boards that we are trying to support
//
static struct pci_device_id cybla_devices[] = {
- {PCI_VENDOR_ID_TRIDENT,CYBERBLADEi1,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+ {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0,}
};
-MODULE_DEVICE_TABLE(pci,cybla_devices);
+MODULE_DEVICE_TABLE(pci, cybla_devices);
static struct pci_driver cyblafb_pci_driver = {
- .name = "cyblafb",
- .id_table = cybla_devices,
- .probe = cybla_pci_probe,
- .remove = __devexit_p(cybla_pci_remove)
+ .name = "cyblafb",
+ .id_table = cybla_devices,
+ .probe = cybla_pci_probe,
+ .remove = __devexit_p(cybla_pci_remove)
};
//=============================================================
//
// kernel command line example:
//
-// video=cyblafb:1280x1024,bpp=16,ref=50 ...
+// video=cyblafb:1280x1024, bpp=16, ref=50 ...
//
// modprobe command line example:
//
@@ -1401,45 +1627,44 @@ static int __devinit cyblafb_init(void)
char *options = NULL;
char *opt;
- if (fb_get_options("cyblafb",&options))
+ if (fb_get_options("cyblafb", &options))
return -ENODEV;
if (options && *options)
- while((opt = strsep(&options,",")) != NULL ) {
- if (!*opt) continue;
- else if (!strncmp(opt,"bpp=",4))
- bpp = simple_strtoul(opt+4,NULL,0);
- else if (!strncmp(opt,"ref=",4))
- ref = simple_strtoul(opt+4,NULL,0);
- else if (!strncmp(opt,"fp",2))
+ while ((opt = strsep(&options, ",")) != NULL) {
+ if (!*opt)
+ continue;
+ else if (!strncmp(opt, "bpp=", 4))
+ bpp = simple_strtoul(opt + 4, NULL, 0);
+ else if (!strncmp(opt, "ref=", 4))
+ ref = simple_strtoul(opt + 4, NULL, 0);
+ else if (!strncmp(opt, "fp", 2))
displaytype = DISPLAY_FP;
- else if (!strncmp(opt,"crt",3))
+ else if (!strncmp(opt, "crt", 3))
displaytype = DISPLAY_CRT;
- else if (!strncmp(opt,"nativex=",8))
- nativex = simple_strtoul(opt+8,NULL,0);
- else if (!strncmp(opt,"center",6))
+ else if (!strncmp(opt, "nativex=", 8))
+ nativex = simple_strtoul(opt + 8, NULL, 0);
+ else if (!strncmp(opt, "center", 6))
center = 1;
- else if (!strncmp(opt,"stretch",7))
+ else if (!strncmp(opt, "stretch", 7))
stretch = 1;
- else if (!strncmp(opt,"pciwb=",6))
- pciwb = simple_strtoul(opt+6,NULL,0);
- else if (!strncmp(opt,"pcirb=",6))
- pcirb = simple_strtoul(opt+6,NULL,0);
- else if (!strncmp(opt,"pciwr=",6))
- pciwr = simple_strtoul(opt+6,NULL,0);
- else if (!strncmp(opt,"pcirr=",6))
- pcirr = simple_strtoul(opt+6,NULL,0);
- else if (!strncmp(opt,"memsize=",8))
- memsize = simple_strtoul(opt+8,NULL,0);
- else if (!strncmp(opt,"verbosity=",10))
- verbosity = simple_strtoul(opt+10,NULL,0);
- else if (!strncmp(opt,"vesafb",6))
- vesafb = 1;
+ else if (!strncmp(opt, "pciwb=", 6))
+ pciwb = simple_strtoul(opt + 6, NULL, 0);
+ else if (!strncmp(opt, "pcirb=", 6))
+ pcirb = simple_strtoul(opt + 6, NULL, 0);
+ else if (!strncmp(opt, "pciwr=", 6))
+ pciwr = simple_strtoul(opt + 6, NULL, 0);
+ else if (!strncmp(opt, "pcirr=", 6))
+ pcirr = simple_strtoul(opt + 6, NULL, 0);
+ else if (!strncmp(opt, "memsize=", 8))
+ memsize = simple_strtoul(opt + 8, NULL, 0);
+ else if (!strncmp(opt, "verbosity=", 10))
+ verbosity = simple_strtoul(opt + 10, NULL, 0);
else
mode = opt;
}
#endif
- output("CyblaFB version %s initializing\n",VERSION);
+ output("CyblaFB version %s initializing\n", VERSION);
return pci_module_init(&cyblafb_pci_driver);
}
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index 00d87f5bb7be..ad1434e3f227 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -223,6 +223,7 @@ static int offb_blank(int blank, struct fb_info *info)
int __init offb_init(void)
{
struct device_node *dp = NULL, *boot_disp = NULL;
+
#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32)
struct device_node *macos_display = NULL;
#endif
@@ -234,60 +235,54 @@ int __init offb_init(void)
if (boot_infos != 0) {
unsigned long addr =
(unsigned long) boot_infos->dispDeviceBase;
+ u32 *addrp;
+ u64 daddr, dsize;
+ unsigned int flags;
+
/* find the device node corresponding to the macos display */
while ((dp = of_find_node_by_type(dp, "display"))) {
int i;
- /*
- * Grrr... It looks like the MacOS ATI driver
- * munges the assigned-addresses property (but
- * the AAPL,address value is OK).
- */
- if (strncmp(dp->name, "ATY,", 4) == 0
- && dp->n_addrs == 1) {
- unsigned int *ap =
- (unsigned int *) get_property(dp,
- "AAPL,address",
- NULL);
- if (ap != NULL) {
- dp->addrs[0].address = *ap;
- dp->addrs[0].size = 0x01000000;
- }
- }
/*
- * The LTPro on the Lombard powerbook has no addresses
- * on the display nodes, they are on their parent.
+ * Look for an AAPL,address property first.
*/
- if (dp->n_addrs == 0
- && device_is_compatible(dp, "ATY,264LTPro")) {
- int na;
- unsigned int *ap = (unsigned int *)
- get_property(dp, "AAPL,address", &na);
- if (ap != 0)
- for (na /= sizeof(unsigned int);
- na > 0; --na, ++ap)
- if (*ap <= addr
- && addr <
- *ap + 0x1000000)
- goto foundit;
+ unsigned int na;
+ unsigned int *ap =
+ (unsigned int *)get_property(dp, "AAPL,address",
+ &na);
+ if (ap != 0) {
+ for (na /= sizeof(unsigned int); na > 0;
+ --na, ++ap)
+ if (*ap <= addr &&
+ addr < *ap + 0x1000000) {
+ macos_display = dp;
+ goto foundit;
+ }
}
/*
* See if the display address is in one of the address
* ranges for this display.
*/
- for (i = 0; i < dp->n_addrs; ++i) {
- if (dp->addrs[i].address <= addr
- && addr <
- dp->addrs[i].address +
- dp->addrs[i].size)
+ i = 0;
+ for (;;) {
+ addrp = of_get_address(dp, i++, &dsize, &flags);
+ if (addrp == NULL)
break;
+ if (!(flags & IORESOURCE_MEM))
+ continue;
+ daddr = of_translate_address(dp, addrp);
+ if (daddr == OF_BAD_ADDR)
+ continue;
+ if (daddr <= addr && addr < (daddr + dsize)) {
+ macos_display = dp;
+ goto foundit;
+ }
}
- if (i < dp->n_addrs) {
- foundit:
+ foundit:
+ if (macos_display) {
printk(KERN_INFO "MacOS display is %s\n",
dp->full_name);
- macos_display = dp;
break;
}
}
@@ -326,8 +321,10 @@ static void __init offb_init_nodriver(struct device_node *dp)
int *pp, i;
unsigned int len;
int width = 640, height = 480, depth = 8, pitch;
- unsigned int rsize, *up;
- unsigned long address = 0;
+ unsigned int flags, rsize, *up;
+ u64 address = OF_BAD_ADDR;
+ u32 *addrp;
+ u64 asize;
if ((pp = (int *) get_property(dp, "depth", &len)) != NULL
&& len == sizeof(int))
@@ -363,7 +360,7 @@ static void __init offb_init_nodriver(struct device_node *dp)
break;
}
if (pdev) {
- for (i = 0; i < 6 && address == 0; i++) {
+ for (i = 0; i < 6 && address == OF_BAD_ADDR; i++) {
if ((pci_resource_flags(pdev, i) &
IORESOURCE_MEM) &&
(pci_resource_len(pdev, i) >= rsize))
@@ -374,27 +371,33 @@ static void __init offb_init_nodriver(struct device_node *dp)
}
#endif /* CONFIG_PCI */
- if (address == 0 &&
- (up = (unsigned *) get_property(dp, "address", &len)) != NULL &&
- len == sizeof(unsigned))
- address = (u_long) * up;
- if (address == 0) {
- for (i = 0; i < dp->n_addrs; ++i)
- if (dp->addrs[i].size >=
- pitch * height * depth / 8)
- break;
- if (i >= dp->n_addrs) {
+ /* This one is dodgy, we may drop it ... */
+ if (address == OF_BAD_ADDR &&
+ (up = (unsigned *) get_property(dp, "address", &len)) != NULL &&
+ len == sizeof(unsigned int))
+ address = (u64) * up;
+
+ if (address == OF_BAD_ADDR) {
+ for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags))
+ != NULL; i++) {
+ if (!(flags & IORESOURCE_MEM))
+ continue;
+ if (asize >= pitch * height * depth / 8)
+ break;
+ }
+ if (addrp == NULL) {
printk(KERN_ERR
"no framebuffer address found for %s\n",
dp->full_name);
return;
}
-
- address = (u_long) dp->addrs[i].address;
-
-#ifdef CONFIG_PPC64
- address += ((struct pci_dn *)dp->data)->phb->pci_mem_offset;
-#endif
+ address = of_translate_address(dp, addrp);
+ if (address == OF_BAD_ADDR) {
+ printk(KERN_ERR
+ "can't translate framebuffer address for %s\n",
+ dp->full_name);
+ return;
+ }
/* kludge for valkyrie */
if (strcmp(dp->name, "valkyrie") == 0)
@@ -459,7 +462,9 @@ static void __init offb_init_fb(const char *name, const char *full_name,
par->cmap_type = cmap_unknown;
if (depth == 8) {
- /* XXX kludge for ati */
+
+ /* Palette hacks disabled for now */
+#if 0
if (dp && !strncmp(name, "ATY,Rage128", 11)) {
unsigned long regbase = dp->addrs[2].address;
par->cmap_adr = ioremap(regbase, 0x1FFF);
@@ -490,6 +495,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
par->cmap_adr = ioremap(regbase + 0x6000, 0x1000);
par->cmap_type = cmap_gxt2000;
}
+#endif
fix->visual = par->cmap_adr ? FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_STATIC_PSEUDOCOLOR;
} else
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index ca4082ae5a18..335e37465559 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -69,6 +69,8 @@ struct fb_info_platinum {
unsigned long total_vram;
int clktype;
int dactype;
+
+ struct resource rsrc_fb, rsrc_reg;
};
/*
@@ -97,9 +99,6 @@ static int platinum_var_to_par(struct fb_var_screeninfo *var,
* Interface used by the world
*/
-int platinumfb_init(void);
-int platinumfb_setup(char*);
-
static struct fb_ops platinumfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = platinumfb_check_var,
@@ -138,13 +137,15 @@ static int platinumfb_set_par (struct fb_info *info)
init = platinum_reg_init[pinfo->vmode-1];
- if (pinfo->vmode == 13 && pinfo->cmode > 0)
- offset = 0x10;
+ if ((pinfo->vmode == VMODE_832_624_75) && (pinfo->cmode > CMODE_8))
+ offset = 0x10;
+
info->screen_base = pinfo->frame_buffer + init->fb_offset + offset;
info->fix.smem_start = (pinfo->frame_buffer_phys) + init->fb_offset + offset;
info->fix.visual = (pinfo->cmode == CMODE_8) ?
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
- info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<<pinfo->cmode) + offset;
+ info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<<pinfo->cmode)
+ + offset;
printk("line_length: %x\n", info->fix.line_length);
return 0;
}
@@ -221,7 +222,9 @@ static int platinumfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
static inline int platinum_vram_reqd(int video_mode, int color_mode)
{
return vmode_attrs[video_mode-1].vres *
- (vmode_attrs[video_mode-1].hres * (1<<color_mode) + 0x20) +0x1000;
+ (vmode_attrs[video_mode-1].hres * (1<<color_mode) +
+ ((video_mode == VMODE_832_624_75) &&
+ (color_mode > CMODE_8)) ? 0x10 : 0x20) + 0x1000;
}
#define STORE_D2(a, d) { \
@@ -481,7 +484,7 @@ static int platinum_var_to_par(struct fb_var_screeninfo *var,
/*
* Parse user speficied options (`video=platinumfb:')
*/
-int __init platinumfb_setup(char *options)
+static int __init platinumfb_setup(char *options)
{
char *this_opt;
@@ -522,19 +525,15 @@ int __init platinumfb_setup(char *options)
#define invalidate_cache(addr)
#endif
-static int __devinit platinumfb_probe(struct of_device* odev, const struct of_device_id *match)
+static int __devinit platinumfb_probe(struct of_device* odev,
+ const struct of_device_id *match)
{
struct device_node *dp = odev->node;
struct fb_info *info;
struct fb_info_platinum *pinfo;
- unsigned long addr, size;
volatile __u8 *fbuffer;
- int i, bank0, bank1, bank2, bank3, rc;
+ int bank0, bank1, bank2, bank3, rc;
- if (dp->n_addrs != 2) {
- printk(KERN_ERR "expecting 2 address for platinum (got %d)", dp->n_addrs);
- return -ENXIO;
- }
printk(KERN_INFO "platinumfb: Found Apple Platinum video hardware\n");
info = framebuffer_alloc(sizeof(*pinfo), &odev->dev);
@@ -542,26 +541,39 @@ static int __devinit platinumfb_probe(struct of_device* odev, const struct of_de
return -ENOMEM;
pinfo = info->par;
- /* Map in frame buffer and registers */
- for (i = 0; i < dp->n_addrs; ++i) {
- addr = dp->addrs[i].address;
- size = dp->addrs[i].size;
- /* Let's assume we can request either all or nothing */
- if (!request_mem_region(addr, size, "platinumfb")) {
- framebuffer_release(info);
- return -ENXIO;
- }
- if (size >= 0x400000) {
- /* frame buffer - map only 4MB */
- pinfo->frame_buffer_phys = addr;
- pinfo->frame_buffer = __ioremap(addr, 0x400000, _PAGE_WRITETHRU);
- pinfo->base_frame_buffer = pinfo->frame_buffer;
- } else {
- /* registers */
- pinfo->platinum_regs_phys = addr;
- pinfo->platinum_regs = ioremap(addr, size);
- }
+ if (of_address_to_resource(dp, 0, &pinfo->rsrc_reg) ||
+ of_address_to_resource(dp, 1, &pinfo->rsrc_fb)) {
+ printk(KERN_ERR "platinumfb: Can't get resources\n");
+ framebuffer_release(info);
+ return -ENXIO;
}
+ if (!request_mem_region(pinfo->rsrc_reg.start,
+ pinfo->rsrc_reg.start -
+ pinfo->rsrc_reg.end + 1,
+ "platinumfb registers")) {
+ framebuffer_release(info);
+ return -ENXIO;
+ }
+ if (!request_mem_region(pinfo->rsrc_fb.start,
+ pinfo->rsrc_fb.start
+ - pinfo->rsrc_fb.end + 1,
+ "platinumfb framebuffer")) {
+ release_mem_region(pinfo->rsrc_reg.start,
+ pinfo->rsrc_reg.end -
+ pinfo->rsrc_reg.start + 1);
+ framebuffer_release(info);
+ return -ENXIO;
+ }
+
+ /* frame buffer - map only 4MB */
+ pinfo->frame_buffer_phys = pinfo->rsrc_fb.start;
+ pinfo->frame_buffer = __ioremap(pinfo->rsrc_fb.start, 0x400000,
+ _PAGE_WRITETHRU);
+ pinfo->base_frame_buffer = pinfo->frame_buffer;
+
+ /* registers */
+ pinfo->platinum_regs_phys = pinfo->rsrc_reg.start;
+ pinfo->platinum_regs = ioremap(pinfo->rsrc_reg.start, 0x1000);
pinfo->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */
request_mem_region(pinfo->cmap_regs_phys, 0x1000, "platinumfb cmap");
@@ -624,18 +636,16 @@ static int __devexit platinumfb_remove(struct of_device* odev)
{
struct fb_info *info = dev_get_drvdata(&odev->dev);
struct fb_info_platinum *pinfo = info->par;
- struct device_node *dp = odev->node;
- unsigned long addr, size;
- int i;
unregister_framebuffer (info);
/* Unmap frame buffer and registers */
- for (i = 0; i < dp->n_addrs; ++i) {
- addr = dp->addrs[i].address;
- size = dp->addrs[i].size;
- release_mem_region(addr, size);
- }
+ release_mem_region(pinfo->rsrc_fb.start,
+ pinfo->rsrc_fb.end -
+ pinfo->rsrc_fb.start + 1);
+ release_mem_region(pinfo->rsrc_reg.start,
+ pinfo->rsrc_reg.end -
+ pinfo->rsrc_reg.start + 1);
iounmap(pinfo->frame_buffer);
iounmap(pinfo->platinum_regs);
release_mem_region(pinfo->cmap_regs_phys, 0x1000);
@@ -662,7 +672,7 @@ static struct of_platform_driver platinum_driver =
.remove = platinumfb_remove,
};
-int __init platinumfb_init(void)
+static int __init platinumfb_init(void)
{
#ifndef MODULE
char *option = NULL;
@@ -676,7 +686,7 @@ int __init platinumfb_init(void)
return 0;
}
-void __exit platinumfb_exit(void)
+static void __exit platinumfb_exit(void)
{
of_unregister_driver(&platinum_driver);
}
diff --git a/drivers/video/platinumfb.h b/drivers/video/platinumfb.h
index 2834fc1c344b..f6bd77cafd17 100644
--- a/drivers/video/platinumfb.h
+++ b/drivers/video/platinumfb.h
@@ -158,7 +158,9 @@ static struct platinum_regvals platinum_reg_init_14 = {
/* 832x624, 75Hz (13) */
static struct platinum_regvals platinum_reg_init_13 = {
0x70,
- { 864, 1680, 3360 }, /* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB */
+ { 864, 1680, 3344 }, /* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB,
+ * and we use 3344 instead of 3360 to fit in 2Mb
+ */
{ 0xff0, 4, 0, 0, 0, 0, 0x299, 0,
0, 0x21e, 0x120, 0x10, 0x23f, 0x1f, 0x25, 0x37,
0x8a, 0x22a, 0x23e, 0x536, 0x534, 4, 9, 0x52,
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
index ce97ec8eae97..2bdeb4baa952 100644
--- a/drivers/video/valkyriefb.c
+++ b/drivers/video/valkyriefb.c
@@ -342,19 +342,19 @@ int __init valkyriefb_init(void)
#else /* ppc (!CONFIG_MAC) */
{
struct device_node *dp;
+ struct resource r;
- dp = find_devices("valkyrie");
+ dp = of_find_node_by_name(NULL, "valkyrie");
if (dp == 0)
return 0;
- if (dp->n_addrs != 1) {
- printk(KERN_ERR "expecting 1 address for valkyrie (got %d)\n",
- dp->n_addrs);
+ if (of_address_to_resource(dp, 0, &r)) {
+ printk(KERN_ERR "can't find address for valkyrie\n");
return 0;
}
- frame_buffer_phys = dp->addrs[0].address;
- cmap_regs_phys = dp->addrs[0].address+0x304000;
+ frame_buffer_phys = r.start;
+ cmap_regs_phys = r.start + 0x304000;
flags = _PAGE_WRITETHRU;
}
#endif /* ppc (!CONFIG_MAC) */
diff --git a/fs/bio.c b/fs/bio.c
index dfe242a21eb4..7b3069589951 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -126,6 +126,7 @@ static void bio_fs_destructor(struct bio *bio)
inline void bio_init(struct bio *bio)
{
bio->bi_next = NULL;
+ bio->bi_bdev = NULL;
bio->bi_flags = 1 << BIO_UPTODATE;
bio->bi_rw = 0;
bio->bi_vcnt = 0;
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 43a2508ac696..55d9a3a954cf 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -207,244 +207,6 @@ static int do_ext3_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
return sys_ioctl(fd, cmd, (unsigned long)compat_ptr(arg));
}
-struct video_tuner32 {
- compat_int_t tuner;
- char name[32];
- compat_ulong_t rangelow, rangehigh;
- u32 flags; /* It is really u32 in videodev.h */
- u16 mode, signal;
-};
-
-static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
-{
- int i;
-
- if(get_user(kp->tuner, &up->tuner))
- return -EFAULT;
- for(i = 0; i < 32; i++)
- __get_user(kp->name[i], &up->name[i]);
- __get_user(kp->rangelow, &up->rangelow);
- __get_user(kp->rangehigh, &up->rangehigh);
- __get_user(kp->flags, &up->flags);
- __get_user(kp->mode, &up->mode);
- __get_user(kp->signal, &up->signal);
- return 0;
-}
-
-static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
-{
- int i;
-
- if(put_user(kp->tuner, &up->tuner))
- return -EFAULT;
- for(i = 0; i < 32; i++)
- __put_user(kp->name[i], &up->name[i]);
- __put_user(kp->rangelow, &up->rangelow);
- __put_user(kp->rangehigh, &up->rangehigh);
- __put_user(kp->flags, &up->flags);
- __put_user(kp->mode, &up->mode);
- __put_user(kp->signal, &up->signal);
- return 0;
-}
-
-struct video_buffer32 {
- compat_caddr_t base;
- compat_int_t height, width, depth, bytesperline;
-};
-
-static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
-{
- u32 tmp;
-
- if (get_user(tmp, &up->base))
- return -EFAULT;
-
- /* This is actually a physical address stored
- * as a void pointer.
- */
- kp->base = (void *)(unsigned long) tmp;
-
- __get_user(kp->height, &up->height);
- __get_user(kp->width, &up->width);
- __get_user(kp->depth, &up->depth);
- __get_user(kp->bytesperline, &up->bytesperline);
- return 0;
-}
-
-static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
-{
- u32 tmp = (u32)((unsigned long)kp->base);
-
- if(put_user(tmp, &up->base))
- return -EFAULT;
- __put_user(kp->height, &up->height);
- __put_user(kp->width, &up->width);
- __put_user(kp->depth, &up->depth);
- __put_user(kp->bytesperline, &up->bytesperline);
- return 0;
-}
-
-struct video_clip32 {
- s32 x, y, width, height; /* Its really s32 in videodev.h */
- compat_caddr_t next;
-};
-
-struct video_window32 {
- u32 x, y, width, height, chromakey, flags;
- compat_caddr_t clips;
- compat_int_t clipcount;
-};
-
-/* You get back everything except the clips... */
-static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
-{
- if(put_user(kp->x, &up->x))
- return -EFAULT;
- __put_user(kp->y, &up->y);
- __put_user(kp->width, &up->width);
- __put_user(kp->height, &up->height);
- __put_user(kp->chromakey, &up->chromakey);
- __put_user(kp->flags, &up->flags);
- __put_user(kp->clipcount, &up->clipcount);
- return 0;
-}
-
-#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32)
-#define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32)
-#define VIDIOCGWIN32 _IOR('v',9, struct video_window32)
-#define VIDIOCSWIN32 _IOW('v',10, struct video_window32)
-#define VIDIOCGFBUF32 _IOR('v',11, struct video_buffer32)
-#define VIDIOCSFBUF32 _IOW('v',12, struct video_buffer32)
-#define VIDIOCGFREQ32 _IOR('v',14, u32)
-#define VIDIOCSFREQ32 _IOW('v',15, u32)
-
-enum {
- MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip)
-};
-
-static int do_set_window(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- struct video_window32 __user *up = compat_ptr(arg);
- struct video_window __user *vw;
- struct video_clip __user *p;
- int nclips;
- u32 n;
-
- if (get_user(nclips, &up->clipcount))
- return -EFAULT;
-
- /* Peculiar interface... */
- if (nclips < 0)
- nclips = VIDEO_CLIPMAP_SIZE;
-
- if (nclips > MaxClips)
- return -ENOMEM;
-
- vw = compat_alloc_user_space(sizeof(struct video_window) +
- nclips * sizeof(struct video_clip));
-
- p = nclips ? (struct video_clip __user *)(vw + 1) : NULL;
-
- if (get_user(n, &up->x) || put_user(n, &vw->x) ||
- get_user(n, &up->y) || put_user(n, &vw->y) ||
- get_user(n, &up->width) || put_user(n, &vw->width) ||
- get_user(n, &up->height) || put_user(n, &vw->height) ||
- get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) ||
- get_user(n, &up->flags) || put_user(n, &vw->flags) ||
- get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) ||
- get_user(n, &up->clips) || put_user(p, &vw->clips))
- return -EFAULT;
-
- if (nclips) {
- struct video_clip32 __user *u = compat_ptr(n);
- int i;
- if (!u)
- return -EINVAL;
- for (i = 0; i < nclips; i++, u++, p++) {
- s32 v;
- if (get_user(v, &u->x) ||
- put_user(v, &p->x) ||
- get_user(v, &u->y) ||
- put_user(v, &p->y) ||
- get_user(v, &u->width) ||
- put_user(v, &p->width) ||
- get_user(v, &u->height) ||
- put_user(v, &p->height) ||
- put_user(NULL, &p->next))
- return -EFAULT;
- }
- }
-
- return sys_ioctl(fd, VIDIOCSWIN, (unsigned long)p);
-}
-
-static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- union {
- struct video_tuner vt;
- struct video_buffer vb;
- struct video_window vw;
- unsigned long vx;
- } karg;
- mm_segment_t old_fs = get_fs();
- void __user *up = compat_ptr(arg);
- int err = 0;
-
- /* First, convert the command. */
- switch(cmd) {
- case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
- case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
- case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
- case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
- case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
- case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
- case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
- };
-
- switch(cmd) {
- case VIDIOCSTUNER:
- case VIDIOCGTUNER:
- err = get_video_tuner32(&karg.vt, up);
- break;
-
- case VIDIOCSFBUF:
- err = get_video_buffer32(&karg.vb, up);
- break;
-
- case VIDIOCSFREQ:
- err = get_user(karg.vx, (u32 __user *)up);
- break;
- };
- if(err)
- goto out;
-
- set_fs(KERNEL_DS);
- err = sys_ioctl(fd, cmd, (unsigned long)&karg);
- set_fs(old_fs);
-
- if(err == 0) {
- switch(cmd) {
- case VIDIOCGTUNER:
- err = put_video_tuner32(&karg.vt, up);
- break;
-
- case VIDIOCGWIN:
- err = put_video_window32(&karg.vw, up);
- break;
-
- case VIDIOCGFBUF:
- err = put_video_buffer32(&karg.vb, up);
- break;
-
- case VIDIOCGFREQ:
- err = put_user(((u32)karg.vx), (u32 __user *)up);
- break;
- };
- }
-out:
- return err;
-}
-
struct compat_dmx_event {
dmx_event_t event;
compat_time_t timeStamp;
@@ -3015,14 +2777,6 @@ COMPATIBLE_IOCTL(EXT3_IOC_GROUP_ADD)
#ifdef CONFIG_JBD_DEBUG
HANDLE_IOCTL(EXT3_IOC32_WAIT_FOR_READONLY, do_ext3_ioctl)
#endif
-HANDLE_IOCTL(VIDIOCGTUNER32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCSTUNER32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCGWIN32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCSWIN32, do_set_window)
-HANDLE_IOCTL(VIDIOCGFBUF32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCSFBUF32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCGFREQ32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCSFREQ32, do_video_ioctl)
/* One SMB ioctl needs translations. */
#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t)
HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid)
diff --git a/include/asm-powerpc/abs_addr.h b/include/asm-powerpc/abs_addr.h
index 18415108fc56..c5c3259e0f86 100644
--- a/include/asm-powerpc/abs_addr.h
+++ b/include/asm-powerpc/abs_addr.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_ABS_ADDR_H
#define _ASM_POWERPC_ABS_ADDR_H
+#ifdef __KERNEL__
#include <linux/config.h>
@@ -70,4 +71,5 @@ static inline unsigned long phys_to_abs(unsigned long pa)
#define iseries_hv_addr(virtaddr) \
(0x8000000000000000 | virt_to_abs(virtaddr))
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_ABS_ADDR_H */
diff --git a/include/asm-powerpc/agp.h b/include/asm-powerpc/agp.h
index 885b4631a6cf..e5ccaca2f5a4 100644
--- a/include/asm-powerpc/agp.h
+++ b/include/asm-powerpc/agp.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_AGP_H
#define _ASM_POWERPC_AGP_H
+#ifdef __KERNEL__
#include <asm/io.h>
@@ -18,4 +19,5 @@
#define free_gatt_pages(table, order) \
free_pages((unsigned long)(table), (order))
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_AGP_H */
diff --git a/include/asm-powerpc/asm-compat.h b/include/asm-powerpc/asm-compat.h
index 8b133efc9f79..8e64be0cc47d 100644
--- a/include/asm-powerpc/asm-compat.h
+++ b/include/asm-powerpc/asm-compat.h
@@ -1,7 +1,6 @@
#ifndef _ASM_POWERPC_ASM_COMPAT_H
#define _ASM_POWERPC_ASM_COMPAT_H
-#include <linux/config.h>
#include <asm/types.h>
#ifdef __ASSEMBLY__
@@ -41,6 +40,7 @@
#endif
+#ifdef __KERNEL__
#ifdef CONFIG_IBM405_ERR77
/* Erratum #77 on the 405 means we need a sync or dcbt before every
* stwcx. The old ATOMIC_SYNC_FIX covered some but not all of this.
@@ -51,5 +51,6 @@
#define PPC405_ERR77(ra,rb)
#define PPC405_ERR77_SYNC
#endif
+#endif
#endif /* _ASM_POWERPC_ASM_COMPAT_H */
diff --git a/include/asm-powerpc/bootx.h b/include/asm-powerpc/bootx.h
new file mode 100644
index 000000000000..57b82e3f89ce
--- /dev/null
+++ b/include/asm-powerpc/bootx.h
@@ -0,0 +1,171 @@
+/*
+ * This file describes the structure passed from the BootX application
+ * (for MacOS) when it is used to boot Linux.
+ *
+ * Written by Benjamin Herrenschmidt.
+ */
+
+
+#ifndef __ASM_BOOTX_H__
+#define __ASM_BOOTX_H__
+
+#include <asm/types.h>
+
+#ifdef macintosh
+#include <Types.h>
+#include "linux_type_defs.h"
+#endif
+
+#ifdef macintosh
+/* All this requires PowerPC alignment */
+#pragma options align=power
+#endif
+
+/* On kernel entry:
+ *
+ * r3 = 0x426f6f58 ('BooX')
+ * r4 = pointer to boot_infos
+ * r5 = NULL
+ *
+ * Data and instruction translation disabled, interrupts
+ * disabled, kernel loaded at physical 0x00000000 on PCI
+ * machines (will be different on NuBus).
+ */
+
+#define BOOT_INFO_VERSION 5
+#define BOOT_INFO_COMPATIBLE_VERSION 1
+
+/* Bit in the architecture flag mask. More to be defined in
+ future versions. Note that either BOOT_ARCH_PCI or
+ BOOT_ARCH_NUBUS is set. The other BOOT_ARCH_NUBUS_xxx are
+ set additionally when BOOT_ARCH_NUBUS is set.
+ */
+#define BOOT_ARCH_PCI 0x00000001UL
+#define BOOT_ARCH_NUBUS 0x00000002UL
+#define BOOT_ARCH_NUBUS_PDM 0x00000010UL
+#define BOOT_ARCH_NUBUS_PERFORMA 0x00000020UL
+#define BOOT_ARCH_NUBUS_POWERBOOK 0x00000040UL
+
+/* Maximum number of ranges in phys memory map */
+#define MAX_MEM_MAP_SIZE 26
+
+/* This is the format of an element in the physical memory map. Note that
+ the map is optional and current BootX will only build it for pre-PCI
+ machines */
+typedef struct boot_info_map_entry
+{
+ __u32 physAddr; /* Physical starting address */
+ __u32 size; /* Size in bytes */
+} boot_info_map_entry_t;
+
+
+/* Here are the boot informations that are passed to the bootstrap
+ * Note that the kernel arguments and the device tree are appended
+ * at the end of this structure. */
+typedef struct boot_infos
+{
+ /* Version of this structure */
+ __u32 version;
+ /* backward compatible down to version: */
+ __u32 compatible_version;
+
+ /* NEW (vers. 2) this holds the current _logical_ base addr of
+ the frame buffer (for use by early boot message) */
+ __u8* logicalDisplayBase;
+
+ /* NEW (vers. 4) Apple's machine identification */
+ __u32 machineID;
+
+ /* NEW (vers. 4) Detected hw architecture */
+ __u32 architecture;
+
+ /* The device tree (internal addresses relative to the beginning of the tree,
+ * device tree offset relative to the beginning of this structure).
+ * On pre-PCI macintosh (BOOT_ARCH_PCI bit set to 0 in architecture), this
+ * field is 0.
+ */
+ __u32 deviceTreeOffset; /* Device tree offset */
+ __u32 deviceTreeSize; /* Size of the device tree */
+
+ /* Some infos about the current MacOS display */
+ __u32 dispDeviceRect[4]; /* left,top,right,bottom */
+ __u32 dispDeviceDepth; /* (8, 16 or 32) */
+ __u8* dispDeviceBase; /* base address (physical) */
+ __u32 dispDeviceRowBytes; /* rowbytes (in bytes) */
+ __u32 dispDeviceColorsOffset; /* Colormap (8 bits only) or 0 (*) */
+ /* Optional offset in the registry to the current
+ * MacOS display. (Can be 0 when not detected) */
+ __u32 dispDeviceRegEntryOffset;
+
+ /* Optional pointer to boot ramdisk (offset from this structure) */
+ __u32 ramDisk;
+ __u32 ramDiskSize; /* size of ramdisk image */
+
+ /* Kernel command line arguments (offset from this structure) */
+ __u32 kernelParamsOffset;
+
+ /* ALL BELOW NEW (vers. 4) */
+
+ /* This defines the physical memory. Valid with BOOT_ARCH_NUBUS flag
+ (non-PCI) only. On PCI, memory is contiguous and it's size is in the
+ device-tree. */
+ boot_info_map_entry_t
+ physMemoryMap[MAX_MEM_MAP_SIZE]; /* Where the phys memory is */
+ __u32 physMemoryMapSize; /* How many entries in map */
+
+
+ /* The framebuffer size (optional, currently 0) */
+ __u32 frameBufferSize; /* Represents a max size, can be 0. */
+
+ /* NEW (vers. 5) */
+
+ /* Total params size (args + colormap + device tree + ramdisk) */
+ __u32 totalParamsSize;
+
+} boot_infos_t;
+
+#ifdef __KERNEL__
+/* (*) The format of the colormap is 256 * 3 * 2 bytes. Each color index
+ * is represented by 3 short words containing a 16 bits (unsigned) color
+ * component. Later versions may contain the gamma table for direct-color
+ * devices here.
+ */
+#define BOOTX_COLORTABLE_SIZE (256UL*3UL*2UL)
+
+/* BootX passes the device-tree using a format that comes from earlier
+ * ppc32 kernels. This used to match what is in prom.h, but not anymore
+ * so we now define it here
+ */
+struct bootx_dt_prop {
+ u32 name;
+ int length;
+ u32 value;
+ u32 next;
+};
+
+struct bootx_dt_node {
+ u32 unused0;
+ u32 unused1;
+ u32 phandle; /* not really available */
+ u32 unused2;
+ u32 unused3;
+ u32 unused4;
+ u32 unused5;
+ u32 full_name;
+ u32 properties;
+ u32 parent;
+ u32 child;
+ u32 sibling;
+ u32 next;
+ u32 allnext;
+};
+
+extern void bootx_init(unsigned long r4, unsigned long phys);
+
+#endif /* __KERNEL__ */
+
+#ifdef macintosh
+#pragma options align=reset
+#endif
+
+#endif
diff --git a/include/asm-powerpc/btext.h b/include/asm-powerpc/btext.h
index 71cce36bc630..906f46e31006 100644
--- a/include/asm-powerpc/btext.h
+++ b/include/asm-powerpc/btext.h
@@ -7,21 +7,22 @@
#define __PPC_BTEXT_H
#ifdef __KERNEL__
-extern void btext_clearscreen(void);
-extern void btext_flushscreen(void);
-
-extern int boot_text_mapped;
-
-extern int btext_initialize(struct device_node *np);
-
-extern void map_boot_text(void);
-extern void init_boot_display(void);
+extern int btext_find_display(int allow_nonstdout);
extern void btext_update_display(unsigned long phys, int width, int height,
int depth, int pitch);
+extern void btext_setup_display(int width, int height, int depth, int pitch,
+ unsigned long address);
+extern void btext_prepare_BAT(void);
+extern void btext_unmap(void);
extern void btext_drawchar(char c);
extern void btext_drawstring(const char *str);
extern void btext_drawhex(unsigned long v);
+extern void btext_drawtext(const char *c, unsigned int len);
+
+extern void btext_clearscreen(void);
+extern void btext_flushscreen(void);
+extern void btext_flushline(void);
#endif /* __KERNEL__ */
#endif /* __PPC_BTEXT_H */
diff --git a/include/asm-powerpc/bug.h b/include/asm-powerpc/bug.h
index b001ecb3cd99..99817a802ca4 100644
--- a/include/asm-powerpc/bug.h
+++ b/include/asm-powerpc/bug.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_BUG_H
#define _ASM_POWERPC_BUG_H
+#ifdef __KERNEL__
#include <asm/asm-compat.h>
/*
@@ -67,4 +68,5 @@ struct bug_entry *find_bug(unsigned long bugaddr);
#include <asm-generic/bug.h>
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_BUG_H */
diff --git a/include/asm-powerpc/checksum.h b/include/asm-powerpc/checksum.h
index d8354d8a49ce..609ecbbd7210 100644
--- a/include/asm-powerpc/checksum.h
+++ b/include/asm-powerpc/checksum.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_CHECKSUM_H
#define _ASM_POWERPC_CHECKSUM_H
+#ifdef __KERNEL__
/*
* This program is free software; you can redistribute it and/or
@@ -129,4 +130,5 @@ static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
}
#endif
+#endif /* __KERNEL__ */
#endif
diff --git a/include/asm-powerpc/compat.h b/include/asm-powerpc/compat.h
index 4db4360c4d4a..accb80c9a339 100644
--- a/include/asm-powerpc/compat.h
+++ b/include/asm-powerpc/compat.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_COMPAT_H
#define _ASM_POWERPC_COMPAT_H
+#ifdef __KERNEL__
/*
* Architecture specific compatibility types
*/
@@ -202,4 +203,5 @@ struct compat_shmid64_ds {
compat_ulong_t __unused6;
};
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_COMPAT_H */
diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h
index d1cfa3f515ea..ef6ead34a773 100644
--- a/include/asm-powerpc/cputable.h
+++ b/include/asm-powerpc/cputable.h
@@ -1,7 +1,6 @@
#ifndef __ASM_POWERPC_CPUTABLE_H
#define __ASM_POWERPC_CPUTABLE_H
-#include <linux/config.h>
#include <asm/asm-compat.h>
#define PPC_FEATURE_32 0x80000000
@@ -28,10 +27,17 @@
* via the mkdefs mechanism.
*/
struct cpu_spec;
-struct op_powerpc_model;
typedef void (*cpu_setup_t)(unsigned long offset, struct cpu_spec* spec);
+enum powerpc_oprofile_type {
+ INVALID = 0,
+ RS64 = 1,
+ POWER4 = 2,
+ G4 = 3,
+ BOOKE = 4,
+};
+
struct cpu_spec {
/* CPU is matched via (PVR & pvr_mask) == pvr_value */
unsigned int pvr_mask;
@@ -57,7 +63,7 @@ struct cpu_spec {
char *oprofile_cpu_type;
/* Processor specific oprofile operations */
- struct op_powerpc_model *oprofile_model;
+ enum powerpc_oprofile_type oprofile_type;
};
extern struct cpu_spec *cur_cpu_spec;
@@ -106,6 +112,7 @@ extern void do_cpu_ftr_fixups(unsigned long offset);
#define CPU_FTR_LOCKLESS_TLBIE ASM_CONST(0x0000040000000000)
#define CPU_FTR_MMCRA_SIHV ASM_CONST(0x0000080000000000)
#define CPU_FTR_CI_LARGE_PAGE ASM_CONST(0x0000100000000000)
+#define CPU_FTR_PAUSE_ZERO ASM_CONST(0x0000200000000000)
#else
/* ensure on 32b processors the flags are available for compiling but
* don't do anything */
@@ -305,12 +312,18 @@ enum {
CPU_FTR_MMCRA_SIHV,
CPU_FTRS_CELL = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 |
- CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT,
+ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT |
+ CPU_FTR_CTRL | CPU_FTR_PAUSE_ZERO,
CPU_FTRS_COMPATIBLE = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2,
#endif
CPU_FTRS_POSSIBLE =
+#ifdef __powerpc64__
+ CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 |
+ CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_CELL |
+ CPU_FTR_CI_LARGE_PAGE |
+#else
#if CLASSIC_PPC
CPU_FTRS_PPC601 | CPU_FTRS_603 | CPU_FTRS_604 | CPU_FTRS_740_NOTAU |
CPU_FTRS_740 | CPU_FTRS_750 | CPU_FTRS_750FX1 |
@@ -344,14 +357,14 @@ enum {
#ifdef CONFIG_E500
CPU_FTRS_E500 | CPU_FTRS_E500_2 |
#endif
-#ifdef __powerpc64__
- CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 |
- CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_CELL |
- CPU_FTR_CI_LARGE_PAGE |
-#endif
+#endif /* __powerpc64__ */
0,
CPU_FTRS_ALWAYS =
+#ifdef __powerpc64__
+ CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 &
+ CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & CPU_FTRS_CELL &
+#else
#if CLASSIC_PPC
CPU_FTRS_PPC601 & CPU_FTRS_603 & CPU_FTRS_604 & CPU_FTRS_740_NOTAU &
CPU_FTRS_740 & CPU_FTRS_750 & CPU_FTRS_750FX1 &
@@ -385,10 +398,7 @@ enum {
#ifdef CONFIG_E500
CPU_FTRS_E500 & CPU_FTRS_E500_2 &
#endif
-#ifdef __powerpc64__
- CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 &
- CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & CPU_FTRS_CELL &
-#endif
+#endif /* __powerpc64__ */
CPU_FTRS_POSSIBLE,
};
diff --git a/include/asm-powerpc/current.h b/include/asm-powerpc/current.h
index 82cd4a9ca99a..1938d6abd255 100644
--- a/include/asm-powerpc/current.h
+++ b/include/asm-powerpc/current.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_CURRENT_H
#define _ASM_POWERPC_CURRENT_H
+#ifdef __KERNEL__
/*
* This program is free software; you can redistribute it and/or
@@ -24,4 +25,5 @@ register struct task_struct *current asm ("r2");
#endif
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_CURRENT_H */
diff --git a/include/asm-powerpc/delay.h b/include/asm-powerpc/delay.h
index 54fe1f4f8fd0..057a60955474 100644
--- a/include/asm-powerpc/delay.h
+++ b/include/asm-powerpc/delay.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_DELAY_H
#define _ASM_POWERPC_DELAY_H
+#ifdef __KERNEL__
/*
* Copyright 1996, Paul Mackerras.
@@ -16,4 +17,5 @@
extern void __delay(unsigned long loops);
extern void udelay(unsigned long usecs);
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_DELAY_H */
diff --git a/include/asm-powerpc/dma-mapping.h b/include/asm-powerpc/dma-mapping.h
index a96e5742ca32..837756ab7dc7 100644
--- a/include/asm-powerpc/dma-mapping.h
+++ b/include/asm-powerpc/dma-mapping.h
@@ -6,6 +6,7 @@
*/
#ifndef _ASM_DMA_MAPPING_H
#define _ASM_DMA_MAPPING_H
+#ifdef __KERNEL__
#include <linux/config.h>
#include <linux/types.h>
@@ -282,4 +283,5 @@ struct dma_mapping_ops {
int (*dac_dma_supported)(struct device *dev, u64 mask);
};
+#endif /* __KERNEL__ */
#endif /* _ASM_DMA_MAPPING_H */
diff --git a/include/asm-powerpc/dma.h b/include/asm-powerpc/dma.h
index 926378d2cd94..4bb57fe37097 100644
--- a/include/asm-powerpc/dma.h
+++ b/include/asm-powerpc/dma.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_DMA_H
#define _ASM_POWERPC_DMA_H
+#ifdef __KERNEL__
/*
* Defines for using and allocating dma channels.
@@ -387,4 +388,5 @@ extern int isa_dma_bridge_buggy;
#endif /* !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) */
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_DMA_H */
diff --git a/include/asm-powerpc/eeh.h b/include/asm-powerpc/eeh.h
index f8633aafe4ba..4395b7bc1ed4 100644
--- a/include/asm-powerpc/eeh.h
+++ b/include/asm-powerpc/eeh.h
@@ -19,6 +19,7 @@
#ifndef _PPC64_EEH_H
#define _PPC64_EEH_H
+#ifdef __KERNEL__
#include <linux/config.h>
#include <linux/init.h>
@@ -57,6 +58,7 @@ void __init pci_addr_cache_build(void);
* to finish the eeh setup for this device.
*/
void eeh_add_device_early(struct device_node *);
+void eeh_add_device_tree_early(struct device_node *);
void eeh_add_device_late(struct pci_dev *);
/**
@@ -72,6 +74,15 @@ void eeh_add_device_late(struct pci_dev *);
void eeh_remove_device(struct pci_dev *);
/**
+ * eeh_remove_device_recursive - undo EEH for device & children.
+ * @dev: pci device to be removed
+ *
+ * As above, this removes the device; it also removes child
+ * pci devices as well.
+ */
+void eeh_remove_bus_device(struct pci_dev *);
+
+/**
* EEH_POSSIBLE_ERROR() -- test for possible MMIO failure.
*
* If this macro yields TRUE, the caller relays to eeh_check_failure()
@@ -107,6 +118,9 @@ static inline void eeh_add_device_late(struct pci_dev *dev) { }
static inline void eeh_remove_device(struct pci_dev *dev) { }
+static inline void eeh_add_device_tree_early(struct device_node *dn) { }
+
+static inline void eeh_remove_bus_device(struct pci_dev *dev) { }
#define EEH_POSSIBLE_ERROR(val, type) (0)
#define EEH_IO_ERROR_VALUE(size) (-1UL)
#endif /* CONFIG_EEH */
@@ -363,4 +377,5 @@ static inline void eeh_insl_ns(unsigned long port, void * buf, int nl)
eeh_check_failure((void __iomem *)(port), *(u32*)buf);
}
+#endif /* __KERNEL__ */
#endif /* _PPC64_EEH_H */
diff --git a/include/asm-powerpc/eeh_event.h b/include/asm-powerpc/eeh_event.h
index d168a30b3866..5e11a00b6fa0 100644
--- a/include/asm-powerpc/eeh_event.h
+++ b/include/asm-powerpc/eeh_event.h
@@ -20,6 +20,7 @@
#ifndef ASM_PPC64_EEH_EVENT_H
#define ASM_PPC64_EEH_EVENT_H
+#ifdef __KERNEL__
/** EEH event -- structure holding pci controller data that describes
* a change in the isolation status of a PCI slot. A pointer
@@ -49,4 +50,5 @@ int eeh_send_failure_event (struct device_node *dn,
int reset_state,
int time_unavail);
+#endif /* __KERNEL__ */
#endif /* ASM_PPC64_EEH_EVENT_H */
diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h
index 3dcd65edf978..c5a635d9bba4 100644
--- a/include/asm-powerpc/elf.h
+++ b/include/asm-powerpc/elf.h
@@ -1,7 +1,10 @@
#ifndef _ASM_POWERPC_ELF_H
#define _ASM_POWERPC_ELF_H
+#ifdef __KERNEL__
#include <linux/sched.h> /* for task_struct */
+#endif
+
#include <asm/types.h>
#include <asm/ptrace.h>
#include <asm/cputable.h>
diff --git a/include/asm-powerpc/firmware.h b/include/asm-powerpc/firmware.h
index 12fabbcb04f0..f804b34cf06a 100644
--- a/include/asm-powerpc/firmware.h
+++ b/include/asm-powerpc/firmware.h
@@ -98,6 +98,12 @@ typedef struct {
extern firmware_feature_t firmware_features_table[];
#endif
+extern void system_reset_fwnmi(void);
+extern void machine_check_fwnmi(void);
+
+/* This is true if we are using the firmware NMI handler (typically LPAR) */
+extern int fwnmi_active;
+
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* __ASM_POWERPC_FIRMWARE_H */
diff --git a/include/asm-powerpc/floppy.h b/include/asm-powerpc/floppy.h
index 64276a3f6153..e258778ca429 100644
--- a/include/asm-powerpc/floppy.h
+++ b/include/asm-powerpc/floppy.h
@@ -9,6 +9,7 @@
*/
#ifndef __ASM_POWERPC_FLOPPY_H
#define __ASM_POWERPC_FLOPPY_H
+#ifdef __KERNEL__
#include <linux/config.h>
#include <asm/machdep.h>
@@ -102,4 +103,5 @@ static int FDC2 = -1;
#define EXTRA_FLOPPY_PARAMS
+#endif /* __KERNEL__ */
#endif /* __ASM_POWERPC_FLOPPY_H */
diff --git a/include/asm-powerpc/grackle.h b/include/asm-powerpc/grackle.h
index 563c7a5e64c9..bd7812a519d4 100644
--- a/include/asm-powerpc/grackle.h
+++ b/include/asm-powerpc/grackle.h
@@ -1,3 +1,6 @@
+#ifndef _ASM_POWERPC_GRACKLE_H
+#define _ASM_POWERPC_GRACKLE_H
+#ifdef __KERNEL__
/*
* Functions for setting up and using a MPC106 northbridge
*/
@@ -5,3 +8,5 @@
#include <asm/pci-bridge.h>
extern void setup_grackle(struct pci_controller *hose);
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_GRACKLE_H */
diff --git a/include/asm-powerpc/hardirq.h b/include/asm-powerpc/hardirq.h
index 3b3e3b49ec12..288e14d53b7f 100644
--- a/include/asm-powerpc/hardirq.h
+++ b/include/asm-powerpc/hardirq.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_HARDIRQ_H
#define _ASM_POWERPC_HARDIRQ_H
+#ifdef __KERNEL__
#include <asm/irq.h>
#include <asm/bug.h>
@@ -24,4 +25,5 @@ static inline void ack_bad_irq(int irq)
BUG();
}
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_HARDIRQ_H */
diff --git a/include/asm-powerpc/heathrow.h b/include/asm-powerpc/heathrow.h
index 22ac179856b9..93f54958a9d1 100644
--- a/include/asm-powerpc/heathrow.h
+++ b/include/asm-powerpc/heathrow.h
@@ -1,3 +1,6 @@
+#ifndef _ASM_POWERPC_HEATHROW_H
+#define _ASM_POWERPC_HEATHROW_H
+#ifdef __KERNEL__
/*
* heathrow.h: definitions for using the "Heathrow" I/O controller chip.
*
@@ -60,3 +63,5 @@
/* Looks like Heathrow has some sort of GPIOs as well... */
#define HRW_GPIO_MODEM_RESET 0x6d
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_HEATHROW_H */
diff --git a/include/asm-powerpc/hvcall.h b/include/asm-powerpc/hvcall.h
index d36da61dbc53..da7af5a720e0 100644
--- a/include/asm-powerpc/hvcall.h
+++ b/include/asm-powerpc/hvcall.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_HVCALL_H
#define _ASM_POWERPC_HVCALL_H
+#ifdef __KERNEL__
#define HVSC .long 0x44000022
@@ -170,4 +171,5 @@ long plpar_hcall_4out(unsigned long opcode,
unsigned long *out4);
#endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_HVCALL_H */
diff --git a/include/asm-powerpc/hvconsole.h b/include/asm-powerpc/hvconsole.h
index 6da93ce74dc0..34daf7b9b62f 100644
--- a/include/asm-powerpc/hvconsole.h
+++ b/include/asm-powerpc/hvconsole.h
@@ -21,6 +21,7 @@
#ifndef _PPC64_HVCONSOLE_H
#define _PPC64_HVCONSOLE_H
+#ifdef __KERNEL__
/*
* This is the max number of console adapters that can/will be found as
@@ -46,4 +47,5 @@ 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 /* __KERNEL__ */
#endif /* _PPC64_HVCONSOLE_H */
diff --git a/include/asm-powerpc/hvcserver.h b/include/asm-powerpc/hvcserver.h
index aecba9665796..67d7da3a4da4 100644
--- a/include/asm-powerpc/hvcserver.h
+++ b/include/asm-powerpc/hvcserver.h
@@ -21,6 +21,7 @@
#ifndef _PPC64_HVCSERVER_H
#define _PPC64_HVCSERVER_H
+#ifdef __KERNEL__
#include <linux/list.h>
@@ -54,4 +55,5 @@ extern int hvcs_register_connection(uint32_t unit_address,
uint32_t p_partition_ID, uint32_t p_unit_address);
extern int hvcs_free_connection(uint32_t unit_address);
+#endif /* __KERNEL__ */
#endif /* _PPC64_HVCSERVER_H */
diff --git a/include/asm-powerpc/i8259.h b/include/asm-powerpc/i8259.h
index fc4bfee124d7..0392159e16e4 100644
--- a/include/asm-powerpc/i8259.h
+++ b/include/asm-powerpc/i8259.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_I8259_H
#define _ASM_POWERPC_I8259_H
+#ifdef __KERNEL__
#include <linux/irq.h>
@@ -9,4 +10,5 @@ extern void i8259_init(unsigned long intack_addr, int offset);
extern int i8259_irq(struct pt_regs *regs);
extern int i8259_irq_cascade(struct pt_regs *regs, void *unused);
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_I8259_H */
diff --git a/include/asm-powerpc/ibmebus.h b/include/asm-powerpc/ibmebus.h
new file mode 100644
index 000000000000..7a42723d107c
--- /dev/null
+++ b/include/asm-powerpc/ibmebus.h
@@ -0,0 +1,85 @@
+/*
+ * IBM PowerPC eBus Infrastructure Support.
+ *
+ * Copyright (c) 2005 IBM Corporation
+ * Heiko J Schick <schickhj@de.ibm.com>
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ASM_EBUS_H
+#define _ASM_EBUS_H
+#ifdef __KERNEL__
+
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
+#include <asm/of_device.h>
+
+extern struct dma_mapping_ops ibmebus_dma_ops;
+extern struct bus_type ibmebus_bus_type;
+
+struct ibmebus_dev {
+ char *name;
+ struct of_device ofdev;
+};
+
+struct ibmebus_driver {
+ char *name;
+ struct of_device_id *id_table;
+ int (*probe) (struct ibmebus_dev *dev, const struct of_device_id *id);
+ int (*remove) (struct ibmebus_dev *dev);
+ struct device_driver driver;
+};
+
+int ibmebus_register_driver(struct ibmebus_driver *drv);
+void ibmebus_unregister_driver(struct ibmebus_driver *drv);
+
+int ibmebus_request_irq(struct ibmebus_dev *dev,
+ u32 ist,
+ irqreturn_t (*handler)(int, void*, struct pt_regs *),
+ unsigned long irq_flags, const char * devname,
+ void *dev_id);
+void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id);
+
+static inline struct ibmebus_driver *to_ibmebus_driver(struct device_driver *drv)
+{
+ return container_of(drv, struct ibmebus_driver, driver);
+}
+
+static inline struct ibmebus_dev *to_ibmebus_dev(struct device *dev)
+{
+ return container_of(dev, struct ibmebus_dev, ofdev.dev);
+}
+
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_IBMEBUS_H */
diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h
index 48938d84d055..68efbea379c9 100644
--- a/include/asm-powerpc/io.h
+++ b/include/asm-powerpc/io.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_IO_H
#define _ASM_POWERPC_IO_H
+#ifdef __KERNEL__
/*
* This program is free software; you can redistribute it and/or
@@ -186,7 +187,6 @@ extern void _outsl_ns(volatile u32 __iomem *port, const void *buf, int nl);
#define IO_SPACE_LIMIT ~(0UL)
-#ifdef __KERNEL__
extern int __ioremap_explicit(unsigned long p_addr, unsigned long v_addr,
unsigned long size, unsigned long flags);
extern void __iomem *__ioremap(unsigned long address, unsigned long size,
@@ -256,8 +256,6 @@ static inline void * phys_to_virt(unsigned long address)
*/
#define BIO_VMERGE_BOUNDARY 0
-#endif /* __KERNEL__ */
-
static inline void iosync(void)
{
__asm__ __volatile__ ("sync" : : : "memory");
@@ -405,8 +403,6 @@ static inline void out_be64(volatile unsigned long __iomem *addr, unsigned long
#include <asm/eeh.h>
#endif
-#ifdef __KERNEL__
-
/**
* check_signature - find BIOS signatures
* @io_addr: mmio address to check
diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h
index f89f06050893..8a8393e50774 100644
--- a/include/asm-powerpc/iommu.h
+++ b/include/asm-powerpc/iommu.h
@@ -20,6 +20,7 @@
#ifndef _ASM_IOMMU_H
#define _ASM_IOMMU_H
+#ifdef __KERNEL__
#include <linux/config.h>
#include <asm/types.h>
@@ -56,7 +57,7 @@ struct device_node;
/* Walks all buses and creates iommu tables */
extern void iommu_setup_pSeries(void);
-extern void iommu_setup_u3(void);
+extern void iommu_setup_dart(void);
/* Frees table for an individual device node */
extern void iommu_free_table(struct device_node *dn);
@@ -104,7 +105,7 @@ extern void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle,
extern void iommu_init_early_pSeries(void);
extern void iommu_init_early_iSeries(void);
-extern void iommu_init_early_u3(void);
+extern void iommu_init_early_dart(void);
#ifdef CONFIG_PCI
extern void pci_iommu_init(void);
@@ -113,6 +114,7 @@ extern void pci_direct_iommu_init(void);
static inline void pci_iommu_init(void) { }
#endif
-extern void alloc_u3_dart_table(void);
+extern void alloc_dart_table(void);
+#endif /* __KERNEL__ */
#endif /* _ASM_IOMMU_H */
diff --git a/include/asm-ppc/ipic.h b/include/asm-powerpc/ipic.h
index 0fe396a2b666..0fe396a2b666 100644
--- a/include/asm-ppc/ipic.h
+++ b/include/asm-powerpc/ipic.h
diff --git a/include/asm-powerpc/iseries/it_lp_reg_save.h b/include/asm-powerpc/iseries/it_lp_reg_save.h
index 288044b702de..81824e1bb767 100644
--- a/include/asm-powerpc/iseries/it_lp_reg_save.h
+++ b/include/asm-powerpc/iseries/it_lp_reg_save.h
@@ -81,4 +81,6 @@ struct ItLpRegSave {
u8 xRsvd3[176]; // Reserved 350-3FF
};
+extern struct ItLpRegSave iseries_reg_save[];
+
#endif /* _ITLPREGSAVE_H */
diff --git a/include/asm-powerpc/kdebug.h b/include/asm-powerpc/kdebug.h
index 9dcbac674811..7c16265568e0 100644
--- a/include/asm-powerpc/kdebug.h
+++ b/include/asm-powerpc/kdebug.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_KDEBUG_H
#define _ASM_POWERPC_KDEBUG_H
+#ifdef __KERNEL__
/* nearly identical to x86_64/i386 code */
@@ -39,4 +40,5 @@ static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,lon
return notifier_call_chain(&powerpc_die_chain, val, &args);
}
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_KDEBUG_H */
diff --git a/include/asm-powerpc/kdump.h b/include/asm-powerpc/kdump.h
new file mode 100644
index 000000000000..a87aed00d61f
--- /dev/null
+++ b/include/asm-powerpc/kdump.h
@@ -0,0 +1,13 @@
+#ifndef _PPC64_KDUMP_H
+#define _PPC64_KDUMP_H
+
+/* How many bytes to reserve at zero for kdump. The reserve limit should
+ * be greater or equal to the trampoline's end address. */
+#define KDUMP_RESERVE_LIMIT 0x8000
+
+#define KDUMP_TRAMPOLINE_START 0x0100
+#define KDUMP_TRAMPOLINE_END 0x3000
+
+extern void kdump_setup(void);
+
+#endif /* __PPC64_KDUMP_H */
diff --git a/include/asm-powerpc/kexec.h b/include/asm-powerpc/kexec.h
index c72ffc709ea8..4263af3cadfd 100644
--- a/include/asm-powerpc/kexec.h
+++ b/include/asm-powerpc/kexec.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_KEXEC_H
#define _ASM_POWERPC_KEXEC_H
+#ifdef __KERNEL__
/*
* Maximum page that is mapped directly into kernel memory.
@@ -30,8 +31,12 @@
#define KEXEC_ARCH KEXEC_ARCH_PPC
#endif
+#define HAVE_ARCH_COPY_OLDMEM_PAGE
+
#ifndef __ASSEMBLY__
+#ifdef CONFIG_KEXEC
+
#define MAX_NOTE_BYTES 1024
typedef u32 note_buf_t[MAX_NOTE_BYTES / sizeof(u32)];
@@ -41,10 +46,18 @@ extern note_buf_t crash_notes[];
extern void kexec_smp_wait(void); /* get and clear naca physid, wait for
master to copy new code to 0 */
extern void __init kexec_setup(void);
-#else
+extern int crashing_cpu;
+extern void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *));
+#endif /* __powerpc64 __ */
+
struct kimage;
-extern void machine_kexec_simple(struct kimage *image);
-#endif
+struct pt_regs;
+extern void default_machine_kexec(struct kimage *image);
+extern int default_machine_kexec_prepare(struct kimage *image);
+extern void default_machine_crash_shutdown(struct pt_regs *regs);
+
+#endif /* !CONFIG_KEXEC */
#endif /* ! __ASSEMBLY__ */
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_KEXEC_H */
diff --git a/include/asm-powerpc/keylargo.h b/include/asm-powerpc/keylargo.h
index a669a3f0f5a2..d8520ef121f9 100644
--- a/include/asm-powerpc/keylargo.h
+++ b/include/asm-powerpc/keylargo.h
@@ -1,3 +1,6 @@
+#ifndef _ASM_POWERPC_KEYLARGO_H
+#define _ASM_POWERPC_KEYLARGO_H
+#ifdef __KERNEL__
/*
* keylargo.h: definitions for using the "KeyLargo" I/O controller chip.
*
@@ -232,10 +235,12 @@
#define K2_FCR1_I2S0_RESET 0x00000800
#define K2_FCR1_I2S0_CLK_ENABLE_BIT 0x00001000
#define K2_FCR1_I2S0_ENABLE 0x00002000
-
#define K2_FCR1_PCI1_CLK_ENABLE 0x00004000
#define K2_FCR1_FW_CLK_ENABLE 0x00008000
#define K2_FCR1_FW_RESET_N 0x00010000
+#define K2_FCR1_I2S1_CELL_ENABLE 0x00020000
+#define K2_FCR1_I2S1_CLK_ENABLE_BIT 0x00080000
+#define K2_FCR1_I2S1_ENABLE 0x00100000
#define K2_FCR1_GMAC_CLK_ENABLE 0x00400000
#define K2_FCR1_GMAC_POWER_DOWN 0x00800000
#define K2_FCR1_GMAC_RESET_N 0x01000000
@@ -246,3 +251,11 @@
#define K2_FCR1_UATA_RESET_N 0x40000000
#define K2_FCR1_UATA_CHOOSE_CLK66 0x80000000
+/* Shasta definitions */
+#define SH_FCR1_I2S2_CELL_ENABLE 0x00000010
+#define SH_FCR1_I2S2_CLK_ENABLE_BIT 0x00000040
+#define SH_FCR1_I2S2_ENABLE 0x00000080
+#define SH_FCR3_I2S2_CLK18_ENABLE 0x00008000
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_KEYLARGO_H */
diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h
index 6cd0a3bfa280..0654f79b06df 100644
--- a/include/asm-powerpc/kprobes.h
+++ b/include/asm-powerpc/kprobes.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_KPROBES_H
#define _ASM_POWERPC_KPROBES_H
+#ifdef __KERNEL__
/*
* Kernel Probes (KProbes)
*
@@ -78,4 +79,5 @@ static inline int kprobe_exceptions_notify(struct notifier_block *self,
return 0;
}
#endif
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_KPROBES_H */
diff --git a/include/asm-powerpc/lmb.h b/include/asm-powerpc/lmb.h
index ea0afe343545..d3546c4c9f46 100644
--- a/include/asm-powerpc/lmb.h
+++ b/include/asm-powerpc/lmb.h
@@ -1,5 +1,6 @@
#ifndef _PPC64_LMB_H
#define _PPC64_LMB_H
+#ifdef __KERNEL__
/*
* Definitions for talking to the Open Firmware PROM on
@@ -78,4 +79,5 @@ lmb_end_pfn(struct lmb_region *type, unsigned long region_nr)
lmb_size_pages(type, region_nr);
}
+#endif /* __KERNEL__ */
#endif /* _PPC64_LMB_H */
diff --git a/include/asm-powerpc/lppaca.h b/include/asm-powerpc/lppaca.h
index c1bedab1515b..ff82ea7c4829 100644
--- a/include/asm-powerpc/lppaca.h
+++ b/include/asm-powerpc/lppaca.h
@@ -18,6 +18,7 @@
*/
#ifndef _ASM_POWERPC_LPPACA_H
#define _ASM_POWERPC_LPPACA_H
+#ifdef __KERNEL__
//=============================================================================
//
@@ -128,4 +129,5 @@ struct lppaca {
u8 pmc_save_area[256]; // PMC interrupt Area x00-xFF
};
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_LPPACA_H */
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
index c011abb8b600..5348b820788c 100644
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -27,6 +27,9 @@ struct device_node;
struct iommu_table;
struct rtc_time;
struct file;
+#ifdef CONFIG_KEXEC
+struct kimage;
+#endif
#ifdef CONFIG_SMP
struct smp_ops_t {
@@ -131,7 +134,7 @@ struct machdep_calls {
void (*nvram_sync)(void);
/* Exception handlers */
- void (*system_reset_exception)(struct pt_regs *regs);
+ int (*system_reset_exception)(struct pt_regs *regs);
int (*machine_check_exception)(struct pt_regs *regs);
/* Motherboard/chipset features. This is a kind of general purpose
@@ -207,19 +210,19 @@ struct machdep_calls {
/* this is for modules, since _machine can be a define -- Cort */
int ppc_machine;
+#endif /* CONFIG_PPC32 */
-#ifdef CONFIG_KEXEC
/* Called to shutdown machine specific hardware not already controlled
* by other drivers.
- * XXX Should we move this one out of kexec scope?
*/
void (*machine_shutdown)(void);
+#ifdef CONFIG_KEXEC
/* Called to do the minimal shutdown needed to run a kexec'd kernel
* to run successfully.
* XXX Should we move this one out of kexec scope?
*/
- void (*machine_crash_shutdown)(void);
+ void (*machine_crash_shutdown)(struct pt_regs *regs);
/* Called to do what every setup is needed on image and the
* reboot code buffer. Returns 0 on success.
@@ -237,7 +240,6 @@ struct machdep_calls {
*/
void (*machine_kexec)(struct kimage *image);
#endif /* CONFIG_KEXEC */
-#endif /* CONFIG_PPC32 */
};
extern void default_idle(void);
diff --git a/include/asm-powerpc/macio.h b/include/asm-powerpc/macio.h
index b553dd4b139e..3a6cb1a513b7 100644
--- a/include/asm-powerpc/macio.h
+++ b/include/asm-powerpc/macio.h
@@ -1,5 +1,6 @@
#ifndef __MACIO_ASIC_H__
#define __MACIO_ASIC_H__
+#ifdef __KERNEL__
#include <asm/of_device.h>
@@ -137,4 +138,5 @@ struct macio_driver
extern int macio_register_driver(struct macio_driver *);
extern void macio_unregister_driver(struct macio_driver *);
+#endif /* __KERNEL__ */
#endif /* __MACIO_ASIC_H__ */
diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h
index 29b0bb0086d3..d096d9e76ad7 100644
--- a/include/asm-powerpc/mmu.h
+++ b/include/asm-powerpc/mmu.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_MMU_H_
#define _ASM_POWERPC_MMU_H_
+#ifdef __KERNEL__
#ifndef CONFIG_PPC64
#include <asm-ppc/mmu.h>
@@ -33,7 +34,8 @@
/* Location of cpu0's segment table */
#define STAB0_PAGE 0x6
-#define STAB0_PHYS_ADDR (STAB0_PAGE<<12)
+#define STAB0_OFFSET (STAB0_PAGE << 12)
+#define STAB0_PHYS_ADDR (STAB0_OFFSET + PHYSICAL_START)
#ifndef __ASSEMBLY__
extern char initial_stab[];
@@ -394,7 +396,12 @@ static inline unsigned long get_vsid(unsigned long context, unsigned long ea)
#define VSID_SCRAMBLE(pvsid) (((pvsid) * VSID_MULTIPLIER) % VSID_MODULUS)
#define KERNEL_VSID(ea) VSID_SCRAMBLE(GET_ESID(ea))
+/* Physical address used by some IO functions */
+typedef unsigned long phys_addr_t;
+
+
#endif /* __ASSEMBLY */
#endif /* CONFIG_PPC64 */
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_MMU_H_ */
diff --git a/include/asm-powerpc/mmu_context.h b/include/asm-powerpc/mmu_context.h
index ea6798c7d5fc..1b8a25fd48f3 100644
--- a/include/asm-powerpc/mmu_context.h
+++ b/include/asm-powerpc/mmu_context.h
@@ -1,5 +1,6 @@
#ifndef __ASM_POWERPC_MMU_CONTEXT_H
#define __ASM_POWERPC_MMU_CONTEXT_H
+#ifdef __KERNEL__
#ifndef CONFIG_PPC64
#include <asm-ppc/mmu_context.h>
@@ -86,4 +87,5 @@ static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
}
#endif /* CONFIG_PPC64 */
+#endif /* __KERNEL__ */
#endif /* __ASM_POWERPC_MMU_CONTEXT_H */
diff --git a/include/asm-powerpc/mmzone.h b/include/asm-powerpc/mmzone.h
index 54958d6cae04..88d70bae7769 100644
--- a/include/asm-powerpc/mmzone.h
+++ b/include/asm-powerpc/mmzone.h
@@ -6,6 +6,7 @@
*/
#ifndef _ASM_MMZONE_H_
#define _ASM_MMZONE_H_
+#ifdef __KERNEL__
#include <linux/config.h>
@@ -47,4 +48,5 @@ extern unsigned long max_pfn;
extern int __init early_pfn_to_nid(unsigned long pfn);
#endif
+#endif /* __KERNEL__ */
#endif /* _ASM_MMZONE_H_ */
diff --git a/include/asm-powerpc/module.h b/include/asm-powerpc/module.h
index 7ecd05e03051..584fabfb4f08 100644
--- a/include/asm-powerpc/module.h
+++ b/include/asm-powerpc/module.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_MODULE_H
#define _ASM_POWERPC_MODULE_H
+#ifdef __KERNEL__
/*
* This program is free software; you can redistribute it and/or
@@ -74,4 +75,5 @@ struct exception_table_entry;
void sort_ex_table(struct exception_table_entry *start,
struct exception_table_entry *finish);
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_MODULE_H */
diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h
index 7083d1f74260..6b9e78142f4f 100644
--- a/include/asm-powerpc/mpic.h
+++ b/include/asm-powerpc/mpic.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_MPIC_H
#define _ASM_POWERPC_MPIC_H
+#ifdef __KERNEL__
#include <linux/irq.h>
@@ -117,7 +118,9 @@ typedef int (*mpic_cascade_t)(struct pt_regs *regs, void *data);
struct mpic_irq_fixup
{
u8 __iomem *base;
- unsigned int irq;
+ u8 __iomem *applebase;
+ u32 data;
+ unsigned int index;
};
#endif /* CONFIG_MPIC_BROKEN_U3 */
@@ -284,4 +287,5 @@ extern int mpic_get_irq(struct pt_regs *regs);
/* global mpic for pSeries */
extern struct mpic *pSeries_mpic;
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_MPIC_H */
diff --git a/include/asm-powerpc/numnodes.h b/include/asm-powerpc/numnodes.h
index 795533aca095..e138edae09dd 100644
--- a/include/asm-powerpc/numnodes.h
+++ b/include/asm-powerpc/numnodes.h
@@ -1,7 +1,9 @@
#ifndef _ASM_POWERPC_MAX_NUMNODES_H
#define _ASM_POWERPC_MAX_NUMNODES_H
+#ifdef __KERNEL__
/* Max 16 Nodes */
#define NODES_SHIFT 4
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_MAX_NUMNODES_H */
diff --git a/include/asm-powerpc/nvram.h b/include/asm-powerpc/nvram.h
index 24bd8c2388ea..f3563e11e260 100644
--- a/include/asm-powerpc/nvram.h
+++ b/include/asm-powerpc/nvram.h
@@ -55,6 +55,7 @@ struct nvram_header {
char name[12];
};
+#ifdef __KERNEL__
struct nvram_partition {
struct list_head partition;
struct nvram_header header;
@@ -69,6 +70,7 @@ extern struct nvram_partition *nvram_find_partition(int sig, const char *name);
extern int pSeries_nvram_init(void);
extern int mmio_nvram_init(void);
+#endif /* __KERNEL__ */
/* PowerMac specific nvram stuffs */
@@ -78,6 +80,7 @@ enum {
pmac_nvram_NR /* MacOS Name Registry partition */
};
+#ifdef __KERNEL__
/* Return partition offset in nvram */
extern int pmac_get_partition(int partition);
@@ -91,6 +94,7 @@ extern void nvram_sync(void);
/* Normal access to NVRAM */
extern unsigned char nvram_read_byte(int i);
extern void nvram_write_byte(unsigned char c, int i);
+#endif
/* Some offsets in XPRAM */
#define PMAC_XPRAM_MACHINE_LOC 0xe4
diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h
index ddb16aae0bd6..6249a7c39639 100644
--- a/include/asm-powerpc/of_device.h
+++ b/include/asm-powerpc/of_device.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_OF_DEVICE_H
#define _ASM_POWERPC_OF_DEVICE_H
+#ifdef __KERNEL__
#include <linux/device.h>
#include <linux/mod_devicetable.h>
@@ -61,4 +62,5 @@ extern struct of_device *of_platform_device_create(struct device_node *np,
struct device *parent);
extern void of_release_dev(struct device *dev);
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_OF_DEVICE_H */
diff --git a/include/asm-powerpc/ohare.h b/include/asm-powerpc/ohare.h
index 023b59772231..0d030f9dea24 100644
--- a/include/asm-powerpc/ohare.h
+++ b/include/asm-powerpc/ohare.h
@@ -1,3 +1,6 @@
+#ifndef _ASM_POWERPC_OHARE_H
+#define _ASM_POWERPC_OHARE_H
+#ifdef __KERNEL__
/*
* ohare.h: definitions for using the "O'Hare" I/O controller chip.
*
@@ -46,3 +49,6 @@
* Contributed by Harry Eaton.
*/
#define STARMAX_FEATURES 0xbeff7a
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_OHARE_H */
diff --git a/include/asm-powerpc/oprofile_impl.h b/include/asm-powerpc/oprofile_impl.h
index 8013cd273ced..338e6a7cff4a 100644
--- a/include/asm-powerpc/oprofile_impl.h
+++ b/include/asm-powerpc/oprofile_impl.h
@@ -11,6 +11,7 @@
#ifndef _ASM_POWERPC_OPROFILE_IMPL_H
#define _ASM_POWERPC_OPROFILE_IMPL_H
+#ifdef __KERNEL__
#define OP_MAX_COUNTER 8
@@ -22,24 +23,22 @@ struct op_counter_config {
unsigned long enabled;
unsigned long event;
unsigned long count;
+ /* Classic doesn't support per-counter user/kernel selection */
unsigned long kernel;
-#ifdef __powerpc64__
- /* We dont support per counter user/kernel selection */
-#endif
unsigned long user;
unsigned long unit_mask;
};
/* System-wide configuration as set via oprofilefs. */
struct op_system_config {
-#ifdef __powerpc64__
+#ifdef CONFIG_PPC64
unsigned long mmcr0;
unsigned long mmcr1;
unsigned long mmcra;
#endif
unsigned long enable_kernel;
unsigned long enable_user;
-#ifdef __powerpc64__
+#ifdef CONFIG_PPC64
unsigned long backtrace_spinlocks;
#endif
};
@@ -49,9 +48,7 @@ struct op_powerpc_model {
void (*reg_setup) (struct op_counter_config *,
struct op_system_config *,
int num_counters);
-#ifdef __powerpc64__
void (*cpu_setup) (void *);
-#endif
void (*start) (struct op_counter_config *);
void (*stop) (void);
void (*handle_interrupt) (struct pt_regs *,
@@ -59,10 +56,19 @@ struct op_powerpc_model {
int num_counters;
};
-#ifdef __powerpc64__
+#ifdef CONFIG_FSL_BOOKE
+extern struct op_powerpc_model op_model_fsl_booke;
+#else /* Otherwise, it's classic */
+
+#ifdef CONFIG_PPC64
extern struct op_powerpc_model op_model_rs64;
extern struct op_powerpc_model op_model_power4;
+#else /* Otherwise, CONFIG_PPC32 */
+extern struct op_powerpc_model op_model_7450;
+#endif
+
+/* All the classic PPC parts use these */
static inline unsigned int ctr_read(unsigned int i)
{
switch(i) {
@@ -78,10 +84,14 @@ static inline unsigned int ctr_read(unsigned int i)
return mfspr(SPRN_PMC5);
case 5:
return mfspr(SPRN_PMC6);
+
+/* No PPC32 chip has more than 6 so far */
+#ifdef CONFIG_PPC64
case 6:
return mfspr(SPRN_PMC7);
case 7:
return mfspr(SPRN_PMC8);
+#endif
default:
return 0;
}
@@ -108,16 +118,21 @@ static inline void ctr_write(unsigned int i, unsigned int val)
case 5:
mtspr(SPRN_PMC6, val);
break;
+
+/* No PPC32 chip has more than 6, yet */
+#ifdef CONFIG_PPC64
case 6:
mtspr(SPRN_PMC7, val);
break;
case 7:
mtspr(SPRN_PMC8, val);
break;
+#endif
default:
break;
}
}
-#endif /* __powerpc64__ */
+#endif /* !CONFIG_FSL_BOOKE */
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_OPROFILE_IMPL_H */
diff --git a/include/asm-powerpc/pSeries_reconfig.h b/include/asm-powerpc/pSeries_reconfig.h
index c0db1ea7f7d1..ea6cfb8efb84 100644
--- a/include/asm-powerpc/pSeries_reconfig.h
+++ b/include/asm-powerpc/pSeries_reconfig.h
@@ -1,5 +1,6 @@
#ifndef _PPC64_PSERIES_RECONFIG_H
#define _PPC64_PSERIES_RECONFIG_H
+#ifdef __KERNEL__
#include <linux/notifier.h>
@@ -22,4 +23,5 @@ static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb)
static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { }
#endif /* CONFIG_PPC_PSERIES */
+#endif /* __KERNEL__ */
#endif /* _PPC64_PSERIES_RECONFIG_H */
diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h
index 92c765c35bd0..3ae52d9dc9ff 100644
--- a/include/asm-powerpc/paca.h
+++ b/include/asm-powerpc/paca.h
@@ -14,11 +14,11 @@
*/
#ifndef _ASM_POWERPC_PACA_H
#define _ASM_POWERPC_PACA_H
+#ifdef __KERNEL__
#include <linux/config.h>
#include <asm/types.h>
#include <asm/lppaca.h>
-#include <asm/iseries/it_lp_reg_save.h>
#include <asm/mmu.h>
register struct paca_struct *local_paca asm("r13");
@@ -31,9 +31,9 @@ struct task_struct;
*
* This structure is not directly accessed by firmware or the service
* processor except for the first two pointers that point to the
- * lppaca area and the ItLpRegSave area for this CPU. Both the
- * lppaca and ItLpRegSave objects are currently contained within the
- * PACA but they do not need to be.
+ * lppaca area and the ItLpRegSave area for this CPU. The lppaca
+ * object is currently contained within the PACA but it doesn't need
+ * to be.
*/
struct paca_struct {
/*
@@ -48,7 +48,9 @@ struct paca_struct {
* accessed by the firmware
*/
struct lppaca *lppaca_ptr; /* Pointer to LpPaca for PLIC */
- struct ItLpRegSave *reg_save_ptr; /* Pointer to LpRegSave for PLIC */
+#ifdef CONFIG_PPC_ISERIES
+ void *reg_save_ptr; /* Pointer to LpRegSave for PLIC */
+#endif /* CONFIG_PPC_ISERIES */
/*
* MAGIC: the spinlock functions in arch/ppc64/lib/locks.c
@@ -59,7 +61,6 @@ struct paca_struct {
u16 lock_token; /* Constant 0x8000, used in locks */
u16 paca_index; /* Logical processor number */
- u32 default_decr; /* Default decrementer value */
u64 kernel_toc; /* Kernel TOC address */
u64 stab_real; /* Absolute address of segment table */
u64 stab_addr; /* Virtual address of segment table */
@@ -90,14 +91,10 @@ struct paca_struct {
struct task_struct *__current; /* Pointer to current */
u64 kstack; /* Saved Kernel stack addr */
u64 stab_rr; /* stab/slb round-robin counter */
- u64 next_jiffy_update_tb; /* TB value for next jiffy update */
u64 saved_r1; /* r1 save for RTAS calls */
u64 saved_msr; /* MSR saved here by enter_rtas */
u8 proc_enabled; /* irq soft-enable flag */
- /* not yet used */
- u64 exdsi[8]; /* used for linear mapping hash table misses */
-
/*
* iSeries structure which the hypervisor knows about -
* this structure should not cross a page boundary.
@@ -110,11 +107,9 @@ struct paca_struct {
* cross a page boundary.
*/
struct lppaca lppaca __attribute__((__aligned__(0x400)));
-#ifdef CONFIG_PPC_ISERIES
- struct ItLpRegSave reg_save;
-#endif
};
extern struct paca_struct paca[];
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_PACA_H */
diff --git a/include/asm-powerpc/page.h b/include/asm-powerpc/page.h
index 18c1e5ee81a3..76d7cb4b4ffc 100644
--- a/include/asm-powerpc/page.h
+++ b/include/asm-powerpc/page.h
@@ -37,8 +37,30 @@
*/
#define PAGE_MASK (~((1 << PAGE_SHIFT) - 1))
+/*
+ * KERNELBASE is the virtual address of the start of the kernel, it's often
+ * the same as PAGE_OFFSET, but _might not be_.
+ *
+ * The kdump dump kernel is one example where KERNELBASE != PAGE_OFFSET.
+ *
+ * To get a physical address from a virtual one you subtract PAGE_OFFSET,
+ * _not_ KERNELBASE.
+ *
+ * If you want to know something's offset from the start of the kernel you
+ * should subtract KERNELBASE.
+ *
+ * If you want to test if something's a kernel address, use is_kernel_addr().
+ */
+
+#ifdef CONFIG_CRASH_DUMP
+/* Kdump kernel runs at 32 MB, change at your peril. */
+#define PHYSICAL_START 0x2000000
+#else
+#define PHYSICAL_START 0x0
+#endif
+
#define PAGE_OFFSET ASM_CONST(CONFIG_KERNEL_START)
-#define KERNELBASE PAGE_OFFSET
+#define KERNELBASE (PAGE_OFFSET + PHYSICAL_START)
#ifdef CONFIG_DISCONTIGMEM
#define page_to_pfn(page) discontigmem_page_to_pfn(page)
@@ -56,7 +78,7 @@
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
-#define __va(x) ((void *)((unsigned long)(x) + KERNELBASE))
+#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET))
#define __pa(x) ((unsigned long)(x) - PAGE_OFFSET)
/*
@@ -86,6 +108,12 @@
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE)
+/*
+ * Don't compare things with KERNELBASE or PAGE_OFFSET to test for
+ * "kernelness", use is_kernel_addr() - it should do what you want.
+ */
+#define is_kernel_addr(x) ((x) >= PAGE_OFFSET)
+
#ifndef __ASSEMBLY__
#undef STRICT_MM_TYPECHECKS
diff --git a/include/asm-powerpc/page_32.h b/include/asm-powerpc/page_32.h
index 7259cfd85da9..2677bad70f40 100644
--- a/include/asm-powerpc/page_32.h
+++ b/include/asm-powerpc/page_32.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_PAGE_32_H
#define _ASM_POWERPC_PAGE_32_H
+#ifdef __KERNEL__
#define VM_DATA_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS32
@@ -37,4 +38,5 @@ extern __inline__ int get_order(unsigned long size)
#endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_PAGE_32_H */
diff --git a/include/asm-powerpc/page_64.h b/include/asm-powerpc/page_64.h
index 6642c0125001..3fb061bab9ec 100644
--- a/include/asm-powerpc/page_64.h
+++ b/include/asm-powerpc/page_64.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_PAGE_64_H
#define _ASM_POWERPC_PAGE_64_H
+#ifdef __KERNEL__
/*
* Copyright (C) 2001 PPC64 Team, IBM Corp
@@ -25,16 +26,6 @@
*/
#define PAGE_FACTOR (PAGE_SHIFT - HW_PAGE_SHIFT)
-#define REGION_SIZE 4UL
-#define REGION_SHIFT 60UL
-#define REGION_MASK (((1UL<<REGION_SIZE)-1UL)<<REGION_SHIFT)
-
-#define VMALLOCBASE ASM_CONST(0xD000000000000000)
-#define VMALLOC_REGION_ID (VMALLOCBASE >> REGION_SHIFT)
-#define KERNEL_REGION_ID (KERNELBASE >> REGION_SHIFT)
-#define USER_REGION_ID (0UL)
-#define REGION_ID(ea) (((unsigned long)(ea)) >> REGION_SHIFT)
-
/* Segment size */
#define SID_SHIFT 28
#define SID_MASK 0xfffffffffUL
@@ -180,4 +171,5 @@ extern unsigned int HPAGE_SHIFT;
#include <asm-generic/page.h>
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_PAGE_64_H */
diff --git a/include/asm-powerpc/param.h b/include/asm-powerpc/param.h
index bdc724f70884..094f63d4d5ca 100644
--- a/include/asm-powerpc/param.h
+++ b/include/asm-powerpc/param.h
@@ -1,8 +1,6 @@
#ifndef _ASM_POWERPC_PARAM_H
#define _ASM_POWERPC_PARAM_H
-#include <linux/config.h>
-
#ifdef __KERNEL__
#define HZ CONFIG_HZ /* internal kernel timer frequency */
#define USER_HZ 100 /* for user interfaces in "ticks" */
diff --git a/include/asm-powerpc/parport.h b/include/asm-powerpc/parport.h
index d86b410a6f8b..897e49a88a6b 100644
--- a/include/asm-powerpc/parport.h
+++ b/include/asm-powerpc/parport.h
@@ -8,6 +8,7 @@
#ifndef _ASM_POWERPC_PARPORT_H
#define _ASM_POWERPC_PARPORT_H
+#ifdef __KERNEL__
static int __devinit parport_pc_find_isa_ports (int autoirq, int autodma);
static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma)
@@ -15,4 +16,5 @@ static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma)
return parport_pc_find_isa_ports (autoirq, autodma);
}
+#endif /* __KERNEL__ */
#endif /* !(_ASM_POWERPC_PARPORT_H) */
diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h
index 223ec7bd81da..1a08860e789e 100644
--- a/include/asm-powerpc/pci-bridge.h
+++ b/include/asm-powerpc/pci-bridge.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_PCI_BRIDGE_H
#define _ASM_POWERPC_PCI_BRIDGE_H
+#ifdef __KERNEL__
#ifndef CONFIG_PPC64
#include <asm-ppc/pci-bridge.h>
@@ -125,9 +126,19 @@ static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
return bus->sysdata; /* Must be root bus (PHB) */
}
+/** Find the bus corresponding to the indicated device node */
+struct pci_bus * pcibios_find_pci_bus(struct device_node *dn);
+
extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
struct device_node *dev, int primary);
+/** Remove all of the PCI devices under this bus */
+void pcibios_remove_pci_devices(struct pci_bus *bus);
+
+/** Discover new pci devices under this bus, and add them */
+void pcibios_add_pci_devices(struct pci_bus * bus);
+void pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus);
+
extern int pcibios_remove_root_bus(struct pci_controller *phb);
extern void phbs_remap_io(void);
@@ -140,14 +151,27 @@ static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus)
return PCI_DN(busdn)->phb;
}
+extern struct pci_controller*
+pci_find_hose_for_OF_device(struct device_node* node);
+
extern struct pci_controller *
pcibios_alloc_controller(struct device_node *dev);
extern void pcibios_free_controller(struct pci_controller *phb);
+#ifdef CONFIG_PCI
+extern unsigned long pci_address_to_pio(phys_addr_t address);
+#else
+static inline unsigned long pci_address_to_pio(phys_addr_t address)
+{
+ return (unsigned long)-1;
+}
+#endif
+
/* Return values for ppc_md.pci_probe_mode function */
#define PCI_PROBE_NONE -1 /* Don't look at this bus at all */
#define PCI_PROBE_NORMAL 0 /* Do normal PCI probing */
#define PCI_PROBE_DEVTREE 1 /* Instantiate from device tree */
#endif /* CONFIG_PPC64 */
+#endif /* __KERNEL__ */
#endif
diff --git a/include/asm-powerpc/pci.h b/include/asm-powerpc/pci.h
index d5934a076bd0..5d2c9e6c4be2 100644
--- a/include/asm-powerpc/pci.h
+++ b/include/asm-powerpc/pci.h
@@ -216,6 +216,8 @@ extern int remap_bus_range(struct pci_bus *bus);
extern void pcibios_fixup_device_resources(struct pci_dev *dev,
struct pci_bus *bus);
+extern void pcibios_claim_one_bus(struct pci_bus *b);
+
extern struct pci_controller *init_phb_dynamic(struct device_node *dn);
extern struct pci_dev *of_create_pci_dev(struct device_node *node,
diff --git a/include/asm-powerpc/pgalloc.h b/include/asm-powerpc/pgalloc.h
index bfc2113b3630..9f5b052784a5 100644
--- a/include/asm-powerpc/pgalloc.h
+++ b/include/asm-powerpc/pgalloc.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_PGALLOC_H
#define _ASM_POWERPC_PGALLOC_H
+#ifdef __KERNEL__
#ifndef CONFIG_PPC64
#include <asm-ppc/pgalloc.h>
@@ -153,4 +154,5 @@ extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
#define check_pgt_cache() do { } while (0)
#endif /* CONFIG_PPC64 */
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_PGALLOC_H */
diff --git a/include/asm-powerpc/pgtable-64k.h b/include/asm-powerpc/pgtable-64k.h
index 154f1840ece4..653915014dcd 100644
--- a/include/asm-powerpc/pgtable-64k.h
+++ b/include/asm-powerpc/pgtable-64k.h
@@ -1,3 +1,7 @@
+#ifndef _ASM_POWERPC_PGTABLE_64K_H
+#define _ASM_POWERPC_PGTABLE_64K_H
+#ifdef __KERNEL__
+
#include <asm-generic/pgtable-nopud.h>
@@ -88,3 +92,5 @@
#endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_PGTABLE_64K_H */
diff --git a/include/asm-powerpc/pgtable.h b/include/asm-powerpc/pgtable.h
index 0303f57366c1..e38931379a72 100644
--- a/include/asm-powerpc/pgtable.h
+++ b/include/asm-powerpc/pgtable.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_PGTABLE_H
#define _ASM_POWERPC_PGTABLE_H
+#ifdef __KERNEL__
#ifndef CONFIG_PPC64
#include <asm-ppc/pgtable.h>
@@ -58,6 +59,17 @@ struct mm_struct;
#define IMALLOC_END (VMALLOC_START + PGTABLE_RANGE)
/*
+ * Region IDs
+ */
+#define REGION_SHIFT 60UL
+#define REGION_MASK (0xfUL << REGION_SHIFT)
+#define REGION_ID(ea) (((unsigned long)(ea)) >> REGION_SHIFT)
+
+#define VMALLOC_REGION_ID (REGION_ID(VMALLOC_START))
+#define KERNEL_REGION_ID (REGION_ID(PAGE_OFFSET))
+#define USER_REGION_ID (0UL)
+
+/*
* Common bits in a linux-style PTE. These match the bits in the
* (hardware-defined) PowerPC PTE as closely as possible. Additional
* bits may be defined in pgtable-*.h
@@ -521,4 +533,5 @@ void pgtable_cache_init(void);
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_PPC64 */
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_PGTABLE_H */
diff --git a/include/asm-powerpc/pmac_feature.h b/include/asm-powerpc/pmac_feature.h
index e9683bcff19b..3221628130c4 100644
--- a/include/asm-powerpc/pmac_feature.h
+++ b/include/asm-powerpc/pmac_feature.h
@@ -121,6 +121,7 @@
#define PMAC_TYPE_IMAC_G5 0x152 /* iMac G5 */
#define PMAC_TYPE_XSERVE_G5 0x153 /* Xserve G5 */
#define PMAC_TYPE_UNKNOWN_K2 0x19f /* Any other K2 based */
+#define PMAC_TYPE_UNKNOWN_SHASTA 0x19e /* Any other Shasta based */
/*
* Motherboard flags
@@ -317,10 +318,6 @@ extern void pmac_register_agp_pm(struct pci_dev *bridge,
extern void pmac_suspend_agp_for_card(struct pci_dev *dev);
extern void pmac_resume_agp_for_card(struct pci_dev *dev);
-/* Used by the via-pmu driver for suspend/resume
- */
-extern void pmac_tweak_clock_spreading(int enable);
-
/*
* The part below is for use by macio_asic.c only, do not rely
* on the data structures or constants below in a normal driver
@@ -341,6 +338,7 @@ enum {
macio_pangea,
macio_intrepid,
macio_keylargo2,
+ macio_shasta,
};
struct macio_chip
@@ -376,5 +374,24 @@ extern struct macio_chip* macio_find(struct device_node* child, int type);
#define MACIO_IN8(r) (in_8(MACIO_FCR8(macio,r)))
#define MACIO_OUT8(r,v) (out_8(MACIO_FCR8(macio,r), (v)))
+/*
+ * Those are exported by pmac feature for internal use by arch code
+ * only like the platform function callbacks, do not use directly in drivers
+ */
+extern spinlock_t feature_lock;
+extern struct device_node *uninorth_node;
+extern u32 __iomem *uninorth_base;
+
+/*
+ * Uninorth reg. access. Note that Uni-N regs are big endian
+ */
+
+#define UN_REG(r) (uninorth_base + ((r) >> 2))
+#define UN_IN(r) (in_be32(UN_REG(r)))
+#define UN_OUT(r,v) (out_be32(UN_REG(r), (v)))
+#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v)))
+#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v)))
+
+
#endif /* __PPC_ASM_PMAC_FEATURE_H */
#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/pmac_low_i2c.h b/include/asm-powerpc/pmac_low_i2c.h
index 809a5963d5e7..131011bd7e76 100644
--- a/include/asm-powerpc/pmac_low_i2c.h
+++ b/include/asm-powerpc/pmac_low_i2c.h
@@ -11,33 +11,97 @@
*/
#ifndef __PMAC_LOW_I2C_H__
#define __PMAC_LOW_I2C_H__
+#ifdef __KERNEL__
/* i2c mode (based on the platform functions format) */
enum {
- pmac_low_i2c_mode_dumb = 1,
- pmac_low_i2c_mode_std = 2,
- pmac_low_i2c_mode_stdsub = 3,
- pmac_low_i2c_mode_combined = 4,
+ pmac_i2c_mode_dumb = 1,
+ pmac_i2c_mode_std = 2,
+ pmac_i2c_mode_stdsub = 3,
+ pmac_i2c_mode_combined = 4,
};
/* RW bit in address */
enum {
- pmac_low_i2c_read = 0x01,
- pmac_low_i2c_write = 0x00
+ pmac_i2c_read = 0x01,
+ pmac_i2c_write = 0x00
};
+/* i2c bus type */
+enum {
+ pmac_i2c_bus_keywest = 0,
+ pmac_i2c_bus_pmu = 1,
+ pmac_i2c_bus_smu = 2,
+};
+
+/* i2c bus features */
+enum {
+ /* can_largesub : supports >1 byte subaddresses (SMU only) */
+ pmac_i2c_can_largesub = 0x00000001u,
+
+ /* multibus : device node holds multiple busses, bus number is
+ * encoded in bits 0xff00 of "reg" of a given device
+ */
+ pmac_i2c_multibus = 0x00000002u,
+};
+
+/* i2c busses in the system */
+struct pmac_i2c_bus;
+struct i2c_adapter;
+
/* Init, called early during boot */
-extern void pmac_init_low_i2c(void);
+extern int pmac_i2c_init(void);
+
+/* Lookup an i2c bus for a device-node. The node can be either the bus
+ * node itself or a device below it. In the case of a multibus, the bus
+ * node itself is the controller node, else, it's a child of the controller
+ * node
+ */
+extern struct pmac_i2c_bus *pmac_i2c_find_bus(struct device_node *node);
+
+/* Get the address for an i2c device. This strips the bus number if
+ * necessary. The 7 bits address is returned 1 bit right shifted so that the
+ * direction can be directly ored in
+ */
+extern u8 pmac_i2c_get_dev_addr(struct device_node *device);
+
+/* Get infos about a bus */
+extern struct device_node *pmac_i2c_get_controller(struct pmac_i2c_bus *bus);
+extern struct device_node *pmac_i2c_get_bus_node(struct pmac_i2c_bus *bus);
+extern int pmac_i2c_get_type(struct pmac_i2c_bus *bus);
+extern int pmac_i2c_get_flags(struct pmac_i2c_bus *bus);
+extern int pmac_i2c_get_channel(struct pmac_i2c_bus *bus);
+
+/* i2c layer adapter attach/detach */
+extern void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus,
+ struct i2c_adapter *adapter);
+extern void pmac_i2c_detach_adapter(struct pmac_i2c_bus *bus,
+ struct i2c_adapter *adapter);
+extern struct i2c_adapter *pmac_i2c_get_adapter(struct pmac_i2c_bus *bus);
+extern struct pmac_i2c_bus *pmac_i2c_adapter_to_bus(struct i2c_adapter *adapter);
+
+/* March a device or bus with an i2c adapter structure, to be used by drivers
+ * to match device-tree nodes with i2c adapters during adapter discovery
+ * callbacks
+ */
+extern int pmac_i2c_match_adapter(struct device_node *dev,
+ struct i2c_adapter *adapter);
+
-/* Locking functions exposed to i2c-keywest */
-int pmac_low_i2c_lock(struct device_node *np);
-int pmac_low_i2c_unlock(struct device_node *np);
+/* (legacy) Locking functions exposed to i2c-keywest */
+extern int pmac_low_i2c_lock(struct device_node *np);
+extern int pmac_low_i2c_unlock(struct device_node *np);
/* Access functions for platform code */
-int pmac_low_i2c_open(struct device_node *np, int channel);
-int pmac_low_i2c_close(struct device_node *np);
-int pmac_low_i2c_setmode(struct device_node *np, int mode);
-int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len);
+extern int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled);
+extern void pmac_i2c_close(struct pmac_i2c_bus *bus);
+extern int pmac_i2c_setmode(struct pmac_i2c_bus *bus, int mode);
+extern int pmac_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
+ u32 subaddr, u8 *data, int len);
+/* Suspend/resume code called by via-pmu directly for now */
+extern void pmac_pfunc_i2c_suspend(void);
+extern void pmac_pfunc_i2c_resume(void);
+#endif /* __KERNEL__ */
#endif /* __PMAC_LOW_I2C_H__ */
diff --git a/include/asm-powerpc/pmac_pfunc.h b/include/asm-powerpc/pmac_pfunc.h
new file mode 100644
index 000000000000..d9728c80f86d
--- /dev/null
+++ b/include/asm-powerpc/pmac_pfunc.h
@@ -0,0 +1,253 @@
+#ifndef __PMAC_PFUNC_H__
+#define __PMAC_PFUNC_H__
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+/* Flags in command lists */
+#define PMF_FLAGS_ON_INIT 0x80000000u
+#define PMF_FLGAS_ON_TERM 0x40000000u
+#define PMF_FLAGS_ON_SLEEP 0x20000000u
+#define PMF_FLAGS_ON_WAKE 0x10000000u
+#define PMF_FLAGS_ON_DEMAND 0x08000000u
+#define PMF_FLAGS_INT_GEN 0x04000000u
+#define PMF_FLAGS_HIGH_SPEED 0x02000000u
+#define PMF_FLAGS_LOW_SPEED 0x01000000u
+#define PMF_FLAGS_SIDE_EFFECTS 0x00800000u
+
+/*
+ * Arguments to a platform function call.
+ *
+ * NOTE: By convention, pointer arguments point to an u32
+ */
+struct pmf_args {
+ union {
+ u32 v;
+ u32 *p;
+ } u[4];
+ unsigned int count;
+};
+
+/*
+ * A driver capable of interpreting commands provides a handlers
+ * structure filled with whatever handlers are implemented by this
+ * driver. Non implemented handlers are left NULL.
+ *
+ * PMF_STD_ARGS are the same arguments that are passed to the parser
+ * and that gets passed back to the various handlers.
+ *
+ * Interpreting a given function always start with a begin() call which
+ * returns an instance data to be passed around subsequent calls, and
+ * ends with an end() call. This allows the low level driver to implement
+ * locking policy or per-function instance data.
+ *
+ * For interrupt capable functions, irq_enable() is called when a client
+ * registers, and irq_disable() is called when the last client unregisters
+ * Note that irq_enable & irq_disable are called within a semaphore held
+ * by the core, thus you should not try to register yourself to some other
+ * pmf interrupt during those calls.
+ */
+
+#define PMF_STD_ARGS struct pmf_function *func, void *instdata, \
+ struct pmf_args *args
+
+struct pmf_function;
+
+struct pmf_handlers {
+ void * (*begin)(struct pmf_function *func, struct pmf_args *args);
+ void (*end)(struct pmf_function *func, void *instdata);
+
+ int (*irq_enable)(struct pmf_function *func);
+ int (*irq_disable)(struct pmf_function *func);
+
+ int (*write_gpio)(PMF_STD_ARGS, u8 value, u8 mask);
+ int (*read_gpio)(PMF_STD_ARGS, u8 mask, int rshift, u8 xor);
+
+ int (*write_reg32)(PMF_STD_ARGS, u32 offset, u32 value, u32 mask);
+ int (*read_reg32)(PMF_STD_ARGS, u32 offset);
+ int (*write_reg16)(PMF_STD_ARGS, u32 offset, u16 value, u16 mask);
+ int (*read_reg16)(PMF_STD_ARGS, u32 offset);
+ int (*write_reg8)(PMF_STD_ARGS, u32 offset, u8 value, u8 mask);
+ int (*read_reg8)(PMF_STD_ARGS, u32 offset);
+
+ int (*delay)(PMF_STD_ARGS, u32 duration);
+
+ int (*wait_reg32)(PMF_STD_ARGS, u32 offset, u32 value, u32 mask);
+ int (*wait_reg16)(PMF_STD_ARGS, u32 offset, u16 value, u16 mask);
+ int (*wait_reg8)(PMF_STD_ARGS, u32 offset, u8 value, u8 mask);
+
+ int (*read_i2c)(PMF_STD_ARGS, u32 len);
+ int (*write_i2c)(PMF_STD_ARGS, u32 len, const u8 *data);
+ int (*rmw_i2c)(PMF_STD_ARGS, u32 masklen, u32 valuelen, u32 totallen,
+ const u8 *maskdata, const u8 *valuedata);
+
+ int (*read_cfg)(PMF_STD_ARGS, u32 offset, u32 len);
+ int (*write_cfg)(PMF_STD_ARGS, u32 offset, u32 len, const u8 *data);
+ int (*rmw_cfg)(PMF_STD_ARGS, u32 offset, u32 masklen, u32 valuelen,
+ u32 totallen, const u8 *maskdata, const u8 *valuedata);
+
+ int (*read_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 len);
+ int (*write_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 len, const u8 *data);
+ int (*set_i2c_mode)(PMF_STD_ARGS, int mode);
+ int (*rmw_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 masklen, u32 valuelen,
+ u32 totallen, const u8 *maskdata,
+ const u8 *valuedata);
+
+ int (*read_reg32_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift,
+ u32 xor);
+ int (*read_reg16_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift,
+ u32 xor);
+ int (*read_reg8_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift,
+ u32 xor);
+
+ int (*write_reg32_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask);
+ int (*write_reg16_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask);
+ int (*write_reg8_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask);
+
+ int (*mask_and_compare)(PMF_STD_ARGS, u32 len, const u8 *maskdata,
+ const u8 *valuedata);
+
+ struct module *owner;
+};
+
+
+/*
+ * Drivers who expose platform functions register at init time, this
+ * causes the platform functions for that device node to be parsed in
+ * advance and associated with the device. The data structures are
+ * partially public so a driver can walk the list of platform functions
+ * and eventually inspect the flags
+ */
+struct pmf_device;
+
+struct pmf_function {
+ /* All functions for a given driver are linked */
+ struct list_head link;
+
+ /* Function node & driver data */
+ struct device_node *node;
+ void *driver_data;
+
+ /* For internal use by core */
+ struct pmf_device *dev;
+
+ /* The name is the "xxx" in "platform-do-xxx", this is how
+ * platform functions are identified by this code. Some functions
+ * only operate for a given target, in which case the phandle is
+ * here (or 0 if the filter doesn't apply)
+ */
+ const char *name;
+ u32 phandle;
+
+ /* The flags for that function. You can have several functions
+ * with the same name and different flag
+ */
+ u32 flags;
+
+ /* The actual tokenized function blob */
+ const void *data;
+ unsigned int length;
+
+ /* Interrupt clients */
+ struct list_head irq_clients;
+
+ /* Refcounting */
+ struct kref ref;
+};
+
+/*
+ * For platform functions that are interrupts, one can register
+ * irq_client structures. You canNOT use the same structure twice
+ * as it contains a link member. Also, the callback is called with
+ * a spinlock held, you must not call back into any of the pmf_* functions
+ * from within that callback
+ */
+struct pmf_irq_client {
+ void (*handler)(void *data);
+ void *data;
+ struct module *owner;
+ struct list_head link;
+};
+
+
+/*
+ * Register/Unregister a function-capable driver and its handlers
+ */
+extern int pmf_register_driver(struct device_node *np,
+ struct pmf_handlers *handlers,
+ void *driverdata);
+
+extern void pmf_unregister_driver(struct device_node *np);
+
+
+/*
+ * Register/Unregister interrupt clients
+ */
+extern int pmf_register_irq_client(struct device_node *np,
+ const char *name,
+ struct pmf_irq_client *client);
+
+extern void pmf_unregister_irq_client(struct device_node *np,
+ const char *name,
+ struct pmf_irq_client *client);
+
+/*
+ * Called by the handlers when an irq happens
+ */
+extern void pmf_do_irq(struct pmf_function *func);
+
+
+/*
+ * Low level call to platform functions.
+ *
+ * The phandle can filter on the target object for functions that have
+ * multiple targets, the flags allow you to restrict the call to a given
+ * combination of flags.
+ *
+ * The args array contains as many arguments as is required by the function,
+ * this is dependent on the function you are calling, unfortunately Apple
+ * mecanism provides no way to encode that so you have to get it right at
+ * the call site. Some functions require no args, in which case, you can
+ * pass NULL.
+ *
+ * You can also pass NULL to the name. This will match any function that has
+ * the appropriate combination of flags & phandle or you can pass 0 to the
+ * phandle to match any
+ */
+extern int pmf_do_functions(struct device_node *np, const char *name,
+ u32 phandle, u32 flags, struct pmf_args *args);
+
+
+
+/*
+ * High level call to a platform function.
+ *
+ * This one looks for the platform-xxx first so you should call it to the
+ * actual target if any. It will fallback to platform-do-xxx if it can't
+ * find one. It will also exclusively target functions that have
+ * the "OnDemand" flag.
+ */
+
+extern int pmf_call_function(struct device_node *target, const char *name,
+ struct pmf_args *args);
+
+
+/*
+ * For low latency interrupt usage, you can lookup for on-demand functions
+ * using the functions below
+ */
+
+extern struct pmf_function *pmf_find_function(struct device_node *target,
+ const char *name);
+
+extern struct pmf_function * pmf_get_function(struct pmf_function *func);
+extern void pmf_put_function(struct pmf_function *func);
+
+extern int pmf_call_one(struct pmf_function *func, struct pmf_args *args);
+
+
+/* Suspend/resume code called by via-pmu directly for now */
+extern void pmac_pfunc_base_suspend(void);
+extern void pmac_pfunc_base_resume(void);
+
+#endif /* __PMAC_PFUNC_H__ */
diff --git a/include/asm-powerpc/pmc.h b/include/asm-powerpc/pmc.h
index 5f41f3a2b293..07d6a4279319 100644
--- a/include/asm-powerpc/pmc.h
+++ b/include/asm-powerpc/pmc.h
@@ -18,6 +18,7 @@
*/
#ifndef _POWERPC_PMC_H
#define _POWERPC_PMC_H
+#ifdef __KERNEL__
#include <asm/ptrace.h>
@@ -44,4 +45,5 @@ void dump_pmcs(void);
extern struct op_powerpc_model op_model_fsl_booke;
#endif
+#endif /* __KERNEL__ */
#endif /* _POWERPC_PMC_H */
diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h
index 36cdc869e580..bdef312900a1 100644
--- a/include/asm-powerpc/ppc-pci.h
+++ b/include/asm-powerpc/ppc-pci.h
@@ -8,6 +8,7 @@
*/
#ifndef _ASM_POWERPC_PPC_PCI_H
#define _ASM_POWERPC_PPC_PCI_H
+#ifdef __KERNEL__
#include <linux/pci.h>
#include <asm/pci-bridge.h>
@@ -93,4 +94,5 @@ void eeh_clear_slot (struct device_node *dn, int mode_flag);
#endif
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_PPC_PCI_H */
diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h
index c27baa0563fe..0dc798d46ea4 100644
--- a/include/asm-powerpc/ppc_asm.h
+++ b/include/asm-powerpc/ppc_asm.h
@@ -94,6 +94,7 @@
#define RFDI .long 0x4c00004e /* rfdi instruction */
#define RFMCI .long 0x4c00004c /* rfmci instruction */
+#ifdef __KERNEL__
#ifdef CONFIG_PPC64
#define XGLUE(a,b) a##b
@@ -325,6 +326,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601)
#define CLR_TOP32(r)
#endif
+#endif /* __KERNEL__ */
+
/* The boring bits... */
/* Condition Register Bit Fields */
diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h
index d12382d292d4..415fa393b00c 100644
--- a/include/asm-powerpc/processor.h
+++ b/include/asm-powerpc/processor.h
@@ -10,7 +10,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <asm/reg.h>
#ifndef __ASSEMBLY__
@@ -50,6 +49,7 @@
#define _CHRP_IBM 0x05 /* IBM chrp, the longtrail and longtrail 2 */
#define _CHRP_Pegasos 0x06 /* Genesi/bplan's Pegasos and Pegasos2 */
+#ifdef __KERNEL__
#define platform_is_pseries() (_machine == PLATFORM_PSERIES || \
_machine == PLATFORM_PSERIES_LPAR)
#define platform_is_lpar() (!!(_machine & PLATFORM_LPAR))
@@ -68,7 +68,6 @@ extern int _chrp_type;
* vendor. Board revision is also made available. This will be moved
* elsewhere soon
*/
-extern unsigned char ucSystemType;
extern unsigned char ucBoardRev;
extern unsigned char ucBoardRevMaj, ucBoardRevMin;
@@ -82,7 +81,7 @@ extern unsigned char ucBoardRevMaj, ucBoardRevMin;
#else
#define _machine 0
#endif /* CONFIG_PPC_MULTIPLATFORM */
-
+#endif /* __KERNEL__ */
/*
* Default implementation of macro that returns current
* instruction pointer ("program counter").
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
index f999df1c5c90..329e9bf62260 100644
--- a/include/asm-powerpc/prom.h
+++ b/include/asm-powerpc/prom.h
@@ -65,49 +65,11 @@ struct boot_param_header
typedef u32 phandle;
typedef u32 ihandle;
-struct address_range {
- unsigned long space;
- unsigned long address;
- unsigned long size;
-};
-
struct interrupt_info {
int line;
int sense; /* +ve/-ve logic, edge or level, etc. */
};
-struct pci_address {
- u32 a_hi;
- u32 a_mid;
- u32 a_lo;
-};
-
-struct isa_address {
- u32 a_hi;
- u32 a_lo;
-};
-
-struct isa_range {
- struct isa_address isa_addr;
- struct pci_address pci_addr;
- unsigned int size;
-};
-
-struct reg_property {
- unsigned long address;
- unsigned long size;
-};
-
-struct reg_property32 {
- unsigned int address;
- unsigned int size;
-};
-
-struct reg_property64 {
- u64 address;
- u64 size;
-};
-
struct property {
char *name;
int length;
@@ -120,8 +82,6 @@ struct device_node {
char *type;
phandle node;
phandle linux_phandle;
- int n_addrs;
- struct address_range *addrs;
int n_intrs;
struct interrupt_info *intrs;
char *full_name;
@@ -223,5 +183,36 @@ extern struct resource *request_OF_resource(struct device_node* node,
int index, const char* name_postfix);
extern int release_OF_resource(struct device_node* node, int index);
+
+/*
+ * OF address retreival & translation
+ */
+
+
+/* Translate an OF address block into a CPU physical address
+ */
+#define OF_BAD_ADDR ((u64)-1)
+extern u64 of_translate_address(struct device_node *np, u32 *addr);
+
+/* Extract an address from a device, returns the region size and
+ * the address space flags too. The PCI version uses a BAR number
+ * instead of an absolute index
+ */
+extern u32 *of_get_address(struct device_node *dev, int index,
+ u64 *size, unsigned int *flags);
+extern u32 *of_get_pci_address(struct device_node *dev, int bar_no,
+ u64 *size, unsigned int *flags);
+
+/* Get an address as a resource. Note that if your address is
+ * a PIO address, the conversion will fail if the physical address
+ * can't be internally converted to an IO token with
+ * pci_address_to_pio(), that is because it's either called to early
+ * or it can't be matched to any host bridge IO space
+ */
+extern int of_address_to_resource(struct device_node *dev, int index,
+ struct resource *r);
+extern int of_pci_address_to_resource(struct device_node *dev, int bar,
+ struct resource *r);
+
#endif /* __KERNEL__ */
#endif /* _POWERPC_PROM_H */
diff --git a/include/asm-powerpc/ptrace.h b/include/asm-powerpc/ptrace.h
index 1f7ecdb0b6ce..9c550b314823 100644
--- a/include/asm-powerpc/ptrace.h
+++ b/include/asm-powerpc/ptrace.h
@@ -87,7 +87,7 @@ extern unsigned long profile_pc(struct pt_regs *regs);
#define force_successful_syscall_return() \
do { \
- current_thread_info()->syscall_noerror = 1; \
+ set_thread_flag(TIF_NOERROR); \
} while(0)
/*
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index eb392d038ed7..12ecc9b9f285 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -145,6 +145,10 @@
#define SPRN_CTR 0x009 /* Count Register */
#define SPRN_CTRLF 0x088
#define SPRN_CTRLT 0x098
+#define CTRL_CT 0xc0000000 /* current thread */
+#define CTRL_CT0 0x80000000 /* thread 0 */
+#define CTRL_CT1 0x40000000 /* thread 1 */
+#define CTRL_TE 0x00c00000 /* thread enable */
#define CTRL_RUNLATCH 0x1
#define SPRN_DABR 0x3F5 /* Data Address Breakpoint Register */
#define DABR_TRANSLATION (1UL << 2)
@@ -257,11 +261,11 @@
#define SPRN_HID6 0x3F9 /* BE HID 6 */
#define HID6_LB (0x0F<<12) /* Concurrent Large Page Modes */
#define HID6_DLP (1<<20) /* Disable all large page modes (4K only) */
-#define SPRN_TSCR 0x399 /* Thread switch control on BE */
-#define SPRN_TTR 0x39A /* Thread switch timeout on BE */
-#define TSCR_DEC_ENABLE 0x200000 /* Decrementer Interrupt */
-#define TSCR_EE_ENABLE 0x100000 /* External Interrupt */
-#define TSCR_EE_BOOST 0x080000 /* External Interrupt Boost */
+#define SPRN_TSC_CELL 0x399 /* Thread switch control on Cell */
+#define TSC_CELL_DEC_ENABLE_0 0x400000 /* Decrementer Interrupt */
+#define TSC_CELL_DEC_ENABLE_1 0x200000 /* Decrementer Interrupt */
+#define TSC_CELL_EE_ENABLE 0x100000 /* External Interrupt */
+#define TSC_CELL_EE_BOOST 0x080000 /* External Interrupt Boost */
#define SPRN_TSC 0x3FD /* Thread switch control on others */
#define SPRN_TST 0x3FC /* Thread switch timeout on others */
#if !defined(SPRN_IAC1) && !defined(SPRN_IAC2)
@@ -375,6 +379,14 @@
#define SPRN_SPRG7 0x117 /* Special Purpose Register General 7 */
#define SPRN_SRR0 0x01A /* Save/Restore Register 0 */
#define SPRN_SRR1 0x01B /* Save/Restore Register 1 */
+#define SRR1_WAKEMASK 0x00380000 /* reason for wakeup */
+#define SRR1_WAKERESET 0x00380000 /* System reset */
+#define SRR1_WAKESYSERR 0x00300000 /* System error */
+#define SRR1_WAKEEE 0x00200000 /* External interrupt */
+#define SRR1_WAKEMT 0x00280000 /* mtctrl */
+#define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */
+#define SRR1_WAKETHERM 0x00100000 /* Thermal management interrupt */
+
#ifndef SPRN_SVR
#define SPRN_SVR 0x11E /* System Version Register */
#endif
@@ -443,12 +455,35 @@
#define SPRN_SDAR 781
#else /* 32-bit */
-#define SPRN_MMCR0 0x3B8 /* Monitor Mode Control Register 0 */
-#define SPRN_MMCR1 0x3BC /* Monitor Mode Control Register 1 */
-#define SPRN_PMC1 0x3B9 /* Performance Counter Register 1 */
-#define SPRN_PMC2 0x3BA /* Performance Counter Register 2 */
-#define SPRN_PMC3 0x3BD /* Performance Counter Register 3 */
-#define SPRN_PMC4 0x3BE /* Performance Counter Register 4 */
+#define SPRN_MMCR0 952 /* Monitor Mode Control Register 0 */
+#define MMCR0_FC 0x80000000UL /* freeze counters */
+#define MMCR0_FCS 0x40000000UL /* freeze in supervisor state */
+#define MMCR0_FCP 0x20000000UL /* freeze in problem state */
+#define MMCR0_FCM1 0x10000000UL /* freeze counters while MSR mark = 1 */
+#define MMCR0_FCM0 0x08000000UL /* freeze counters while MSR mark = 0 */
+#define MMCR0_PMXE 0x04000000UL /* performance monitor exception enable */
+#define MMCR0_FCECE 0x02000000UL /* freeze ctrs on enabled cond or event */
+#define MMCR0_TBEE 0x00400000UL /* time base exception enable */
+#define MMCR0_PMC1CE 0x00008000UL /* PMC1 count enable*/
+#define MMCR0_PMCnCE 0x00004000UL /* count enable for all but PMC 1*/
+#define MMCR0_TRIGGER 0x00002000UL /* TRIGGER enable */
+#define MMCR0_PMC1SEL 0x00001fc0UL /* PMC 1 Event */
+#define MMCR0_PMC2SEL 0x0000003fUL /* PMC 2 Event */
+
+#define SPRN_MMCR1 956
+#define MMCR1_PMC3SEL 0xf8000000UL /* PMC 3 Event */
+#define MMCR1_PMC4SEL 0x07c00000UL /* PMC 4 Event */
+#define MMCR1_PMC5SEL 0x003e0000UL /* PMC 5 Event */
+#define MMCR1_PMC6SEL 0x0001f800UL /* PMC 6 Event */
+#define SPRN_MMCR2 944
+#define SPRN_PMC1 953 /* Performance Counter Register 1 */
+#define SPRN_PMC2 954 /* Performance Counter Register 2 */
+#define SPRN_PMC3 957 /* Performance Counter Register 3 */
+#define SPRN_PMC4 958 /* Performance Counter Register 4 */
+#define SPRN_PMC5 945 /* Performance Counter Register 5 */
+#define SPRN_PMC6 946 /* Performance Counter Register 6 */
+
+#define SPRN_SIAR 955 /* Sampled Instruction Address Register */
/* Bit definitions for MMCR0 and PMC1 / PMC2. */
#define MMCR0_PMC1_CYCLES (1 << 7)
@@ -458,7 +493,6 @@
#define MMCR0_PMC2_CYCLES 0x1
#define MMCR0_PMC2_ITLB 0x7
#define MMCR0_PMC2_LOADMISSTIME 0x5
-#define MMCR0_PMXE (1 << 26)
#endif
/* Processor Version Register (PVR) field extraction */
diff --git a/include/asm-powerpc/rtas.h b/include/asm-powerpc/rtas.h
index d1bb611ea626..3428889e27b7 100644
--- a/include/asm-powerpc/rtas.h
+++ b/include/asm-powerpc/rtas.h
@@ -1,5 +1,6 @@
#ifndef _POWERPC_RTAS_H
#define _POWERPC_RTAS_H
+#ifdef __KERNEL__
#include <linux/spinlock.h>
#include <asm/page.h>
@@ -229,4 +230,5 @@ extern unsigned long rtas_rmo_buf;
#define GLOBAL_INTERRUPT_QUEUE 9005
+#endif /* __KERNEL__ */
#endif /* _POWERPC_RTAS_H */
diff --git a/include/asm-powerpc/seccomp.h b/include/asm-powerpc/seccomp.h
index 1e1cfe12882b..853765eb1f65 100644
--- a/include/asm-powerpc/seccomp.h
+++ b/include/asm-powerpc/seccomp.h
@@ -1,6 +1,10 @@
#ifndef _ASM_POWERPC_SECCOMP_H
+#define _ASM_POWERPC_SECCOMP_H
+#ifdef __KERNEL__
#include <linux/thread_info.h>
+#endif
+
#include <linux/unistd.h>
#define __NR_seccomp_read __NR_read
diff --git a/include/asm-powerpc/sections.h b/include/asm-powerpc/sections.h
index 47be2ac2a925..916018e425c4 100644
--- a/include/asm-powerpc/sections.h
+++ b/include/asm-powerpc/sections.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_SECTIONS_H
#define _ASM_POWERPC_SECTIONS_H
+#ifdef __KERNEL__
#include <asm-generic/sections.h>
@@ -17,4 +18,5 @@ static inline int in_kernel_text(unsigned long addr)
#endif
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_SECTIONS_H */
diff --git a/include/asm-powerpc/serial.h b/include/asm-powerpc/serial.h
index b273d630b32f..6dc9546d6908 100644
--- a/include/asm-powerpc/serial.h
+++ b/include/asm-powerpc/serial.h
@@ -15,4 +15,6 @@
/* Default baud base if not found in device-tree */
#define BASE_BAUD ( 1843200 / 16 )
+extern void find_legacy_serial_ports(void);
+
#endif /* _PPC64_SERIAL_H */
diff --git a/include/asm-powerpc/signal.h b/include/asm-powerpc/signal.h
index 694c8d2dab87..a4d8f8648541 100644
--- a/include/asm-powerpc/signal.h
+++ b/include/asm-powerpc/signal.h
@@ -2,10 +2,13 @@
#define _ASM_POWERPC_SIGNAL_H
#include <linux/types.h>
-#include <linux/config.h>
#define _NSIG 64
-#define _NSIG_BPW BITS_PER_LONG
+#ifdef __powerpc64__
+#define _NSIG_BPW 64
+#else
+#define _NSIG_BPW 32
+#endif
#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
typedef unsigned long old_sigset_t; /* at least 32 bits */
diff --git a/include/asm-powerpc/smu.h b/include/asm-powerpc/smu.h
index 76c29a9784dd..134c2b5be0f2 100644
--- a/include/asm-powerpc/smu.h
+++ b/include/asm-powerpc/smu.h
@@ -4,9 +4,11 @@
/*
* Definitions for talking to the SMU chip in newer G5 PowerMacs
*/
-
+#ifdef __KERNEL__
#include <linux/config.h>
#include <linux/list.h>
+#endif
+#include <linux/types.h>
/*
* Known SMU commands
@@ -356,6 +358,9 @@ extern unsigned long smu_cmdbuf_abs;
* Kenrel asynchronous i2c interface
*/
+#define SMU_I2C_READ_MAX 0x1d
+#define SMU_I2C_WRITE_MAX 0x15
+
/* SMU i2c header, exactly matches i2c header on wire */
struct smu_i2c_param
{
@@ -366,12 +371,9 @@ struct smu_i2c_param
u8 subaddr[3]; /* subaddress */
u8 caddr; /* combined address, filled by SMU driver */
u8 datalen; /* length of transfer */
- u8 data[7]; /* data */
+ u8 data[SMU_I2C_READ_MAX]; /* data */
};
-#define SMU_I2C_READ_MAX 0x0d
-#define SMU_I2C_WRITE_MAX 0x05
-
struct smu_i2c_cmd
{
/* public */
@@ -385,7 +387,7 @@ struct smu_i2c_cmd
int read;
int stage;
int retries;
- u8 pdata[0x10];
+ u8 pdata[32];
struct list_head link;
};
@@ -487,8 +489,8 @@ struct smu_sdbp_slotspow {
#define SMU_SDB_SENSORTREE_ID 0x25
struct smu_sdbp_sensortree {
- u8 model_id;
- u8 unknown[3];
+ __u8 model_id;
+ __u8 unknown[3];
};
/* This partition contains CPU thermal control PID informations. So far
@@ -498,13 +500,13 @@ struct smu_sdbp_sensortree {
#define SMU_SDB_CPUPIDDATA_ID 0x17
struct smu_sdbp_cpupiddata {
- u8 unknown1;
- u8 target_temp_delta;
- u8 unknown2;
- u8 history_len;
- s16 power_adj;
- u16 max_power;
- s32 gp,gr,gd;
+ __u8 unknown1;
+ __u8 target_temp_delta;
+ __u8 unknown2;
+ __u8 history_len;
+ __s16 power_adj;
+ __u16 max_power;
+ __s32 gp,gr,gd;
};
@@ -517,7 +519,7 @@ struct smu_sdbp_cpupiddata {
* if not found. The data format is described below
*/
extern struct smu_sdbp_header *smu_get_sdb_partition(int id,
- unsigned int *size);
+ unsigned int *size);
#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/sparsemem.h b/include/asm-powerpc/sparsemem.h
index ba1b34fdb967..38b1ea3b58fd 100644
--- a/include/asm-powerpc/sparsemem.h
+++ b/include/asm-powerpc/sparsemem.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_SPARSEMEM_H
#define _ASM_POWERPC_SPARSEMEM_H 1
+#ifdef __KERNEL__
#ifdef CONFIG_SPARSEMEM
/*
@@ -13,8 +14,17 @@
#ifdef CONFIG_MEMORY_HOTPLUG
extern void create_section_mapping(unsigned long start, unsigned long end);
+#ifdef CONFIG_NUMA
+extern int hot_add_scn_to_nid(unsigned long scn_addr);
+#else
+static inline int hot_add_scn_to_nid(unsigned long scn_addr)
+{
+ return 0;
+}
+#endif /* CONFIG_NUMA */
#endif /* CONFIG_MEMORY_HOTPLUG */
#endif /* CONFIG_SPARSEMEM */
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_SPARSEMEM_H */
diff --git a/include/asm-powerpc/spinlock.h b/include/asm-powerpc/spinlock.h
index caa4b14e0e94..754900901cd8 100644
--- a/include/asm-powerpc/spinlock.h
+++ b/include/asm-powerpc/spinlock.h
@@ -1,5 +1,6 @@
#ifndef __ASM_SPINLOCK_H
#define __ASM_SPINLOCK_H
+#ifdef __KERNEL__
/*
* Simple spin lock operations.
@@ -266,4 +267,5 @@ static __inline__ void __raw_write_unlock(raw_rwlock_t *rw)
rw->lock = 0;
}
+#endif /* __KERNEL__ */
#endif /* __ASM_SPINLOCK_H */
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
new file mode 100644
index 000000000000..38bacf2f6e0c
--- /dev/null
+++ b/include/asm-powerpc/spu.h
@@ -0,0 +1,600 @@
+/*
+ * SPU core / file system interface and HW structures
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.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, 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 _SPU_H
+#define _SPU_H
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+#include <linux/kref.h>
+#include <linux/workqueue.h>
+
+#define LS_SIZE (256 * 1024)
+#define LS_ADDR_MASK (LS_SIZE - 1)
+
+#define MFC_PUT_CMD 0x20
+#define MFC_PUTS_CMD 0x28
+#define MFC_PUTR_CMD 0x30
+#define MFC_PUTF_CMD 0x22
+#define MFC_PUTB_CMD 0x21
+#define MFC_PUTFS_CMD 0x2A
+#define MFC_PUTBS_CMD 0x29
+#define MFC_PUTRF_CMD 0x32
+#define MFC_PUTRB_CMD 0x31
+#define MFC_PUTL_CMD 0x24
+#define MFC_PUTRL_CMD 0x34
+#define MFC_PUTLF_CMD 0x26
+#define MFC_PUTLB_CMD 0x25
+#define MFC_PUTRLF_CMD 0x36
+#define MFC_PUTRLB_CMD 0x35
+
+#define MFC_GET_CMD 0x40
+#define MFC_GETS_CMD 0x48
+#define MFC_GETF_CMD 0x42
+#define MFC_GETB_CMD 0x41
+#define MFC_GETFS_CMD 0x4A
+#define MFC_GETBS_CMD 0x49
+#define MFC_GETL_CMD 0x44
+#define MFC_GETLF_CMD 0x46
+#define MFC_GETLB_CMD 0x45
+
+#define MFC_SDCRT_CMD 0x80
+#define MFC_SDCRTST_CMD 0x81
+#define MFC_SDCRZ_CMD 0x89
+#define MFC_SDCRS_CMD 0x8D
+#define MFC_SDCRF_CMD 0x8F
+
+#define MFC_GETLLAR_CMD 0xD0
+#define MFC_PUTLLC_CMD 0xB4
+#define MFC_PUTLLUC_CMD 0xB0
+#define MFC_PUTQLLUC_CMD 0xB8
+#define MFC_SNDSIG_CMD 0xA0
+#define MFC_SNDSIGB_CMD 0xA1
+#define MFC_SNDSIGF_CMD 0xA2
+#define MFC_BARRIER_CMD 0xC0
+#define MFC_EIEIO_CMD 0xC8
+#define MFC_SYNC_CMD 0xCC
+
+#define MFC_MIN_DMA_SIZE_SHIFT 4 /* 16 bytes */
+#define MFC_MAX_DMA_SIZE_SHIFT 14 /* 16384 bytes */
+#define MFC_MIN_DMA_SIZE (1 << MFC_MIN_DMA_SIZE_SHIFT)
+#define MFC_MAX_DMA_SIZE (1 << MFC_MAX_DMA_SIZE_SHIFT)
+#define MFC_MIN_DMA_SIZE_MASK (MFC_MIN_DMA_SIZE - 1)
+#define MFC_MAX_DMA_SIZE_MASK (MFC_MAX_DMA_SIZE - 1)
+#define MFC_MIN_DMA_LIST_SIZE 0x0008 /* 8 bytes */
+#define MFC_MAX_DMA_LIST_SIZE 0x4000 /* 16K bytes */
+
+#define MFC_TAGID_TO_TAGMASK(tag_id) (1 << (tag_id & 0x1F))
+
+/* Events for Channels 0-2 */
+#define MFC_DMA_TAG_STATUS_UPDATE_EVENT 0x00000001
+#define MFC_DMA_TAG_CMD_STALL_NOTIFY_EVENT 0x00000002
+#define MFC_DMA_QUEUE_AVAILABLE_EVENT 0x00000008
+#define MFC_SPU_MAILBOX_WRITTEN_EVENT 0x00000010
+#define MFC_DECREMENTER_EVENT 0x00000020
+#define MFC_PU_INT_MAILBOX_AVAILABLE_EVENT 0x00000040
+#define MFC_PU_MAILBOX_AVAILABLE_EVENT 0x00000080
+#define MFC_SIGNAL_2_EVENT 0x00000100
+#define MFC_SIGNAL_1_EVENT 0x00000200
+#define MFC_LLR_LOST_EVENT 0x00000400
+#define MFC_PRIV_ATTN_EVENT 0x00000800
+#define MFC_MULTI_SRC_EVENT 0x00001000
+
+/* Flags indicating progress during context switch. */
+#define SPU_CONTEXT_SWITCH_PENDING 0UL
+#define SPU_CONTEXT_SWITCH_ACTIVE 1UL
+
+struct spu_context;
+struct spu_runqueue;
+
+struct spu {
+ char *name;
+ unsigned long local_store_phys;
+ u8 *local_store;
+ struct spu_problem __iomem *problem;
+ struct spu_priv1 __iomem *priv1;
+ struct spu_priv2 __iomem *priv2;
+ struct list_head list;
+ struct list_head sched_list;
+ int number;
+ u32 isrc;
+ u32 node;
+ u64 flags;
+ u64 dar;
+ u64 dsisr;
+ struct kref kref;
+ size_t ls_size;
+ unsigned int slb_replace;
+ struct mm_struct *mm;
+ struct spu_context *ctx;
+ struct spu_runqueue *rq;
+ unsigned long long timestamp;
+ pid_t pid;
+ int prio;
+ int class_0_pending;
+ spinlock_t register_lock;
+
+ u32 stop_code;
+ void (* wbox_callback)(struct spu *spu);
+ void (* ibox_callback)(struct spu *spu);
+ void (* stop_callback)(struct spu *spu);
+
+ char irq_c0[8];
+ char irq_c1[8];
+ char irq_c2[8];
+};
+
+struct spu *spu_alloc(void);
+void spu_free(struct spu *spu);
+int spu_irq_class_0_bottom(struct spu *spu);
+int spu_irq_class_1_bottom(struct spu *spu);
+void spu_irq_setaffinity(struct spu *spu, int cpu);
+
+extern struct spufs_calls {
+ asmlinkage long (*create_thread)(const char __user *name,
+ unsigned int flags, mode_t mode);
+ asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc,
+ __u32 __user *ustatus);
+ struct module *owner;
+} spufs_calls;
+
+#ifdef CONFIG_SPU_FS_MODULE
+int register_spu_syscalls(struct spufs_calls *calls);
+void unregister_spu_syscalls(struct spufs_calls *calls);
+#else
+static inline int register_spu_syscalls(struct spufs_calls *calls)
+{
+ return 0;
+}
+static inline void unregister_spu_syscalls(struct spufs_calls *calls)
+{
+}
+#endif /* MODULE */
+
+
+/* access to priv1 registers */
+void spu_int_mask_and(struct spu *spu, int class, u64 mask);
+void spu_int_mask_or(struct spu *spu, int class, u64 mask);
+void spu_int_mask_set(struct spu *spu, int class, u64 mask);
+u64 spu_int_mask_get(struct spu *spu, int class);
+void spu_int_stat_clear(struct spu *spu, int class, u64 stat);
+u64 spu_int_stat_get(struct spu *spu, int class);
+void spu_int_route_set(struct spu *spu, u64 route);
+u64 spu_mfc_dar_get(struct spu *spu);
+u64 spu_mfc_dsisr_get(struct spu *spu);
+void spu_mfc_dsisr_set(struct spu *spu, u64 dsisr);
+void spu_mfc_sdr_set(struct spu *spu, u64 sdr);
+void spu_mfc_sr1_set(struct spu *spu, u64 sr1);
+u64 spu_mfc_sr1_get(struct spu *spu);
+void spu_mfc_tclass_id_set(struct spu *spu, u64 tclass_id);
+u64 spu_mfc_tclass_id_get(struct spu *spu);
+void spu_tlb_invalidate(struct spu *spu);
+void spu_resource_allocation_groupID_set(struct spu *spu, u64 id);
+u64 spu_resource_allocation_groupID_get(struct spu *spu);
+void spu_resource_allocation_enable_set(struct spu *spu, u64 enable);
+u64 spu_resource_allocation_enable_get(struct spu *spu);
+
+
+/*
+ * This defines the Local Store, Problem Area and Privlege Area of an SPU.
+ */
+
+union mfc_tag_size_class_cmd {
+ struct {
+ u16 mfc_size;
+ u16 mfc_tag;
+ u8 pad;
+ u8 mfc_rclassid;
+ u16 mfc_cmd;
+ } u;
+ struct {
+ u32 mfc_size_tag32;
+ u32 mfc_class_cmd32;
+ } by32;
+ u64 all64;
+};
+
+struct mfc_cq_sr {
+ u64 mfc_cq_data0_RW;
+ u64 mfc_cq_data1_RW;
+ u64 mfc_cq_data2_RW;
+ u64 mfc_cq_data3_RW;
+};
+
+struct spu_problem {
+#define MS_SYNC_PENDING 1L
+ u64 spc_mssync_RW; /* 0x0000 */
+ u8 pad_0x0008_0x3000[0x3000 - 0x0008];
+
+ /* DMA Area */
+ u8 pad_0x3000_0x3004[0x4]; /* 0x3000 */
+ u32 mfc_lsa_W; /* 0x3004 */
+ u64 mfc_ea_W; /* 0x3008 */
+ union mfc_tag_size_class_cmd mfc_union_W; /* 0x3010 */
+ u8 pad_0x3018_0x3104[0xec]; /* 0x3018 */
+ u32 dma_qstatus_R; /* 0x3104 */
+ u8 pad_0x3108_0x3204[0xfc]; /* 0x3108 */
+ u32 dma_querytype_RW; /* 0x3204 */
+ u8 pad_0x3208_0x321c[0x14]; /* 0x3208 */
+ u32 dma_querymask_RW; /* 0x321c */
+ u8 pad_0x3220_0x322c[0xc]; /* 0x3220 */
+ u32 dma_tagstatus_R; /* 0x322c */
+#define DMA_TAGSTATUS_INTR_ANY 1u
+#define DMA_TAGSTATUS_INTR_ALL 2u
+ u8 pad_0x3230_0x4000[0x4000 - 0x3230]; /* 0x3230 */
+
+ /* SPU Control Area */
+ u8 pad_0x4000_0x4004[0x4]; /* 0x4000 */
+ u32 pu_mb_R; /* 0x4004 */
+ u8 pad_0x4008_0x400c[0x4]; /* 0x4008 */
+ u32 spu_mb_W; /* 0x400c */
+ u8 pad_0x4010_0x4014[0x4]; /* 0x4010 */
+ u32 mb_stat_R; /* 0x4014 */
+ u8 pad_0x4018_0x401c[0x4]; /* 0x4018 */
+ u32 spu_runcntl_RW; /* 0x401c */
+#define SPU_RUNCNTL_STOP 0L
+#define SPU_RUNCNTL_RUNNABLE 1L
+ u8 pad_0x4020_0x4024[0x4]; /* 0x4020 */
+ u32 spu_status_R; /* 0x4024 */
+#define SPU_STOP_STATUS_SHIFT 16
+#define SPU_STATUS_STOPPED 0x0
+#define SPU_STATUS_RUNNING 0x1
+#define SPU_STATUS_STOPPED_BY_STOP 0x2
+#define SPU_STATUS_STOPPED_BY_HALT 0x4
+#define SPU_STATUS_WAITING_FOR_CHANNEL 0x8
+#define SPU_STATUS_SINGLE_STEP 0x10
+#define SPU_STATUS_INVALID_INSTR 0x20
+#define SPU_STATUS_INVALID_CH 0x40
+#define SPU_STATUS_ISOLATED_STATE 0x80
+#define SPU_STATUS_ISOLATED_LOAD_STAUTUS 0x200
+#define SPU_STATUS_ISOLATED_EXIT_STAUTUS 0x400
+ u8 pad_0x4028_0x402c[0x4]; /* 0x4028 */
+ u32 spu_spe_R; /* 0x402c */
+ u8 pad_0x4030_0x4034[0x4]; /* 0x4030 */
+ u32 spu_npc_RW; /* 0x4034 */
+ u8 pad_0x4038_0x14000[0x14000 - 0x4038]; /* 0x4038 */
+
+ /* Signal Notification Area */
+ u8 pad_0x14000_0x1400c[0xc]; /* 0x14000 */
+ u32 signal_notify1; /* 0x1400c */
+ u8 pad_0x14010_0x1c00c[0x7ffc]; /* 0x14010 */
+ u32 signal_notify2; /* 0x1c00c */
+} __attribute__ ((aligned(0x20000)));
+
+/* SPU Privilege 2 State Area */
+struct spu_priv2 {
+ /* MFC Registers */
+ u8 pad_0x0000_0x1100[0x1100 - 0x0000]; /* 0x0000 */
+
+ /* SLB Management Registers */
+ u8 pad_0x1100_0x1108[0x8]; /* 0x1100 */
+ u64 slb_index_W; /* 0x1108 */
+#define SLB_INDEX_MASK 0x7L
+ u64 slb_esid_RW; /* 0x1110 */
+ u64 slb_vsid_RW; /* 0x1118 */
+#define SLB_VSID_SUPERVISOR_STATE (0x1ull << 11)
+#define SLB_VSID_SUPERVISOR_STATE_MASK (0x1ull << 11)
+#define SLB_VSID_PROBLEM_STATE (0x1ull << 10)
+#define SLB_VSID_PROBLEM_STATE_MASK (0x1ull << 10)
+#define SLB_VSID_EXECUTE_SEGMENT (0x1ull << 9)
+#define SLB_VSID_NO_EXECUTE_SEGMENT (0x1ull << 9)
+#define SLB_VSID_EXECUTE_SEGMENT_MASK (0x1ull << 9)
+#define SLB_VSID_4K_PAGE (0x0 << 8)
+#define SLB_VSID_LARGE_PAGE (0x1ull << 8)
+#define SLB_VSID_PAGE_SIZE_MASK (0x1ull << 8)
+#define SLB_VSID_CLASS_MASK (0x1ull << 7)
+#define SLB_VSID_VIRTUAL_PAGE_SIZE_MASK (0x1ull << 6)
+ u64 slb_invalidate_entry_W; /* 0x1120 */
+ u64 slb_invalidate_all_W; /* 0x1128 */
+ u8 pad_0x1130_0x2000[0x2000 - 0x1130]; /* 0x1130 */
+
+ /* Context Save / Restore Area */
+ struct mfc_cq_sr spuq[16]; /* 0x2000 */
+ struct mfc_cq_sr puq[8]; /* 0x2200 */
+ u8 pad_0x2300_0x3000[0x3000 - 0x2300]; /* 0x2300 */
+
+ /* MFC Control */
+ u64 mfc_control_RW; /* 0x3000 */
+#define MFC_CNTL_RESUME_DMA_QUEUE (0ull << 0)
+#define MFC_CNTL_SUSPEND_DMA_QUEUE (1ull << 0)
+#define MFC_CNTL_SUSPEND_DMA_QUEUE_MASK (1ull << 0)
+#define MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION (0ull << 8)
+#define MFC_CNTL_SUSPEND_IN_PROGRESS (1ull << 8)
+#define MFC_CNTL_SUSPEND_COMPLETE (3ull << 8)
+#define MFC_CNTL_SUSPEND_DMA_STATUS_MASK (3ull << 8)
+#define MFC_CNTL_DMA_QUEUES_EMPTY (1ull << 14)
+#define MFC_CNTL_DMA_QUEUES_EMPTY_MASK (1ull << 14)
+#define MFC_CNTL_PURGE_DMA_REQUEST (1ull << 15)
+#define MFC_CNTL_PURGE_DMA_IN_PROGRESS (1ull << 24)
+#define MFC_CNTL_PURGE_DMA_COMPLETE (3ull << 24)
+#define MFC_CNTL_PURGE_DMA_STATUS_MASK (3ull << 24)
+#define MFC_CNTL_RESTART_DMA_COMMAND (1ull << 32)
+#define MFC_CNTL_DMA_COMMAND_REISSUE_PENDING (1ull << 32)
+#define MFC_CNTL_DMA_COMMAND_REISSUE_STATUS_MASK (1ull << 32)
+#define MFC_CNTL_MFC_PRIVILEGE_STATE (2ull << 33)
+#define MFC_CNTL_MFC_PROBLEM_STATE (3ull << 33)
+#define MFC_CNTL_MFC_KEY_PROTECTION_STATE_MASK (3ull << 33)
+#define MFC_CNTL_DECREMENTER_HALTED (1ull << 35)
+#define MFC_CNTL_DECREMENTER_RUNNING (1ull << 40)
+#define MFC_CNTL_DECREMENTER_STATUS_MASK (1ull << 40)
+ u8 pad_0x3008_0x4000[0x4000 - 0x3008]; /* 0x3008 */
+
+ /* Interrupt Mailbox */
+ u64 puint_mb_R; /* 0x4000 */
+ u8 pad_0x4008_0x4040[0x4040 - 0x4008]; /* 0x4008 */
+
+ /* SPU Control */
+ u64 spu_privcntl_RW; /* 0x4040 */
+#define SPU_PRIVCNTL_MODE_NORMAL (0x0ull << 0)
+#define SPU_PRIVCNTL_MODE_SINGLE_STEP (0x1ull << 0)
+#define SPU_PRIVCNTL_MODE_MASK (0x1ull << 0)
+#define SPU_PRIVCNTL_NO_ATTENTION_EVENT (0x0ull << 1)
+#define SPU_PRIVCNTL_ATTENTION_EVENT (0x1ull << 1)
+#define SPU_PRIVCNTL_ATTENTION_EVENT_MASK (0x1ull << 1)
+#define SPU_PRIVCNT_LOAD_REQUEST_NORMAL (0x0ull << 2)
+#define SPU_PRIVCNT_LOAD_REQUEST_ENABLE_MASK (0x1ull << 2)
+ u8 pad_0x4048_0x4058[0x10]; /* 0x4048 */
+ u64 spu_lslr_RW; /* 0x4058 */
+ u64 spu_chnlcntptr_RW; /* 0x4060 */
+ u64 spu_chnlcnt_RW; /* 0x4068 */
+ u64 spu_chnldata_RW; /* 0x4070 */
+ u64 spu_cfg_RW; /* 0x4078 */
+ u8 pad_0x4080_0x5000[0x5000 - 0x4080]; /* 0x4080 */
+
+ /* PV2_ImplRegs: Implementation-specific privileged-state 2 regs */
+ u64 spu_pm_trace_tag_status_RW; /* 0x5000 */
+ u64 spu_tag_status_query_RW; /* 0x5008 */
+#define TAG_STATUS_QUERY_CONDITION_BITS (0x3ull << 32)
+#define TAG_STATUS_QUERY_MASK_BITS (0xffffffffull)
+ u64 spu_cmd_buf1_RW; /* 0x5010 */
+#define SPU_COMMAND_BUFFER_1_LSA_BITS (0x7ffffull << 32)
+#define SPU_COMMAND_BUFFER_1_EAH_BITS (0xffffffffull)
+ u64 spu_cmd_buf2_RW; /* 0x5018 */
+#define SPU_COMMAND_BUFFER_2_EAL_BITS ((0xffffffffull) << 32)
+#define SPU_COMMAND_BUFFER_2_TS_BITS (0xffffull << 16)
+#define SPU_COMMAND_BUFFER_2_TAG_BITS (0x3full)
+ u64 spu_atomic_status_RW; /* 0x5020 */
+} __attribute__ ((aligned(0x20000)));
+
+/* SPU Privilege 1 State Area */
+struct spu_priv1 {
+ /* Control and Configuration Area */
+ u64 mfc_sr1_RW; /* 0x000 */
+#define MFC_STATE1_LOCAL_STORAGE_DECODE_MASK 0x01ull
+#define MFC_STATE1_BUS_TLBIE_MASK 0x02ull
+#define MFC_STATE1_REAL_MODE_OFFSET_ENABLE_MASK 0x04ull
+#define MFC_STATE1_PROBLEM_STATE_MASK 0x08ull
+#define MFC_STATE1_RELOCATE_MASK 0x10ull
+#define MFC_STATE1_MASTER_RUN_CONTROL_MASK 0x20ull
+ u64 mfc_lpid_RW; /* 0x008 */
+ u64 spu_idr_RW; /* 0x010 */
+ u64 mfc_vr_RO; /* 0x018 */
+#define MFC_VERSION_BITS (0xffff << 16)
+#define MFC_REVISION_BITS (0xffff)
+#define MFC_GET_VERSION_BITS(vr) (((vr) & MFC_VERSION_BITS) >> 16)
+#define MFC_GET_REVISION_BITS(vr) ((vr) & MFC_REVISION_BITS)
+ u64 spu_vr_RO; /* 0x020 */
+#define SPU_VERSION_BITS (0xffff << 16)
+#define SPU_REVISION_BITS (0xffff)
+#define SPU_GET_VERSION_BITS(vr) (vr & SPU_VERSION_BITS) >> 16
+#define SPU_GET_REVISION_BITS(vr) (vr & SPU_REVISION_BITS)
+ u8 pad_0x28_0x100[0x100 - 0x28]; /* 0x28 */
+
+
+ /* Interrupt Area */
+ u64 int_mask_RW[3]; /* 0x100 */
+#define CLASS0_ENABLE_DMA_ALIGNMENT_INTR 0x1L
+#define CLASS0_ENABLE_INVALID_DMA_COMMAND_INTR 0x2L
+#define CLASS0_ENABLE_SPU_ERROR_INTR 0x4L
+#define CLASS0_ENABLE_MFC_FIR_INTR 0x8L
+#define CLASS1_ENABLE_SEGMENT_FAULT_INTR 0x1L
+#define CLASS1_ENABLE_STORAGE_FAULT_INTR 0x2L
+#define CLASS1_ENABLE_LS_COMPARE_SUSPEND_ON_GET_INTR 0x4L
+#define CLASS1_ENABLE_LS_COMPARE_SUSPEND_ON_PUT_INTR 0x8L
+#define CLASS2_ENABLE_MAILBOX_INTR 0x1L
+#define CLASS2_ENABLE_SPU_STOP_INTR 0x2L
+#define CLASS2_ENABLE_SPU_HALT_INTR 0x4L
+#define CLASS2_ENABLE_SPU_DMA_TAG_GROUP_COMPLETE_INTR 0x8L
+ u8 pad_0x118_0x140[0x28]; /* 0x118 */
+ u64 int_stat_RW[3]; /* 0x140 */
+ u8 pad_0x158_0x180[0x28]; /* 0x158 */
+ u64 int_route_RW; /* 0x180 */
+
+ /* Interrupt Routing */
+ u8 pad_0x188_0x200[0x200 - 0x188]; /* 0x188 */
+
+ /* Atomic Unit Control Area */
+ u64 mfc_atomic_flush_RW; /* 0x200 */
+#define mfc_atomic_flush_enable 0x1L
+ u8 pad_0x208_0x280[0x78]; /* 0x208 */
+ u64 resource_allocation_groupID_RW; /* 0x280 */
+ u64 resource_allocation_enable_RW; /* 0x288 */
+ u8 pad_0x290_0x3c8[0x3c8 - 0x290]; /* 0x290 */
+
+ /* SPU_Cache_ImplRegs: Implementation-dependent cache registers */
+
+ u64 smf_sbi_signal_sel; /* 0x3c8 */
+#define smf_sbi_mask_lsb 56
+#define smf_sbi_shift (63 - smf_sbi_mask_lsb)
+#define smf_sbi_mask (0x301LL << smf_sbi_shift)
+#define smf_sbi_bus0_bits (0x001LL << smf_sbi_shift)
+#define smf_sbi_bus2_bits (0x100LL << smf_sbi_shift)
+#define smf_sbi2_bus0_bits (0x201LL << smf_sbi_shift)
+#define smf_sbi2_bus2_bits (0x300LL << smf_sbi_shift)
+ u64 smf_ato_signal_sel; /* 0x3d0 */
+#define smf_ato_mask_lsb 35
+#define smf_ato_shift (63 - smf_ato_mask_lsb)
+#define smf_ato_mask (0x3LL << smf_ato_shift)
+#define smf_ato_bus0_bits (0x2LL << smf_ato_shift)
+#define smf_ato_bus2_bits (0x1LL << smf_ato_shift)
+ u8 pad_0x3d8_0x400[0x400 - 0x3d8]; /* 0x3d8 */
+
+ /* TLB Management Registers */
+ u64 mfc_sdr_RW; /* 0x400 */
+ u8 pad_0x408_0x500[0xf8]; /* 0x408 */
+ u64 tlb_index_hint_RO; /* 0x500 */
+ u64 tlb_index_W; /* 0x508 */
+ u64 tlb_vpn_RW; /* 0x510 */
+ u64 tlb_rpn_RW; /* 0x518 */
+ u8 pad_0x520_0x540[0x20]; /* 0x520 */
+ u64 tlb_invalidate_entry_W; /* 0x540 */
+ u64 tlb_invalidate_all_W; /* 0x548 */
+ u8 pad_0x550_0x580[0x580 - 0x550]; /* 0x550 */
+
+ /* SPU_MMU_ImplRegs: Implementation-dependent MMU registers */
+ u64 smm_hid; /* 0x580 */
+#define PAGE_SIZE_MASK 0xf000000000000000ull
+#define PAGE_SIZE_16MB_64KB 0x2000000000000000ull
+ u8 pad_0x588_0x600[0x600 - 0x588]; /* 0x588 */
+
+ /* MFC Status/Control Area */
+ u64 mfc_accr_RW; /* 0x600 */
+#define MFC_ACCR_EA_ACCESS_GET (1 << 0)
+#define MFC_ACCR_EA_ACCESS_PUT (1 << 1)
+#define MFC_ACCR_LS_ACCESS_GET (1 << 3)
+#define MFC_ACCR_LS_ACCESS_PUT (1 << 4)
+ u8 pad_0x608_0x610[0x8]; /* 0x608 */
+ u64 mfc_dsisr_RW; /* 0x610 */
+#define MFC_DSISR_PTE_NOT_FOUND (1 << 30)
+#define MFC_DSISR_ACCESS_DENIED (1 << 27)
+#define MFC_DSISR_ATOMIC (1 << 26)
+#define MFC_DSISR_ACCESS_PUT (1 << 25)
+#define MFC_DSISR_ADDR_MATCH (1 << 22)
+#define MFC_DSISR_LS (1 << 17)
+#define MFC_DSISR_L (1 << 16)
+#define MFC_DSISR_ADDRESS_OVERFLOW (1 << 0)
+ u8 pad_0x618_0x620[0x8]; /* 0x618 */
+ u64 mfc_dar_RW; /* 0x620 */
+ u8 pad_0x628_0x700[0x700 - 0x628]; /* 0x628 */
+
+ /* Replacement Management Table (RMT) Area */
+ u64 rmt_index_RW; /* 0x700 */
+ u8 pad_0x708_0x710[0x8]; /* 0x708 */
+ u64 rmt_data1_RW; /* 0x710 */
+ u8 pad_0x718_0x800[0x800 - 0x718]; /* 0x718 */
+
+ /* Control/Configuration Registers */
+ u64 mfc_dsir_R; /* 0x800 */
+#define MFC_DSIR_Q (1 << 31)
+#define MFC_DSIR_SPU_QUEUE MFC_DSIR_Q
+ u64 mfc_lsacr_RW; /* 0x808 */
+#define MFC_LSACR_COMPARE_MASK ((~0ull) << 32)
+#define MFC_LSACR_COMPARE_ADDR ((~0ull) >> 32)
+ u64 mfc_lscrr_R; /* 0x810 */
+#define MFC_LSCRR_Q (1 << 31)
+#define MFC_LSCRR_SPU_QUEUE MFC_LSCRR_Q
+#define MFC_LSCRR_QI_SHIFT 32
+#define MFC_LSCRR_QI_MASK ((~0ull) << MFC_LSCRR_QI_SHIFT)
+ u8 pad_0x818_0x820[0x8]; /* 0x818 */
+ u64 mfc_tclass_id_RW; /* 0x820 */
+#define MFC_TCLASS_ID_ENABLE (1L << 0L)
+#define MFC_TCLASS_SLOT2_ENABLE (1L << 5L)
+#define MFC_TCLASS_SLOT1_ENABLE (1L << 6L)
+#define MFC_TCLASS_SLOT0_ENABLE (1L << 7L)
+#define MFC_TCLASS_QUOTA_2_SHIFT 8L
+#define MFC_TCLASS_QUOTA_1_SHIFT 16L
+#define MFC_TCLASS_QUOTA_0_SHIFT 24L
+#define MFC_TCLASS_QUOTA_2_MASK (0x1FL << MFC_TCLASS_QUOTA_2_SHIFT)
+#define MFC_TCLASS_QUOTA_1_MASK (0x1FL << MFC_TCLASS_QUOTA_1_SHIFT)
+#define MFC_TCLASS_QUOTA_0_MASK (0x1FL << MFC_TCLASS_QUOTA_0_SHIFT)
+ u8 pad_0x828_0x900[0x900 - 0x828]; /* 0x828 */
+
+ /* Real Mode Support Registers */
+ u64 mfc_rm_boundary; /* 0x900 */
+ u8 pad_0x908_0x938[0x30]; /* 0x908 */
+ u64 smf_dma_signal_sel; /* 0x938 */
+#define mfc_dma1_mask_lsb 41
+#define mfc_dma1_shift (63 - mfc_dma1_mask_lsb)
+#define mfc_dma1_mask (0x3LL << mfc_dma1_shift)
+#define mfc_dma1_bits (0x1LL << mfc_dma1_shift)
+#define mfc_dma2_mask_lsb 43
+#define mfc_dma2_shift (63 - mfc_dma2_mask_lsb)
+#define mfc_dma2_mask (0x3LL << mfc_dma2_shift)
+#define mfc_dma2_bits (0x1LL << mfc_dma2_shift)
+ u8 pad_0x940_0xa38[0xf8]; /* 0x940 */
+ u64 smm_signal_sel; /* 0xa38 */
+#define smm_sig_mask_lsb 12
+#define smm_sig_shift (63 - smm_sig_mask_lsb)
+#define smm_sig_mask (0x3LL << smm_sig_shift)
+#define smm_sig_bus0_bits (0x2LL << smm_sig_shift)
+#define smm_sig_bus2_bits (0x1LL << smm_sig_shift)
+ u8 pad_0xa40_0xc00[0xc00 - 0xa40]; /* 0xa40 */
+
+ /* DMA Command Error Area */
+ u64 mfc_cer_R; /* 0xc00 */
+#define MFC_CER_Q (1 << 31)
+#define MFC_CER_SPU_QUEUE MFC_CER_Q
+ u8 pad_0xc08_0x1000[0x1000 - 0xc08]; /* 0xc08 */
+
+ /* PV1_ImplRegs: Implementation-dependent privileged-state 1 regs */
+ /* DMA Command Error Area */
+ u64 spu_ecc_cntl_RW; /* 0x1000 */
+#define SPU_ECC_CNTL_E (1ull << 0ull)
+#define SPU_ECC_CNTL_ENABLE SPU_ECC_CNTL_E
+#define SPU_ECC_CNTL_DISABLE (~SPU_ECC_CNTL_E & 1L)
+#define SPU_ECC_CNTL_S (1ull << 1ull)
+#define SPU_ECC_STOP_AFTER_ERROR SPU_ECC_CNTL_S
+#define SPU_ECC_CONTINUE_AFTER_ERROR (~SPU_ECC_CNTL_S & 2L)
+#define SPU_ECC_CNTL_B (1ull << 2ull)
+#define SPU_ECC_BACKGROUND_ENABLE SPU_ECC_CNTL_B
+#define SPU_ECC_BACKGROUND_DISABLE (~SPU_ECC_CNTL_B & 4L)
+#define SPU_ECC_CNTL_I_SHIFT 3ull
+#define SPU_ECC_CNTL_I_MASK (3ull << SPU_ECC_CNTL_I_SHIFT)
+#define SPU_ECC_WRITE_ALWAYS (~SPU_ECC_CNTL_I & 12L)
+#define SPU_ECC_WRITE_CORRECTABLE (1ull << SPU_ECC_CNTL_I_SHIFT)
+#define SPU_ECC_WRITE_UNCORRECTABLE (3ull << SPU_ECC_CNTL_I_SHIFT)
+#define SPU_ECC_CNTL_D (1ull << 5ull)
+#define SPU_ECC_DETECTION_ENABLE SPU_ECC_CNTL_D
+#define SPU_ECC_DETECTION_DISABLE (~SPU_ECC_CNTL_D & 32L)
+ u64 spu_ecc_stat_RW; /* 0x1008 */
+#define SPU_ECC_CORRECTED_ERROR (1ull << 0ul)
+#define SPU_ECC_UNCORRECTED_ERROR (1ull << 1ul)
+#define SPU_ECC_SCRUB_COMPLETE (1ull << 2ul)
+#define SPU_ECC_SCRUB_IN_PROGRESS (1ull << 3ul)
+#define SPU_ECC_INSTRUCTION_ERROR (1ull << 4ul)
+#define SPU_ECC_DATA_ERROR (1ull << 5ul)
+#define SPU_ECC_DMA_ERROR (1ull << 6ul)
+#define SPU_ECC_STATUS_CNT_MASK (256ull << 8)
+ u64 spu_ecc_addr_RW; /* 0x1010 */
+ u64 spu_err_mask_RW; /* 0x1018 */
+#define SPU_ERR_ILLEGAL_INSTR (1ull << 0ul)
+#define SPU_ERR_ILLEGAL_CHANNEL (1ull << 1ul)
+ u8 pad_0x1020_0x1028[0x1028 - 0x1020]; /* 0x1020 */
+
+ /* SPU Debug-Trace Bus (DTB) Selection Registers */
+ u64 spu_trig0_sel; /* 0x1028 */
+ u64 spu_trig1_sel; /* 0x1030 */
+ u64 spu_trig2_sel; /* 0x1038 */
+ u64 spu_trig3_sel; /* 0x1040 */
+ u64 spu_trace_sel; /* 0x1048 */
+#define spu_trace_sel_mask 0x1f1fLL
+#define spu_trace_sel_bus0_bits 0x1000LL
+#define spu_trace_sel_bus2_bits 0x0010LL
+ u64 spu_event0_sel; /* 0x1050 */
+ u64 spu_event1_sel; /* 0x1058 */
+ u64 spu_event2_sel; /* 0x1060 */
+ u64 spu_event3_sel; /* 0x1068 */
+ u64 spu_trace_cntl; /* 0x1070 */
+} __attribute__ ((aligned(0x2000)));
+
+#endif /* __KERNEL__ */
+#endif
diff --git a/include/asm-powerpc/spu_csa.h b/include/asm-powerpc/spu_csa.h
new file mode 100644
index 000000000000..ba18d7d4dde2
--- /dev/null
+++ b/include/asm-powerpc/spu_csa.h
@@ -0,0 +1,255 @@
+/*
+ * spu_csa.h: Definitions for SPU context save area (CSA).
+ *
+ * (C) Copyright IBM 2005
+ *
+ * Author: Mark Nutter <mnutter@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, 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 _SPU_CSA_H_
+#define _SPU_CSA_H_
+#ifdef __KERNEL__
+
+/*
+ * Total number of 128-bit registers.
+ */
+#define NR_SPU_GPRS 128
+#define NR_SPU_SPRS 9
+#define NR_SPU_REGS_PAD 7
+#define NR_SPU_SPILL_REGS 144 /* GPRS + SPRS + PAD */
+#define SIZEOF_SPU_SPILL_REGS NR_SPU_SPILL_REGS * 16
+
+#define SPU_SAVE_COMPLETE 0x3FFB
+#define SPU_RESTORE_COMPLETE 0x3FFC
+
+/*
+ * Definitions for various 'stopped' status conditions,
+ * to be recreated during context restore.
+ */
+#define SPU_STOPPED_STATUS_P 1
+#define SPU_STOPPED_STATUS_I 2
+#define SPU_STOPPED_STATUS_H 3
+#define SPU_STOPPED_STATUS_S 4
+#define SPU_STOPPED_STATUS_S_I 5
+#define SPU_STOPPED_STATUS_S_P 6
+#define SPU_STOPPED_STATUS_P_H 7
+#define SPU_STOPPED_STATUS_P_I 8
+#define SPU_STOPPED_STATUS_R 9
+
+#ifndef __ASSEMBLY__
+/**
+ * spu_reg128 - generic 128-bit register definition.
+ */
+struct spu_reg128 {
+ u32 slot[4];
+};
+
+/**
+ * struct spu_lscsa - Local Store Context Save Area.
+ * @gprs: Array of saved registers.
+ * @fpcr: Saved floating point status control register.
+ * @decr: Saved decrementer value.
+ * @decr_status: Indicates decrementer run status.
+ * @ppu_mb: Saved PPU mailbox data.
+ * @ppuint_mb: Saved PPU interrupting mailbox data.
+ * @tag_mask: Saved tag group mask.
+ * @event_mask: Saved event mask.
+ * @srr0: Saved SRR0.
+ * @stopped_status: Conditions to be recreated by restore.
+ * @ls: Saved contents of Local Storage Area.
+ *
+ * The LSCSA represents state that is primarily saved and
+ * restored by SPU-side code.
+ */
+struct spu_lscsa {
+ struct spu_reg128 gprs[128];
+ struct spu_reg128 fpcr;
+ struct spu_reg128 decr;
+ struct spu_reg128 decr_status;
+ struct spu_reg128 ppu_mb;
+ struct spu_reg128 ppuint_mb;
+ struct spu_reg128 tag_mask;
+ struct spu_reg128 event_mask;
+ struct spu_reg128 srr0;
+ struct spu_reg128 stopped_status;
+ struct spu_reg128 pad[119]; /* 'ls' must be page-aligned. */
+ unsigned char ls[LS_SIZE];
+};
+
+/*
+ * struct spu_problem_collapsed - condensed problem state area, w/o pads.
+ */
+struct spu_problem_collapsed {
+ u64 spc_mssync_RW;
+ u32 mfc_lsa_W;
+ u32 unused_pad0;
+ u64 mfc_ea_W;
+ union mfc_tag_size_class_cmd mfc_union_W;
+ u32 dma_qstatus_R;
+ u32 dma_querytype_RW;
+ u32 dma_querymask_RW;
+ u32 dma_tagstatus_R;
+ u32 pu_mb_R;
+ u32 spu_mb_W;
+ u32 mb_stat_R;
+ u32 spu_runcntl_RW;
+ u32 spu_status_R;
+ u32 spu_spc_R;
+ u32 spu_npc_RW;
+ u32 signal_notify1;
+ u32 signal_notify2;
+ u32 unused_pad1;
+};
+
+/*
+ * struct spu_priv1_collapsed - condensed privileged 1 area, w/o pads.
+ */
+struct spu_priv1_collapsed {
+ u64 mfc_sr1_RW;
+ u64 mfc_lpid_RW;
+ u64 spu_idr_RW;
+ u64 mfc_vr_RO;
+ u64 spu_vr_RO;
+ u64 int_mask_class0_RW;
+ u64 int_mask_class1_RW;
+ u64 int_mask_class2_RW;
+ u64 int_stat_class0_RW;
+ u64 int_stat_class1_RW;
+ u64 int_stat_class2_RW;
+ u64 int_route_RW;
+ u64 mfc_atomic_flush_RW;
+ u64 resource_allocation_groupID_RW;
+ u64 resource_allocation_enable_RW;
+ u64 mfc_fir_R;
+ u64 mfc_fir_status_or_W;
+ u64 mfc_fir_status_and_W;
+ u64 mfc_fir_mask_R;
+ u64 mfc_fir_mask_or_W;
+ u64 mfc_fir_mask_and_W;
+ u64 mfc_fir_chkstp_enable_RW;
+ u64 smf_sbi_signal_sel;
+ u64 smf_ato_signal_sel;
+ u64 mfc_sdr_RW;
+ u64 tlb_index_hint_RO;
+ u64 tlb_index_W;
+ u64 tlb_vpn_RW;
+ u64 tlb_rpn_RW;
+ u64 tlb_invalidate_entry_W;
+ u64 tlb_invalidate_all_W;
+ u64 smm_hid;
+ u64 mfc_accr_RW;
+ u64 mfc_dsisr_RW;
+ u64 mfc_dar_RW;
+ u64 rmt_index_RW;
+ u64 rmt_data1_RW;
+ u64 mfc_dsir_R;
+ u64 mfc_lsacr_RW;
+ u64 mfc_lscrr_R;
+ u64 mfc_tclass_id_RW;
+ u64 mfc_rm_boundary;
+ u64 smf_dma_signal_sel;
+ u64 smm_signal_sel;
+ u64 mfc_cer_R;
+ u64 pu_ecc_cntl_RW;
+ u64 pu_ecc_stat_RW;
+ u64 spu_ecc_addr_RW;
+ u64 spu_err_mask_RW;
+ u64 spu_trig0_sel;
+ u64 spu_trig1_sel;
+ u64 spu_trig2_sel;
+ u64 spu_trig3_sel;
+ u64 spu_trace_sel;
+ u64 spu_event0_sel;
+ u64 spu_event1_sel;
+ u64 spu_event2_sel;
+ u64 spu_event3_sel;
+ u64 spu_trace_cntl;
+};
+
+/*
+ * struct spu_priv2_collapsed - condensed priviliged 2 area, w/o pads.
+ */
+struct spu_priv2_collapsed {
+ u64 slb_index_W;
+ u64 slb_esid_RW;
+ u64 slb_vsid_RW;
+ u64 slb_invalidate_entry_W;
+ u64 slb_invalidate_all_W;
+ struct mfc_cq_sr spuq[16];
+ struct mfc_cq_sr puq[8];
+ u64 mfc_control_RW;
+ u64 puint_mb_R;
+ u64 spu_privcntl_RW;
+ u64 spu_lslr_RW;
+ u64 spu_chnlcntptr_RW;
+ u64 spu_chnlcnt_RW;
+ u64 spu_chnldata_RW;
+ u64 spu_cfg_RW;
+ u64 spu_tag_status_query_RW;
+ u64 spu_cmd_buf1_RW;
+ u64 spu_cmd_buf2_RW;
+ u64 spu_atomic_status_RW;
+};
+
+/**
+ * struct spu_state
+ * @lscsa: Local Store Context Save Area.
+ * @prob: Collapsed Problem State Area, w/o pads.
+ * @priv1: Collapsed Privileged 1 Area, w/o pads.
+ * @priv2: Collapsed Privileged 2 Area, w/o pads.
+ * @spu_chnlcnt_RW: Array of saved channel counts.
+ * @spu_chnldata_RW: Array of saved channel data.
+ * @suspend_time: Time stamp when decrementer disabled.
+ * @slb_esid_RW: Array of saved SLB esid entries.
+ * @slb_vsid_RW: Array of saved SLB vsid entries.
+ *
+ * Structure representing the whole of the SPU
+ * context save area (CSA). This struct contains
+ * all of the state necessary to suspend and then
+ * later optionally resume execution of an SPU
+ * context.
+ *
+ * The @lscsa region is by far the largest, and is
+ * allocated separately so that it may either be
+ * pinned or mapped to/from application memory, as
+ * appropriate for the OS environment.
+ */
+struct spu_state {
+ struct spu_lscsa *lscsa;
+ struct spu_problem_collapsed prob;
+ struct spu_priv1_collapsed priv1;
+ struct spu_priv2_collapsed priv2;
+ u64 spu_chnlcnt_RW[32];
+ u64 spu_chnldata_RW[32];
+ u32 spu_mailbox_data[4];
+ u32 pu_mailbox_data[1];
+ unsigned long suspend_time;
+ u64 slb_esid_RW[8];
+ u64 slb_vsid_RW[8];
+ spinlock_t register_lock;
+};
+
+extern void spu_init_csa(struct spu_state *csa);
+extern void spu_fini_csa(struct spu_state *csa);
+extern int spu_save(struct spu_state *prev, struct spu *spu);
+extern int spu_restore(struct spu_state *new, struct spu *spu);
+extern int spu_switch(struct spu_state *prev, struct spu_state *new,
+ struct spu *spu);
+
+#endif /* __KERNEL__ */
+#endif /* !__ASSEMBLY__ */
+#endif /* _SPU_CSA_H_ */
diff --git a/include/asm-powerpc/synch.h b/include/asm-powerpc/synch.h
index 4660c0394a77..794870ab8fd3 100644
--- a/include/asm-powerpc/synch.h
+++ b/include/asm-powerpc/synch.h
@@ -1,7 +1,6 @@
#ifndef _ASM_POWERPC_SYNCH_H
#define _ASM_POWERPC_SYNCH_H
-
-#include <linux/config.h>
+#ifdef __KERNEL__
#ifdef __powerpc64__
#define __SUBARCH_HAS_LWSYNC
@@ -47,5 +46,6 @@ static inline void isync(void)
#define isync_on_smp() __asm__ __volatile__("": : :"memory")
#endif
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_SYNCH_H */
diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
index 5341b75c75cb..0c58e32a9570 100644
--- a/include/asm-powerpc/system.h
+++ b/include/asm-powerpc/system.h
@@ -4,7 +4,6 @@
#ifndef _ASM_POWERPC_SYSTEM_H
#define _ASM_POWERPC_SYSTEM_H
-#include <linux/config.h>
#include <linux/kernel.h>
#include <asm/hw_irq.h>
@@ -42,6 +41,7 @@
#define set_mb(var, value) do { var = value; mb(); } while (0)
#define set_wmb(var, value) do { var = value; wmb(); } while (0)
+#ifdef __KERNEL__
#ifdef CONFIG_SMP
#define smp_mb() mb()
#define smp_rmb() rmb()
@@ -54,7 +54,6 @@
#define smp_read_barrier_depends() do { } while(0)
#endif /* CONFIG_SMP */
-#ifdef __KERNEL__
struct task_struct;
struct pt_regs;
diff --git a/include/asm-powerpc/tce.h b/include/asm-powerpc/tce.h
index 980a094fd5a7..6fa200ad7a7f 100644
--- a/include/asm-powerpc/tce.h
+++ b/include/asm-powerpc/tce.h
@@ -20,6 +20,7 @@
#ifndef _ASM_POWERPC_TCE_H
#define _ASM_POWERPC_TCE_H
+#ifdef __KERNEL__
/*
* Tces come in two formats, one for the virtual bus and a different
@@ -61,4 +62,5 @@ union tce_entry {
};
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_TCE_H */
diff --git a/include/asm-powerpc/thread_info.h b/include/asm-powerpc/thread_info.h
index e525f49bd179..ac1e80e6033e 100644
--- a/include/asm-powerpc/thread_info.h
+++ b/include/asm-powerpc/thread_info.h
@@ -37,8 +37,7 @@ struct thread_info {
int preempt_count; /* 0 => preemptable,
<0 => BUG */
struct restart_block restart_block;
- /* set by force_successful_syscall_return */
- unsigned char syscall_noerror;
+ void *nvgprs_frame;
/* low level flags - has atomic operations done on it */
unsigned long flags ____cacheline_aligned_in_smp;
};
@@ -123,6 +122,9 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_SINGLESTEP 9 /* singlestepping active */
#define TIF_MEMDIE 10
#define TIF_SECCOMP 11 /* secure computing */
+#define TIF_RESTOREALL 12 /* Restore all regs (implies NOERROR) */
+#define TIF_SAVE_NVGPRS 13 /* Save r14-r31 in signal frame */
+#define TIF_NOERROR 14 /* Force successful syscall return */
/* as above, but as bit values */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
@@ -136,10 +138,14 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
#define _TIF_SECCOMP (1<<TIF_SECCOMP)
+#define _TIF_RESTOREALL (1<<TIF_RESTOREALL)
+#define _TIF_SAVE_NVGPRS (1<<TIF_SAVE_NVGPRS)
+#define _TIF_NOERROR (1<<TIF_NOERROR)
#define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP)
#define _TIF_USER_WORK_MASK (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
- _TIF_NEED_RESCHED)
+ _TIF_NEED_RESCHED | _TIF_RESTOREALL)
+#define _TIF_PERSYSCALL_MASK (_TIF_RESTOREALL|_TIF_NOERROR|_TIF_SAVE_NVGPRS)
#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/tlb.h b/include/asm-powerpc/tlb.h
index 56659f121779..601a53cf96d5 100644
--- a/include/asm-powerpc/tlb.h
+++ b/include/asm-powerpc/tlb.h
@@ -11,6 +11,7 @@
*/
#ifndef _ASM_POWERPC_TLB_H
#define _ASM_POWERPC_TLB_H
+#ifdef __KERNEL__
#include <linux/config.h>
#ifndef __powerpc64__
@@ -67,4 +68,5 @@ static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep,
}
#endif
+#endif /* __KERNEL__ */
#endif /* __ASM_POWERPC_TLB_H */
diff --git a/include/asm-powerpc/topology.h b/include/asm-powerpc/topology.h
index db8095cbe09b..9f3d4da261c4 100644
--- a/include/asm-powerpc/topology.h
+++ b/include/asm-powerpc/topology.h
@@ -1,5 +1,6 @@
#ifndef _ASM_POWERPC_TOPOLOGY_H
#define _ASM_POWERPC_TOPOLOGY_H
+#ifdef __KERNEL__
#include <linux/config.h>
@@ -55,10 +56,15 @@ static inline int node_to_first_cpu(int node)
.nr_balance_failed = 0, \
}
+extern void __init dump_numa_cpu_topology(void);
+
#else
+static inline void dump_numa_cpu_topology(void) {}
+
#include <asm-generic/topology.h>
#endif /* CONFIG_NUMA */
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_TOPOLOGY_H */
diff --git a/include/asm-powerpc/udbg.h b/include/asm-powerpc/udbg.h
index a383383bc4d4..479f2d8ff74a 100644
--- a/include/asm-powerpc/udbg.h
+++ b/include/asm-powerpc/udbg.h
@@ -9,12 +9,13 @@
#ifndef _ASM_POWERPC_UDBG_H
#define _ASM_POWERPC_UDBG_H
+#ifdef __KERNEL__
#include <linux/compiler.h>
#include <linux/init.h>
-extern void (*udbg_putc)(unsigned char c);
-extern unsigned char (*udbg_getc)(void);
+extern void (*udbg_putc)(char c);
+extern int (*udbg_getc)(void);
extern int (*udbg_getc_poll)(void);
extern void udbg_puts(const char *s);
@@ -23,9 +24,17 @@ extern int udbg_read(char *buf, int buflen);
extern void register_early_udbg_console(void);
extern void udbg_printf(const char *fmt, ...);
+extern void udbg_progress(char *s, unsigned short hex);
-extern void udbg_init_uart(void __iomem *comport, unsigned int speed);
+extern void udbg_init_uart(void __iomem *comport, unsigned int speed,
+ unsigned int clock);
+extern unsigned int udbg_probe_uart_speed(void __iomem *comport,
+ unsigned int clock);
struct device_node;
-extern void udbg_init_scc(struct device_node *np);
+extern void udbg_scc_init(int force_scc);
+extern int udbg_adb_init(int force_btext);
+extern void udbg_adb_init_early(void);
+
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_UDBG_H */
diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h
index 0991dfceef1d..19eaac3fbbf9 100644
--- a/include/asm-powerpc/unistd.h
+++ b/include/asm-powerpc/unistd.h
@@ -296,8 +296,10 @@
#define __NR_inotify_init 275
#define __NR_inotify_add_watch 276
#define __NR_inotify_rm_watch 277
+#define __NR_spu_run 278
+#define __NR_spu_create 279
-#define __NR_syscalls 278
+#define __NR_syscalls 280
#ifdef __KERNEL__
#define __NR__exit __NR_exit
diff --git a/include/asm-powerpc/vdso_datapage.h b/include/asm-powerpc/vdso_datapage.h
index 411832d5bbdb..7aa92086c3fb 100644
--- a/include/asm-powerpc/vdso_datapage.h
+++ b/include/asm-powerpc/vdso_datapage.h
@@ -1,5 +1,6 @@
#ifndef _VDSO_DATAPAGE_H
#define _VDSO_DATAPAGE_H
+#ifdef __KERNEL__
/*
* Copyright (C) 2002 Peter Bergner <bergner@vnet.ibm.com>, IBM
@@ -105,4 +106,5 @@ extern struct vdso_data *vdso_data;
#endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
#endif /* _SYSTEMCFG_H */
diff --git a/include/asm-powerpc/vio.h b/include/asm-powerpc/vio.h
index e0ccf108277c..0544ece51761 100644
--- a/include/asm-powerpc/vio.h
+++ b/include/asm-powerpc/vio.h
@@ -13,6 +13,7 @@
#ifndef _ASM_POWERPC_VIO_H
#define _ASM_POWERPC_VIO_H
+#ifdef __KERNEL__
#include <linux/config.h>
#include <linux/init.h>
@@ -103,4 +104,5 @@ static inline struct vio_dev *to_vio_dev(struct device *dev)
return container_of(dev, struct vio_dev, dev);
}
+#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_VIO_H */
diff --git a/include/asm-ppc/bseip.h b/include/asm-ppc/bseip.h
deleted file mode 100644
index 691f4a52b0a5..000000000000
--- a/include/asm-ppc/bseip.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * A collection of structures, addresses, and values associated with
- * the Bright Star Engineering ip-Engine board. Copied from the MBX stuff.
- *
- * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
- */
-#ifndef __MACH_BSEIP_DEFS
-#define __MACH_BSEIP_DEFS
-
-#ifndef __ASSEMBLY__
-/* A Board Information structure that is given to a program when
- * prom starts it up.
- */
-typedef struct bd_info {
- unsigned int bi_memstart; /* Memory start address */
- unsigned int bi_memsize; /* Memory (end) size in bytes */
- unsigned int bi_intfreq; /* Internal Freq, in Hz */
- unsigned int bi_busfreq; /* Bus Freq, in Hz */
- unsigned char bi_enetaddr[6];
- unsigned int bi_baudrate;
-} bd_t;
-
-extern bd_t m8xx_board_info;
-
-/* Memory map is configured by the PROM startup.
- * All we need to get started is the IMMR.
- */
-#define IMAP_ADDR ((uint)0xff000000)
-#define IMAP_SIZE ((uint)(64 * 1024))
-#define PCMCIA_MEM_ADDR ((uint)0x04000000)
-#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
-#endif /* !__ASSEMBLY__ */
-
-/* We don't use the 8259.
-*/
-#define NR_8259_INTS 0
-
-#endif
diff --git a/include/asm-ppc/btext.h b/include/asm-ppc/btext.h
index ccaefabe0bf5..ed3630251b3b 100644
--- a/include/asm-ppc/btext.h
+++ b/include/asm-ppc/btext.h
@@ -17,7 +17,7 @@ extern unsigned long disp_BAT[2];
extern boot_infos_t disp_bi;
extern int boot_text_mapped;
-extern void init_boot_display(void);
+extern void btext_init(boot_infos_t *bi);
extern void btext_welcome(void);
extern void btext_prepare_BAT(void);
extern void btext_setup_display(int width, int height, int depth, int pitch,
diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h
index f01255bd1dc3..39200def8d11 100644
--- a/include/asm-ppc/machdep.h
+++ b/include/asm-ppc/machdep.h
@@ -35,8 +35,10 @@ struct machdep_calls {
int (*get_irq)(struct pt_regs *);
/* A general init function, called by ppc_init in init/main.c.
- May be NULL. */
+ May be NULL. DEPRECATED ! */
void (*init)(void);
+ /* For compatibility with merged platforms */
+ void (*init_early)(void);
void (*restart)(char *cmd);
void (*power_off)(void);
diff --git a/include/asm-ppc/mpc85xx.h b/include/asm-ppc/mpc85xx.h
index 9d14baea3d71..c8a96aa44fb7 100644
--- a/include/asm-ppc/mpc85xx.h
+++ b/include/asm-ppc/mpc85xx.h
@@ -37,6 +37,10 @@
#ifdef CONFIG_STX_GP3
#include <platforms/85xx/stx_gp3.h>
#endif
+#if defined(CONFIG_TQM8540) || defined(CONFIG_TQM8541) || \
+ defined(CONFIG_TQM8555) || defined(CONFIG_TQM8560)
+#include <platforms/85xx/tqm85xx.h>
+#endif
#define _IO_BASE isa_io_base
#define _ISA_MEM_BASE isa_mem_base
diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h
index e58c78f90a5a..9d5230689b31 100644
--- a/include/asm-ppc/pci-bridge.h
+++ b/include/asm-ppc/pci-bridge.h
@@ -137,5 +137,14 @@ static inline unsigned char bridge_swizzle(unsigned char pin,
*/
extern int pciauto_bus_scan(struct pci_controller *, int);
+#ifdef CONFIG_PCI
+extern unsigned long pci_address_to_pio(phys_addr_t address);
+#else
+static inline unsigned long pci_address_to_pio(phys_addr_t address)
+{
+ return (unsigned long)-1;
+}
+#endif
+
#endif
#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h
index 3e39827ed566..eb317a0806e4 100644
--- a/include/asm-ppc/prom.h
+++ b/include/asm-ppc/prom.h
@@ -136,5 +136,37 @@ extern unsigned long sub_reloc_offset(unsigned long);
#define PTRRELOC(x) ((typeof(x))add_reloc_offset((unsigned long)(x)))
#define PTRUNRELOC(x) ((typeof(x))sub_reloc_offset((unsigned long)(x)))
+
+/*
+ * OF address retreival & translation
+ */
+
+
+/* Translate an OF address block into a CPU physical address
+ */
+#define OF_BAD_ADDR ((u64)-1)
+extern u64 of_translate_address(struct device_node *np, u32 *addr);
+
+/* Extract an address from a device, returns the region size and
+ * the address space flags too. The PCI version uses a BAR number
+ * instead of an absolute index
+ */
+extern u32 *of_get_address(struct device_node *dev, int index,
+ u64 *size, unsigned int *flags);
+extern u32 *of_get_pci_address(struct device_node *dev, int bar_no,
+ u64 *size, unsigned int *flags);
+
+/* Get an address as a resource. Note that if your address is
+ * a PIO address, the conversion will fail if the physical address
+ * can't be internally converted to an IO token with
+ * pci_address_to_pio(), that is because it's either called to early
+ * or it can't be matched to any host bridge IO space
+ */
+extern int of_address_to_resource(struct device_node *dev, int index,
+ struct resource *r);
+extern int of_pci_address_to_resource(struct device_node *dev, int bar,
+ struct resource *r);
+
+
#endif /* _PPC_PROM_H */
#endif /* __KERNEL__ */
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index fb0985377421..02a585faa62c 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -118,9 +118,9 @@ struct request_list {
* try to put the fields that are referenced together in the same cacheline
*/
struct request {
- struct list_head queuelist; /* looking for ->queue? you must _not_
- * access it directly, use
- * blkdev_dequeue_request! */
+ struct list_head queuelist;
+ struct list_head donelist;
+
unsigned long flags; /* see REQ_ bits below */
/* Maintain bio traversal state for part by part I/O submission.
@@ -141,6 +141,7 @@ struct request {
struct bio *biotail;
void *elevator_private;
+ void *completion_data;
unsigned short ioprio;
@@ -291,6 +292,7 @@ typedef int (merge_bvec_fn) (request_queue_t *, struct bio *, struct bio_vec *);
typedef void (activity_fn) (void *data, int rw);
typedef int (issue_flush_fn) (request_queue_t *, struct gendisk *, sector_t *);
typedef void (prepare_flush_fn) (request_queue_t *, struct request *);
+typedef void (softirq_done_fn)(struct request *);
enum blk_queue_state {
Queue_down,
@@ -332,6 +334,7 @@ struct request_queue
activity_fn *activity_fn;
issue_flush_fn *issue_flush_fn;
prepare_flush_fn *prepare_flush_fn;
+ softirq_done_fn *softirq_done_fn;
/*
* Dispatch queue sorting
@@ -592,7 +595,6 @@ extern void generic_make_request(struct bio *bio);
extern void blk_put_request(struct request *);
extern void __blk_put_request(request_queue_t *, struct request *);
extern void blk_end_sync_rq(struct request *rq, int error);
-extern void blk_attempt_remerge(request_queue_t *, struct request *);
extern struct request *blk_get_request(request_queue_t *, int, gfp_t);
extern void blk_insert_request(request_queue_t *, struct request *, int, void *);
extern void blk_requeue_request(request_queue_t *, struct request *);
@@ -646,6 +648,17 @@ extern int end_that_request_first(struct request *, int, int);
extern int end_that_request_chunk(struct request *, int, int);
extern void end_that_request_last(struct request *, int);
extern void end_request(struct request *req, int uptodate);
+extern void blk_complete_request(struct request *);
+
+static inline int rq_all_done(struct request *rq, unsigned int nr_bytes)
+{
+ if (blk_fs_request(rq))
+ return (nr_bytes >= (rq->hard_nr_sectors << 9));
+ else if (blk_pc_request(rq))
+ return nr_bytes >= rq->data_len;
+
+ return 0;
+}
/*
* end_that_request_first/chunk() takes an uptodate argument. we account
@@ -694,6 +707,7 @@ extern void blk_queue_segment_boundary(request_queue_t *, unsigned long);
extern void blk_queue_prep_rq(request_queue_t *, prep_rq_fn *pfn);
extern void blk_queue_merge_bvec(request_queue_t *, merge_bvec_fn *);
extern void blk_queue_dma_alignment(request_queue_t *, int);
+extern void blk_queue_softirq_done(request_queue_t *, softirq_done_fn *);
extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
extern int blk_queue_ordered(request_queue_t *, unsigned, prepare_flush_fn *);
extern void blk_queue_issue_flush_fn(request_queue_t *, issue_flush_fn *);
diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h
index 119f9d064cc6..339878952f12 100644
--- a/include/linux/compat_ioctl.h
+++ b/include/linux/compat_ioctl.h
@@ -218,32 +218,6 @@ COMPATIBLE_IOCTL(VT_RESIZE)
COMPATIBLE_IOCTL(VT_RESIZEX)
COMPATIBLE_IOCTL(VT_LOCKSWITCH)
COMPATIBLE_IOCTL(VT_UNLOCKSWITCH)
-/* Little v */
-/* Little v, the video4linux ioctls (conflict?) */
-COMPATIBLE_IOCTL(VIDIOCGCAP)
-COMPATIBLE_IOCTL(VIDIOCGCHAN)
-COMPATIBLE_IOCTL(VIDIOCSCHAN)
-COMPATIBLE_IOCTL(VIDIOCGPICT)
-COMPATIBLE_IOCTL(VIDIOCSPICT)
-COMPATIBLE_IOCTL(VIDIOCCAPTURE)
-COMPATIBLE_IOCTL(VIDIOCKEY)
-COMPATIBLE_IOCTL(VIDIOCGAUDIO)
-COMPATIBLE_IOCTL(VIDIOCSAUDIO)
-COMPATIBLE_IOCTL(VIDIOCSYNC)
-COMPATIBLE_IOCTL(VIDIOCMCAPTURE)
-COMPATIBLE_IOCTL(VIDIOCGMBUF)
-COMPATIBLE_IOCTL(VIDIOCGUNIT)
-COMPATIBLE_IOCTL(VIDIOCGCAPTURE)
-COMPATIBLE_IOCTL(VIDIOCSCAPTURE)
-/* BTTV specific... */
-COMPATIBLE_IOCTL(_IOW('v', BASE_VIDIOCPRIVATE+0, char [256]))
-COMPATIBLE_IOCTL(_IOR('v', BASE_VIDIOCPRIVATE+1, char [256]))
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int))
-COMPATIBLE_IOCTL(_IOW('v' , BASE_VIDIOCPRIVATE+3, char [16])) /* struct bttv_pll_info */
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+4, int))
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+5, int))
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+6, int))
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+7, int))
/* Little p (/dev/rtc, /dev/envctrl, etc.) */
COMPATIBLE_IOCTL(RTC_AIE_ON)
COMPATIBLE_IOCTL(RTC_AIE_OFF)
diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h
index d41df7047ed7..c8cbd90ba375 100644
--- a/include/linux/dvb/frontend.h
+++ b/include/linux/dvb/frontend.h
@@ -240,6 +240,15 @@ struct dvb_frontend_event {
};
+/**
+ * When set, this flag will disable any zigzagging or other "normal" tuning
+ * behaviour. Additionally, there will be no automatic monitoring of the lock
+ * status, and hence no frontend events will be generated. If a frontend device
+ * is closed, this flag will be automatically turned off when the device is
+ * reopened read-write.
+ */
+#define FE_TUNE_MODE_ONESHOT 0x01
+
#define FE_GET_INFO _IOR('o', 61, struct dvb_frontend_info)
@@ -260,6 +269,7 @@ struct dvb_frontend_event {
#define FE_SET_FRONTEND _IOW('o', 76, struct dvb_frontend_parameters)
#define FE_GET_FRONTEND _IOR('o', 77, struct dvb_frontend_parameters)
+#define FE_SET_FRONTEND_TUNE_MODE _IO('o', 81) /* unsigned int */
#define FE_GET_EVENT _IOR('o', 78, struct dvb_frontend_event)
#define FE_DISHNETWORK_SEND_LEGACY_CMD _IO('o', 80) /* unsigned int */
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index fb80fa44c4dd..4a6f50e31c73 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -114,8 +114,6 @@ extern ssize_t elv_iosched_store(request_queue_t *, const char *, size_t);
extern int elevator_init(request_queue_t *, char *);
extern void elevator_exit(elevator_t *);
extern int elv_rq_merge_ok(struct request *, struct bio *);
-extern int elv_try_merge(struct request *, struct bio *);
-extern int elv_try_last_merge(request_queue_t *, struct bio *);
/*
* Return values from elevator merger
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index fb46f8d56999..6ff2d365895f 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -103,6 +103,7 @@
#define I2C_DRIVERID_SAA711X 73 /* saa711x video encoders */
#define I2C_DRIVERID_AKITAIOEXP 74 /* IO Expander on Sharp SL-C1000 */
#define I2C_DRIVERID_INFRARED 75 /* I2C InfraRed on Video boards */
+#define I2C_DRIVERID_TVP5150 76 /* TVP5150 video decoder */
#define I2C_DRIVERID_I2CDEV 900
#define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 4dd6694963c0..ef8d0cbb832f 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -1001,6 +1001,7 @@ extern int noautodma;
extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs);
extern int __ide_end_request (ide_drive_t *drive, struct request *rq, int uptodate, int nrsecs);
+extern void ide_softirq_done(struct request *rq);
/*
* This is used on exit from the driver to designate the next irq handler
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index e50a95fbeb11..2c08fdc2bdf7 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -112,7 +112,7 @@ enum
TIMER_SOFTIRQ,
NET_TX_SOFTIRQ,
NET_RX_SOFTIRQ,
- SCSI_SOFTIRQ,
+ BLOCK_SOFTIRQ,
TASKLET_SOFTIRQ
};
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index aef6042f8f0b..ccd3e13de1e8 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -27,14 +27,15 @@ struct mmc_command {
#define MMC_RSP_MASK (3 << 0)
#define MMC_RSP_CRC (1 << 3) /* expect valid crc */
#define MMC_RSP_BUSY (1 << 4) /* card may send busy */
+#define MMC_RSP_OPCODE (1 << 5) /* response contains opcode */
/*
* These are the response types, and correspond to valid bit
* patterns of the above flags. One additional valid pattern
* is all zeros, which means we don't expect a response.
*/
-#define MMC_RSP_R1 (MMC_RSP_SHORT|MMC_RSP_CRC)
-#define MMC_RSP_R1B (MMC_RSP_SHORT|MMC_RSP_CRC|MMC_RSP_BUSY)
+#define MMC_RSP_R1 (MMC_RSP_SHORT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+#define MMC_RSP_R1B (MMC_RSP_SHORT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY)
#define MMC_RSP_R2 (MMC_RSP_LONG|MMC_RSP_CRC)
#define MMC_RSP_R3 (MMC_RSP_SHORT)
#define MMC_RSP_R6 (MMC_RSP_SHORT|MMC_RSP_CRC)
@@ -64,6 +65,7 @@ struct mmc_data {
#define MMC_DATA_WRITE (1 << 8)
#define MMC_DATA_READ (1 << 9)
#define MMC_DATA_STREAM (1 << 10)
+#define MMC_DATA_MULTI (1 << 11)
unsigned int bytes_xfered;
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index e2a089b051ed..d27a78b71297 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -196,6 +196,7 @@
#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */
#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */
#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */
+#define PCI_CAP_ID_HT_IRQCONF 0x08 /* HyperTransport IRQ Configuration */
#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */
#define PCI_CAP_ID_EXP 0x10 /* PCI Express */
#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */
diff --git a/include/linux/pmu.h b/include/linux/pmu.h
index 373bd3b9b330..217d3daf7336 100644
--- a/include/linux/pmu.h
+++ b/include/linux/pmu.h
@@ -140,7 +140,7 @@ extern int find_via_pmu(void);
extern int pmu_request(struct adb_request *req,
void (*done)(struct adb_request *), int nbytes, ...);
-
+extern int pmu_queue_request(struct adb_request *req);
extern void pmu_poll(void);
extern void pmu_poll_adb(void); /* For use by xmon */
extern void pmu_wait_complete(struct adb_request *req);
@@ -160,12 +160,6 @@ extern void pmu_unlock(void);
extern int pmu_present(void);
extern int pmu_get_model(void);
-extern int pmu_i2c_combined_read(int bus, int addr, int subaddr, u8* data, int len);
-extern int pmu_i2c_stdsub_write(int bus, int addr, int subaddr, u8* data, int len);
-extern int pmu_i2c_simple_read(int bus, int addr, u8* data, int len);
-extern int pmu_i2c_simple_write(int bus, int addr, u8* data, int len);
-
-
#ifdef CONFIG_PM
/*
* Stuff for putting the powerbook to sleep and waking it again.
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 51747cd88d1a..a1d26cb28925 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -125,36 +125,7 @@ static inline void rcu_bh_qsctr_inc(int cpu)
rdp->passed_quiesc = 1;
}
-static inline int __rcu_pending(struct rcu_ctrlblk *rcp,
- struct rcu_data *rdp)
-{
- /* This cpu has pending rcu entries and the grace period
- * for them has completed.
- */
- if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch))
- return 1;
-
- /* This cpu has no pending entries, but there are new entries */
- if (!rdp->curlist && rdp->nxtlist)
- return 1;
-
- /* This cpu has finished callbacks to invoke */
- if (rdp->donelist)
- return 1;
-
- /* The rcu core waits for a quiescent state from the cpu */
- if (rdp->quiescbatch != rcp->cur || rdp->qs_pending)
- return 1;
-
- /* nothing to do */
- return 0;
-}
-
-static inline int rcu_pending(int cpu)
-{
- return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) ||
- __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu));
-}
+extern int rcu_pending(int cpu);
/**
* rcu_read_lock - mark the beginning of an RCU read-side critical section.
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index e910d1a481df..3eed47347013 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -514,4 +514,9 @@ asmlinkage long sys_set_mempolicy(int mode, unsigned long __user *nmask,
asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode,
const unsigned long __user *from, const unsigned long __user *to);
+asmlinkage long sys_spu_run(int fd, __u32 __user *unpc,
+ __u32 __user *ustatus);
+asmlinkage long sys_spu_create(const char __user *name,
+ unsigned int flags, mode_t mode);
+
#endif
diff --git a/include/linux/video_decoder.h b/include/linux/video_decoder.h
index 0e9e48b83e3b..121e26da2c18 100644
--- a/include/linux/video_decoder.h
+++ b/include/linux/video_decoder.h
@@ -1,6 +1,8 @@
#ifndef _LINUX_VIDEO_DECODER_H
#define _LINUX_VIDEO_DECODER_H
+#define HAVE_VIDEO_DECODER 1
+
struct video_decoder_capability { /* this name is too long */
__u32 flags;
#define VIDEO_DECODER_PAL 1 /* can decode PAL signal */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 1cded681eb6d..ce40675324bd 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -642,6 +642,12 @@ typedef __u64 v4l2_std_id;
#define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000)
#define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000)
+/* some merged standards */
+#define V4L2_STD_MN (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC)
+#define V4L2_STD_B (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B)
+#define V4L2_STD_GH (V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H)
+#define V4L2_STD_DK (V4L2_STD_PAL_DK|V4L2_STD_SECAM_DK)
+
/* some common needed stuff */
#define V4L2_STD_PAL_BG (V4L2_STD_PAL_B |\
V4L2_STD_PAL_B1 |\
@@ -662,7 +668,8 @@ typedef __u64 v4l2_std_id;
V4L2_STD_SECAM_G |\
V4L2_STD_SECAM_H |\
V4L2_STD_SECAM_DK |\
- V4L2_STD_SECAM_L)
+ V4L2_STD_SECAM_L |\
+ V4L2_STD_SECAM_LC)
#define V4L2_STD_525_60 (V4L2_STD_PAL_M |\
V4L2_STD_PAL_60 |\
@@ -888,7 +895,6 @@ struct v4l2_audio
/* Flags for the 'mode' field */
#define V4L2_AUDMODE_AVL 0x00001
-#define V4L2_AUDMODE_32BITS 0x00002
struct v4l2_audioout
{
@@ -1110,7 +1116,6 @@ int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local);
/* names for fancy debug output */
extern char *v4l2_field_names[];
extern char *v4l2_type_names[];
-extern char *v4l2_ioctl_names[];
/* Compatibility layer interface -- v4l1-compat module */
typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file,
@@ -1118,6 +1123,11 @@ typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file,
int v4l_compat_translate_ioctl(struct inode *inode, struct file *file,
int cmd, void *arg, v4l2_kioctl driver_ioctl);
+/* 32 Bits compatibility layer for 64 bits processors */
+extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd,
+ unsigned long arg);
+
+
#endif /* __KERNEL__ */
#endif /* __LINUX_VIDEODEV2_H */
diff --git a/include/media/audiochip.h b/include/media/audiochip.h
index b7d4b0930408..295d256ee811 100644
--- a/include/media/audiochip.h
+++ b/include/media/audiochip.h
@@ -23,11 +23,6 @@ enum audiochip {
/* ---------------------------------------------------------------------- */
-/* v4l device was opened in Radio mode */
-#define AUDC_SET_RADIO _IO('m',2)
-/* select from TV,radio,extern,MUTE */
-#define AUDC_SET_INPUT _IOW('m',17,int)
-
/* audio inputs */
#define AUDIO_TUNER 0x00
#define AUDIO_RADIO 0x01
@@ -40,15 +35,4 @@ enum audiochip {
#define AUDIO_MUTE 0x80
#define AUDIO_UNMUTE 0x81
-/* all the stuff below is obsolete and just here for reference. I'll
- * remove it once the driver is tested and works fine.
- *
- * Instead creating alot of tiny API's for all kinds of different
- * chips, we'll just pass throuth the v4l ioctl structs (v4l2 not
- * yet...). It is a bit less flexible, but most/all used i2c chips
- * make sense in v4l context only. So I think that's acceptable...
- */
-
-/* misc stuff to pass around config info to i2c chips */
-#define AUDC_CONFIG_PINNACLE _IOW('m',32,int)
#endif /* AUDIOCHIP_H */
diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h
index 16af9299315f..e5e749e984ee 100644
--- a/include/media/saa7146_vv.h
+++ b/include/media/saa7146_vv.h
@@ -178,6 +178,8 @@ struct saa7146_ext_vv
struct saa7146_extension_ioctls *ioctls;
int (*ioctl)(struct saa7146_fh*, unsigned int cmd, void *arg);
+
+ struct file_operations vbi_fops;
};
struct saa7146_use_ops {
diff --git a/include/media/tuner.h b/include/media/tuner.h
index b37cde606692..7674b121ce8b 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -82,9 +82,9 @@
#define TUNER_PHILIPS_FM1236_MK3 43
#define TUNER_PHILIPS_4IN1 44 /* ATI TV Wonder Pro - Conexant */
-/* Microtune mergeged with Temic 12/31/1999 partially financed by Alps - these may be similar to Temic */
+/* Microtune merged with Temic 12/31/1999 partially financed by Alps - these may be similar to Temic */
#define TUNER_MICROTUNE_4049FM5 45
-#define TUNER_MICROTUNE_4042_FI5 46
+#define TUNER_PANASONIC_VP27 46
#define TUNER_LG_NTSC_TAPE 47
#define TUNER_TNF_8831BGFF 48
@@ -102,7 +102,7 @@
#define TUNER_YMEC_TVF_8531MF 58
#define TUNER_YMEC_TVF_5533MF 59 /* Pixelview Pro Ultra NTSC */
-#define TUNER_THOMSON_DTT7611 60 /* DViCO FusionHDTV 3 Gold-T */
+#define TUNER_THOMSON_DTT761X 60 /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
#define TUNER_TENA_9533_DI 61
#define TUNER_TEA5767 62 /* Only FM Radio Tuner */
#define TUNER_PHILIPS_FMD1216ME_MK3 63
@@ -115,47 +115,26 @@
#define TUNER_PHILIPS_TUV1236D 68 /* ATI HDTV Wonder */
#define TUNER_TNF_5335MF 69 /* Sabrent Bt848 */
-#define NOTUNER 0
-#define PAL 1 /* PAL_BG */
-#define PAL_I 2
-#define NTSC 3
-#define SECAM 4
-#define ATSC 5
-#define RADIO 6
-
-#define NoTuner 0
-#define Philips 1
-#define TEMIC 2
-#define Sony 3
-#define Alps 4
-#define LGINNOTEK 5
-#define SHARP 6
-#define Samsung 7
-#define Microtune 8
-#define HITACHI 9
-#define Panasonic 10
-#define TCL 11
-#define THOMSON 12
-
-#define TUNER_SET_TYPE_ADDR _IOW('T',3,int)
-#define TUNER_SET_STANDBY _IOW('T',4,int)
-#define TDA9887_SET_CONFIG _IOW('t',5,int)
-
/* tv card specific */
-# define TDA9887_PRESENT (1<<0)
-# define TDA9887_PORT1_INACTIVE (1<<1)
-# define TDA9887_PORT2_INACTIVE (1<<2)
-# define TDA9887_QSS (1<<3)
-# define TDA9887_INTERCARRIER (1<<4)
-# define TDA9887_PORT1_ACTIVE (1<<5)
-# define TDA9887_PORT2_ACTIVE (1<<6)
-# define TDA9887_INTERCARRIER_NTSC (1<<7)
+#define TDA9887_PRESENT (1<<0)
+#define TDA9887_PORT1_INACTIVE (1<<1)
+#define TDA9887_PORT2_INACTIVE (1<<2)
+#define TDA9887_QSS (1<<3)
+#define TDA9887_INTERCARRIER (1<<4)
+#define TDA9887_PORT1_ACTIVE (1<<5)
+#define TDA9887_PORT2_ACTIVE (1<<6)
+#define TDA9887_INTERCARRIER_NTSC (1<<7)
+/* Tuner takeover point adjustment, in dB, -16 <= top <= 15 */
+#define TDA9887_TOP_MASK (0x3f << 8)
+#define TDA9887_TOP_SET (1 << 13)
+#define TDA9887_TOP(top) (TDA9887_TOP_SET | (((16 + (top)) & 0x1f) << 8))
+
/* config options */
-# define TDA9887_DEEMPHASIS_MASK (3<<16)
-# define TDA9887_DEEMPHASIS_NONE (1<<16)
-# define TDA9887_DEEMPHASIS_50 (2<<16)
-# define TDA9887_DEEMPHASIS_75 (3<<16)
-# define TDA9887_AUTOMUTE (1<<18)
+#define TDA9887_DEEMPHASIS_MASK (3<<16)
+#define TDA9887_DEEMPHASIS_NONE (1<<16)
+#define TDA9887_DEEMPHASIS_50 (2<<16)
+#define TDA9887_DEEMPHASIS_75 (3<<16)
+#define TDA9887_AUTOMUTE (1<<18)
#ifdef __KERNEL__
@@ -167,10 +146,26 @@ enum tuner_mode {
T_STANDBY = 1 << 31
};
+/* Older boards only had a single tuner device. Nowadays multiple tuner
+ devices may be present on a single board. Using TUNER_SET_TYPE_ADDR
+ to pass the tuner_setup structure it is possible to setup each tuner
+ device in turn.
+
+ Since multiple devices may be present it is no longer sufficient to
+ send a command to a single i2c device. Instead you should broadcast
+ the command to all i2c devices.
+
+ By setting the mode_mask correctly you can select which commands are
+ accepted by a specific tuner device. For example, set mode_mask to
+ T_RADIO if the device is a radio-only tuner. That specific tuner will
+ only accept commands when the tuner is in radio mode and ignore them
+ when the tuner is set to TV mode.
+ */
+
struct tuner_setup {
- unsigned short addr;
- unsigned int type;
- unsigned int mode_mask;
+ unsigned short addr; /* I2C address */
+ unsigned int type; /* Tuner type */
+ unsigned int mode_mask; /* Allowed tuner modes */
};
struct tuner {
@@ -207,7 +202,6 @@ struct tuner {
void (*standby)(struct i2c_client *c);
};
-extern unsigned int tuner_debug;
extern unsigned const int tuner_count;
extern int microtune_init(struct i2c_client *c);
@@ -219,15 +213,15 @@ extern int tea5767_autodetection(struct i2c_client *c);
#define tuner_warn(fmt, arg...) do {\
printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
- t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
#define tuner_info(fmt, arg...) do {\
printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
- t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
#define tuner_dbg(fmt, arg...) do {\
- if (tuner_debug) \
- printk(KERN_DEBUG "%s %d-%04x: " fmt, \
- t->i2c.driver->driver.name, \
- t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
+ extern int debug; \
+ if (debug) \
+ printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
#endif /* __KERNEL__ */
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index d3fd48157eb8..3cc3132f391e 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -26,12 +26,57 @@
#ifndef V4L2_COMMON_H_
#define V4L2_COMMON_H_
-/* VIDIOC_INT_AUDIO_CLOCK_FREQ */
-enum v4l2_audio_clock_freq {
- V4L2_AUDCLK_32_KHZ = 32000,
- V4L2_AUDCLK_441_KHZ = 44100,
- V4L2_AUDCLK_48_KHZ = 48000,
-};
+/* v4l debugging and diagnostics */
+
+/* Common printk constucts for v4l-i2c drivers. These macros create a unique
+ prefix consisting of the driver name, the adapter number and the i2c
+ address. */
+#define v4l_printk(level, name, adapter, addr, fmt, arg...) \
+ printk(level "%s %d-%04x: " fmt, name, i2c_adapter_id(adapter), addr , ## arg)
+
+#define v4l_client_printk(level, client, fmt, arg...) \
+ v4l_printk(level, (client)->driver->driver.name, (client)->adapter, \
+ (client)->addr, fmt , ## arg)
+
+#define v4l_err(client, fmt, arg...) \
+ v4l_client_printk(KERN_ERR, client, fmt , ## arg)
+
+#define v4l_warn(client, fmt, arg...) \
+ v4l_client_printk(KERN_WARNING, client, fmt , ## arg)
+
+#define v4l_info(client, fmt, arg...) \
+ v4l_client_printk(KERN_INFO, client, fmt , ## arg)
+
+/* These three macros assume that the debug level is set with a module
+ parameter called 'debug'. */
+#define v4l_dbg(level, client, fmt, arg...) \
+ do { \
+ extern int debug; \
+ if (debug >= (level)) \
+ v4l_client_printk(KERN_DEBUG, client, fmt , ## arg); \
+ } while (0)
+
+/* Prints the ioctl in a human-readable format */
+extern void v4l_printk_ioctl(unsigned int cmd);
+
+/* Use this macro for non-I2C drivers. Pass the driver name as the first arg. */
+#define v4l_print_ioctl(name, cmd) \
+ do { \
+ printk(KERN_DEBUG "%s: ", name); \
+ v4l_printk_ioctl(cmd); \
+ } while (0)
+
+/* Use this macro in I2C drivers where 'client' is the struct i2c_client
+ pointer */
+#define v4l_i2c_print_ioctl(client, cmd) \
+ do { \
+ v4l_client_printk(KERN_DEBUG, client, ""); \
+ v4l_printk_ioctl(cmd); \
+ } while (0)
+
+/* ------------------------------------------------------------------------- */
+
+/* Internal ioctls */
/* VIDIOC_INT_G_REGISTER and VIDIOC_INT_S_REGISTER */
struct v4l2_register {
@@ -70,6 +115,20 @@ enum v4l2_chip_ident {
V4L2_IDENT_CX25843 = 243,
};
+/* audio ioctls */
+/* v4l device was opened in Radio mode */
+#define AUDC_SET_RADIO _IO('d',88)
+/* select from TV,radio,extern,MUTE */
+#define AUDC_SET_INPUT _IOW('d',89,int)
+
+/* tuner ioctls */
+/* Sets tuner type and its I2C addr */
+#define TUNER_SET_TYPE_ADDR _IOW('d',90,int)
+/* Puts tuner on powersaving state, disabling it, except for i2c */
+#define TUNER_SET_STANDBY _IOW('d',91,int)
+/* Sets tda9887 specific stuff, like port1, port2 and qss */
+#define TDA9887_SET_CONFIG _IOW('d',92,int)
+
/* only implemented if CONFIG_VIDEO_ADV_DEBUG is defined */
#define VIDIOC_INT_S_REGISTER _IOR ('d', 100, struct v4l2_register)
#define VIDIOC_INT_G_REGISTER _IOWR('d', 101, struct v4l2_register)
@@ -77,10 +136,12 @@ enum v4l2_chip_ident {
/* Reset the I2C chip */
#define VIDIOC_INT_RESET _IO ('d', 102)
-/* Set the frequency of the audio clock output.
+/* Set the frequency (in Hz) of the audio clock output.
Used to slave an audio processor to the video decoder, ensuring that audio
- and video remain synchronized. */
-#define VIDIOC_INT_AUDIO_CLOCK_FREQ _IOR ('d', 103, enum v4l2_audio_clock_freq)
+ and video remain synchronized.
+ Usual values for the frequency are 48000, 44100 or 32000 Hz.
+ If the frequency is not supported, then -EINVAL is returned. */
+#define VIDIOC_INT_AUDIO_CLOCK_FREQ _IOW ('d', 103, u32)
/* Video decoders that support sliced VBI need to implement this ioctl.
Field p of the v4l2_sliced_vbi_line struct is set to the start of the VBI
@@ -107,4 +168,10 @@ enum v4l2_chip_ident {
be made. */
#define VIDIOC_INT_G_CHIP_IDENT _IOR ('d', 107, enum v4l2_chip_ident *)
+/* Sets I2S speed in bps. This is used to provide a standard way to select I2S
+ clock used by driving digital audio streams at some board designs.
+ Usual values for the frequency are 1024000 and 2048000.
+ If the frequency is not supported, then -EINVAL is returned. */
+#define VIDIOC_INT_I2S_CLOCK_FREQ _IOW ('d', 108, u32)
+
#endif /* V4L2_COMMON_H_ */
diff --git a/include/video/cyblafb.h b/include/video/cyblafb.h
index a9948232b131..717440575380 100644
--- a/include/video/cyblafb.h
+++ b/include/video/cyblafb.h
@@ -153,6 +153,10 @@
#define GE04 (GEBase+0x04) // source 2, p 111
#define GE08 (GEBase+0x08) // destination 1, p 111
#define GE0C (GEBase+0x0C) // destination 2, p 112
+#define GE10 (GEBase+0x10) // right view base & enable, p 112
+#define GE13 (GEBase+0x13) // left view base & enable, p 112
+#define GE18 (GEBase+0x18) // block write start address, p 112
+#define GE1C (GEBase+0x1C) // block write end address, p 112
#define GE20 (GEBase+0x20) // engine status, p 113
#define GE24 (GEBase+0x24) // reset all GE pointers
#define GE44 (GEBase+0x44) // command register, p 126
diff --git a/kernel/crash_dump.c b/kernel/crash_dump.c
index 334c37f5218a..fccb27dbc623 100644
--- a/kernel/crash_dump.c
+++ b/kernel/crash_dump.c
@@ -14,10 +14,12 @@
#include <asm/io.h>
#include <asm/uaccess.h>
+#include <asm/kexec.h>
/* Stores the physical address of elf header of crash image. */
unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
+#ifndef HAVE_ARCH_COPY_OLDMEM_PAGE
/**
* copy_oldmem_page - copy one page from "oldmem"
* @pfn: page frame number to be copied
@@ -59,3 +61,4 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
kfree(page);
return csize;
}
+#endif
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 30b0bba03859..ccc45d49ce71 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -429,6 +429,36 @@ static void rcu_process_callbacks(unsigned long unused)
&__get_cpu_var(rcu_bh_data));
}
+static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
+{
+ /* This cpu has pending rcu entries and the grace period
+ * for them has completed.
+ */
+ if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch))
+ return 1;
+
+ /* This cpu has no pending entries, but there are new entries */
+ if (!rdp->curlist && rdp->nxtlist)
+ return 1;
+
+ /* This cpu has finished callbacks to invoke */
+ if (rdp->donelist)
+ return 1;
+
+ /* The rcu core waits for a quiescent state from the cpu */
+ if (rdp->quiescbatch != rcp->cur || rdp->qs_pending)
+ return 1;
+
+ /* nothing to do */
+ return 0;
+}
+
+int rcu_pending(int cpu)
+{
+ return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) ||
+ __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu));
+}
+
void rcu_check_callbacks(int cpu, int user)
{
if (user ||
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index bd3b9bfcfcec..17313b99e53d 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -112,3 +112,5 @@ cond_syscall(sys_pciconfig_iobase);
cond_syscall(sys32_ipc);
cond_syscall(sys32_sysctl);
cond_syscall(ppc_rtas);
+cond_syscall(sys_spu_run);
+cond_syscall(sys_spu_create);
diff --git a/mm/memory.c b/mm/memory.c
index 7197f9bcd384..3944fec38012 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2267,6 +2267,8 @@ int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
return handle_pte_fault(mm, vma, address, pte, pmd, write_access);
}
+EXPORT_SYMBOL_GPL(__handle_mm_fault);
+
#ifndef __PAGETABLE_PUD_FOLDED
/*
* Allocate page upper directory.
diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c
index 073aebdf0f67..f8dca31be5dd 100644
--- a/net/ieee80211/ieee80211_crypt_wep.c
+++ b/net/ieee80211/ieee80211_crypt_wep.c
@@ -75,22 +75,14 @@ static void prism2_wep_deinit(void *priv)
kfree(priv);
}
-/* Perform WEP encryption on given skb that has at least 4 bytes of headroom
- * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
- * so the payload length increases with 8 bytes.
- *
- * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
- */
-static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+/* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */
+static int prism2_wep_build_iv(struct sk_buff *skb, int hdr_len, void *priv)
{
struct prism2_wep_data *wep = priv;
- u32 crc, klen, len;
- u8 key[WEP_KEY_LEN + 3];
- u8 *pos, *icv;
- struct scatterlist sg;
-
- if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
- skb->len < hdr_len)
+ u32 klen, len;
+ u8 *pos;
+
+ if (skb_headroom(skb) < 4 || skb->len < hdr_len)
return -1;
len = skb->len - hdr_len;
@@ -112,15 +104,47 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
}
/* Prepend 24-bit IV to RC4 key and TX frame */
- *pos++ = key[0] = (wep->iv >> 16) & 0xff;
- *pos++ = key[1] = (wep->iv >> 8) & 0xff;
- *pos++ = key[2] = wep->iv & 0xff;
+ *pos++ = (wep->iv >> 16) & 0xff;
+ *pos++ = (wep->iv >> 8) & 0xff;
+ *pos++ = wep->iv & 0xff;
*pos++ = wep->key_idx << 6;
+ return 0;
+}
+
+/* Perform WEP encryption on given skb that has at least 4 bytes of headroom
+ * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
+ * so the payload length increases with 8 bytes.
+ *
+ * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
+ */
+static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+ struct prism2_wep_data *wep = priv;
+ u32 crc, klen, len;
+ u8 *pos, *icv;
+ struct scatterlist sg;
+ u8 key[WEP_KEY_LEN + 3];
+
+ /* other checks are in prism2_wep_build_iv */
+ if (skb_tailroom(skb) < 4)
+ return -1;
+
+ /* add the IV to the frame */
+ if (prism2_wep_build_iv(skb, hdr_len, priv))
+ return -1;
+
+ /* Copy the IV into the first 3 bytes of the key */
+ memcpy(key, skb->data + hdr_len, 3);
+
/* Copy rest of the WEP key (the secret part) */
memcpy(key + 3, wep->key, wep->key_len);
+
+ len = skb->len - hdr_len - 4;
+ pos = skb->data + hdr_len + 4;
+ klen = 3 + wep->key_len;
- /* Append little-endian CRC32 and encrypt it to produce ICV */
+ /* Append little-endian CRC32 over only the data and encrypt it to produce ICV */
crc = ~crc32_le(~0, pos, len);
icv = skb_put(skb, 4);
icv[0] = crc;
@@ -231,6 +255,7 @@ static struct ieee80211_crypto_ops ieee80211_crypt_wep = {
.name = "WEP",
.init = prism2_wep_init,
.deinit = prism2_wep_deinit,
+ .build_iv = prism2_wep_build_iv,
.encrypt_mpdu = prism2_wep_encrypt,
.decrypt_mpdu = prism2_wep_decrypt,
.encrypt_msdu = NULL,
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
index 445f206e65e0..e5b33c8d5dbc 100644
--- a/net/ieee80211/ieee80211_tx.c
+++ b/net/ieee80211/ieee80211_tx.c
@@ -288,7 +288,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
/* Determine total amount of storage required for TXB packets */
bytes = skb->len + SNAP_SIZE + sizeof(u16);
- if (host_encrypt)
+ if (host_encrypt || host_build_iv)
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
IEEE80211_FCTL_PROTECTED;
else
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index 181755f2aa8b..406d5b964905 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -284,7 +284,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
};
int i, key, key_provided, len;
struct ieee80211_crypt_data **crypt;
- int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
+ int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
IEEE80211_DEBUG_WX("SET_ENCODE\n");
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 7849cac14d3a..a67f1b44c9a3 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -402,7 +402,7 @@ static int netlink_create(struct socket *sock, int protocol)
groups = nl_table[protocol].groups;
netlink_unlock_table();
- if ((err = __netlink_create(sock, protocol) < 0))
+ if ((err = __netlink_create(sock, protocol)) < 0)
goto out_module;
nlk = nlk_sk(sock->sk);
diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
index cebd881b91ae..74f975676ccb 100644
--- a/sound/oss/dmasound/dmasound_awacs.c
+++ b/sound/oss/dmasound/dmasound_awacs.c
@@ -125,6 +125,7 @@ static int awacs_rate_index;
static int awacs_subframe;
static struct device_node* awacs_node;
static struct device_node* i2s_node;
+static struct resource awacs_rsrc[3];
static char awacs_name[64];
static int awacs_revision;
@@ -667,9 +668,12 @@ static void PMacIrqCleanup(void)
iounmap(awacs_txdma);
iounmap(awacs_rxdma);
- release_OF_resource(awacs_node, 0);
- release_OF_resource(awacs_node, 1);
- release_OF_resource(awacs_node, 2);
+ release_mem_region(awacs_rsrc[0].start,
+ awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
+ release_mem_region(awacs_rsrc[1].start,
+ awacs_rsrc[1].end - awacs_rsrc[1].start + 1);
+ release_mem_region(awacs_rsrc[2].start,
+ awacs_rsrc[2].end - awacs_rsrc[2].start + 1);
kfree(awacs_tx_cmd_space);
kfree(awacs_rx_cmd_space);
@@ -2863,46 +2867,58 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n");
* other info if necessary (early AWACS we want to read chip ids)
*/
- if (io->n_addrs < 3 || io->n_intrs < 3) {
+ if (of_get_address(io, 2, NULL, NULL) == NULL || io->n_intrs < 3) {
/* OK - maybe we need to use the 'awacs' node (on earlier
* machines).
- */
+ */
if (awacs_node) {
io = awacs_node ;
- if (io->n_addrs < 3 || io->n_intrs < 3) {
- printk("dmasound_pmac: can't use %s"
- " (%d addrs, %d intrs)\n",
- io->full_name, io->n_addrs, io->n_intrs);
+ if (of_get_address(io, 2, NULL, NULL) == NULL ||
+ io->n_intrs < 3) {
+ printk("dmasound_pmac: can't use %s\n",
+ io->full_name);
return -ENODEV;
}
- } else {
- printk("dmasound_pmac: can't use %s (%d addrs, %d intrs)\n",
- io->full_name, io->n_addrs, io->n_intrs);
- }
+ } else
+ printk("dmasound_pmac: can't use %s\n", io->full_name);
}
- if (!request_OF_resource(io, 0, NULL)) {
+ if (of_address_to_resource(io, 0, &awacs_rsrc[0]) ||
+ request_mem_region(awacs_rsrc[0].start,
+ awacs_rsrc[0].end - awacs_rsrc[0].start + 1,
+ " (IO)") == NULL) {
printk(KERN_ERR "dmasound: can't request IO resource !\n");
return -ENODEV;
}
- if (!request_OF_resource(io, 1, " (tx dma)")) {
- release_OF_resource(io, 0);
- printk(KERN_ERR "dmasound: can't request TX DMA resource !\n");
+ if (of_address_to_resource(io, 1, &awacs_rsrc[1]) ||
+ request_mem_region(awacs_rsrc[1].start,
+ awacs_rsrc[1].end - awacs_rsrc[1].start + 1,
+ " (tx dma)") == NULL) {
+ release_mem_region(awacs_rsrc[0].start,
+ awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
+ printk(KERN_ERR "dmasound: can't request Tx DMA resource !\n");
return -ENODEV;
}
-
- if (!request_OF_resource(io, 2, " (rx dma)")) {
- release_OF_resource(io, 0);
- release_OF_resource(io, 1);
- printk(KERN_ERR "dmasound: can't request RX DMA resource !\n");
+ if (of_address_to_resource(io, 2, &awacs_rsrc[2]) ||
+ request_mem_region(awacs_rsrc[2].start,
+ awacs_rsrc[2].end - awacs_rsrc[2].start + 1,
+ " (rx dma)") == NULL) {
+ release_mem_region(awacs_rsrc[0].start,
+ awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
+ release_mem_region(awacs_rsrc[1].start,
+ awacs_rsrc[1].end - awacs_rsrc[1].start + 1);
+ printk(KERN_ERR "dmasound: can't request Rx DMA resource !\n");
return -ENODEV;
}
awacs_beep_dev = input_allocate_device();
if (!awacs_beep_dev) {
- release_OF_resource(io, 0);
- release_OF_resource(io, 1);
- release_OF_resource(io, 2);
+ release_mem_region(awacs_rsrc[0].start,
+ awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
+ release_mem_region(awacs_rsrc[1].start,
+ awacs_rsrc[1].end - awacs_rsrc[1].start + 1);
+ release_mem_region(awacs_rsrc[2].start,
+ awacs_rsrc[2].end - awacs_rsrc[2].start + 1);
printk(KERN_ERR "dmasound: can't allocate input device !\n");
return -ENOMEM;
}
@@ -2916,11 +2932,11 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n");
/* all OF versions I've seen use this value */
if (i2s_node)
- i2s = ioremap(io->addrs[0].address, 0x1000);
+ i2s = ioremap(awacs_rsrc[0].start, 0x1000);
else
- awacs = ioremap(io->addrs[0].address, 0x1000);
- awacs_txdma = ioremap(io->addrs[1].address, 0x100);
- awacs_rxdma = ioremap(io->addrs[2].address, 0x100);
+ awacs = ioremap(awacs_rsrc[0].start, 0x1000);
+ awacs_txdma = ioremap(awacs_rsrc[1].start, 0x100);
+ awacs_rxdma = ioremap(awacs_rsrc[2].start, 0x100);
/* first of all make sure that the chip is powered up....*/
pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, io, 0, 1);
@@ -3083,9 +3099,10 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev);
struct device_node* mio;
macio_base = NULL;
for (mio = io->parent; mio; mio = mio->parent) {
- if (strcmp(mio->name, "mac-io") == 0
- && mio->n_addrs > 0) {
- macio_base = ioremap(mio->addrs[0].address, 0x40);
+ if (strcmp(mio->name, "mac-io") == 0) {
+ struct resource r;
+ if (of_address_to_resource(mio, 0, &r) == 0)
+ macio_base = ioremap(r.start, 0x40);
break;
}
}
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index 9b2b00fdc1ae..a642e4cfcf45 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -803,21 +803,17 @@ static int snd_pmac_free(struct snd_pmac *chip)
iounmap(chip->playback.dma);
if (chip->capture.dma)
iounmap(chip->capture.dma);
-#ifndef CONFIG_PPC64
+
if (chip->node) {
int i;
-
for (i = 0; i < 3; i++) {
- if (chip->of_requested & (1 << i)) {
- if (chip->is_k2)
- release_OF_resource(chip->node->parent,
- i);
- else
- release_OF_resource(chip->node, i);
- }
+ if (chip->requested & (1 << i))
+ release_mem_region(chip->rsrc[i].start,
+ chip->rsrc[i].end -
+ chip->rsrc[i].start + 1);
}
}
-#endif /* CONFIG_PPC64 */
+
if (chip->pdev)
pci_dev_put(chip->pdev);
kfree(chip);
@@ -991,6 +987,11 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
chip->can_byte_swap = 0; /* FIXME: check this */
chip->control_mask = MASK_IEPC | 0x11;/* disable IEE */
break;
+ default:
+ printk(KERN_ERR "snd: Unknown layout ID 0x%x\n",
+ layout_id);
+ return -ENODEV;
+
}
}
prop = (unsigned int *)get_property(sound, "device-id", NULL);
@@ -1175,46 +1176,69 @@ int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
}
np = chip->node;
+ chip->requested = 0;
if (chip->is_k2) {
- if (np->parent->n_addrs < 2 || np->n_intrs < 3) {
+ static char *rnames[] = {
+ "Sound Control", "Sound DMA" };
+ if (np->n_intrs < 3) {
err = -ENODEV;
goto __error;
}
- for (i = 0; i < 2; i++) {
-#ifndef CONFIG_PPC64
- static char *name[2] = { "- Control", "- DMA" };
- if (! request_OF_resource(np->parent, i, name[i])) {
- snd_printk(KERN_ERR "pmac: can't request resource %d!\n", i);
+ for (i = 0; i < 2; i ++) {
+ if (of_address_to_resource(np->parent, i,
+ &chip->rsrc[i])) {
+ printk(KERN_ERR "snd: can't translate rsrc "
+ " %d (%s)\n", i, rnames[i]);
+ err = -ENODEV;
+ goto __error;
+ }
+ if (request_mem_region(chip->rsrc[i].start,
+ chip->rsrc[i].end -
+ chip->rsrc[i].start + 1,
+ rnames[i]) == NULL) {
+ printk(KERN_ERR "snd: can't request rsrc "
+ " %d (%s: 0x%08lx:%08lx)\n",
+ i, rnames[i], chip->rsrc[i].start,
+ chip->rsrc[i].end);
err = -ENODEV;
goto __error;
}
- chip->of_requested |= (1 << i);
-#endif /* CONFIG_PPC64 */
- ctrl_addr = np->parent->addrs[0].address;
- txdma_addr = np->parent->addrs[1].address;
- rxdma_addr = txdma_addr + 0x100;
+ chip->requested |= (1 << i);
}
-
+ ctrl_addr = chip->rsrc[0].start;
+ txdma_addr = chip->rsrc[1].start;
+ rxdma_addr = txdma_addr + 0x100;
} else {
- if (np->n_addrs < 3 || np->n_intrs < 3) {
+ static char *rnames[] = {
+ "Sound Control", "Sound Tx DMA", "Sound Rx DMA" };
+ if (np->n_intrs < 3) {
err = -ENODEV;
goto __error;
}
-
- for (i = 0; i < 3; i++) {
-#ifndef CONFIG_PPC64
- static char *name[3] = { "- Control", "- Tx DMA", "- Rx DMA" };
- if (! request_OF_resource(np, i, name[i])) {
- snd_printk(KERN_ERR "pmac: can't request resource %d!\n", i);
+ for (i = 0; i < 3; i ++) {
+ if (of_address_to_resource(np->parent, i,
+ &chip->rsrc[i])) {
+ printk(KERN_ERR "snd: can't translate rsrc "
+ " %d (%s)\n", i, rnames[i]);
+ err = -ENODEV;
+ goto __error;
+ }
+ if (request_mem_region(chip->rsrc[i].start,
+ chip->rsrc[i].end -
+ chip->rsrc[i].start + 1,
+ rnames[i]) == NULL) {
+ printk(KERN_ERR "snd: can't request rsrc "
+ " %d (%s: 0x%08lx:%08lx)\n",
+ i, rnames[i], chip->rsrc[i].start,
+ chip->rsrc[i].end);
err = -ENODEV;
goto __error;
}
- chip->of_requested |= (1 << i);
-#endif /* CONFIG_PPC64 */
- ctrl_addr = np->addrs[0].address;
- txdma_addr = np->addrs[1].address;
- rxdma_addr = np->addrs[2].address;
+ chip->requested |= (1 << i);
}
+ ctrl_addr = chip->rsrc[0].start;
+ txdma_addr = chip->rsrc[1].start;
+ rxdma_addr = chip->rsrc[2].start;
}
chip->awacs = ioremap(ctrl_addr, 0x1000);
@@ -1266,9 +1290,11 @@ int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
} else if (chip->is_pbook_G3) {
struct device_node* mio;
for (mio = chip->node->parent; mio; mio = mio->parent) {
- if (strcmp(mio->name, "mac-io") == 0
- && mio->n_addrs > 0) {
- chip->macio_base = ioremap(mio->addrs[0].address, 0x40);
+ if (strcmp(mio->name, "mac-io") == 0) {
+ struct resource r;
+ if (of_address_to_resource(mio, 0, &r) == 0)
+ chip->macio_base =
+ ioremap(r.start, 0x40);
break;
}
}
diff --git a/sound/ppc/pmac.h b/sound/ppc/pmac.h
index 086da7a18909..3a9bd4dbb9a6 100644
--- a/sound/ppc/pmac.h
+++ b/sound/ppc/pmac.h
@@ -113,7 +113,8 @@ struct snd_pmac {
unsigned int initialized : 1;
unsigned int feature_is_set : 1;
- unsigned int of_requested;
+ unsigned int requested;
+ struct resource rsrc[3];
int num_freqs;
int *freq_table;